Skip to content
/ emacs.d Public

Rewriting the old .emacs.d in org-mode, and will clean up in future

Notifications You must be signed in to change notification settings

yang-l/emacs.d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Emacs Configuration

This file re-organises the old init files

Installation

Backup existing ~/.emacs.d, and then follow by

git clone https://github.com/yang-l/emacs.d.git ~/.emacs.d

Emacs init.el

Initialisation

Load files

Path to non ELPA included lisp files

(add-to-list 'load-path "~/.emacs.d/lisp/")

Path to personal/credential info in ~/.emacs.d/private.el

(defvar default-directory                       ; default folder
  (concat (getenv "HOME") "/"))
(defvar my-win-default-directory default-directory)
(defvar my-lin-default-directory default-directory)
(defvar my-erc-nick "")                         ; ERC
(defvar my-erc-user-full-name "")
(defvar my-erc-email-userid "")
(defvar my-op/repository-directory "")          ; org-page
(defvar my-op/site-domain "")
(defvar my-op/personal-github-link "")

;; override
(when (file-exists-p (concat user-emacs-directory "private.el"))
  (load (expand-file-name "private.el" user-emacs-directory) 'no-error))

Package management

straight.el defined in init.el

Call pp-macroexpand-last-sexp to check the expanded macro done by use-package

use-package related delay-hook stuffs

;; https://github.com/jwiegley/use-package/issues/889
;; https://github.com/Ergus/EmacsConfig/blob/master/early-init.el
(defvar lo/gc-cons-default (* 1024 1024 32))
(defvar lo/gc-cons-lsp (* 1024 1024 128))

(defsubst lo/unset-gc ()
  "Defer garbage collection"
  (setq gc-cons-threshold most-positive-fixnum))
(use-package gcmh
  :defer 3
  :diminish
  :demand t
  :config (gcmh-mode 1))
;; benchmarking emacs boot sequence
(use-package benchmark-init
  :disabled                                     ; by default
  :config
  ;; To disable collection of benchmark data after init is done.
  (add-hook 'after-init-hook 'benchmark-init/deactivate))

Configuration for use-package. The packages below should be loaded first before any use-package has been invoked

(defvar backup-directory                        ; backup and autosave directory
  (if (eq system-type 'windows-nt)              ; Windows
      (concat "C:/tmp/emacs/" (user-login-name) "/")
    (expand-file-name
     (concat "~/emacs/" (user-login-name) "/")) ; Linux & Mac
    ))
(if (not (file-exists-p backup-directory))
    (make-directory backup-directory t))

(use-package no-littering                       ; keep `litter` files in one location
  :init
  (setq no-littering-var-directory (expand-file-name (convert-standard-filename "cache/var/") backup-directory)
        no-littering-etc-directory (expand-file-name (convert-standard-filename "cache/etc/") backup-directory))
  )

(use-package diminish)                          ; shorten mode-line

UTF-8 on everything

(prefer-coding-system 'utf-8-unix)              ; UTF-8 on everything
(unless (eq system-type 'windows-nt)
    (set-selection-coding-system 'utf-8))
(setq x-select-request-type                     ; pasting
    '(UTF8_STRING COMPOUND_TEXT TEXT STRING))

Variable Initialisation

(setq-default
    ad-redefinition-action 'accept              ; silence functions getting redefined messages
    column-number-mode t                        ; show cursor position
    custom-file                                 ; save customisations into a sibling file
    (no-littering-expand-etc-file-name "custom.el")
    default-major-mode 'text-mode               ; set new buffers as text files
    enable-recursive-minibuffers t              ; enable minibuffer recursive
    fill-column 80                              ; column space
    frame-title-format "emacs@%b"               ; show on title
    indent-tabs-mode nil                        ; space instead of tab
    kill-ring-max 1000                          ; kill ring size
    mouse-wheel-scroll-amount '(1 ((shift) .1)) ; scroll one line at a time
    frame-resize-pixelwise t
    read-buffer-completion-ignore-case t        ; ignore case-sensitivity
    read-file-name-completion-ignore-case t
    require-final-newline t                     ; always add a new line at the end of a file
    save-interprogram-paste-before-kill t       ; put clipboard into killring
    scroll-margin 3                             ; auto scrolling
    scroll-step 1                               ; line-by-line scrolling
    scroll-conservatively 10000                 ; do not jump to centre point in the window
    scroll-preserve-screen-position t           ; make the cursor steady when scrolling
    tab-width 2                                 ; 2 space indentation
    visible-bell 1                              ; no bell in windows
    window-combination-resize t                 ; split windows equally
    x-stretch-cursor t                          ; stretch cursor to cover wide characters
    vc-follow-symlinks t                        ; visiting a symbolic link to a file under version control
    )
(fset 'yes-or-no-p 'y-or-n-p)                   ; fast confirmation

;; tuning for very long line
(setq-default bidi-display-reordering nil)
(setq bidi-inhibit-bpa t
      long-line-threshold 1000
      large-hscroll-threshold 1000
      syntax-wholeline-max 1000)

PATH

(use-package exec-path-from-shell
  :defer 0.1
  :custom (exec-path-from-shell-arguments '("-l"))
  :config
  (when (eq system-type 'darwin)                    ; only apply to under OSX graphic and console UI
    (setq exec-path-from-shell-arguments nil
          exec-path-from-shell-check-startup-files nil)
    (exec-path-from-shell-initialize))

  (exec-path-from-shell-copy-env "SSH_AGENT_PID")   ; inherent ssh-agent from system
  (exec-path-from-shell-copy-env "SSH_AUTH_SOCK")

  (setenv "PATH"
          (concat
           (getenv "PATH")
           ))
  )

Server mode

Run Emacs as a daemon, and edit via emacsclient. emacsclient -t for terminal / emacsclient -c for graphic

(use-package server
  :disabled
  :defer 1
  :config
  (unless (and (fboundp 'server-running-p)
               (server-running-p))
    (server-start)))

Customisation

Key binding

Use the stock key bindings when possible.

(global-unset-key (kbd "C-SPC"))                ; set-mark-command
(global-unset-key (kbd "C-x f"))                ; set-fill-column
(global-unset-key (kbd "C-z"))                  ; suspend-frame

passing tmux keystrokes within emacs terminal

(defadvice terminal-init-screen
    ;; The advice is named `tmux', and is run before `terminal-init-screen' runs.
    (before tmux activate)
    ;; Docstring.  This describes the advice and is made available inside emacs;
    ;; for example when doing C-h f terminal-init-screen RET
    "Apply xterm keymap, allowing use of keys passed through tmux."
    ;; This is the elisp code that is run before `terminal-init-screen'.
    (if (getenv "TMUX")
        (let ((map (copy-keymap xterm-function-map)))
          (set-keymap-parent map (keymap-parent input-decode-map))
          (set-keymap-parent input-decode-map map))))

OSX-only key bindings

(when (eq system-type 'darwin)                  ; mac only settings
  (setq mac-option-modifier 'meta
        mac-right-option-modifier 'alt))        ; only work under gui

Browse URL

(defvar browser-path
  (cond
   ((executable-find "firefox")
    "firefox")
   ((executable-find "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome")
    "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome")))

(setq browse-url-browser-function 'browse-url-generic       ; default browser
      browse-url-generic-program  browser-path)

Emacs Setup

(add-hook 'window-setup-hook
    #'(lambda () (progn
        (mouse-avoidance-mode 'animate)         ; mouse avoidance
        (when (fboundp                          ; windmove
               'windmove-default-keybindings)
          (windmove-default-keybindings)
          (with-eval-after-load `switch-window
            (advice-add #'windmove-do-window-select
                        :after
                        #'(lambda (&rest args)
                            "Auto-reszie the window size"
                            (switch-window--auto-resize-window)))))
        (setq eval-expression-print-length nil  ; do not truncate output in the echo area
              message-log-max 10000             ; increase number of lines in *Messages*
              use-dialog-box nil)               ; disable usage of dialog box, and in echo area instead
    )))
(dolist
    (hook
     (list
      'term-exec-hook
      ))
  (add-hook hook #'redraw-display))             ; force redraw
(add-hook 'window-setup-hook
          #'(lambda ()
            (toggle-frame-fullscreen)           ; fullscreen
            (toggle-frame-maximized))           ; maximised
          t)
(when (daemonp)                                 ; when calling "emacsclient -c -n" under daemon
  (add-hook 'after-make-frame-functions
            #'(lambda (frame)
              (when (display-graphic-p frame)
                (toggle-frame-fullscreen)       ; fullscreen
                (toggle-frame-maximized)        ; maximised
                ))
            ))
; https://blog.d46.us/advanced-emacs-startup/
(add-hook 'emacs-startup-hook
          #'(lambda ()
            (message "Emacs ready in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))

(run-with-idle-timer 2 nil #'(lambda () (with-eval-after-load `gcmh (setq gcmh-high-cons-threshold lo/gc-cons-default))))    ; https://www.reddit.com/r/emacs/comments/3kqt6e/2_easy_little_known_steps_to_speed_up_emacs_start/

; https://emacs.stackexchange.com/questions/32150/how-to-add-a-timestamp-to-each-entry-in-emacs-messages-buffer
(advice-add 'message :before                    ; add timestamp in *Messages* buffer
            #'(lambda (FORMAT-STRING &rest args)
                "Advice to run before `message' that prepends a timestamp to each message."
                (if message-log-max
                    (let ((deactivate-mark nil)
                          (inhibit-read-only t))
                      (with-current-buffer "*Messages*"
                        (goto-char (point-max))
                        (if (not (bolp))
                            (newline))
                        (insert (format-time-string "[%F %T.%3N %:z] ")))))
                ))

(unless (display-graphic-p) (mouse-wheel-mode 0))   ; disable 'mouse-wheel-mode' under character-based terminal

Folder

Default folder

(setq default-directory
    (if (eq system-type 'windows-nt)
        my-win-default-directory                ; Win
    my-lin-default-directory                    ; Linux/Mac
    ))

Emacs backup folder

(setq backup-directory-alist `((".*" . ,backup-directory))
      auto-save-list-file-prefix backup-directory
      auto-save-file-name-transforms `((".*" ,backup-directory t)))
(setq make-backup-files t                       ; backup of a file the first time it is saved.
      backup-by-copying t                       ; don't clobber symlinks
      version-control t                         ; version numbers for backup files
      delete-old-versions t                     ; delete excess backup files silently
      kept-old-versions 5                       ; oldest versions to keep when a new numbered backup is made (default: 2)
      kept-new-versions 15                      ; newest versions to keep when a new numbered backup is made (default: 2)
      auto-save-default t                       ; auto-save every buffer that visits a file
      auto-save-timeout 10                      ; number of seconds idle time before auto-save (default: 30)
      auto-save-interval 200                    ; number of keystrokes between auto-saves (default: 300)
      vc-make-backup-files t                    ; backup versioned files
      )
; ignore file backups @ http://stackoverflow.com/questions/482256/
(defvar my-backup-ignore-regexps (list "\\.vcf$" "\\.gpg$")
  "*List of filename regexps to not backup")
(defun my-backup-enable-p (name)
  "Filter certain file backups"
  (when (normal-backup-enable-predicate name)
    (let ((backup t))
      (mapc (lambda (re)
              (setq backup (and backup (not (string-match re name)))))
            my-backup-ignore-regexps)
      backup)))
(setq backup-enable-predicate 'my-backup-enable-p)

Note - the .#foo files are file locks, and #foo# files are cached for auto-save (info)

Minibuffer backup

savehist - save the minibuffer histories

(use-package savehist
  :defer 0.5
  :hook (window-setup . (lambda () (savehist-mode 1)))
  :config
  (setq-default savehist-additional-variables '(kill-ring search-ring regexp-search-ring extended-command-history)
                savehist-autosave-interval 60
                history-length 10000))

Create missing parent directories

(defun create-non-existent-directory ()
  (let ((parent-directory (file-name-directory buffer-file-name)))
    (when (and (not (file-exists-p parent-directory))
               (y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory)))
      (make-directory parent-directory t))))
(add-to-list 'find-file-not-found-functions #'create-non-existent-directory)

Buildin Mode Setting

Abbrev Mode

(use-package abbrev
  :bind (("M-/"   . dabbrev-completion)
         ("C-M-/" . dabbrev-expand))
  :diminish
  :straight (:type built-in)
  :custom
  (save-abbrevs 'silently)
  (dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'"))
  :config (if (file-exists-p abbrev-file-name) (quietly-read-abbrev-file)))

Auto-compression

Open compressed files on the fly

(use-package jka-cmpr-hook
  :hook (window-setup . auto-compression-mode)
  :straight (:type built-in))

Case

(cl-loop for fn in '(downcase-region            ; enable commands
                     upcase-region
                     erase-buffer)
        do (put fn 'disabled nil))

Comint

Command interpreter

(use-package comint
  :disabled
  :hook (comint-mode . (lambda () (setq comint-scroll-show-maximum-output nil)))
  :straight (:type built-in))

Dired

(use-package dired
  :disabled
  :straight (:type built-in)
  :config
  (load "dired-x")
  ;; http://emacswiki.org/emacs/DiredOmitMode
  (setq-default dired-omit-files-p t)
  (setq dired-omit-files
        (concat dired-omit-files "\\|^\\..+$"))

  (when (string= system-type "darwin")
    (setq dired-use-ls-dired nil))

  ;; http://ann77.emacser.com/Emacs/EmacsDiredExt.html
  ;; 排序功能
  (make-local-variable  'dired-sort-map)
  (setq dired-sort-map (make-sparse-keymap))
  (define-key dired-mode-map "s" dired-sort-map)
  (define-key dired-sort-map "s"
    '(lambda () "sort by Size"
       (interactive) (dired-sort-other (concat dired-listing-switches "S"))))
  (define-key dired-sort-map "x"
    '(lambda () "sort by eXtension"
       (interactive) (dired-sort-other (concat dired-listing-switches "X"))))
  (define-key dired-sort-map "t"
    '(lambda () "sort by Time"
       (interactive) (dired-sort-other (concat dired-listing-switches "t"))))
  (define-key dired-sort-map "n"
    '(lambda () "sort by Name"
       (interactive) (dired-sort-other (concat dired-listing-switches ""))))

  ;; http://www.emacswiki.org/emacs/DiredSortDirectoriesFirst
  (defun mydired-sort ()
    "Sort dired listings with directories first."
    (save-excursion
      (let (buffer-read-only)
        (forward-line 2) ;; beyond dir. header
        (sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
      (set-buffer-modified-p nil)))
  (defadvice dired-readin
      (after dired-after-updating-hook first () activate)
    "Sort dired listings with directories first before adding marks."
    (mydired-sort))

  ;; single buffer
  (put 'dired-find-alternate-file 'disabled nil)
  ;; http://www.emacswiki.org/emacs/DiredReuseDirectoryBuffer
  (define-key dired-mode-map (kbd "^")
    (lambda () (interactive) (find-alternate-file "..")))
  ;; http://ergoemacs.org/emacs/emacs_dired_tips.html
  (define-key dired-mode-map (kbd "<return>")
    'dired-find-alternate-file)

  ;; copy split windows
  ;; C-o / C-0 o to paste the original filename
  ;; https://appsmth.appspot.com/smth/subject/Emacs/94609
  (setq dired-dwim-target t)

  (setq dired-recursive-deletes 'top            ; recursive delection
        dired-recursive-copies 'always)         ; recursive copy

  (defadvice shell-command                      ; allow running multiple async commands simultaneously
      (after shell-in-new-buffer
             (command &optional output-buffer error-buffer))
    (when (get-buffer "*Async Shell Command*")
      (with-current-buffer "*Async Shell Command*"
        (rename-uniquely))))
  (ad-activate 'shell-command)
  )

Ediff

Call ediff or ediff3 in Emace for file comparisons

(use-package ediff
  :commands (ediff ediff3)
  :hook (ediff-before-setup . (lambda () (setq ediff-saved-window-configuration (current-window-configuration))))
  :custom
  ;; horizontal window split
  (ediff-split-window-function 'split-window-horizontally)
  (ediff-merge-split-window-function 'split-window-vertically)
  (ediff-window-setup-function 'ediff-setup-windows-plain)
  :init
  (let ((restore-window-configuration
         (lambda ()
           (set-window-configuration ediff-saved-window-configuration))))
    (add-hook 'ediff-quit-hook restore-window-configuration 'append)
    (add-hook 'ediff-suspend-hook restore-window-configuration 'append))
  )

GnuTLS

(use-package gnutls
  :disabled
  :config
  (setq-default gnutls-verify-error t)          ; check tls/ssl
  (cond
   ((string-equal system-type "darwin")         ; Mac OS X
    (progn
      (add-to-list 'gnutls-trustfiles "/private/etc/ssl/cert.pem")
      )))
  )

Hideshow

Code folding

(use-package hideshow
  :disabled
  :diminish hs-minor-mode
  :hook ((prog-mode) . hs-minor-mode))

HL

Highlight the current line

(use-package hl-line
  :hook (window-setup . global-hl-line-mode)
  :init
  (custom-set-faces
   '(hl-line ((nil (:background "gray22"))))))

Imenu

(use-package imenu
  :disabled
  :config
  (set-default 'imenu-auto-rescan t))           ; automatic buffer rescan

Line Numbering

new line number mode since Emacs 26

(use-package display-line-numbers
  :hook ((prog-mode org-mode text-mode) . display-line-numbers-mode)
  :custom
  (display-line-numbers-type 'relative)
  (display-line-numbers-width-start t)
  :config
  (set-face-foreground 'line-number "#5c5c5c")
  (set-face-background 'line-number-current-line "#000000")
  (set-face-foreground 'line-number-current-line "#ababab"))

Makefile

build automation

(use-package make-mode
  :mode (("\\Makefile\\'" . makefile-mode)
         ("\\.mk\\'"      . makefile-mode)))

Markdown

Markup language often for readme

(use-package markdown-mode
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init (setq markdown-command "multimarkdown")
  :custom
  (markdown-fontify-code-blocks-natively t)
  )

Narrowing

(cl-loop for fn in '(narrow-to-defun            ; enable commands
                     narrow-to-page
                     narrow-to-region)
        do (put fn 'disabled nil))

Shell & Term

(with-eval-after-load `shell (setq-default shell-dirtrackp nil)); disable global 'shell-dirtrack-mode'
vterm

Terminal emulator inside Emacs

(use-package vterm :disabled)

(use-package vterm-toggle
  :disabled
  :custom
  (vterm-toggle-scope 'project)
  (vterm-toggle-hide-method 'reset-window-configration)
  :hook
  (vterm-toggle-show . meow-insert-mode))

saveplace

(use-package saveplace
  :defer 0.5
  :init (setq save-place-file (expand-file-name "saveplace" no-littering-var-directory))
  :hook (after-init . save-place-mode))

simple.el

(use-package simple
  :defer 1
  :diminish visual-line-mode
  :hook ((window-setup . visual-line-mode)      ; soft line warpping
         (window-setup . size-indication-mode)) ; show total buffer size
  :straight (:type built-in))

Tramp

M-x tramp-cleanup-all-connections - flush remote connections

(use-package tramp
  :init (autoload #'tramp-register-crypt-file-name-handler "tramp-crypt")
  :config
  (setq tramp-default-method "ssh"              ; faster than the default scp
        tramp-use-connection-share nil)
  (add-to-list 'tramp-remote-path 'tramp-own-remote-path)
  (tramp-set-completion-function
   "ssh"
   '((tramp-parse-sconfig "~/.ssh/config")
     ))
  (add-to-list 'backup-directory-alist          ; local backup directory for remote files
               (cons tramp-file-name-regexp (expand-file-name backup-directory)))
  )

uniquify

(use-package uniquify
  :defer 2
  :straight (:type built-in)
  :custom
  (uniquify-buffer-name-style 'post-forward)
  )

view-mode

Buffer readonly mode

(use-package view
  :bind([remap read-only-mode] . view-mode))    ; C-x C-q

which-func

(use-package which-func
  :hook ((prog-mode) .
         (lambda ()
           (run-with-idle-timer
            5 nil
            #'(lambda ()
                (unless (bound-and-true-p lsp-mode)
                  (which-function-mode))))))
  :custom (which-func-unknown ""))

winner-mode

Undo Emacs window changes

(use-package winner
  :defer 2
  :config (winner-mode))

ZapUpToChar

(use-package misc
  :commands zap-up-to-char
  :bind ([remap zap-to-char] . zap-up-to-char)  ; M-z
  :straight (:type built-in))

Style

Font

Emacs GUI font settings - https://emacs-china.org/t/emacs/15676

(when (display-graphic-p)
  (add-hook
   'window-setup-hook
   #'(lambda ()
       (cond
        ((eq system-type 'windows-nt)           ; Win
         (set-face-attribute 'default nil :font "Consolas:antialias=natural" :height 100))
        ((eq system-type 'gnu/linux)            ; Linux
         (cond
          ((find-font (font-spec :name "Terminus"))
           (set-face-attribute 'default nil :font "Terminus" :height 120))
          ((find-font (font-spec :maker "misc"
                                 :family "fixed"
                                 :widthtype "normal"
                                 :pixels "14"
                                 :height "130"
                                 :horiz "75"
                                 :vert "75"
                                 ))             ; fallback to "7x14" bitmap
           ; 7x14 / -misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1
           (set-face-attribute 'default nil :font "7x14"))
          )
         (when (member "WenQuanYi Zen Hei Sharp" (font-family-list))
           (set-fontset-font "fontset-default"  ; 中文字体
                             'han '("WenQuanYi Zen Hei Sharp" . "unicode-bmp"))))
        ((eq system-type 'darwin)               ; macOS
         (set-face-attribute 'default nil :font "Monaco" :height 120))
        (t                                      ; default
         (when (member "Inconsolata" (font-family-list))
           (set-face-attribute 'default nil :font "Inconsolata" :height 120)))
        )
       )))

(when (daemonp)                                 ; for emacsclient -c
  (add-hook 'after-make-frame-functions
            #'(lambda (frame)
                (select-frame frame)
                (cond
                 ((eq system-type 'darwin)      ; macOS
                  (set-face-attribute 'default nil :font "Monaco" :height 120))
                 (t                             ; default
                  (when (member "Inconsolata" (font-family-list))
                    (set-face-attribute 'default nil :font "Inconsolata" :height 120)))
                 )
                )))

Theme

Spacemacs dark theme

(add-hook
 'window-setup-hook
 #'(lambda ()
     ;; when failed in use-package, remove `README.el*` and reopen this file again
     (use-package spacemacs-theme
       :defer t
       :init
       (custom-set-variables
        '(spacemacs-theme-custom-colors
          '((border . "#4f4f4f"))))
       (load-theme 'spacemacs-dark t))

     (when (eq system-type 'darwin)             ; mac only
       (when (display-graphic-p)                ; gui only
         (let ((win-sys (window-system)))
           (when (eq win-sys 'ns)               ; emacs ns port
             (setq
              x-colors (ns-list-colors)         ; fix macports emacs-app port bug
              ns-use-thin-smoothing t
              )
             )))

       (when (daemonp)                          ; for emacsclient -c
         (add-hook 'after-make-frame-functions
                   #'(lambda (frame)
                       (select-frame frame)
                       (when (display-graphic-p frame)
                         (let ((win-sys (window-system)))
                           (when (eq win-sys 'ns)           ; emacs ns port
                             (setq
                              x-colors (ns-list-colors)     ; fix macports emacs-app port bug
                              ns-use-thin-smoothing t
                              )
                             ))))
                   ))
       )
     ))

Transparent

(set-frame-parameter
    (selected-frame) 'alpha '(98 98))

Development

(defun modes/prog-mode ()
    "prog-mode hook"
    (setq
        compilation-ask-about-save nil          ; save before compiling
        compilation-always-kill t               ; always kill old compile processes before
                                                ; starting the new one
        compilation-scroll-output 'first-error  ; Automatically scroll to first error
      )
    (goto-address-prog-mode)                    ; highlight URL
    (push '(">=" . ?≥) prettify-symbols-alist)  ; prettify symbols
    (push '("<=" . ?≤) prettify-symbols-alist)
    (push '("delta" . ) prettify-symbols-alist)
    (prettify-symbols-mode)
    (local-set-key (kbd "RET") 'newline-and-indent)

    ; (defconst intellij-java-style               ; coding style
    ;   '((c-basic-offset . 4)
    ;     (c-comment-only-line-offset . (0 . 0))
    ;     (c-offsets-alist
    ;      .
    ;      ((inline-open . 0)
    ;       (topmost-intro-cont    . +)
    ;       (statement-block-intro . +)
    ;       (knr-argdecl-intro     . +)
    ;       (substatement-open     . +)
    ;       (substatement-label    . +)
    ;       (case-label            . +)
    ;       (label                 . +)
    ;       (statement-case-open   . +)
    ;       (statement-cont        . ++)
    ;       (arglist-intro         . 0)
    ;       (arglist-cont-nonempty . ++)
    ;       (arglist-close         . --)
    ;       (inexpr-class          . 0)
    ;       (access-label          . 0)
    ;       (inher-intro           . ++)
    ;       (inher-cont            . ++)
    ;       (brace-list-intro      . +)
    ;       (func-decl-cont        . ++))))
    ;   "Elasticsearch's Intellij Java Programming Style")
    ; (c-add-style "intellij" intellij-java-style)
    )
(add-hook 'prog-mode-hook 'modes/prog-mode)
(add-hook 'before-save-hook #'delete-trailing-whitespace)   ; remove trailing whitespace

(use-package quickrun :commands (quickrun quickrun-region quickrun-shell))

Respect to the .editorconfig file in a project

(use-package editorconfig :diminish editorconfig-mode :hook (prog-mode . (lambda () (editorconfig-mode 1))))

apheleia

(use-package apheleia :disabled :diminish apheleia-mode :hook (prog-mode . apheleia-mode))

separedit

(use-package separedit
  :bind (:map prog-mode-map
              ("C-c \"" . separedit))
  :custom
  (separedit-buffer-creation-hook #'auto-fill-mode)
  (separedit-continue-fill-column t)
  (separedit-default-mode 'markdown-mode)
  (separedit-preserve-string-indentation t)
  (separedit-remove-trailing-spaces-in-comment t)
  (separedit-write-file-when-execute-save t))

tree-sitter

Code highlighting (for now)

(use-package tree-sitter
  :diminish tree-sitter-mode
  :hook (((enh-ruby-mode
           go-mode
           json-mode
           sh-mode
           typescript-mode) . tree-sitter-mode)
         (tree-sitter-after-on . tree-sitter-hl-mode))
  :config
  (with-eval-after-load `enh-ruby-mode
    (add-to-list 'tree-sitter-major-mode-language-alist '(enh-ruby-mode . ruby)))
  )

(use-package tree-sitter-langs :after tree-sitter)

turbo-log

(use-package turbo-log
  :after (:any go-mode typescript-mode)
  :straight '(turbo-log :host github
                        :branch "master"
                        :repo "artawower/turbo-log.el")
  :custom
  (turbo-log-allow-insert-without-tree-sitter-p t)
  (turbo-log-msg-format-template "\"%s\""))

Git

git-gutter

(use-package git-gutter
  :diminish git-gutter-mode
  :hook ((prog-mode org-mode) . git-gutter-mode)
  :custom
  (git-gutter:update-interval 0.02)
  :config
  (custom-set-variables                         ; backend
   '(git-gutter:handled-backends
     (quote (git))))
  )

magit

(use-package magit
  :bind (("C-x g" . magit-status))
  :config
  (setq magit-completing-read-function
        (quote magit-builtin-completing-read)
        magit-diff-refine-hunk t                ; highlight changes
        )

  ;; full screen magit-status
  (defadvice magit-status (around magit-fullscreen activate)
    (window-configuration-to-register :magit-fullscreen)
    ad-do-it
    (delete-other-windows))
  )

(use-package autorevert :diminish auto-revert-mode)

Web

web-mode

(use-package web-mode
  :mode ("\\.html\\'" . web-mode)
  :custom (web-mode-enable-css-colorization t))

Scripting

(add-hook 'after-save-hook                      ; make shell script executable on save
    'executable-make-buffer-file-executable-if-script-p)

Emacs Lisp

(use-package eldoc
  :diminish eldoc-mode
  :hook ((eval-expression-minibuffer-setup prog-mode) . eldoc-mode) ; show eldoc for 'Eval:'
  :init
  (global-eldoc-mode -1)                                            ; ignore eldoc globally
  :config
  (setq eldoc-idle-delay 0.2))

Groovy

(use-package groovy-mode :mode "\\.groovy\\'\\|\\.gradle\\'")

Infrastructure

ansiable

(use-package ansible :disabled :diminish ansible :hook (yaml-mode . ansible))

es-mode

(use-package es-mode :config (setq es-always-pretty-print t))

jinja2

(use-package jinja2-mode :disabled)

json

(use-package json-mode :mode ("\\.json.erb\\'" . json-mode))

nix-mode

(use-package nix-mode)

puppet-mode

(use-package puppet-mode :disabled)

restclient

Explore and test HTTP REST webservices

(use-package restclient
  :mode ("\\.\\(http\\|https\\|rest\\)$" . restclient-mode)
  :config
  (defun restclient-ignore-ssl ()
    "Ignore SSL verification. Identical to \=curl -k\="
    (interactive)
    (custom-reevaluate-setting 'gnutls-verify-error)
    (make-local-variable 'gnutls-verify-error)
    (setq gnutls-verify-error nil)
    )
  )

yaml

(use-package yaml-mode
  :mode (("\\.ya?ml$"       . yaml-mode)
         ("\\.ya?ml.erb\\'" . yaml-mode)))

DB

(add-hook 'sql-interactive-mode-hook
          (lambda ()
            (toggle-truncate-lines t)))         ; no line wrap when working on DB

C/C++

;(defun modes/c-mode ()
;  "c/c++ mode hook"
;  (progn
;    (setq gdb-many-windows t)                   ; gdb

;    (local-set-key (kbd "C-c -")                ; fold tag
;                   'senator-fold-tag)
;    (local-set-key (kbd "C-c +")
;                   'senator-unfold-tag)

;    (add-to-list (make-local-variable 'company-backends)
;                 '(company-gtags company-semantic))
;    ))

;(dolist
;    (hook
;     (list
;      'c-mode-hook
;      'c++-mode-hook
;      ))
;  (add-hook hook #'modes/c-mode))

Programming / Scripting

Shared Functions

Helper function to create a Python virtualenv used for LSP servers

;(dolist
;    (mode-hook
;     '(python-mode-hook))
;  (add-hook mode-hook
;    #'(lambda ()
;        (defun create-virtualenv (virtualenv-folder setup-cmd python-version requirement-file &optional version install-packages)
;          "Create a python pip based virtualenv and install packages based on the supplied requirement file"
;          (use-package pyvenv
;            :commands pyvenv-activate
;            :init
;            (defvar python-virtualenv-directory (concat backup-directory virtualenv-folder))
;            (if (not (file-exists-p python-virtualenv-directory))
;                (progn
;                  (make-directory python-virtualenv-directory t)
;                  (shell-command
;                   (concat
;                    "bash" " "
;                    (expand-file-name (concat user-emacs-directory setup-cmd)) " "
;                    (expand-file-name (concat python-virtualenv-directory)) " "
;                    python-version " "
;                    (expand-file-name (concat user-emacs-directory requirement-file))
;                    (when version (concat " " version))
;                    (when install-packages (concat " " install-packages))
;                    ))
;                  ))
;            (pyvenv-activate python-virtualenv-directory)
;            (pyvenv-tracking-mode t)
;            ))
;        )))

LSP

Language Server Protocol

(use-package lsp-mode
  :commands (lsp lsp-deferred)
  :hook ((lsp-mode . (lambda ()
                       (let ((lsp-keymap-prefix "C-c l"))
                         #'lsp-enable-which-key-integration)
                       (advice-add 'lsp-completion--enable :after
                                   #'(lambda ()
                                       (setq-local completion-at-point-functions
                                                   (list
                                                    (cape-capf-buster
                                                     (cape-capf-super
                                                      #'tabnine-completion-at-point
                                                      #'lsp-completion-at-point)
                                                     'equal)))))))
         (lsp-completion-mode . (lambda ()
                                  (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
                                        '(orderless))))
         (lsp-managed-mode . lsp-modeline-diagnostics-mode)
         (dockerfile-mode . lsp-deferred)
         (enh-ruby-mode . lsp-deferred)
         (go-mode . lsp-deferred)
         (js2-mode . lsp-deferred)
         (json-mode . lsp-deferred)
         (python-mode . lsp-deferred)
         (sh-mode . lsp-deferred)
         (terraform-mode . lsp-deferred)
         (typescript-mode . lsp-deferred)
         (yaml-mode . lsp-deferred))
  :custom
  (lsp-auto-guess-root t)
  (lsp-client-packages '(lsp-bash
                         lsp-dockerfile
                         lsp-go
                         lsp-javascript
                         lsp-json
                         lsp-pyright
                         lsp-solargraph
                         lsp-terraform ; 'terraform' is managed by 'asdf'
                                       ; Nix installed lsp server won't do lookups properly
                                       ; require to manually install as =~/.config/local/bin/terraform-ls=
                         lsp-yaml))
  (lsp-clients-typescript-server-args '("--stdio"))
  (lsp-completion-provider :none)               ; handled by corfu
  (lsp-idle-delay 0.3)
  (lsp-log-io nil)
  (lsp-prefer-flymake nil)
  (lsp-response-timeout 3)
  (lsp-yaml-schema-store-local-db (expand-file-name (convert-standard-filename "lsp/lsp-yaml-schemas.json") no-littering-var-directory))    ; lsp-yaml
  :config
  (define-key lsp-mode-map (kbd "C-c l") lsp-command-map)

  (with-eval-after-load `lsp-mode
    (run-with-idle-timer
     5 nil #'(lambda ()
               (with-eval-after-load `gcmh
                 (setq gcmh-high-cons-threshold lo/gc-cons-lsp))    ; performance tuning @ https://emacs-lsp.github.io/lsp-mode/page/performance/
               (setq read-process-output-max (* 1024 1024 4)))))

  (when (derived-mode-p 'enh-ruby-mode)
    (with-eval-after-load `lsp-solargraph
      ; load libraries
      (add-to-list 'lsp-solargraph-library-directories (expand-file-name "~/.asdf/installs/ruby/"))
      (add-to-list 'lsp-solargraph-library-directories
                   (concat (expand-file-name (shell-command-to-string "( git rev-parse --show-toplevel 2> /dev/null || echo $(pwd) ) | tr -d $'\n'")) "/vendor/bundle/"))
      ))

  ;; Use lsp servers from PATH installed by Nix
  (with-eval-after-load 'lsp-json (lsp-dependency 'vscode-json-languageserver `(:system ,(executable-find "vscode-json-languageserver"))))

  ;; ignore directories on lsp file watcher
  (with-eval-after-load 'lsp-mode
    (let* ((proj-root (lsp-workspace-root))
           (ignore-folders (list ".terragrunt-cache")))
      (when proj-root
        (dolist (folder ignore-folders)
          (dolist (f (directory-files-recursively proj-root folder t))
            (add-to-list 'lsp-file-watch-ignored-directories f)))))
    (add-to-list 'lsp-file-watch-ignored-directories (expand-file-name "~/.asdf")))
  )

(use-package lsp-pyright
  :after lsp-mode
  :config (when (executable-find "python3") (setq lsp-pyright-python-executable-cmd "python3")))

(use-package lsp-diagnostics :after lsp-mode :straight lsp-mode)
(use-package lsp-headerline :after lsp-mode :straight lsp-mode)
(use-package lsp-lens
  :after lsp-mode
  :straight lsp-mode
  :custom
  (lsp-lens-debounce-interval 0.5)
  (lsp-lens-enable t))
(use-package lsp-modeline
  :after lsp-mode
  :straight lsp-mode
  :custom
  (lsp-modeline-code-actions-segments	'(count icon name)))

(use-package lsp-ui
  :after (lsp-mode yasnippet)
  :bind-keymap ("C-c l" . lsp-command-map)
  :bind ((:map lsp-ui-mode-map
               ([remap xref-find-definitions] . lsp-ui-peek-find-definitions)
               ([remap xref-find-references]  . lsp-ui-peek-find-references))
         (:map lsp-command-map
               ("d f" . lsp-ui-doc-focus-frame) ; keyboard scrolling in the lsp-ui-doc popup frame, and graphic display only
               ("d u" . lsp-ui-doc-unfocus-frame)))
  :commands lsp-ui-mode
  :hook ((lsp-mode . lsp-ui-mode)
         (lsp-ui-mode . yas-minor-mode))
  :custom
  (lsp-modeline-code-actions-enable nil)
  (lsp-ui-doc-enable nil)
  (lsp-ui-sideline-ignore-duplicate t)
  (lsp-ui-sideline-show-code-actions t)
  (lsp-ui-flycheck-list-position 'right)
  :config
  ;; https://www.reddit.com/r/emacs/comments/x1nwxi/how_to_customize_lspuisideline/
  (defun lsp-ui-sideline--compute-height nil '(height unspecified)))

(use-package lsp-ui-flycheck :after lsp-ui :defer 2 :straight lsp-ui)
(use-package lsp-ui-imenu :after lsp-ui :defer 2 :straight lsp-ui)

(use-package consult-lsp
  :after lsp-mode
  :bind (:map lsp-mode-map
              ([remap xref-find-apropos] . consult-lsp-symbols)))

(use-package lsp-treemacs
  :after lsp-mode
  :commands lsp-treemacs-errors-list
  :custom
  (lsp-treemacs-sync-mode t)
  )

(use-package dap-mode
  :after (lsp-mode lsp-modeline)
  :hook (python typescript-mode)
  :init
  (unless (display-graphic-p)
    (custom-set-faces
     '(dap-ui-marker-face ((t (:background "color-166"))))
     '(dap-ui-pending-breakpoint-face ((t (:background "blue" :underline "dim gray"))))
     '(dap-ui-verified-breakpoint-face ((t (:background "green" :underline "green")))))
    ))

Bash

(use-package sh-script
  :mode (("\\.*bashrc$"      . sh-mode)
         ("\\.*bash_profile" . sh-mode))
  :custom
  (sh-indent-comment t)
  :config
  ; Fixing OSX/node "Operation not permitted" - add 'node' under "Security & Privacy"
  ;; -> http://osxdaily.com/2018/10/09/fix-operation-not-permitted-terminal-error-macos/

  (run-with-idle-timer
   0.1 nil
   #'(lambda ()
       (when (derived-mode-p 'sh-mode)
           (when (eq 1 (point-max))                ; new file template
             (insert
              "#!/usr/bin/env bash\n"
              "\n"
              "set -Eeuxo pipefail\n"
              "\n"
              "err() {\n"
              "  echo \"errexit with status [$?] at line $(caller)\" >&2\n"
              "  awk 'NR>L-5 && NR<L+3 { printf \"%-5d%3s%s\\n\",NR,(NR==L?\">> \":\"\"),$0 }' L=$1 $0\n"
              "}\n"
              "trap 'err $LINENO' ERR\n"
              "\n\n\n\n"
              "main() {\n"
              "  return\n"
              "}\n"
              "main \"$@\"\n"
              ))
         )))
  )

Dockerfile

(use-package dockerfile-mode
  :mode (("\\.dockerfile\\'" . dockerfile-mode)
         ("/Dockerfile\\(?:\\.[^/\\]*\\)?\\'" . dockerfile-mode)))

Go

(use-package go-mode
  :if (executable-find "go")
  :hook
  ((go-mode . (lambda ()
                (add-hook 'before-save-hook #'(lambda ()
                                                (lsp-format-buffer)
                                                (lsp-organize-imports)))

                (unless (file-exists-p (concat (expand-file-name (shell-command-to-string "( git rev-parse --show-toplevel 2> /dev/null || echo $(pwd) ) | tr -d $'\n'")) "/go.mod"))
                  (setenv "GO111MODULE" "off")))))      ; turn off for one-off file
  :config
  (run-with-idle-timer
   0.1 nil
   #'(lambda ()
       (when (derived-mode-p 'go-mode)
         (when (eq 1 (point-max))               ; new file template
           (insert
            "package main\n\n"
            "import (\n"
            "\t\"bufio\"\n"
            "\t\"fmt\"\n"
            "\t\"os/exec\"\n"
            "\t\"strings\"\n"
            "\t)\n\n"
            "func main() {\n"
            "\tcmdName := `sh -c \"ls\"`\n"
            "\tcmdArgs := strings.Fields(cmdName)\n"
            "\tcmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)\n\n"
            "\tstdout, err := cmd.StdoutPipe()\n"
            "\tif err != nil {\n"
            "\t\tfmt.Println(err)\n"
            "\t}\n\n"
            "\tif err = cmd.Start(); err != nil {\n"
            "\t\tfmt.Println(err)\n"
            "\t}\n\n"
            "\tscanner := bufio.NewScanner(stdout)\n"
            "\tfor scanner.Scan() {\n"
            "\t\tmsg := scanner.Text()\n"
            "\t\tfmt.Println(msg)\n"
            "\t}\n\n"
            "\tif err = cmd.Wait(); err != nil {\n"
            "\t\tfmt.Println(err)\n"
            "\t}\n"
            "}\n"))
         ))))

(use-package gotest
  :after go-mode
  :bind (:map go-mode-map
              ("C-x x f" . go-test-current-file)
              ("C-x x t" . go-test-current-test)
              ("C-x x x" . go-run))
  :commands (go-test-current-file go-test-current-test go-run))

Java

;(defun modes/java-mode ()
;  "java mode hook"
;  (progn
;    (c-set-style "intellij" t)                  ; code style
;    (setq c-basic-offset 2)
;
;    (use-package lsp-java)                      ; Java LSP
;                                                ; check on github on how to install the server
;    ; set workspace
;    (setq lsp-java-workspace-dir (expand-file-name (concat backup-directory "jdt-workspace/"))
;          lsp-java-workspace-cache-dir (expand-file-name (concat lsp-java-workspace-dir ".cache/"))
;          lsp-java--workspace-folders
;            (list
;             ((lambda ()
;                (let ((root_dir (locate-dominating-file (expand-file-name (file-name-directory buffer-file-name)) "pom.xml")))
;                  (if root_dir
;                      (expand-file-name root_dir)
;                    (expand-file-name (file-name-directory buffer-file-name))))
;                ))
;             ))
;
;    (setq lsp-inhibit-message t
;          lsp-ui-sideline-update-mode 'point)
;
;    (lsp-java-enable)                           ; make this one the last step
;    ))
;(add-hook 'java-mode-hook #'modes/java-mode t)

JavaScript

(use-package js2-mode
  :interpreter "node"
  :mode (("\\.js\\'" . js2-mode))
  :custom
  (js2-basic-offset 2)
  (js2-bounce-indent-p t)
  (js2-strict-missing-semi-warning nil)
  (js2-concat-multiline-strings nil)
  (js2-include-node-externs t)
  (js2-skip-preprocessor-directives t)
  (js2-strict-inconsistent-return-warning nil))

Powershell

;(use-package powershell
;  :config
;  (use-package lsp-pwsh
;    :after lsp-mode
;    :if (executable-find "pwsh")
;    :init
;    (setq
;     lsp-pwsh-ext-path (expand-file-name "lsp-pwsh/.cache/lsp/pwsh" no-littering-var-directory)
;     lsp-pwsh-dir (expand-file-name "PowerShellEditorServices" lsp-pwsh-ext-path)
;     lsp-pwsh-exe (executable-find "pwsh"))
;    :config
;    (lsp)
;    )
;  )

Python

(use-package python
  :if (executable-find "python3")
  :interpreter ("python" . python-mode)
  :mode ("\\.wsgi$" . python-mode)
  :custom
  (python-indent-guess-indent-offset t)
  (python-indent-guess-indent-offset-verbose nil)
  :config
  (setenv "PYTHONPATH" (shell-command-to-string "$SHELL --login -c 'echo -n $PYTHONPATH'"))

  (when (eq 1 (point-max))                ; new file template
    (insert
     "#!/usr/bin/env python3\n"
     "\n\n"
     "def main():\n"
     "    pass\n"
     "\n\n"
     "if __name__ == \"__main__\":\n"
     "    main()\n"
     ))

  (defun python-lsp-organise-imports ()
    "pyright does not provide source.organizeImports code action,
so using Autoflake to implement the same function"
    (interactive)
    (save-buffer)                               ; work on file only, and need to save the file first
    (shell-command (format "autoflake --remove-all-unused-imports -i %s"
                           (shell-quote-argument (buffer-file-name))))
    (revert-buffer t t t))

  (defun python-lsp-document-formatting ()
    "pyright does not provide document formatting code action,
so using Black to implement the same function"
    (interactive)
    (save-buffer)                               ; work on file only, and need to save the file first
    (shell-command (format "python -m black -q %s"
                           (shell-quote-argument (buffer-file-name))))
    (revert-buffer t t t))
  )

(use-package dap-python                         ; lsp debugger
  :after (python dap-mode)
  :custom (dap-python-debugger 'debugpy)
  :defer 2
  :demand t
  :straight dap-mode)

Ruby

(use-package enh-ruby-mode
  :mode
  (("\\.rb\\'"       . enh-ruby-mode)
   ("\\.rake\\'"     . enh-ruby-mode)
   ("Rakefile\\'"    . enh-ruby-mode)
   ("\\.gemspec\\'"  . enh-ruby-mode)
   ("\\.ru\\'"       . enh-ruby-mode)
   ("Gemfile\\'"     . enh-ruby-mode)
   ("Cheffile\\'"    . enh-ruby-mode)
   ("Vagrantfile\\'" . enh-ruby-mode))
  :custom
  (enh-ruby-add-encoding-comment-on-save nil)
  (rspec-compilation-buffer-name "*rspec-compilation*")
  (rspec-use-opts-file-when-available nil)
  (rspec-use-rake-when-possible nil)
  (ruby-insert-encoding-magic-comment nil)
  :init
  (setenv "RUBYOPT" "--jit")
  :config
  (add-to-list 'exec-path
               (concat (expand-file-name "~/.asdf/installs/ruby/") (shell-command-to-string (concat "grep ruby " (expand-file-name "~/.tool-versions") " 2>/dev/null | cut -d' ' -f2 | tr -d $'\n'" )) "/bin"))
  (setenv "PATH" (concat (getenv "PATH") ":" (expand-file-name "~/.asdf/installs/ruby/") (shell-command-to-string (concat "grep ruby " (expand-file-name "~/.tool-versions") " 2>/dev/null | cut -d' ' -f2 | tr -d $'\n'" )) "/bin"))
  )

(use-package inf-ruby
  :after enh-ruby-mode
  :hook (compilation-filter . inf-ruby-auto-enter)
  )

(use-package rspec-mode
  :after enh-ruby-mode
  :diminish rspec-mode
  :hook (enh-ruby-mode . rspec-mode)
  )

Terraform

(use-package terraform-mode
  :mode "\\.tf\\(vars\\)?\\'"
  :custom (terraform-indent-level 2))

  (use-package terraform-doc :after terraform-mode)

TypeScript

(use-package typescript-mode
  :interpreter "node"
  :hook (typescript-mode . js2-minor-mode)
  :mode ("\\.tsx\\'" . typescript-mode)
  :custom
  (typescript-indent-level 2))

(use-package dap-node
  :after (typescript-mode dap-mode)
  :defer 2
  :straight dap-mode
  :config
  (dap-register-debug-template "node::launch::debug_current_file"
                               (list :type "node"
                                     :request "launch"
                                     :smartStep t
                                     :cwd "${workspaceFolder}"
                                     :outFiles ["${workspaceFolder}/**/*.js"]
                                     :skipFiles ["<node_internals>/**"]
                                     :program "${file}"
                                     ;; Or
                                     ;; :program "${workspaceFolder}//APP.ts" ; replace with the filename & path to debug
                                     ;; :args (list "")                       ; uncomment & replace with the arguments to program
                                     ))
  (dap-register-debug-template "node::launch::npm"
                               (list :type "node"
                                     :request "launch"
                                     :smartStep t
                                     :cwd "${workspaceFolder}"
                                     :outFiles ["${workspaceFolder}/**/*.js"]
                                     :skipFiles ["<node_internals>/**"]
                                     :runtimeExecutable "npm"
                                     :runtimeArgs ["run-script", "test"]
                                     ))
  (dap-register-debug-template "node::launch::yarn"
                               (list :type "node"
                                     :request "launch"
                                     :smartStep t
                                     :cwd "${workspaceFolder}"
                                     :outFiles ["${workspaceFolder}/**/*.js"]
                                     :skipFiles ["<node_internals>/**"]
                                     :runtimeExecutable "yarn"
                                     :runtimeArgs ["test"]
                                     )))

AI

copilot.el

(use-package copilot
  :straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
  :requires editorconfig
  :init
  (use-package jsonrpc :defer t))

Mode Setting

avy

Char-based jumping

(use-package avy
  :bind ([remap goto-char] . avy-goto-char-2)   ; M-g c
  :commands avy-goto-char-2)

bm

Visible bookmarks

(use-package bm
  :init
  (setq bm-restore-repository-on-load t)        ; restore on load
  :config
  (setq bm-cycle-all-buffers t)                 ; cycle through bookmarks in all open buffers
  (setq-default bm-buffer-persistence t)        ; save/load/restore bookmarks
  (add-hook' after-init-hook #'bm-repository-load)
  (add-hook 'find-file-hook #'bm-buffer-restore)
  (add-hook 'kill-buffer-hook #'bm-buffer-save)
  (add-hook 'kill-emacs-hook #'(lambda nil
                                 (bm-buffer-save-all)
                                 (bm-repository-save)))
  (add-hook 'after-save-hook #'bm-buffer-save)
  (add-hook 'find-file-hook  #'bm-buffer-restore)
  (add-hook 'after-revert-hook #'bm-buffer-restore)
  )

drag-stuff

moving word/line/region around

(use-package drag-stuff
  :diminish drag-stuff-mode
  :hook ((prog-mode org-mode text-mode) . drag-stuff-mode)
  :config
  (setq drag-stuff-modifier 'alt)               ; alt-up/down/left/rigth key bindings
  (drag-stuff-define-keys)
  )

dumb-jump

simple implementation of jumping to definition/source

(use-package dumb-jump
  :diminish dumb-jump-mode
  :hook (prog-mode . (lambda () (add-hook 'xref-backend-functions #'dumb-jump-xref-activate t)))
  :custom
  (dumb-jump-prefer-searcher 'rg))

erc

(autoload 'define-erc-response-handler "erc-backend" nil t)
(with-eval-after-load `erc
  (progn
    (setq erc-server  "irc.freenode.net"        ; default to freenode.net
          erc-port    "6697"
          erc-nick my-erc-nick
          erc-user-full-name my-erc-user-full-name
          erc-email-userid my-erc-email-userid
          erc-hide-list                         ; hide unwanted messages
          '("JOIN" "PART" "QUIT")
          erc-interpret-mirc-color t            ; color highlighting
          erc-rename-buffers t                  ; Rename buffers to the current network name instead of SERVER:PORT
          erc-server-coding-system              ; always utf-8
          '(utf-8 . utf-8)
          erc-log-mode t                        ; enable logging
          erc-generate-log-file-name-function
          (quote erc-generate-log-file-name-with-date)
          erc-hide-timestamps t                 ; hide logging timestamp when chatting
          erc-log-channels-directory            ; directory
          (concat backup-directory "erc.logs/")
          erc-log-insert-log-on-open nil        ; ignore previous messages
          erc-log-file-coding-system 'utf-8-unix
          erc-button-url-regexp                 ; Button URL
            "\\([-a-zA-Z0-9_=!?#$@~`%&*+\\/:;,]+\\.\\)+[-a-zA-Z0-9_=!?#$@~`%&*+\\/:;,]*[-a-zA-Z0-9\\/]"
          erc-prompt (lambda () (concat "[" (buffer-name) "]"))
          erc-auto-discard-away t               ; autoaway
          erc-autoaway-idle-seconds 600
          erc-autoaway-use-emacs-idle t
          erc-query-display 'buffer             ; open query in the current window
          )
    (erc-log-mode)
    (erc-truncate-mode +1)                      ; truncate long irc buffers
    (require 'erc-sasl)                         ; sasl
    (add-to-list 'erc-sasl-server-regexp-list "irc\\.freenode\\.net")

    ;; for erc-sasl
    (defun erc-login ()
      "Perform user authentication at the IRC server."
      (erc-log (format "login: nick: %s, user: %s %s %s :%s"
                       (erc-current-nick)
                       (user-login-name)
                       (or erc-system-name (system-name))
                       erc-session-server
                       erc-session-user-full-name))
      (if erc-session-password
          (erc-server-send (format "PASS %s" erc-session-password))
        (message "Logging in without password"))
      (when (and (featurep 'erc-sasl) (erc-sasl-use-sasl-p))
        (erc-server-send "CAP REQ :sasl"))
      (erc-server-send (format "NICK %s" (erc-current-nick)))
      (erc-server-send
       (format "USER %s %s %s :%s"
               (if erc-anonymous-login erc-email-userid (user-login-name))
               "0" "*"
               erc-session-user-full-name))
      (erc-update-mode-line))
    ))

evil-nerd-commenter

Comment code block

(use-package evil-nerd-commenter
  :bind ([remap comment-dwim] . evilnc-comment-or-uncomment-lines)  ; M-;
  :config (evilnc-default-hotkeys t t))         ; disable default key bindings

elfeed

(use-package elfeed
  :disabled
  :bind ("C-x w" . elfeed)
  :init (setf url-queue-timeout 30)
  :config
  (setq my-elfeed-timer                         ; 1hr update timer
        (run-at-time t (* 60 60) #'elfeed-update)
        elfeed-feeds
        '(("http://www.reddit.com/r/devops/.rss" devops reddit)
          ("http://feeds.dzone.com/devops" devops dzone)
          ("https://www.infoq.com/feed/devops/news" devops infoq)
          ("http://www.reddit.com/r/emacs/.rss" emacs reddit)
          )
        )
  )

flycheck

(use-package flycheck
  :diminish flycheck-mode
  :hook (prog-mode . (lambda () (run-with-idle-timer 1 nil #'(lambda () (flycheck-mode)))))
  :init
  (custom-set-faces
   '(flycheck-error ((nil (:background "red"))))
   '(flycheck-warning ((nil (:background "yellow")))))
  :config
  (setq flycheck-buffer-switch-check-intermediate-buffers t
        flycheck-check-syntax-automatically '(new-line idle-change save)
        flycheck-idle-change-delay (if flycheck-current-errors 0.5 15.0)
        flycheck-python-pylint-executable "pyright")
  (flymake-mode -1)                             ; disable flymake
  )

flyspell

(use-package flyspell
  :diminish flyspell-mode
  :hook ((after-change-major-mode find-file)
         . (lambda ()
             (run-with-idle-timer
              1 nil
              #'(lambda ()
                  (if (not (symbol-value flyspell-mode))
                      (cond
                       ((derived-mode-p 'prog-mode)
                        (progn
	                        (message "Flyspell on (code)")
	                        (flyspell-prog-mode)))
                       ((derived-mode-p 'text-mode)
                        (progn
	                        (message "Flyspell on (text)")
	                        (flyspell-mode 1))))
                    )))))
  :custom
  (flyspell-issue-message-flag nil)
  (flyspell-issue-welcome-flag nil)
  (ispell-list-command "--list")
  (ispell-program-name "aspell")
  (ispell-extra-args '("--sug-mode=ultra" "--run-together" "--run-together-limit=8"))
  :config
  (advice-add 'message :around
              #'(lambda (old-fun format &rest args)
                  "Supress \"Starting \"look\" process\" message from \=ispell-lookup-words\="
                  (if (string= format "Starting \"%s\" process...")
                      (ignore)
                    (apply old-fun format args))))
  :init
  (setq flyspell-use-meta-tab nil))              ; do not bundle to M-Tab

(use-package flyspell-correct :after flyspell)  ; C-u/C-u C-u/C-u C-u C-u M-x flyspell-correct-wrapper

indent-guide

(use-package indent-guide
  :disabled
  :diminish indent-guide-mode
  :hook ((prog-mode org-mode) . indent-guide-mode)
  :custom
  (indent-guide-delay 0.3)
  :config (set-face-foreground 'indent-guide-face "dimgray"))

indent-yank

Indent at yank/paste

(use-package indent-yank
  :disabled
  :defer 5
  :hook (window-setup . indent-yank-mode)
  :straight '(indent-yank :host github
                          :branch "master"
                          :repo "HuangBoHong/indent-yank"))

keycast

Show the key pressed on the modeline

(use-package keycast
  :defer 2
  :init
  (custom-set-faces
   '(keycast-key ((nil (:height 1 :background "gray30" :foreground "gray70")))))
  :custom
  (keycast-remove-tail-elements nil)
  (keycast-separator-width 2)
  (keycast-mode-line-insert-after 'mode-line-misc-info)
  (keycast-mode-line-format "%10s%k%c%r%5s")
  :config
  (keycast-mode-line-mode)
  )

meow

(use-package meow
  :defer 0.2
  :config
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  (meow-leader-define-key
   '("e" . "C-x C-e") ; eval-last-sexp
   '("," . xref-pop-marker-stack)
   '("." . xref-find-definitions)
   ;; 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))

  (setq meow-expand-hint-remove-delay 5
        meow-keypad-describe-delay 3
        meow-use-cursor-position-hack t
        meow-use-enhanced-selection-effect t)

  (meow-setup-line-number)
  (meow-global-mode 1)

  (defun exit-meow-insert-mode ()
    "Reset back to box cursor on terminal"
    (unless (display-graphic-p)
      (when (bound-and-true-p meow-insert-mode)
        (meow-insert-exit))))
  (advice-add #'save-buffers-kill-terminal
              :before
              (lambda (func &rest args)
                (exit-meow-insert-mode))))

mwim

move where I mean

(use-package mwim
  :bind (("C-a" . mwim-beginning-of-code-or-line-or-comment)
         ("C-e" . mwim-end-of-code-or-line))
  :commands (mwim-beginning-of-code-or-line-or-comment mwim-end-of-code-or-line))

perspective-el

Grouping buffers

(use-package perspective
  :defer 1
  :custom
  (persp-mode-prefix-key (kbd "C-c p z"))
  :init
  (unless (equal persp-mode t)
    (persp-mode)))

puni

C-c DEL to delete active region

(use-package puni
  :init
  (puni-global-mode)
  (dolist (hook '(vterm-toggle-show-hook)) (add-hook hook #'puni-disable-puni-mode)))

(use-package elec-pair :hook (after-init . electric-pair-mode))
(use-package paren
  :custom
  (show-paren-delay 0.03)
  (show-paren-style 'mixed)
  (show-paren-when-point-inside-paren t)
  :hook (after-init . show-paren-mode)
  :init
  (custom-set-faces
   '(show-paren-match ((nil (:background "#767676" :foreground "#00cd00" :weight extra-bold))))))

Treemacs

(use-package treemacs
  :bind (("M-0" . treemacs-select-window)
         ("C-c p t 1" . treemacs-delete-other-windows)
         ("C-c p t t" . treemacs)
         ("C-c p t B" . treemacs-bookmark)
         ("C-c p t C-t" . treemacs-find-file)
         ("C-c p t M-t" . treemacs-find-tag))
  :init (defvar treemacs-no-load-time-warnings t))

(use-package treemacs-magit :after (treemacs magit))

(use-package treemacs-perspective
  :after (treemacs perspective)
  :config (treemacs-set-scope-type 'Perspectives))

(use-package treemacs-projectile
  :after (treemacs projectile)
  :bind ("C-c p t p" . treemacs-projectile))

scratch-pop

(use-package scratch-pop
  :defer 0.1
  :init
  (setq scratch-pop-backup-directory (expand-file-name (convert-standard-filename "scratch-pop/") no-littering-var-directory))
  (add-hook 'kill-emacs-hook #'scratch-pop-backup-scratches)
  )

so-long

(use-package so-long :hook (after-init-hook . global-so-long-mode))

subword

navigate into CamelCaseWords

(use-package subword
  :diminish subword-mode
  :hook ((prog-mode org-mode) . subword-mode))

super-save

auto-save buffers

(use-package super-save
  :defer 3
  :diminish super-save-mode
  :config
  (super-save-mode +1)
  (setq super-save-auto-save-when-idle t))

switch-window

(use-package switch-window
  :bind (([remap other-window] . switch-window)
         ([remap delete-other-windows] . switch-window-then-maximize)
         ([remap split-window-below] . switch-window-then-split-below)
         ([remap split-window-right] . switch-window-then-split-right)
         ([remap delete-window] . switch-window-then-delete)
         ([remap dired-other-window] . switch-window-then-dired)
         ([remap find-file-other-window] . switch-window-then-find-file)
         ([remap compose-mail-other-window] . switch-window-then-compose-mail)
         ([remap find-file-read-only-other-window] . switch-window-then-find-file-read-only)
         ([remap find-file-other-window] . switch-window-then-find-file)
         ([remap display-buffer] . switch-window-then-display-buffer)
         ([remap kill-buffer-and-window] . switch-window-then-kill-buffer))
  :custom
  (switch-window-auto-resize-window (lambda () (if (ignore-errors (dap--cur-session-or-die)) nil t)))    ; do not resizing under dap-mode debug session
  (switch-window-default-window-size '(0.618 . 0.618))
  (switch-window-minibuffer-shortcut ?z)
  (switch-window-shortcut-appearance 'asciiart)
  (switch-window-shortcut-style 'qwerty))

symbol-overlay

(use-package symbol-overlay
  :commands (symbol-overlay-put
             symbol-overlay-jump-prev
             symbol-overlay-jump-next
             symbol-overlay-switch-backward
             symbol-overlay-switch-forward
             symbol-overlay-remove-all)
  :custom (symbol-overlay-idle-time 0.1)
  :custom-face (symbol-overlay-default-face ((t (:inherit (region bold)))))
  :diminish
  :hook ((prog-mode org-mode) . symbol-overlay-mode))

undo-tree

(use-package undo-tree
  :commands undo-tree-visualize
  :diminish undo-tree-mode
  :config
  (add-to-list 'undo-tree-history-directory-alist
			         (cons "." (concat backup-directory "/undo-tree")))
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-diff t
        undo-tree-visualizer-timestamps t
        undo-tree-auto-save-history t)
  )

vimish-fold

vim-like text folding

(use-package vimish-fold :commands (vimish-fold vimish-fold-delete vimish-fold-toggle))

which-key

Display the key bindings in a popup.

(use-package which-key
  :defer 2
  :diminish which-key-mode
  :custom
  (which-key-idle-delay 0.5)                    ; popup delay
  (which-key-compute-remaps t)
  (which-key-allow-multiple-replacements t)
  :config
  (which-key-mode)
  (which-key-setup-side-window-right-bottom)
  )

yasnippet

(use-package yasnippet
  :commands yas-minor-mode
  :diminish yas-minor-mode
  :custom (yas-keymap-disable-hook t)
  :config (yas-reload-all))
(use-package yasnippet-snippets :after yasnippet)

ztree

Diff between directories

(use-package ztree :config (setq ztree-draw-unicode-lines t))

Ivy

projectile

(use-package projectile
  :bind(:map projectile-mode-map
             ("C-c p p" . projectile-command-map))
  :custom
  (projectile-enable-caching t)                             ; enable caching unconditionally
  (projectile-file-exists-remote-cache-expire nil)          ; disable remote file exists cache
  (projectile-remember-window-configs t)
  (projectile-switch-project-action #'consult-projectile-find-file)
  (projectile-sort-order 'modification-time)
  :config
  (setq projectile-globally-ignored-directories (append
                                                 '(".metadata" "node_modules" "vendor") projectile-globally-ignored-directories)
        projectile-globally-ignored-files (append
                                           '(".DS_Store") projectile-globally-ignored-files))
  (setq-default projectile-mode-line
                '(:eval
                  (if (file-remote-p default-directory)
	                    " Pr"
                    (format " Proj[%s]" (projectile-project-name)))))
  (cond
   ((executable-find "ag")
    (setq projectile-generic-command
          (concat "ag -0 -l --nocolor"
                  ; https://github.com/ggreer/the_silver_searcher/issues/1060
                  (mapconcat #'identity (cons "" projectile-globally-ignored-directories) " --ignore /")
                  (mapconcat #'identity (cons "" projectile-globally-ignored-directories) " --ignore /**/"))))
   ((executable-find "rg")
    (setq projectile-generic-command
          (let ((rg-cmd ""))
            (dolist (dir projectile-globally-ignored-directories)
              (setq rg-cmd (format "%s --glob '!%s'" rg-cmd dir)))
            (concat "rg -0 --files --color=never --hidden" rg-cmd)))))
  (if (eq system-type 'windows-nt)                    ; external indexing under windows
      (setq projectile-indexing-method 'alien))
  )

(use-package consult-projectile
  :bind (:map prog-mode-map
              ("C-c p SPC" . consult-projectile))
  :config
  (unless (equal projectile-mode t)
    (projectile-mode)))

(use-package rg :bind ("C-c p R" . rg-menu))

Vertico

(use-package vertico
  :bind (("C-c p v r" . vertico-repeat)
         :map vertico-map
              ("C-j" . vertico-directory-enter)
              ("C-l" . vertico-directory-up)
              ("C-q" . vertico-quick-exit)
              ("M-q" . vertico-quick-insert))
  :config
  (minibuffer-depth-indicate-mode)
  :custom
  (enable-recursive-minibuffers t)
  (vertico-cycle t)
  (vertico-resize t)
  :hook ((after-init . vertico-mode)
         (minibuffer-setup . vertico-repeat-save)
         (rfn-eshadow-update-overlay . vertico-directory-tidy))
  :straight (vertico :files (:defaults "extensions/vertico-*.el")
                     :includes (vertico-directory vertico-quick vertico-repeat)))

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

(use-package marginalia
  :after vertico
  :init (marginalia-mode))

(use-package embark
  :bind (("C-c p v ." . embark-act)
         ("C-c p v ;" . embark-dwim))
  :commands (embark-act embark-dwim)
  :config
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none))))
  :custom
  (embark-quit-after-action nil)
  (embark-cycle-key ".")
  (embark-help-key "?"))

(use-package embark-consult
  :after (embark consult)
  :demand t
  :hook (embark-collect-mode . consult-preview-at-point-mode))

(use-package consult
  :bind
  (("C-c p G" . consult-git-grep)
   ("C-c p g" . consult-grep)
   ("C-c p r" . consult-ripgrep)
   ([remap describe-bindings] . local/consult-descbinds)  ; C-h b
   ([remap goto-line]         . consult-goto-line)        ; M-g g
   ([remap isearch-forward]   . consult-line)             ; C-s
   ([remap isearch-backward]  . consult-line)             ; C-r
   ([remap switch-to-buffer]  . consult-buffer)           ; C-x b
   )
  :config
  (with-eval-after-load `perspective
    (consult-customize consult--source-buffer :hidden t :default nil)
    (defvar consult--source-perspective
      (list :name     "Perspective"
            :narrow   ?s
            :category 'buffer
            :state    #'consult--buffer-state
            :default  t
            :items    #'persp-get-buffer-names))
    (push consult--source-perspective consult-buffer-sources))
  :custom
  (consult-narrow-key "<")
  (xref-show-xrefs-function #'consult-xref)
  (xref-show-definitions-function #'consult-xref)
  :init
  ;; https://github.com/WorldsEndless/emacs-clojure/blob/master/emacs.el
  (defun local/consult-descbinds ()
    (interactive)
    (describe-bindings)
    (other-window 1)
    (call-interactively #'consult-focus-lines)))

(use-package corfu
  :bind (:map corfu-map
              ("M-d"     . corfu-info-documentation)
              ("M-l"     . corfu-info-location)
              ("TAB"     . corfu-next)
              ([tab]     . corfu-next)
              ("S-TAB"   . corfu-previous)
              ([backtab] . corfu-previous)
              ("M-q"     . corfu-quick-insert))
  :config
  (corfu-history-mode 1)
  (add-to-list 'savehist-additional-variables 'corfu-history)
  :custom
  (corfu-auto t)
  (corfu-bar-width 0)               ; hide popup right scroll bar
  (corfu-cycle t)
  (corfu-min-width 30)
  (corfu-preselect-first nil)
  (corfu-right-margin-width 0)      ; hide popup right scroll bar
  :hook ((prog-mode
          terraform-mode
          text-mode) . (lambda ()
                         (let ((frame (selected-frame)))
                           (run-with-idle-timer
                            1 nil
                            #'(lambda ()
                                (when (active-minibuffer-window)
                                  "Sometime, the minibuffer window is focused during the initialisation, and this function switches back to the orinal frame"
                                  (select-frame frame))
                                (unless (bound-and-true-p corfu-mode)
                                  (corfu-mode)                ; corfu
                                  (unless (display-graphic-p) ; corfu-terminal
                                    (corfu-terminal-mode 1))
                                  (add-to-list                ; kind-icon
                                   'corfu-margin-formatters #'kind-icon-margin-formatter)))))))
  :init
  (setq completion-cycle-threshold 3)
  :straight (corfu :files (:defaults "extensions/*")
                   :includes (corfu-history corfu-info corfu-quick)))

(use-package popon
  :after corfu
  :straight (popon :type git :repo "https://codeberg.org/akib/emacs-popon.git")
  :unless (display-graphic-p))

(use-package corfu-terminal
  :after (corfu popon)
  :straight (corfu-terminal :type git :repo "https://codeberg.org/akib/emacs-corfu-terminal.git")
  :unless (display-graphic-p))

(use-package kind-icon
  :after corfu
  :config
  (add-to-list 'kind-icon-mapping '(tabnine "ai" :icon "cloud" :face shadow) t)
  :custom
  (kind-icon-default-face 'corfu-default)
  (kind-icon-blend-background nil)
  (kind-icon-blend-frac 0.08)
  (svg-lib-icons-dir (no-littering-expand-var-file-name "svg-lib/cache/")))

(use-package cape
  :after corfu
  :init
  (add-to-list 'completion-at-point-functions
               (cape-capf-buster
                (cape-capf-super
                 #'tabnine-completion-at-point
                 #'cape-dabbrev
                 #'cape-dict
                 #'cape-keyword)
                'equal)
               t)
  (add-to-list 'completion-at-point-functions #'cape-file t))

(use-package tabnine-capf
  :after cape
  :commands (tabnine-completion-at-point)
  :hook (kill-emacs . tabnine-capf-kill-process)
  :straight (:host github :repo "50ways2sayhard/tabnine-capf" :files ("*.el" "*.sh")))

Org

org-mode

(use-package org
  :bind ("C-c o b" . org-switchb)
  :straight (:type built-in)
  :config
  (setq truncate-lines nil                      ; line wrap
        org-edit-src-content-indentation 0      ; no indentation in SRC block
        org-export-with-smart-quotes t
        org-log-done 'time
        org-html-doctype "html5"
        org-pretty-entities t                   ; show symbols without math delimiters
        org-src-preserve-indentation t
        org-src-fontify-natively t              ; native fontification
        org-src-tab-acts-natively t             ; mative tab in SRC block
        org-use-speed-commands t                ; speed keys
        org-startup-indented t
        org-hide-leading-stars t)

  (org-indent-mode t)                           ; list-oriented
  (diminish 'org-indent-mode)

  (add-hook 'org-shiftup-final-hook 'windmove-up)  ; active windmove
  (add-hook 'org-shiftleft-final-hook 'windmove-left)
  (add-hook 'org-shiftdown-final-hook 'windmove-down)
  (add-hook 'org-shiftright-final-hook 'windmove-right)

  ;; recompile README.org/.el/.elc
  (add-hook 'after-save-hook
            #'(lambda ()
                "Load and compile README.org"
                (when (equal (buffer-file-name) (expand-file-name (concat user-emacs-directory "README.org")))
                  (org-babel-tangle nil (expand-file-name (concat user-emacs-directory "README.el")) "emacs-lisp")
                  (byte-compile-file (expand-file-name (concat user-emacs-directory "README.el")))
                  (when (fboundp 'native-compile)
                    (native-compile (expand-file-name (concat user-emacs-directory "README.el"))))
                  )))
  )

org-page

Static site generator in org-mode

Two stpes to write a blog

  • op/new-post
  • op/do-publication

To configure the org-page site variables, put the below settings into ~/.emacs.d/private.el

(setq my-op/repository-directory "~/repos/public/yang-l.github.io"
      my-op/site-domain "http://yang-l.github.io/"
      my-op/personal-github-link "https://github.com/yang-l")
(use-package org-page
  :disabled
  :commands (op/new-repository op/new-post op/do-publication)
  :config
  (setq op/repository-directory my-op/repository-directory
        op/site-domain my-op/site-domain
        op/personal-github-link my-op/personal-github-link
        op/site-main-title "@Home"
        op/site-sub-title "")
  )

Research

AUCTex

;; (when (locate-library "auctex") (progn
;;     (defun modes/auctex-mode ()
;;         "auctex-mode hook"
;;         ;; set latexmk the default LaTeX compiler
;;         (push
;;          '("Latexmk" "latexmk -outdir=/tmp/emacs/latex -bibtex -pdf -pv %s" TeX-run-command nil t
;;            :help "Run Latexmk on file")
;;          TeX-command-list)
;;         (setq TeX-command-default "Latexmk")

;;         ;; auto directory for auto-generated info
;;         (setq TeX-auto-local "/tmp/emacs/latex/auctex-auto/")
;;         (setq TeX-parse-self t) ; enable parse on load
;;         (setq TeX-auto-save t) ; enable parse on save

;;         (setq-default TeX-master nil)
;;         (setq TeX-save-query nil) ; autosave before compiling

;;         (TeX-fold-mode 1) ; enable code folding
;;         (TeX-fold-buffer)

;;         ;; smart quotes
;;         (setq TeX-open-quote "<<")
;;         (setq TeX-close-quote ">>")

;;         ;; detect master files
;;         (defun guess-TeX-master (filename)
;;           "Guess the master file for FILENAME from currently open .tex files."
;;           (let ((candidate nil)
;;                 (filename (file-name-nondirectory filename)))
;;             (save-excursion
;;               (dolist (buffer (buffer-list))
;;                 (with-current-buffer buffer
;;                   (let ((name (buffer-name))
;;                         (file buffer-file-name))
;;                     (if (and file (string-match "\\.tex$" file))
;;                         (progn
;;                           (goto-char (point-min))
;;                           (if (re-search-forward (concat "\\\\input{" filename "}") nil t)
;;                               (setq candidate file))
;;                           (if (re-search-forward (concat "\\\\include{" (file-name-sans-extension filename) "}") nil t)
;;                               (setq candidate file))))))))
;;             (if candidate
;;                 (message "TeX master document: %s" (file-name-nondirectory candidate)))
;;             candidate))
;;         (setq TeX-master (guess-TeX-master (buffer-file-name))))
;;     (add-hook 'LaTeX-mode-hook 'modes/auctex-mode)

;;     ;; activate the Ref mode
;;     (add-hook 'LaTeX-mode-hook 'turn-on-reftex)     ; with AUCTeX LaTeX mode

;;     (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode)    ; auctex LaTeX math mode
;;     (add-hook 'LaTeX-mode-hook 'visual-line-mode)   ; with AUCTeX LaTeX mode

;;     ;; enable flyspell-mode
;;     (add-hook 'LaTeX-mode-hook 'flyspell-mode)

;;     ;; activate syntax highlighting - font-lock-mode
;;     (add-hook 'LaTeX-mode-hook 'turn-on-font-lock)

;;     ;; AUCTEX / EMACS / EVINCE - Forward & Inverse Search
;;     (add-hook 'LaTeX-mode-hook 'TeX-source-correlate-mode)
;;     (setq TeX-source-correlate-method 'synctex)
;;     (setq TeX-source-correlate-start-server t)

;;     ;; evince(pdf) -> emacs(latex) search - inverse search
;;     ;; ctrl + mouse right button in evince
;;     ;;(defun un-urlify (fname-or-url)
;;     ;;  "A trivial function that replaces a prefix of file:/// with just /."
;;     ;;  (if (string= (substring fname-or-url 0 8) "file:///")
;;     ;;      (substring fname-or-url 7)
;;     ;;    fname-or-url))

;;     (defun th-evince-sync (file linecol &rest ignored)
;;       (let* ((fname (un-urlify file))
;;              (buf (find-file fname))
;;              (line (car linecol))
;;              (col (cadr linecol)))
;;         (if (null buf)
;;             (message "[Synctex]: %s is not opened..." fname)
;;           (switch-to-buffer buf)
;;           (with-no-warnings
;;             (goto-line (car linecol)))
;;           (unless (= col -1)
;;             (move-to-column col)))))

;;     (defvar *dbus-evince-signal* nil)

;;     (defun enable-evince-sync ()
;;       (eval-when-compile (require 'dbus))
;;       (when (and
;;              (eq window-system 'x)
;;              (fboundp 'dbus-register-signal))
;;         (unless *dbus-evince-signal*
;;           (setf *dbus-evince-signal*
;;                 (dbus-register-signal
;;                  :session nil "/org/gnome/evince/Window/0"
;;                  "org.gnome.evince.Window" "SyncSource"
;;                  'th-evince-sync)))))
;;     (add-hook 'LaTeX-mode-hook 'enable-evince-sync)

;;     ;; emacs(latex) -> evince(pdf) - forward search
;;     ;; c-c c-c -> View -> pdf-forward-search in emacs
;;     (add-hook 'LaTeX-mode-hook 'TeX-PDF-mode)
;;     (add-hook 'LaTeX-mode-hook (lambda()
;;     ;; https://github.com/MassimoLauria/dotemacs/blob/42fd1978da3780df725198862fa9f28c0ac4218c/init-latex.le
;;     ;; https://gist.github.com/2297447

;;     ;; http://tex.stackexchange.com/a/78051
;;     ;; un-urlify and urlify-escape-only should be improved to handle all special characters, not only spaces.
;;     ;; The fix for spaces is based on the first comment on http://emacswiki.org/emacs/AUCTeX#toc20
;;     (defun un-urlify (fname-or-url)
;;       "Transform file:///absolute/path from Gnome into /absolute/path with very limited support for special characters"
;;       (if (string= (substring fname-or-url 0 8) "file:///")
;;           (url-unhex-string (substring fname-or-url 7))
;;         fname-or-url))

;;     (defun urlify-escape-only (path)
;;       "Handle special characters for urlify"
;;       (replace-regexp-in-string " " "%20" path))

;;     (defun urlify (absolute-path)
;;       "Transform /absolute/path to file:///absolute/path for Gnome with very limited support for special characters"
;;       (if (string= (substring absolute-path 0 1) "/")
;;           (concat "file://" (urlify-escape-only absolute-path))
;;         absolute-path))

;;     ;; universal time, need by evince
;;     (defun utime ()
;;       (let ((high (nth 0 (current-time)))
;;             (low (nth 1 (current-time))))
;;         (+ (* high (lsh 1 16) ) low)))

;;     ;; Forward search.
;;     ;; Adapted from http://dud.inf.tu-dresden.de/~ben/evince_synctex.tar.gz
;;     (defun auctex-evince-forward-sync (pdffile texfile line)
;;       (let ((dbus-name
;;              (dbus-call-method :session
;;                                "org.gnome.evince.Daemon"  ; service
;;                                "/org/gnome/evince/Daemon" ; path
;;                                "org.gnome.evince.Daemon"  ; interface
;;                                "FindDocument"
;;                                (urlify pdffile)
;;                                t     ; Open a new window if the file is not opened.
;;                                )))
;;         (dbus-call-method :session
;;                           dbus-name
;;                           "/org/gnome/evince/Window/0"
;;                           "org.gnome.evince.Window"
;;                           "SyncView"
;;                           (urlify-escape-only texfile)
;;                           (list :struct :int32 line :int32 1)
;;                           (utime))))

;;     (defun pdf-forward-search ()
;;       (let (
;;             (pdf (concat "/tmp/emacs/latex/" (TeX-master-file (TeX-output-extension))))
;;             (tex (buffer-file-name))
;;             (line (line-number-at-pos)))
;;         (auctex-evince-forward-sync pdf tex line)))

;;     ;; PDF forward search : emacs -> dbus -> evince
;;     (setq TeX-view-program-list '())
;;     (add-to-list 'TeX-view-program-list
;;                  '("EvinceForward" pdf-forward-search))

;;     (setq TeX-view-program-selection '())
;;     (add-to-list 'TeX-view-program-selection
;;                  '(output-pdf "EvinceForward"))
;;     ))))

Maxima

;; (when (locate-library "maxima")
;;     (autoload 'maxima-mode "maxima" nil t)
;;     (setq auto-mode-alist (cons '("\\.ma?[cx]" . maxima-mode) auto-mode-alist))
;;     )

Octave

;; (autoload 'octave-mode "octave-mod" nil t)
;; (setq auto-mode-alist (append '(("\\.m$" . octave-mode)) auto-mode-alist))

;; (with-eval-after-load 'octave-mod
;;     '(progn
;;         (abbrev-mode 1)
;;         (auto-fill-mode 1)
;;         (if (eq window-system 'x)
;;             (font-lock-mode 1))

;;         (run-octave)

;;         (add-hook 'inferior-octave-mode-hook
;;             (lambda ()
;;                 (turn-on-font-lock)
;;                 (define-key inferior-octave-mode-map [up]
;;                   'comint-previous-input)
;;                 (define-key inferior-octave-mode-map [down]
;;                   'comint-next-input)))
;;         ))

Useful Functions

Indentation

(defun indent-whole-buffer ()                   ; indentation
  "indent whole buffer"
  (interactive)
  (delete-trailing-whitespace)
  (indent-region (point-min) (point-max) nil)
  (untabify (point-min) (point-max)))
(defun indent-current-paragraph ()              ; code cleanup
  "indent current paragraph"
  (interactive)
  (save-excursion
    (delete-trailing-whitespace)
    (mark-paragraph)
    (indent-region (region-beginning) (region-end) nil)))

Line Indent

(defun indent-text (distance)
  (if (use-region-p)
      (let ((mark (mark)))
        (save-excursion
          (indent-rigidly (region-beginning)
                          (region-end)
                          distance)
          (push-mark mark t t)
          (setq deactivate-mark nil)))
    (indent-rigidly (line-beginning-position)
                    (line-end-position)
                    distance)))

(defun inc-line-indent (count)
  (interactive "p")
  (indent-text count))

(defun dec-line-indent (count)
  (interactive "p")
  (indent-text (- count)))

;(global-set-key (kbd "C-c > >") #'(lambda () (interactive) (inc-line-indent 4)))
;(global-set-key (kbd "C-c < <") #'(lambda () (interactive) (dec-line-indent 4)))

File Format Convertion

(defun dos2unix ()                              ; EoL conversion
  "dos2unix on current buffer."
  (interactive)
  (set-buffer-file-coding-system 'unix))
(defun unix2dos ()
  "unix2dos on current buffer."
  (interactive)
  (set-buffer-file-coding-system 'dos))

Copy N Paste

Selective copy and paste

;; require xsel
(defun copy-to-clipboard ()
  (interactive)
  (if (display-graphic-p)
      (progn
        (message "Yanked region to x-clipboard!")
        (call-interactively 'clipboard-kill-ring-save)
        )
    (if (region-active-p)
        (progn
          (shell-command-on-region (region-beginning) (region-end) "xsel -i -b")
          (message "Yanked region to clipboard!")
          (deactivate-mark))
      (message "No region active; can't yank to clipboard!")))
  )

(defun paste-from-clipboard ()
  (interactive)
  (if (display-graphic-p)
      (progn
        (clipboard-yank)
        (message "graphics active")
        )
    (insert (shell-command-to-string "xsel -o -b"))
    )
  )

Dired

File manager

(defun dired-open-home ()
  (interactive)
  (dired "~/")
  )

Json Formatter

(defun json-format ()
  (interactive)
  (save-excursion
    (shell-command-on-region (mark) (point) "python3 -m json.tool" (buffer-name) t)
    )
  )

URL Encode & Decode

(defun urldecode ()
  (interactive)
  (save-excursion
    (shell-command-on-region (mark) (point) "python3 -c \"import sys; from urllib.parse import unquote_plus; print(unquote_plus(sys.stdin.read()));\" " (buffer-name) t)
    )
  )

(defun urlencode ()
  (interactive)
  (save-excursion
    (shell-command-on-region (mark) (point) "python3 -c \"import sys; from urllib.parse import quote_plus; print(quote_plus(sys.stdin.read()));\""  (buffer-name) t)
    )
  )

Tips

Keybindings

keybindingsalternativemodedescription
C-u 4 C-x Tab / C-4 C-x TabC-c > >buildinindent the region by 4 spaces
C-u -4 C-x Tab / C--4 C-x TabC-c < <buildinun-indent the region by 4 spaces
C-x SPCbuildinrectangular selection
C-x r tbuildinreplace rectangule content
C-c '​orgedit SRC block in separate buffer
S-<arrow>C-x obuildinmove point between windows
M-<num>window-numberjump to window by number
C-S-BackspaceC-a C-kbuildindelete a whole line
C-x zbuildinrepeat last command
zbuildinrepeat last command again
M-<buildintop of buffer
M->buildinend of buffer
C-NUM C-x $hideshowbuildinhide lines indented more NUM colums
C-x $hideshowbuildinshow all lines
C-x =buildinshow current cursor position
M-z CHARbuildindel up to CHAR (but not included)
C-x r bbuildincreate bookmark
C-x r mbuildinjump to bookmark
C-x r lbuildinlist bookmark
;; Local Variables:
;; byte-compile-warnings: (not free-vars unresolved)
;; End:

About

Rewriting the old .emacs.d in org-mode, and will clean up in future

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published