Skip to content

Latest commit

 

History

History
4046 lines (3577 loc) · 127 KB

README.org

File metadata and controls

4046 lines (3577 loc) · 127 KB

Ian Emacs config

Personal Keymap

(setq user-full-name "Ian Fernandez"
      user-mail-address "[email protected]")
(global-set-key (kbd "<menu>")
          (lambda () (interactive) (find-file "~/.emacs.d/README.org")))

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

Beginning

;(eval-when-compile
; (setq use-package-expand-minimally byte-compile-current-file))
;; ;;-----------------


(defvar current-user
  (getenv
   (if (equal system-type 'windows-nt) "USERNAME" "USER")))

(message "Let the coding begin! Be patient, %s!" current-user)

;; Always load newest byte code
(setq load-prefer-newer t)

Performance adjustments

;; (use-package gcmh
;;    :ensure t
;;    :delight gcmh-mode
;;    :init
;;    (setq gcmh-verbose t)
;;    :config
;;    (setq gc-cons-threshold #x40000000)
;;    (gcmh-mode 1))

(defvar read-process-output-max (* 1024 2048)) ; 1 megabyte

(setq inhibit-compacting-font-caches t)

Repos

  ;;;; Packaging
(setq package-enable-at-startup nil)
(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
     ;;("marmalade" . "https://marmalade-repo.org/packages/")
     ;;("melpa-stable" . "https://stable.melpa.org/packages/")
             ("jcs-elpa" . "https://jcs-emacs.github.io/jcs-elpa/packages/")
     ("tromey" . "http://tromey.com/elpa/")
     ("melpa" . "https://melpa.org/packages/")
     ("org" . "https://orgmode.org/elpa/")))
(package-initialize)

;;;; use-package
(eval-and-compile
  (setq use-package-always-ensure t))

(unless (package-installed-p 'use-package)
   (package-refresh-contents)
   (package-install 'use-package)
 (eval-and-compile
   (setq use-package-always-ensure t)))

(eval-when-compile (require 'use-package))

(setq use-package-always-ensure t)


(defvar straight-use-package-by-default)
(setq straight-use-package-by-default t)

;; auto-package-update
(use-package auto-package-update
  :config
  (auto-package-update-maybe))

Custom

(unless (file-exists-p (concat user-emacs-directory "custom/custom.el"))
 (make-directory (concat user-emacs-directory "custom"))
 (make-empty-file (concat user-emacs-directory "custom/custom.el")))

(setq custom-file (expand-file-name (concat user-emacs-directory "custom/custom.el")))
(load custom-file)

Async

(use-package async
  :ensure t
  :defer t
  :init
  (dired-async-mode 1)
  (async-bytecomp-package-mode 1)
  :custom
  (async-bytecomp-allowed-packages '(all)))

Mac custom keyboard

(defun paste-from-osx ()
  (shell-command-to-string "pbpaste"))

(defun copy-to-osx (text &optional push)
  (let ((process-connection-type nil))
    (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
      (process-send-string proc text)
      (process-send-eof proc))))

  ;; Check the system
(when (eq system-type 'darwin)
  (setq ;; interprogram-cut-function 'copy-to-osx
        ;; interprogram-paste-function 'paste-from-osx
        mac-emulate-three-button-mouse nil
        mac-option-modifier 'command
        mac-command-modifier 'meta
        mac-right-command-modifier 'meta
        mac-right-option-modifier 'control
        ;;mac-option-key-is-control t
  ))

Clipboard

Allow pasting selection outside of Emacs

(setq x-select-enable-clipboard t)

Say you copied a link from your web browser, then switched to Emacs to paste it somewhere. Before you do that, you notice something you want to kill. Doing that will place the last kill to the clipboard, thus overriding the thing you copied earlier. We can have a kill ring solution:

(setq save-interprogram-paste-before-kill t)

Exec-path from shell

(use-package exec-path-from-shell
  :config
  (exec-path-from-shell-initialize))

(setenv "PATH" (concat "/usr/local/bin" path-separator (getenv "PATH")))

(when (eq system-type 'darwin)
  (setenv "PATH" (concat (getenv "PATH") ":/usr/local/bin:/opt/homebrew/bin"))
  (setq exec-path (append exec-path '("/usr/local/bin"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (setenv "NODE_VERSION"									 ;;
;;         (concat "/home/ianffcs/.nvm/versions/node/"						 ;;
;;                 (substring (shell-command-to-string "/usr/bin/node --version") 0 -1) "/bin")) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (setq exec-path                  ;;
;;       (nconc exec-path (getenv "NODE_VERSION"))) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;(setq exec-path
;;      (append exec-path '("/home/ianffcs/.nvm/versions/node/v12.11.1/bin")))

Visual Interface

UTF-8

(set-charset-priority 'unicode)
(set-terminal-coding-system  'utf-8)   ; pretty
(set-keyboard-coding-system  'utf-8)   ; pretty
(set-selection-coding-system 'utf-8)   ; please
(prefer-coding-system        'utf-8)   ; with sugar on top
(setq default-process-coding-system '(utf-8-unix . utf-8-unix)
      locale-coding-system          'utf-8)
(set-language-environment "UTF-8")
(set-default-coding-systems 'utf-8)

Visual

Find out what face something at point have.

(defun what-face (pos)
  (interactive "d")
  (let ((face (or (get-char-property (point) 'read-face-name)
                  (get-char-property (point) 'face))))
    (if face (message "Face: %s" face) (message "No face at %d" pos))))
(defconst my-frame-alist
  `((scroll-bar           . -1)
    (height               . 60)
    (width                . 95)
    (alpha                . 95)
    (vertical-scroll-bars . nil)))

(setq default-frame-alist my-frame-alist)

(use-package all-the-icons
     :ensure t)

Themes

(use-package doom-themes
  :init (setq doom-themes-enable-bold t doom-themes-enable-italic t)
  :config
  (doom-themes-org-config))

(use-package zenburn-theme
  :defer t)

(use-package solarized-theme
  :defer t)

(use-package organic-green-theme
  :defer t)

(use-package django-theme
  :defer t)

(load-theme 'doom-acario-light t)

Cleaning

invasive graphical elements.

(add-hook 'window-setup-hook 'toggle-frame-maximized t)
(add-to-list 'default-frame-alist '(fullscreen . maximized))
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

Emacs convention is to show help and other inline documentation in the message area. Show help there instead of OS tooltip.

(when
  (display-graphic-p)
  (tooltip-mode -1))

Let’s remove some crunchy messages at startup time.

(setq inhibit-startup-screen t
  inhibit-splash-screen  t
  inhibit-startup-echo-area-message t)

(setq line-number-mode              0
  column-number-mode            +1
  show-paren-mode               1
  show-paren-delay              0
  transient-mark-mode           1
  scroll-bar-mode               -1
  browser-url-browse-function   'browse-url-firefox
  linum-format                  "%5d"
  tab-width                     4
  global-hl-line-mode           t
  indent-tabs-mode              nil
  truncate-partial-width-windows 1
  fill-column                   80
  truncate-lines                1
  confirm-kill-processes        nil
  create-lockfiles              nil
  make-backup-files             nil)

Which-key mode

Describing keystrokes

(use-package which-key
  :ensure t
  :config (which-key-mode))

Emacs Cursor

(global-display-fill-column-indicator-mode)
(blink-cursor-mode 0)

Beacon, never lose your cursor

(use-package beacon
    :ensure t
    :config
    (setq beacon-push-mark 35
          beacon-color "#666600")
    (beacon-mode 1))

Change the highlight color for selection text.

(set-face-attribute 'region nil :background "#666" :foreground "#ffffff")

Make cursor the width of the character it is under.

(setq x-stretch-cursor t)

Mouse Scrolling

Smooth mouse scrolling

(setq transentient-mark-mode        t
      mouse-wheel-follow-mouse      t
      scroll-step                   1
      scroll-conservatively         101
      mouse-wheel-scroll-amount     '(1)
      mouse-wheel-progressive-speed nil)

(use-package smooth-scrolling
  :config (smooth-scrolling-mode 1))

Frame

(defun custom-set-frame-size ()
  (add-to-list 'default-frame-alist '(height . 50))
  (add-to-list 'default-frame-alist '(width . 178)))
(custom-set-frame-size)
(add-hook 'before-make-frame-hook 'custom-set-frame-size)

(defun set-frame-alpha (value)
  "Set the transparency of the frame. 0 = transparent/100 = opaque"
  (interactive "Alpha value (0-100): ")
  (set-frame-parameter (selected-frame) 'alpha value))

(set-frame-alpha 90)

Minor modes

This package implements a menu that lists all enabled minor modes. Emacs mode line can become pretty long, so this can be handy, and perhaps I don’t need to use :diminish everywhere anymore.

(use-package minions
  :commands minions-mode
  :init (minions-mode 1))

Time

(use-package time
  :ensure nil
  :init
  (setq display-time-default-load-average nil
        display-time-format "%Hh%M "
        display-time-day-and-date t)
  :config
  (display-time-mode t))

Fringe

Control the fringe around the frame.

(fringe-mode '(10 . 1))

Preview line numbers when prompting for line number.

(define-advice goto-line (:before (&rest _) preview-line-number)
  "Preview line number when prompting for goto-line."
  (interactive
   (lambda (spec)
     (if (and (boundp 'display-line-numbers)
              (not display-line-numbers))
         (unwind-protect
             (progn (display-line-numbers-mode)
                    (advice-eval-interactive-spec spec))
           (display-line-numbers-mode -1))
       (advice-eval-interactive-spec spec)))))

Extra-stuff

(use-package mode-icons
  :config (mode-icons-mode))

(use-package nyan-mode
  :ensure t
  :init
  (setq nyan-animate-nyancat t
    nyan-wavy-trail t
    mode-line-format
    (list '(:eval (list (nyan-create)))))
  (nyan-mode t))

(use-package parrot
  :config
  (global-set-key (kbd "C-c p") 'parrot-rotate-prev-word-at-point)
  (global-set-key (kbd "C-c n") 'parrot-rotate-next-word-at-point)
  (parrot-set-parrot-type 'emacs)
  (parrot-mode)
  (add-hook 'before-save-hook 'parrot-start-animation))

(use-package emojify)

;; HIGHLIGHT WHEN ;; TODO
(use-package hl-todo
  :config
  (global-hl-todo-mode 1))

;; Show current key-sequence in minibuffer, like vim does. Any feedback
;; after typing is better UX than no feedback at all
(setq echo-keystrokes 0.2)

Backup

(setq backup-by-copying 1      ; don't clobber symlinks
      ;; store all backup and autosave files in the tmp dir
      backup-directory-alist  `((".*" . ,temporary-file-directory))
      auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
                                        ; use versioned backups
      delete-old-versions 1
      kept-new-versions 6
      kept-old-versions 2
      version-control 1)

(use-package savehist
  :config
  (setq savehist-additional-variables
        ;; search entries
        '(search-ring regexp-search-ring)
        ;; save every minute
        savehist-autosave-interval 60
        ;; keep the home clean
        savehist-mode +1))

Proced (htop builtin)

(setq proced-auto-update-flag t
      proced-auto-update-interval 1
      proced-descend t)

Completion Framework Ivy

(use-package ivy
  :diminish (ivy-mode)
  :bind (("C-x b" . ivy-switch-buffer)
         ("C-c C-r" . ivy-resume))
  :config
  (ivy-mode 1)
  (setq ivy-use-virtual-buffers t)
  (setq ivy-count-format "%d/%d ")
  (setq ivy-display-style 'fancy))

(use-package swiper
  :bind (("C-s" . swiper-isearch))
  :config
  (ivy-mode 1))

(use-package anzu
  :config
  (global-anzu-mode)
  (global-set-key (kbd "M-%") 'anzu-query-replace)
  (global-set-key (kbd "C-M-%") 'anzu-query-replace-regexp))

(use-package counsel
  :bind
  (("M-x" . counsel-M-x)
   ("M-y" . counsel-yank-pop)
   :map ivy-minibuffer-map
   ("M-y" . ivy-next-line))
  :config
  (define-key read-expression-map (kbd "C-r") 'counsel-expression-history)
  (global-set-key (kbd "C-x C-f") 'counsel-find-file))

Ivy-rich

It is also interesting to use ivy-rich for a… richer… Ivy experience.

;; Function for buffer icons
(defun ivy-rich-switch-buffer-icon (candidate)
  (with-current-buffer
      (get-buffer candidate)
    (let ((icon (all-the-icons-icon-for-mode major-mode)))
      (if (symbolp icon)
          (all-the-icons-icon-for-mode 'fundamental-mode)
        icon))))

(use-package ivy-rich
  :config (progn
            (ivy-rich-mode 1)
            (setcdr (assq t ivy-format-functions-alist)
                    #'ivy-format-function-line)
            (setq ivy-rich-display-transformers-list
                  '(ivy-switch-buffer
                    (:columns
                     (;; Buffer icon
                      (ivy-rich-switch-buffer-icon (:width 2))
                      ;; return the candidate itself
                      (ivy-rich-candidate (:width 30))
                      ;; return the buffer size
                      ;;(ivy-rich-switch-buffer-size (:width 7))
                      ;; return the buffer indicators
                      (ivy-rich-switch-buffer-indicators
                       (:width 4 :face error :align right))
                      ;; return the major mode info
                      (ivy-rich-switch-buffer-major-mode
                       (:width 12 :face warning))
                      ;; return project name using `projectile'
                      ;; (ivy-rich-switch-buffer-project
                      ;;  (:width 15 :face success))
                      ;; return file path relative to project root
                      ;; or `default-directory' if project is nil
                      (ivy-rich-switch-buffer-path
                       (:width (lambda (x)
                                 (ivy-rich-switch-buffer-shorten-path
                                  x
                                  (ivy-rich-minibuffer-width 0.3))))))
                     :predicate
                     (lambda (cand) (get-buffer cand)))
                    counsel-M-x
                    ;; (:columns
                    ;;  ;; the original transformer
                    ;;  ((counsel-M-x-transformer (:width 40))
                    ;;   (ivy-rich-counsel-function-docstring
                    ;;    ;; return the docstring of the command
                    ;;    (:face font-lock-doc-face))))
                    ;; Two-column mode
                    (:columns
                     ((counsel-M-x-transformer (:width 40))
                      (ivy-rich-counsel-function-docstring
                       (:face font-lock-doc-face))))
                    counsel-describe-function
                    (:columns
                     ;; the original transformer
                     ((counsel-describe-function-transformer (:width 40))
                      ;; return the docstring of the function
                      (ivy-rich-counsel-function-docstring
                       (:face font-lock-doc-face))))
                    counsel-describe-variable
                    (:columns
                     ;; the original transformer
                     ((counsel-describe-variable-transformer (:width 40))
                      (ivy-rich-counsel-variable-docstring
                       ;; return the docstring of the variable
                       (:face font-lock-doc-face))))
                    counsel-recentf
                    (:columns
                     ;; return the candidate itself
                     ((ivy-rich-candidate (:width 0.8))
                      (ivy-rich-file-last-modified-time
                       ;; return the last modified time of the file
                       (:face font-lock-comment-face))))))))

Ivy-posframe

Floaty stuff is floaty. But floaty stuff can only be floaty when EXWM is not being used.

;; (use-package ivy-posframe
;;   :config (progn
;;             (setq ivy-posframe-display-functions-alist
;;                   '((t . ivy-posframe-display-at-frame-center))
;;                   ivy-posframe-parameters
;;                   '((left-fringe   . 8)
;;                     (right-fringe  . 8)))
;;             (ivy-posframe-mode 1)))

Ivy-YouTube

This queries YouTube stuff from Emacs and plays it on the browser.

(use-package ivy-youtube
  :bind (("C-c y" . ivy-youtube)))

Editor confs

(setq ring-bell-function 'ignore)

(setq-default indent-tabs-mode nil  ;; don't use tabs to indent
              tab-width 4         ;; but maintain correct appearance
              fill-column 80)

;; revert buffers automatically when underlying files are changed externally
(use-package autorevert
  :ensure nil
  :config
  (global-auto-revert-mode +1)
  (setq auto-revert-interval 2
        auto-revert-check-vc-info t
        global-auto-revert-non-file-buffers t
        auto-revert-verbose nil))


;; Newline at end of file
(setq require-final-newline t)

;; Word wrapping
(setq-default word-wrap t
              truncate-lines t
              truncate-partial-width-windows nil
              sentence-end-double-space nil
              delete-trailing-lines nil
              require-final-newline t
              tabify-regexp "^\t* [ \t]+")

;; Favor hard-wrapping in text modes
;; (defun auto-fill ()
;;   "My autofill setup for text buffers."
;;   (auto-fill-mode t)
;;   (delight 'auto-fill-mode))

;; (add-hook 'text-mode-hook #'auto-fill)

(setq shift-select-mode nil)

;; clean up obsolete buffers automatically
(use-package midnight)

(defmacro with-region-or-buffer (func)
  "When called with no active region, call FUNC on current buffer."
  `(defadvice ,func (before with-region-or-buffer activate compile)
     (interactive
      (if mark-active
          (list (region-beginning) (region-end))
        (list (point-min) (point-max))))))

(with-region-or-buffer indent-region)
(with-region-or-buffer untabify)

Recentf

This is a built-in mode that keeps track of the files you have opened allowing you go back to them faster. It can also integrate with a completion framework to populate a virtual buffers list.

(use-package recentf
  :ensure nil
  :init
  (setq recentf-max-saved-items 50
        recentf-max-menu-items 15
        recentf-show-file-shortcuts-flag nil
        recentf-auto-cleanup 'never)
  :config
  (add-to-list 'recentf-exclude "\\.gpg\\")
  (recentf-mode t))

Registers

Emacs registers are compartments where you can save text, rectangles, positions, and other things for later use. Once you save text or a rectangle in a register, you can copy it into the buffer once or many times; once you save a position in a register, you can jump back to that position once or many times.

For more information: `C-h r’ and then letter i to search for registers and the amazing video from Protesilaos.

The prefix to all commands of registers is C-x r

commanddescription
M-x view-register Rsee what register R contains
C-x r ssave region to register
C-x r iinsert text from a register
C-x r nrecord a number defaults to 0
C-x r +increment a number from register
C-x r SPCrecord a position into register
C-x r jjump to positions or windows config
C-x r wsave a window configuration
C-x r fsave a frame configuration

Important note: the data saved into the register is persistent as long as you don’t override it.

The way to specify a number, is to use an universal argument e.g. C-u <number> C-x n

Clean all the registers you saved.

(defun clear-registers ()
  "Remove all saved registers."
  (interactive)
  (setq register-alist nil))
(set-register ?e '(file . "~/.emacs.d/README.org"))
(set-register ?t '(file . "~/org/todo.org"))
(set-register ?c '(file . "~/.emacs.d/docs/cheatsheet.org"))

IBuffer

ibuffer-expertStop asking for confirmation after every action in Ibuffer
ibuffer-auto-modeKeeps the buffer list up to date
(use-package ibuffer
  :ensure nil
  :init
  (setq ibuffer-expert t)
  (setq ibuffer-show-empty-filter-groups t)
  (setq ibuffer-saved-filter-groups
        '(("Main"
           ("Directories" (mode . dired-mode))
           ("Rest" (mode . restclient-mode))
           ("Docker" (or
                      (mode . docker-compose-mode)
                      (mode . dockerfile-mode)))
           ("Programming" (or
                           (mode . clojure-mode)
                           (mode . emacs-lisp-mode)
                           (mode . python-mode)))
           ("Browser" (or
                       (name . "qutebrowser:\*")
                       (name . "Firefox:\*")))
           ("Org" (mode . org-mode))
           ("Markdown" (or
                        (mode . markdown-mode)
                        (mode . gfm-mode)))
           ("Git" (or
                   (mode . magit-blame-mode)
                   (mode . magit-cherry-mode)
                   (mode . magit-diff-mode)
                   (mode . magit-log-mode)
                   (mode . magit-process-mode)
                   (mode . magit-status-mode)))
           ("Emacs" (or
                     (name . "^\\*Help\\*$")
                     (name . "^\\*Custom.*")
                     (name . "^\\*Org Agenda\\*$")
                     (name . "^\\*info\\*$")
                     (name . "^\\*ielm\\*$")
                     (name . "^\\*scratch\\*$")
                     (name . "^\\*Backtrace\\*$")
                     (name . "^\\*Messages\\*$"))))))
     :config
     (add-hook 'ibuffer-mode-hook
           (lambda ()
             (ibuffer-auto-mode 1)
             (ibuffer-switch-to-saved-filter-groups "Main"))))

(global-set-key (kbd "C-x C-b") 'ibuffer)

  ;; Package =ibuffer-vc= let you filter the Ibuffer by projects
  ;; definitions (in my case, every folder that has a =.git= folder
  ;; inside is considered a project).


(use-package ibuffer-vc
  :ensure t
  :after ibuffer)

  ;;  Increasing the width of each column in ibuffer. Some buffers names
  ;;  are very large in EXWM.


(setq ibuffer-formats
    '((mark modified read-only " "
            (name 60 60 :left :elide) ; change: 60s were originally 18s
            " "
            (size 9 -1 :right)
            " "
            (mode 16 16 :left :elide)
            " " filename-and-process)
      (mark " "
            (name 16 -1)
            " " filename)))

(use-package ibuffer-tramp)

(use-package ibuffer-projectile)

(use-package ibuffer-sidebar
  :commands (ibuffer-sidebar-toggle-sidebar)
  :config
  (setq ibuffer-sidebar-use-custom-font t)
  (setq ibuffer-sidebar-face `(:family "Helvetica" :height 140)))

(setq kill-buffer-query-functions
      (delq 'process-kill-buffer-query-function kill-buffer-query-functions))

(defun close-all-buffers ()
    "Kill all buffers without regard for their origin."
    (interactive)
    (mapc 'kill-buffer (buffer-list)))

(global-set-key (kbd "C-M-s-k") 'close-all-buffers)

Authentication Source / Security

Auth Source is a generic interface for common backends such as your operating sysetm’s keychain and your local ~/.authinfo file. Auth Source solves the problem of mapping passwords and usernames to hosts.

Keepass

(use-package keepass-mode)

gpg

(setq auth-sources
    '((:source "~/.authinfo.gpg")
      (:source "~/.netrc")))

(setq auth-source-debug t)

Help

Is good to know how to ask for help in Emacs

(use-package helpful
  :bind
  (("C-h f" . helpful-callable)
   ("C-h v" . helpful-variable)
   ("C-h k" . helpful-key)
   ("C-h ," . helpful-at-point)))

Text editing stuff?

Paragraph

See also bidi-paragraph-direction; setting that non-nil might speed up redisplay.

(setq bidi-paragraph-direction 'left-to-right)

Very large files

Since I am using EXWM, I might open very large files, there is a package to help Emacs handle this kind of files.

(use-package vlf
  :defer t)

I found a good paper about log files in Emacs where they mention vlf package. This paper is very worth reading nevertheless.

move through edit points

Emacs leaves a trail of breadcrumbs (the mark ring) through which we can navigate to hop around to places you’ve been in the buffer. A nice alternative is to move round through points at which you made edits in a buffer.

(use-package goto-chg
  :ensure t
  :config
  (global-set-key (kbd "C-c b ,") 'goto-last-change)
  (global-set-key (kbd "C-c b .") 'goto-last-change-reverse))

Now we can use C-c b , and C-c b . to go back and forth through the edit points in your buffer. It takes you through your undo history without undoing anything.

Highlights

Visual feedback on some operations like yank, kill, undo. An example is that if you paste the next key. This is just a small tweak, but gives a nice bit of visual feedback.

(use-package volatile-highlights
  :ensure t
  :delight volatile-highlights-mode
  :defer t
  :config
  (volatile-highlights-mode t))

Very often is useful to highlight some symbols.

(use-package highlight-symbol
  :ensure t
  :delight highlight-symbol-mode
  :hook
  ((highlight-symbol-mode . highlight-symbol-nav-mode)
   (prog-mode . highlight-symbol-mode))
  :custom
  (highlight-symbol-highlight-single-occurrence nil)
  (highlight-symbol-idle-delay 0.25)
  (highlight-symbol-on-navigation-p t))

Multiple Cursors

Multiple cursors is a very nice package that lets you create several cursors that all do the same thing as you type.

(use-package multiple-cursors
  :bind
  (("C->" . mc/mark-next-like-this)
   ("C-<" . mc/mark-previous-like-this)
   ("C-S-<mouse-1>" . mc/add-cursor-on-click)
   ("C-c m c" . mc/edit-lines)))

To use mc/edit-lines you need to highlight the lines on which you wish to have cursors and use C-c m c. Now you can edit away and press enter when you are done to exit multiple cursors.

There is this amazing video from magnars showing off multiple cursors features.

However, occasionally the best way to get the cursors where you want them is with the mouse. With the following code, C-S-<left mouse click> adds a new cursor.

Smart move to beginning of visible line (or not)

Very nice default.

;; `C-a' first takes you to the first non-whitespace char as
;; `back-to-indentation' on a line, and if pressed again takes you to
;; the actual beginning of the line.
(defun smarter-move-beginning-of-line (arg)
  "Move depending on ARG to beginning of visible line or not.
  From https://emacsredux.com/blog/2013/05/22/smarter-navigation-to-the-beginning-of-a-line/."
  (interactive "^p")
  (setq arg (or arg 1))
  (when (/= arg 1)
    (let ((line-move-visual nil))
  (forward-line (1- arg))))
  (let ((orig-point (point)))
    (back-to-indentation)
    (when (= orig-point (point))
  (move-beginning-of-line 1))))

(global-set-key [remap move-beginning-of-line] 'smarter-move-beginning-of-line)

Duplicate line or region

(defun duplicate-current-line-or-region (arg)
  "Duplicates the current line or region ARG times.
If there's no region, the current line will be duplicated."
  (interactive "p")
  (save-excursion
    (if (region-active-p)
        (duplicate-region arg)
      (duplicate-current-line arg))))

(defun duplicate-region (num &optional start end)
  "Duplicates the region bounded by START and END NUM times.
If no START and END is provided, the current region-beginning
region-end is used."
  (interactive "p")
  (let* ((start (or start (region-beginning)))
         (end (or end (region-end)))
         (region (buffer-substring start end)))
    (goto-char start)
    (dotimes (i num)
      (insert region))))

(defun duplicate-current-line (num)
  "Duplicate the current line NUM times."
  (interactive "p")
  (when (eq (point-at-eol) (point-max))
    (goto-char (point-max))
    (newline)
    (forward-char -1))
  (duplicate-region num (point-at-bol) (1+ (point-at-eol))))

Let’s bind the top level function to a sensible key.

(global-set-key (kbd "C-c 2") 'duplicate-current-line-or-region)

Extra functions

; deletes all the whitespace when you hit backspace or delete
;; (use-package hungry-delete
;;   :ensure t
;;   :config
;;   (global-hungry-delete-mode))

;;; Stefan Monnier <foo at acm.org>. It is the opposite of fill-paragraph
(defun unfill-paragraph (&optional region)
  "Takes a multi-line paragraph and makes it into a single line of text."
  (interactive (progn (barf-if-buffer-read-only) '(t)))
  (let ((fill-column (point-max))
    ;; This would override `fill-column' if it's an integer.
        (emacs-lisp-docstring-fill-column t))
    (fill-paragraph nil region)))

(defun unfill-region (beg end)
  "Unfill the region, joining text paragraphs into a single
   logical line.  This is useful, e.g., for use with `visual-line-mode'."
  (interactive "*r")
  (let ((fill-column (point-max)))
    (fill-region beg end)))

;; before save clears whitespace
(add-hook 'before-save-hook 'whitespace-cleanup)


(global-set-key (kbd "<f5>") 'revert-buffer)

(global-set-key (kbd "C-c i") 'string-inflection-all-cycle)

Flyspell

(use-package flyspell
  :config
  (setq flyspell-mode +1)
  (setq ispell-program-name "aspell" ; use aspell instead of ispell
        ispell-extra-args '("--sug-mode=ultra")))

Dired

Dired sidebar config

;; dired - reuse current buffer by pressing 'a'
(put 'dired-find-alternate-file 'disabled nil)

;; always delete and copy recursively
(setq dired-recursive-deletes 'always)
(setq dired-recursive-copies 'always)

;; if there is a dired buffer displayed in the next window, use its
;; current subdir, instead of the current subdir of this dired buffer
(setq dired-dwim-target t)

(use-package dired-sidebar
  :bind (("C-x C-n" . dired-sidebar-toggle-sidebar))
  :ensure t
  :commands (dired-sidebar-toggle-sidebar)
  :init
  (add-hook 'dired-sidebar-mode-hook
            (lambda ()
              (unless (file-remote-p default-directory)
                (auto-revert-mode))))
  :config
  (push 'toggle-window-split dired-sidebar-toggle-hidden-commands)
  (push 'rotate-windows dired-sidebar-toggle-hidden-commands)

  (setq dired-sidebar-subtree-line-prefix "__"
        dired-sidebar-use-term-integration t
        dired-sidebar-use-custom-font t)
  ;; (setq dired-sidebar-theme 'vscode)
  )

(defun sidebar-toggle ()
  "Toggle both `dired-sidebar' and `ibuffer-sidebar'."
  (interactive)
  (dired-sidebar-toggle-sidebar)
  (ibuffer-sidebar-toggle-sidebar))

(global-set-key (kbd "C-x <menu>") 'sidebar-toggle)

Functions

Some custom functions for Dired.

(require 'dired-x)

(defun dired-xdg-open ()
  "Open the file at point with xdg-open."
  (interactive)
  (let ((file (dired-get-filename nil t)))
    (message "Opening %s..." file)
    (call-process "xdg-open" nil 0 nil file)
    (message "Opening %s done" file)))

(eval-after-load 'dired
  '(define-key dired-mode-map (kbd "O") 'dired-xdg-open))
(defun dired-directories-first ()
  "Sort dired listings with directories first."
  (save-excursion
    (let (buffer-read-only)
      (forward-line 2)
      (sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max)))
    (set-buffer-modified-p nil)))

(advice-add 'dired-readin :after #'dired-directories-first)

M-up is nicer in dired if it moves to the third line - straight to the “..”, which M-down is nicer if it moves to the last file and finally C-a moving back to start of files.

(defun dired-back-to-top ()
  (interactive)
  (beginning-of-buffer)
  (next-line 2)
  (dired-back-to-start-of-files))

(defun dired-back-to-bottom ()
  (interactive)
  (end-of-buffer)
  (next-line -1)
  (dired-back-to-start-of-files))

(defun dired-back-to-start-of-files ()
  (interactive)
  (backward-char (- (current-column) 2)))

Let’s bind the functions defined above so it can take effect in dired.

(eval-after-load 'dired
  '(progn
     (define-key dired-mode-map (kbd "M-p") 'dired-back-to-top)
     (define-key dired-mode-map (kbd "M-n") 'dired-back-to-bottom)
     (define-key dired-mode-map (kbd "C-a") 'dired-back-to-start-of-files)))

Eshell

(use-package eshell-bookmark
  :ensure t
  :config
  (add-hook 'eshell-mode-hook 'eshell-bookmark-setup))

(setenv "PAGER" "cat")

(defun eshell-clear-buffer ()
  "Clear the terminal buffer."
  (interactive)
  (let ((inhibit-read-only t))
    (erase-buffer)
    (eshell-send-input)))

(add-hook 'eshell-mode-hook (lambda ()
                          (local-set-key (kbd "C-l") 'eshell-clear-buffer)))
(require 'em-alias)
(add-hook 'eshell-mode-hook
          (lambda ()
            (eshell/alias "e" "find-file $1")
            (eshell/alias "ee" "find-file-other-window $1")))

This is very useful if you want to keep some default windows around while you edit in your main programming environment. For example, to keep a eshell and dired buffer around.

(use-package emacs
  :custom
  (display-buffer-alist
   '(("\\*e?shell\\*"
      (display-buffer-in-side-window)
      (window-height . 0.30)
      (side . bottom)
      (slot . -1))))
  :bind
  ("<f8>" . window-toggle-side-windows))

Smartparens & Parens-thing

(use-package smartparens
  :diminish
  :init
  (define-key smartparens-mode-map (kbd "M-(") 'sp-wrap-round)
  (define-key smartparens-mode-map (kbd "M-[") 'sp-wrap-square)
  (define-key smartparens-mode-map (kbd "M-{") 'sp-wrap-curly)
  (define-key smartparens-mode-map (kbd "C-c (") 'sp-splice-sexp)
  :config
  (require 'smartparens-config)
  (setq sp-base-key-bindings 'paredit)
  (setq sp-autoskip-closing-pair 'always)
  (setq sp-hybrid-kill-entire-symbol nil)
  (sp-use-paredit-bindings)
  (show-smartparens-global-mode +1)
  (sp-local-pair '(emacs-lisp-mode) "'" "'" :actions nil)
  (sp-local-pair '(common-lisp-mode) "'" "'" :actions nil)
  (sp-local-pair '(clojure-mode) "'" "'" :actions nil)
  (sp-local-pair '(cider-repl-mode) "'" "'" :actions nil)
  (sp-local-pair '(scheme-mode) "'" "'" :actions nil)
  (sp-local-pair '(lisp-mode) "'" "'" :actions nil)
  (setq smartparens-global-strict-mode 1))

(use-package highlight-parentheses)

(use-package highlight-sexp)

Movin’ around baby

split-switch

(use-package switch-window
  :ensure t
  :config
    (setq switch-window-input-style 'minibuffer)
    (setq switch-window-increase 4)
    (setq switch-window-threshold 2)
    (setq switch-window-shortcut-style 'qwerty)
    (setq switch-window-qwerty-shortcuts
        '("a" "s" "d" "f" "j" "k" "l" "i" "o"))
  :bind
    ([remap other-window] . switch-window))

  (defun split-and-follow-horizontally ()
    (interactive)
    (split-window-below)
    (balance-windows)
    (other-window 1))
  (global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)

  (defun split-and-follow-vertically ()
    (interactive)
    (split-window-right)
    (balance-windows)
    (other-window 1))
  (global-set-key (kbd "C-x 3") 'split-and-follow-vertically)

(use-package windmove
  :config
  (windmove-default-keybindings))

;; avy allows us to effectively navigate to visible things
(use-package avy
  :bind (("M-s a" . avy-goto-char))
  :config
  (setq avy-background t
          avy-style 'at-full))

(use-package ace-window
        :ensure t
        :init
        (setq aw-keys '(?h ?j ?k ?l ?y ?u ?i ?o ?p)
          aw-background nil
          aw-scope 'frame
          aw-dispatch-alist
          '((?s aw-swap-window "swap window")
            (?2 aw-split-window-vert "split window vertically")
            (?3 aw-split-window-horz "split window horizontally")
            (?? aw-show-dispatch-help)))
        :config
        (ace-window-display-mode -1)
        (global-set-key (kbd "C-x o") 'ace-window))

;; Don't popup certain buffers

(add-to-list 'display-buffer-alist
             (cons "\\*Async Shell Command\\*.*"
                   (cons #'display-buffer-no-window nil)))

Mark-Multiple

I can barely contain my joy. This extension allows you to quickly mark the next occurence of a region and edit them all at once. Wow!

(use-package mark-multiple
  :ensure t
  :bind ("C-c q" . 'mark-next-like-this))

Improved kill-word

Why on earth does a function called kill-word not .. kill a word. It instead deletes characters from your cursors position to the end of the word, let’s make a quick fix and bind it properly.

(defun kill-inner-word ()
  "Kills the entire word your cursor is in. Equivalent to 'ciw' in vim."
  (interactive)
  (forward-char 1)
  (backward-word)
  (kill-word 1))
(global-set-key (kbd "C-c w k") 'kill-inner-word)

Improved copy-word

And again, the same as above but we make sure to not delete the source word.

(defun copy-whole-word ()
  (interactive)
  (save-excursion
    (forward-char 1)
    (backward-word)
    (kill-word 1)
    (yank)))
(global-set-key (kbd "C-c w c") 'copy-whole-word)

Copy a line

Regardless of where your cursor is, this quickly copies a line.

(defun copy-whole-line ()
  "Copies a line without regard for cursor position."
  (interactive)
  (save-excursion
    (kill-new
     (buffer-substring
      (point-at-bol)
      (point-at-eol)))))
(global-set-key (kbd "C-c l c") 'copy-whole-line)

Kill a line

And this quickly deletes a line.

(global-set-key (kbd "C-c l k") 'kill-whole-line)

Beacon

While changing buffers or workspaces, the first thing you do is look for your cursor. Unless you know its position, you can not move it efficiently. Every time you change buffers, the current position of your cursor will be briefly highlighted now.

(use-package beacon
  :ensure t
  :config
    (beacon-mode 1))

Zapping to char

A nifty little package that kills all text between your cursor and a selected character. A lot more useful than you might think. If you wish to include the selected character in the killed region, change zzz-up-to-char into zzz-to-char.

(use-package zzz-to-char
  :ensure t
  :bind ("M-z" . zzz-up-to-char))

Shackle

https://www.reddit.com/r/emacs/comments/7au3hj/how_do_you_manage_your_emacs_windows_and_stay_sane/ https://github.com/Alexander-Miller/dotfiles/blob/master/.config/spacemacs/user-config.org#shackle

Gives you the means to put an end to popped up buffers not behaving the 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.

(use-package shackle
  :ensure t
  :config
  (setq shackle-rules '(("*Ledger Report*" :same t)))
  (add-hook 'after-init-hook 'shackle-mode))

Winner

Winner is a built-in tool that keeps a record of buffer and window layout changes. It then allows us to move back and forth in the history of said changes. The mnemonic is related to Emacs default commands to operating on windows (C-x 4) and the undo operations with [uU] letter.

There are some buffers that winner will not restore, I list them in the winner-boring-buffers.

(use-package winner
  :ensure nil
  :hook ((after-init . winner-mode))
  :init
  (setq winner-dont-bind-my-keys t)
  (setq winner-boring-buffers
        '("*Completions*"
          "*Compile-Log*"
          "*inferior-lisp*"
          "*Fuzzy Completions*"
          "*Apropos*"
          "*Help*"
          "*cvs*"
          "*Buffer List*"
          "*Ibuffer*"
          "*esh command on file*"))
  :bind (("C-x 4 u" . winner-undo)
         ("C-x 4 U" . winner-redo)))

Restart Emacs

(use-package restart-emacs
  :ensure t)

Kill ring

There is a lot of customization to the kill ring, and while I have not used it much before, I decided that it was time to change that.

Maximum entries on the ring

The default is 60, I personally need more sometimes.

(setq kill-ring-max 100)

popup-kill-ring

Out of all the packages I tried out, this one, being the simplest, appealed to me most. With a simple M-y you can now browse your kill-ring like browsing autocompletion items. C-n and C-p totally work for this.

(use-package popup-kill-ring
  :ensure t
  :bind ("M-y" . popup-kill-ring))

Autocomplete

(use-package auto-complete
  :init
  (progn
    (ac-config-default)
    (global-auto-complete-mode t)))

Projectile

(use-package projectile
  :config
  (projectile-mode t))

Yasnippet

(use-package yasnippet
  :ensure t
  :init
  (yas-global-mode 1))

(use-package auto-yasnippet
  :ensure t)

(use-package yasnippet-snippets
  :after (yas-global-mode))

Langs

General

Prog mode

(add-hook 'prog-mode-hook 'display-line-numbers-mode)
(use-package rainbow-delimiters
  :ensure t
  :hook ((cider-mode . rainbow-delimiters-mode)
         (cider-repl-mode-hook . rainbow-delimiters-mode)
         (emacs-lisp-mode . rainbow-delimiters-mode)
         (common-lisp-mode . rainbow-delimiters-mode)
         (scheme-mode . rainbow-delimiters-mode)
         (lisp-mode . rainbow-delimiters-mode)))

(use-package smartparens
  :config
  (progn
    (setq sp-base-key-bindings 'paredit
         sp-autoskip-closing-pair 'always
         sp-hybrid-kill-entire-symbol nil)
    (sp-use-paredit-bindings)))

(use-package aggressive-indent)

(use-package eldoc
  :init
  (setq eldoc-idle-delay 0.1
        eldoc-echo-area-use-multiline-p nil))

smart shift

(use-package smart-shift
  :ensure t
  :config
  (global-smart-shift-mode t))

Hide block of code

Enable hide definitions functions

(use-package hideshow
  :defer t
  :commands (hs-toggle-hiding)
  :delight hs-minor-mode
  :config
  (add-hook 'prog-mode-hook 'hs-minor-mode)
  (global-set-key (kbd "C-c h") 'hs-toggle-hiding))

expand region

(use-package expand-region)

Lisp General Mode

(use-package highlight-numbers
  :config (add-hook 'prog-mode-hook 'highlight-numbers-mode))
(require 'semantic)

;; (global-semanticdb-minor-mode        1)
;; (global-semantic-idle-scheduler-mode 1)
;; (global-semantic-stickyfunc-mode     0)

;; (semantic-mode 1)

Org and Mu4e’s compose buffer use auto-fill-mode. I like to wrap on column 80.

(setq fill-column 80)

Highlight Numbers

(use-package highlight-numbers
  :config (add-hook 'prog-mode-hook 'highlight-numbers-mode))

Flycheck confs

(use-package flycheck
  :config (progn
            (add-hook 'after-init-hook #'global-flycheck-mode)
            ;; Disable JSHint and json-jsonlist
            (setq-default flycheck-disabled-checkers
                          (append flycheck-disabled-checkers
                                  '(javascript-jshint
                                    json-jsonlist)))))
(use-package flycheck-clj-kondo
 :after flycheck)

Semantic confs

(require 'semantic)

(global-semanticdb-minor-mode        1)
(global-semantic-idle-scheduler-mode 1)
(global-semantic-stickyfunc-mode     0)

(semantic-mode 1)

Company confs

(use-package company-tabnine
  :ensure t
  :after company)

(use-package company
  :delight company-mode
  :init
  (setq company-show-numbers t
        company-dabbrev-downcase nil
        company-dabbrev-ignore-case t
        company-tooltip-limit 10
        company-minimum-prefix-length 2
        company-require-match 'never
        company-tooltip-align-annotations t
        company-transformers '(company-sort-by-occurrence)
        company-idle-delay 0.5
        company-tooltip-align-annotations t
        company-tooltip-flip-when-above t)
  :config
  (setq company-idle-delay 0
        company-minimum-prefix-length 3)
  (global-company-mode))
(defun ora-company-number ()
  "Choose the candidate based on his number at candidate list."
  (interactive)
  (let* ((k (this-command-keys))
         (re (concat "^" company-prefix k)))
    (if (cl-find-if (lambda (s) (string-match re s)) company-candidates)
        (self-insert-command)
      (company-complete-number (string-to-number k)))))

(defun ora-activate-number ()
  "Activate the number-based choices in company."
  (interactive)
  (let ((map company-active-map))
    (mapc
     (lambda (x)
       (define-key map (format "%d" x) 'ora-company-number))
     (number-sequence 0 9))
    ;; (define-key map " " (lambda ()
    ;;                       (interactive)
    ;;                       (company-abort)
    ;;                       (self-insert-command 1)))
    (define-key map (kbd "<return>") nil)))

(eval-after-load 'company
  '(ora-activate-number))

Hippie Expand

Hippie Expand is a more feature complete completion engine than the default dabbrev engine. The main feature I use over dabbrev is that is supports a wide range of backends for finding completions - dabbrev only looks at currently open buffers.

(setq hippie-expand-try-functions-list
      '(try-expand-dabbrev
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-complete-file-name-partially
        try-complete-file-name
        try-expand-all-abbrevs
        try-expand-list
        try-expand-line
        try-complete-lisp-symbol-partially
        try-complete-lisp-symbol))

Then we override dabbrev-expand’s keybinding to use hippie-expand instead.

(define-key (current-global-map) [remap dabbrev-expand] 'hippie-expand)

Aggressive Indent

;;(use-package aggressive-indent)

NVM

(use-package nvm)

LSP Mode

(use-package lsp-mode
  :ensure t
  :hook ((clojure-mode . lsp)
         (clojurec-mode . lsp)
         (clojurescript-mode . lsp)
         (dart-mode . lsp)
         (docker-mode . lsp)
         (haskell-mode . lsp)
         (elixir-mode . lsp)
         (python-mode . lsp)
         (go-mode . lsp)
         (c++-mode . lsp)
         (c-mode . lsp)
         (terraform-mode . lsp))
  ;; :custom ((lsp-clojure-server-command '("java" "-jar" "/home/ianffcs/clj-kondo-lsp-server-2020.07.29-standalone.jar")))
  :config
  (progn
    (dolist (m  '(clojure-mode
                   clojurec-mode
                   clojurescript-mode
                   clojurex-mode))
          (add-to-list 'lsp-language-id-configuration `(,m . "clojure")))
     (setq lsp-clojure-server-command (cond ((eq system-type 'darwin) '("/opt/homebrew/bin/clojure-lsp"))
                                            ((eq system-type 'gnu/linux) '("/usr/bin/clojure-lsp")))
           lsp-enable-indentation nil)
     (defvar lsp-elixir--config-options (make-hash-table))
     (setq lsp-haskell-process-path-hie "ghcide")
     (setq lsp-haskell-process-args-hie '())
     (setq lsp-lens-enable t)
     (add-hook
       'lsp-after-initialize-hook
       (lambda ()
         (lsp--set-configuration `(:elixirLS, lsp-elixir--config-options))))
         (add-to-list 'exec-path "/home/ianffcs/elixir-ls/release/"))
  :commands lsp)

;; (use-package lsp-jedi
;;   :ensure t
;;   :config
;;   (with-eval-after-load "lsp-mode"
;;     (add-to-list 'lsp-disabled-clients 'pyls)
;;    (add-to-list 'lsp-enabled-clients 'jedi)))

;; (use-package lsp-python-ms
;;   :ensure t
;;   :init (setq lsp-python-ms-auto-install-server t)
;;   :hook (python-mode . (lambda ()
;;                           (require 'lsp-python-ms)
;;                           (lsp))))

(use-package lsp-ui
  :config
  (setq lsp-headerline-breadcrumb-enable nil)
  :commands lsp-ui-mode)

(use-package company-lsp
  :ensure t
  :commands company-lsp)

(use-package eglot
  :config
  (add-to-list 'eglot-server-programs '(haskell-mode . ("ghcide" "--lsp"))
  (add-to-list 'eglot-server-programs `(elixir-mode "/home/ianffcs/elixir-ls/release/language_server.sh"))))

(use-package dap-mode
  :after lsp-mode
  :config
  (dap-mode 1)
  (dap-ui-mode 1)
  (dap-tooltip-mode 1)
  (tooltip-mode 1)
  (dap-ui-controls-mode 1))

By Lang Configuration

Bash

  (add-hook 'shell-mode-hook 'yas-minor-mode)
  (add-hook 'shell-mode-hook 'flycheck-mode)
  (add-hook 'shell-mode-hook 'company-mode)

  (defun shell-mode-company-init ()
    (setq-local company-backends '((company-shell
                                    company-shell-env
                                    company-etags
                                    company-dabbrev-code))))

  (use-package company-shell
    :ensure t
    :config
      (require 'company)
      (add-hook 'shell-mode-hook 'shell-mode-company-init))

(use-package vterm
    :ensure t)

C

(require 'cc-mode)

(defun my-c-mode-hook ()
  (local-set-key (kbd "C-c c") 'compile)
  ;(setq c-basic-offset   4
  ;      c-default-style  "k&r"
  ;        indent-tabs-mode nil)
  (c-set-offset 'substatement-open 0))

(add-hook 'c++-mode-hook #'my-c-mode-hook)
(add-hook 'c-mode-hook   #'my-c-mode-hook)

(use-package company-irony
  :ensure t
  :config
  (add-to-list 'company-backends 'company-irony))

(use-package irony
  :ensure t
  :config
  (add-hook 'c++-mode-hook 'irony-mode)
  (add-hook 'c-mode-hook 'irony-mode)
  (add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options))

(use-package irony-eldoc
  :ensure t
  :config
  (add-hook 'irony-mode-hook #'irony-eldoc))

Clisp

(use-package slime-company
  :after slime-mode)

;; (load (expand-file-name "~/.roswell/helper.el"))
;; (add-hook 'slime-mode-hook #'smartparens-strict-mode)
;; (add-hook 'slime-repl-mode-hook #'smartparens-strict-mode)
;; (add-hook 'slime-mode-hook #'rainbow-delimiters-mode)
;; (add-hook 'slime-repl-mode-hook #'rainbow-delimiters-mode)
;; (add-hook 'slime-mode-hook #'highlight-parentheses-mode)
;; (add-hook 'slime-repl-mode-hook #'highlight-parentheses-mode)

(use-package slime
  :hook ((slime-mode . lisp-mode)
         (slime-mode . smartparens-strict-mode)
         (slime-mode . rainbow-delimiters-mode)
         (slime-mode . highlight-parentheses-mode)
         (slime-repl-mode . smartparens-strict-mode)
         (slime-repl-mode . rainbow-delimiters-mode)
         (slime-repl-mode . highlight-parentheses-mode))
  :bind (:map slime-mode
         ("M-TAB" . company-complete)
         ("C-c M-j" . slime)
         ("C-c C-d C-s" . slime-describe-symbol)
         ("C-c C-d C-f" . slime-describe-function)
         ("C-c C-s" . slime-selector)
         ("C-x C-e" . slime-eval-last-expression)
         ("C-c C-p" . slime-eval-print-last-expression)
         ("C-c C-c" . slime-eval-last-expression-in-repl))
  :mode
  ("\\.lisp$" . slime-mode)
  :config
  (progn (lambda ()
           (use-package slime-repl-ansi-color)
           (load (expand-file-name "~/quicklisp/slime-helper.el"))
           (whitespace-mode -1)))
  (setq slime-contribs '(slime-repl slime-autodoc slime-banner slime-repl-ansi-color)
        inferior-lisp-program "ros run"
        slime-net-coding-system 'utf-8-unix
        slime-lisp-implementations '((ccl ("ccl"))
                                     (clisp ("clisp" "-q"))
                                     (cmucl ("cmucl" "-quiet"))
                                     (sbcl ("sbcl" "--noinform") :coding-system utf-8-unix))
        slime-default-lisp 'sbcl
        slime-contribs '(slime-fancy slime-company slime-cl-indent)
        slime-complete-symbol-function 'slime-fuzzy-complete-symbol
        slime-fuzzy-completion-in-place t
        slime-enable-evaluate-in-emacs t
        slime-autodoc-use-multiline-p t
        common-lisp-hyperspec-root "/opt/homebrew/share/doc/hyperspec/HyperSpec/"
        common-lisp-hyperspec-symbol-table (concat common-lisp-hyperspec-root "Data/Map_Sym.txt")
        common-lisp-hyperspec-issuex-table (concat common-lisp-hyperspec-root "Data/Map_IssX.txt")))

(defun slime-description-fontify ()
  (with-current-buffer "*slime-description*"
    (slime-company-doc-mode)))

(defadvice slime-show-description (after slime-description-fontify activate)
  "Fontify sections of SLIME Description."
  (slime-description-fontify))

Elisp

(add-hook 'emacs-lisp-mode-hook #'smartparens-strict-mode)
(add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode)
(add-hook 'emacs-lisp-mode-hook #'highlight-parentheses-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'smartparens-strict-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'rainbow-delimiters-mode)
(add-hook 'eval-expression-minibuffer-setup-hook #'highlight-parentheses-mode)
(add-hook 'ielm-mode-hook             #'smartparens-strict-mode)
(add-hook 'ielm-mode-hook             #'rainbow-delimiters-mode)
(add-hook 'ielm-mode-hook #'highlight-parentheses-mode)
(add-hook 'lisp-mode-hook             #'smartparens-strict-mode)
(add-hook 'lisp-mode-hook             #'rainbow-delimiters-mode)
(add-hook 'lisp-mode-hook #'highlight-parentheses-mode)
(add-hook 'lisp-interaction-mode-hook #'smartparens-strict-mode)
(add-hook 'lisp-interaction-mode-hook #'rainbow-delimiters-mode)
(add-hook 'lisp-interaction-mode-hook #'highlight-parentheses-mode)
(add-hook 'scheme-mode-hook           #'smartparens-strict-mode)
(add-hook 'scheme-mode-hook           #'rainbow-delimiters-mode)
(add-hook 'scheme-mode-hook #'highlight-parentheses-mode)
;;(add-hook 'emacs-lisp-mode-hook  #'highlight-sexp-mode)
;; eldoc-mode shows documentation in the minibuffer when writing code
;; http://www.emacswiki.org/emacs/ElDoc
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
(add-hook 'lisp-interaction-mode-hook 'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)

(defun ielm-auto-complete ()
  "Enables `auto-complete' support in \\[ielm]."
  (setq ac-sources '(ac-source-functions
                     ac-source-variables
                     ac-source-features
                     ac-source-symbols
                     ac-source-words-in-same-mode-buffers))
  (auto-complete-mode 1))

(defun ielm/clear-repl ()
  "Clear current REPL buffer."
  (interactive)
  (let ((inhibit-read-only t))
    (erase-buffer)
    (ielm-send-input)))
(use-package eval-sexp-fu)

Clojure

;;(require 'auto-complete-config)

(use-package ac-cider)

(use-package clojure-mode-extra-font-locking)

(defalias 'cquit 'cider-quit)

(use-package parinfer-rust-mode
  :hook emacs-lisp-mode)

(use-package cider
  :hook ((cider-repl-mode . subword-mode)
         (cider-repl-mode . company-mode)
         (cider-repl-mode . smartparens-strict-mode)
         (cider-repl-mode . rainbow-delimiters-mode)
         (cider-repl-mode . set-auto-complete-as-completion-at-point-function)
         (cider-repl-mode . eldoc-mode)
         ;;(cider-repl-mode . prettify-some-chars)
         (cider-mode . subword-mode)
         (cider-mode . company-mode)
         (cider-mode . eldoc-mode)
         (cider-mode . smartparens-strict-mode)
         (cider-mode . rainbow-delimiters-mode)
         (cider-mode . set-auto-complete-as-completion-at-point-function)
         (cider-mode . highlight-parentheses-mode))
  :bind (:map
         cider-mode-map
         ("C-c C-d" . cider-debug-defun-at-point)
         :map
         cider-repl-mode-map
         ("C-c M-o" . cider-repl-clear-buffer))
  :config
  (progn
    (add-hook 'cider-repl-mode-hook #'cider-company-enable-fuzzy-completion)
    (add-hook 'cider-mode-hook #'cider-company-enable-fuzzy-completion)
    (setq cider-repl-pop-to-buffer-on-connect nil
          cider-repl-use-clojure-font-lock nil
          cider-annotate-completion-candidates t
          cider-prompt-for-symbol nil
          cider-repl-use-pretty-printing t
          cider-repl-wrap-history t
          cider-repl-pop-to-buffer-on-connect nil
          cider-repl-prompt-function 'cider-repl-prompt-custom
          cider-jdk-src-paths '("~/projects/java/clojure-1.10.2-sources"
                                "~/projects/java/openjdk-11/src")
          ;;cider-repl-result-prefix ";; =>"
          cider-repl-require-ns-on-set t
          cider-repl-display-in-current-window t
          cider-repl-wrap-history t
          cider-repl-use-pretty-printing 't
          cider-pprint-fn 'puget
          cider-print-options '(("print-color" "true"))
          cider-repl-use-clojure-font-lock t
          cider-auto-select-error-buffer nil
          org-babel-clojure-backend 'cider
          cider-eldoc-display-context-dependent-info t
          cider-save-file-on-load t
          cider-jump-to-pop-to-buffer-actions '((display-buffer-same-window))
          cider-eldoc-display-for-symbol-at-point nil
          nrepl-use-ssh-fallback-for-remote-hosts t
          ;; lsp-enable-completion-at-point nil
          ;; emidje-load-facts-on-eval t
          )
    (when window-system
      (setq pretty-mode t))
    )
  ;; (eval-after-load 'cider #'emidje-enable-nrepl-middleware)
  )

(use-package cider-eval-sexp-fu)
;; (use-package nrepl-eval-sexp-fu)

   ;; (defun prettify-some-chars ()
   ;;   (dolist (x '((true        т)
   ;;                (false       ғ)
   ;;                (:keys       ӄ)
   ;;                (:strs       ş)
   ;;                (nil           Ø)
   ;;                (partial     Ƥ)
   ;;                (with-redefs я)
   ;;                (defn        ƒ)
   ;;                (comp        º)
   ;;                (apply       ζ)
   ;;                (a-fn1       α)
   ;;                (a-fn2       β)
   ;;                (a-fn3       γ)
   ;;                (no-op       ε)))

   ;;     (font-lock-add-keywords
   ;;      nil `((,(concat "[\[({[:space:]]"
   ;;                                "\\(" (symbol-name (first x)) "\\)"
   ;;                                "[\])}[:space:]]")
   ;;                       (0 (progn (compose-region (match-beginning 1)
   ;;                                                 (match-end 1) ,(symbol-name (second x)))
   ;;                                 nil)))))
   ;;     (font-lock-add-keywords
   ;;      nil `((,(concat "^"
   ;;                      "\\(" (symbol-name (first x)) "\\)"
   ;;                      "[\])}[:space:]]")
   ;;             (0 (progn (compose-region (match-beginning 1)
   ;;                                       (match-end 1) ,(symbol-name (second x)))
   ;;                       nil)))))
   ;;     (font-lock-add-keywords
   ;;      nil `((,(concat "[\[({[:space:]]"
   ;;                                 "\\(" (symbol-name (first x)) "\\)"
   ;;                                 "$")
   ;;                        (0 (progn (compose-region (match-beginning 1)
   ;;                                                  (match-end 1) ,(symbol-name (second x)))
   ;;                                  nil)))))
   ;;     ;; prettify set
   ;;     (font-lock-add-keywords
   ;;      nil `(("\\(#\\){"
   ;;             (0 (progn (compose-region (match-beginning 1) (match-end 1)
   ;;                                       "∈")
   ;;                     nil)))))
   ;;     ;; prettify fn's
   ;;     (font-lock-add-keywords
   ;;      nil `(("\\(#\\)("
   ;;           (0 (progn (compose-region (match-beginning 1) (match-end 1)
   ;;                                     ,(make-char 'greek-iso8859-7 107))
;;                     nil)))))))

(use-package clojure-mode
  :hook ( ;;(clojure-mode . aggressive-indent-mode)
         (clojure-mode . smartparens-strict-mode)
         (clojure-mode . subword-mode)
         (clojure-mode . cider-mode)
         (clojure-mode . clj-refactor-mode)
         (clojure-mode . company-mode)
         (clojure-mode . eldoc-mode)
         (clojure-mode . rainbow-delimiters-mode)
         ;;(clojure-mode . highlight-sexp-mode)
         (clojure-mode . highlight-parentheses-mode)
         ;; (clojure-mode . prettify-some-chars)
         )
  :mode (("\\.clj$" . clojure-mode)
         ("\\.cljs$" . clojurescript-mode)
         ("\\.edn$" . clojure-mode)
         ("\\.boot$" . clojure-mode))
  :config
  (progn
    (eval-after-load 'clojure-mode
      '(define-clojure-indent
         (train-n 3)
         (for-all 1)
         (fdef 1)
         (defresolver 1)
         (mlet 1)
         (alet 1)
         ;;(async 1)
         (defapi '(2 nil nil (1)))
         (server 2)
         (sniptest 1)
         (reg-event-db 1)
         (reg-sub 1)
         (reg-sub-raw 1)
         (reg-event-fx 1)
         (reg-fx 1)
         (reg-cofx 1)
         (at-media 1)
         (GET 2)
         (not-join 1)
         (recursive-path 2)
         (wcar 1)
         (implement '(1 (1)))
         (letfn     '(1 ((:defn)) nil))
         (proxy     '(2 nil nil (1)))
         (reify     '(:defn (1)))
         (deftype   '(2 nil nil (1)))
         (defrecord '(2 nil nil (1)))
         (specify   '(1 (1)))))
    (hack-local-variables)
    (define-key clojure-mode-map (kbd "C-t") 'cider-test-rerun-test)
    (setq clojure-thread-all-but-last t
          clojure-align-forms-automatically t
          cider-ns-refresh-show-log-buffer t
          cider-show-error-buffer t;'only-in-repl
          cider-font-lock-dynamically '(macro core function var deprecated)
          yas-minor-mode 1)))

(use-package html-to-hiccup
  :ensure t
  :config
  (define-key clojure-mode-map (kbd "H-h") 'html-to-hiccup-convert-region))

(defun cider-repl-prompt-custom (namespace)
  "Return a prompt string that mentions NAMESPACE."
  (format "λ %s\n" namespace))

(use-package clj-refactor
  :config
  (progn
    (setq cljr-warn-on-eval nil
          cljr-eagerly-build-asts-on-startup nil
          ;;cljr-clojure-test-declaration "[midje.sweet :refer :all]"
          clj-refactor-mode 1
          cljr-magic-require-namespaces
          '(("s"   . "schema.core")
            ("th"  . "common-core.test-helpers")
            ("gen" . "common-test.generators")
            ("d-pro" . "common-datomic.protocols.datomic")
            ("ex" . "common-core.exceptions")
            ("dth" . "common-datomic.test-helpers")
            ("t-money" . "common-core.types.money")
            ("t-time" . "common-core.types.time")
            ("d" . "datomic.api")
            ("m" . "matcher-combinators.matchers")
            ("pp" . "clojure.pprint")
            ("init" . "postman-aux.init")))
    (add-hook 'clojure-mode-hook
              (lambda () (clj-refactor-mode 1)
                (yas-minor-mode 1)
                (cljr-add-keybindings-with-prefix "C-c C-m")))))

(use-package flycheck-joker
  :after clojure-mode
  :ensure t)

(use-package flycheck-clj-kondo
  :ensure t
  :after clojure-mode
  :config
  (dolist (checker
           '(clj-kondo-clj clj-kondo-cljs clj-kondo-cljc clj-kondo-edn))
    (setq flycheck-checkers
          (cons checker (delq checker flycheck-checkers))))
  (dolist (checkers '((clj-kondo-clj . clojure-joker)
                      (clj-kondo-cljs . clojurescript-joker)
                      (clj-kondo-cljc . clojure-joker)
                      (clj-kondo-edn . edn-joker)))
    (flycheck-add-next-checker (car checkers) (cons 'error (cdr checkers)))))

(defun set-auto-complete-as-completion-at-point-function ()
  (setq completion-at-point-functions '(auto-complete)))

(use-package clojure-snippets
  :ensure t
  :defer t)

Dart

(use-package dart-mode
  :config
  (define-key dart-mode-map (kbd "C-c C-o") 'dart-format-buffer)
  (with-eval-after-load "projectile"
  (add-to-list 'projectile-project-root-files-bottom-up "pubspec.yaml")
  (add-to-list 'projectile-project-root-files-bottom-up "BUILD"))
  (setq lsp-auto-guess-root t))

(use-package dart-server)

(use-package lsp-dart
  :ensure t
  :hook (dart-mode . lsp)
  :init
  ;; TODO fix here after
  ;; (dap-register-debug-template "Flutter :: Custom debug"
  ;;                              (list :flutterPlatform "x86_64"
  ;;                                    :program "lib/main_debug.dart"
  ;;                                    :args '("--flavor" "customer_a")))
  )

Elixir

(use-package alchemist)

(use-package elixir-mode
  :hook ((elixir-mode . aggressive-indent-mode)
         (elixir-mode . smartparens-strict-mode)
         (elixir-mode . subword-mode)
         (elixir-mode . rainbow-delimiters-mode)
         (elixir-mode . highlight-parentheses-mode)
         (elixir-mode . alchemist-mode))
  :mode (("\\.ex'" . elixir-mode)
         ("\\.exs\\'" . elixir-mode)
         ("\\.lex\\'" . elixir-mode))
  :init (add-hook 'elixir-mode-hook
                  (lambda () (add-hook 'before-save-hook 'elixir-format nil t))))

(use-package exunit)

Forth

(use-package forth-mode
  :config (progn
            (define-key forth-mode-map (kbd "C-x C-e") #'forth-eval-last-expression)
            (define-key forth-mode-map (kbd "C-c C-c") #'forth-eval-region)))

Kotlin

(use-package kotlin-mode)

(use-package flycheck-kotlin)

(use-package ob-kotlin)

Docker

(use-package dockerfile-mode
  :mode ("\\Dockerfile$" . dockerfile-mode))

(use-package docker-compose-mode)

Elixir

(defun format-elixir-buffer ()
  "Format elixir buffer."
  (add-hook 'before-save-hook 'elixir-format nil t))

(use-package elixir-mode
  :hook ((elixir-mode . format-elixir-buffer)
         (elixir-mode . flycheck-mix-setup))
  :mode (("\\.ex$" . elixir-mode)
         ("\\.exs$" . elixir-mode)))

(use-package alchemist
  :hook ((elixir-mode . alchemist-mode)))

(use-package flycheck-mix)
(use-package exunit)

Java support

We install Java support and setup LSP for Java mode.

(use-package lsp-java)

After first run, lsp-java will detect and download Eclipse JDT Language Server automatically.

Nginx

(use-package nginx-mode)

Python

(use-package python
  :mode ("\\.py" . python-mode)
  :hook ((python-mode . jedi:setup))
  :config (setq python-shell-interpreter "ipython"
                python-shell-interpreter-args "-i"
                py-python-command "python3"))

(use-package jedi
  :config (setq jedi:complete-on-dot t))

(use-package company-jedi
  :ensure t
  :config
  (add-to-list 'company-backends 'company-jedi))

(use-package elpy
  :hook ((python-mode . elpy-mode)
         (python-mode . elpy-enable))
  :custom
  (elpy-rpc-backend "jedi")
  :bind (:map elpy-mode-map
              ("M-." . elpy-goto-definition)
              ("M-," . pop-tag-mark)
              ("<M-S-left>" . elpy-nav-indent-shift-left)
              ("<M-S-right>" . elpy-nav-indent-shift-right)
              ("C-c i" . elpy-autopep8-fix-code)
              ("C-c C-d" . elpy-doc)))

(use-package pip-requirements
  :hook ((pip-requirements-mode . #'pip-requirements-auto-complete-setup)))

(use-package py-autopep8
  :hook ((elpy-mode . py-autopep8-mode)))

(use-package virtualenvwrapper
  :ensure t
  :config
  (venv-initialize-interactive-shells)
  (venv-initialize-eshell))

(use-package pipenv
  :hook (python-mode . pipenv-mode)
  :init
  (setq pipenv-projectile-after-switch-function
        #'pipenv-projectile-after-switch-extended))

(use-package ein)

Hy

(use-package hy-mode)

Rust

(use-package rustic)

Haskell

(use-package lsp-haskell
 :ensure t
 :config
 (setq lsp-haskell-process-path-hie "ghcide"
       lsp-haskell-process-args-hie '())
  ;; Comment/uncomment this line to see interactions between lsp client/server.
 ;; (setq lsp-log-io t)
 )

(use-package haskell-mode
  :ensure t
  :hook (haskell-mode . interactive-haskell-mode))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (use-package intero                                            ;;
;;   :ensure t :config                                            ;;
;;   (progn                                                       ;;
;;     (add-hook 'haskell-mode-hook 'intero-mode)))               ;;
;;                                                                ;;
;; (setq flycheck-check-syntax-automatically '(save new-line))    ;;
;; (flycheck-add-next-checker 'intero '(warning . haskell-hlint)) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WebMode

(use-package web-mode
  :ensure t
  :config
  (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  (add-to-list 'auto-mode-alist '("\\.vue?\\'" . web-mode))
  (setq web-mode-engines-alist
        '(("django"    . "\\.html\\'")))
  (setq web-mode-ac-sources-alist
        '(("css" . (ac-source-css-property))
          ("vue" . (ac-source-words-in-buffer ac-source-abbrev))
          ("html" . (ac-source-words-in-buffer ac-source-abbrev))))

(setq web-mode-enable-auto-closing t))
(setq web-mode-enable-auto-quoting t) ; this fixes the quote problem I mentioned

JS

(use-package js2-mode
  :ensure t
  :ensure ac-js2
  :init
  (progn
    (add-hook 'js-mode-hook 'js2-minor-mode)
    (add-hook 'js2-mode-hook 'ac-js2-mode)))

(use-package js2-refactor
  :ensure t
  :config
  (progn
    (js2r-add-keybindings-with-prefix "C-c C-m")
;; eg. extract function with `C-c C-m ef`.
    (add-hook 'js2-mode-hook #'js2-refactor-mode)))

(use-package tern
  :ensure tern
  :ensure tern-auto-complete
  :config
  (progn
    (add-hook 'js-mode-hook (lambda () (tern-mode t)))
    (add-hook 'js2-mode-hook (lambda () (tern-mode t)))
    (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
    ;;(tern-ac-setup)
))

;;(use-package jade
;;:ensure t
;;)

;; use web-mode for .jsx files
(add-to-list 'auto-mode-alist '("\\.jsx$" . web-mode))


;; turn on flychecking globally
(add-hook 'after-init-hook #'global-flycheck-mode)

;; disable jshint since we prefer eslint checking
(setq-default flycheck-disabled-checkers
  (append flycheck-disabled-checkers
    '(javascript-jshint)))

;; use eslint with web-mode for jsx files
(flycheck-add-mode 'javascript-eslint 'web-mode)

;; customize flycheck temp file prefix
(setq-default flycheck-temp-prefix ".flycheck")

;; disable json-jsonlist checking for json files
(setq-default flycheck-disabled-checkers
  (append flycheck-disabled-checkers
    '(json-jsonlist)))

;; adjust indents for web-mode to 2 spaces
(defun my-web-mode-hook ()
  "Hooks for Web mode. Adjust indents"
  ;;; http://web-mode.org/
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-code-indent-offset 2))

(add-hook 'web-mode-hook  'my-web-mode-hook)

(use-package company-web
  :after web-mode)

(use-package rjsx-mode
  :mode ("\\.jsx$" . rjsx-mode)
  :magic ("%React" . rjsx-mode))

(use-package vue-mode
  :mode
  ("\\.vue$" . vue-mode))

(use-package indium
  :after js2-mode
  :hook ((js2-mode . indium-interaction-mode))
  :bind (:map indium-interaction-mode-map
              ("C-x C-e" . indium-eval-last-node)
              ("C-<f6>" . vs/stop-indium-debug)
              ("S-<f6>" . indium-connect)
              ("<f6>" . indium-launch))
  :config (delight indium-interaction-mode))

(use-package mocha
  :init (setq mocha-reporter "spec")
  :bind (:map js2-mode-map
              (("C-c t" . mocha-test-project))))

(use-package json-mode
  :mode
  ("\\.json$" . json-mode))

TypeScript

(use-package tide
  :ensure t
  :after (typescript-mode company flycheck)
  :hook ((typescript-mode . tide-setup)
         (typescript-mode . tide-hl-identifier-mode)
         (before-save . tide-format-before-save)))

Markdown

(use-package markdown-mode
  :hook ((markdown-mode . visual-line-mode)))

(use-package markdown-mode+)

(use-package markdownfmt
  :config
  (add-hook 'markdown-mode-hook #'markdownfmt-enable-on-save))

(custom-set-variables
 '(markdown-command "/usr/local/bin/pandoc"))

(use-package markdown-preview-mode)

Latex

;; (use-package tex
  ;; :ensure t)

;; (use-package cdlatex
;;   :ensure t)

;; ;;
;(use-package auctex
;;   :ensure t
;;   :config (setq TeX-auto-save t)
;;   (setq TeX-parse-self t)
;;   (setq TeX-close-quote "")
;;   (setq TeX-open-quote ""))


;; (defcustom
;;   prelude-latex-fast-math-entry 'LaTeX-math-mode
;;   "Method used for fast math symbol entry in LaTeX."
;;   :link '(function-link :tag "AUCTeX Math Mode" LaTeX-math-mode)
;;   :link '(emacs-commentary-link :tag "CDLaTeX" "cdlatex.el")
;;   :group 'prelude
;;   :type '(choice (const :tag "None" nil)
;;                  (const :tag "AUCTeX Math Mode" LaTeX-math-mode)
;; (const :tag "CDLaTeX" cdlatex)))

;; (defun tex-view ()
;;   (interactive)
;;   (tex-send-command "evince" (tex-append tex-print-file ".pdf")))

;; (require 'latex-pretty-symbols)
;; (add-hook 'markdown-mode-hook 'pandoc-mode)
;; (add-hook 'markdown-mode-hook 'latex-unicode-simplified)
;; (setq markdown-enable-math 1)
;; (add-hook 'org-mode-hook 'latex-unicode-simplified)

;; (eval-after-load "tex"
;;   '(add-to-list 'TeX-command-list '("latexmk" "latexmk -synctex=1 -shell-escape -pdf %s" TeX-run-TeX nil t :help "Process file with latexmk")))
;; (eval-after-load "tex"
;;   '(add-to-list 'TeX-command-list '("xelatexmk" "latexmk -synctex=1 -shell-escape -xelatex %s" TeX-run-TeX nil t :help "Process file with xelatexmk")))
;; (add-hook 'TeX-mode-hook '(lambda () (setq TeX-command-default "latexmk")))

Scheme

(use-package geiser
  :ensure t
  :hook ((geiser-repl-mode . subword-mode)
         (geiser-repl-mode . company-mode)
         (geiser-repl-mode . smartparens-strict-mode)
         (geiser-repl-mode . rainbow-delimiters-mode)
         (geiser-repl-mode . highlight-parentheses-mode)
         (geiser-mode . smartparens-strict-mode)
         (geiser-mode . rainbow-delimiters-mode)
         (geiser-mode . highlight-parentheses-mode))
  :config (setq geiser-mode-start-repl-p t
                geiser-active-implementations '(guile racket)))

TeX

I used to use latex-preview-pane for comfortable editing, but not anymore…

;; (use-package latex-preview-pane
;;   :config
;;   (when (display-graphic-p)
;;     (latex-preview-pane-enable)))

To compile the current file, we resort to Rubber, an external tool.

(defun rubber-compile-file ()
  (interactive)
  (shell-command
   (concat "rubber -d " buffer-file-name))
  (message "Finished LaTeX compilation."))

It is also interesting to have pretty symbols for our LaTeX files.

(use-package latex-pretty-symbols)

R

(use-package ess
  :ensure t)

OpenSCAD

(use-package scad-mode)

CSS

CSV

(use-package csv-mode
  :ensure t
  :config
  (setq csv-separators '("," ";" "|" " " )))

Plantuml

(use-package plantuml-mode
  :mode ("\\.plantuml\\'" . plantuml-mode)
  :config
  (let ((plantuml-directory (concat user-emacs-directory "private/"))
        (plantuml-link "http://sourceforge.net/projects/plantuml/files/plantuml.jar/download"))
    (let ((plantuml-target (concat plantuml-directory "plantuml.jar")))
      (if (not (file-exists-p plantuml-target))
          (progn (message "Downloading plantuml.jar")
                 (shell-command
                  (mapconcat 'identity (list "wget" plantuml-link "-O" plantuml-target) " "))
                 (kill-buffer "*Shell Command Output*")))
      (setq org-plantuml-jar-path plantuml-target
            plantuml-jar-path plantuml-target
            plantuml-default-exec-mode 'jar
            plantuml-output-type "svg"))))

;;(use-package flycheck-plantuml
;;  :config (flycheck-plantuml-setup))

Go

(use-package go-mode
  :hook ((go-mode . smartparens-strict-mode)
         (go-mode . rainbow-delimiters-mode)
         (before-save-hook . gofmt-before-save))
  :init (add-hook 'go-mode-hook
                  (lambda ()
                    ;;(setq gofmt-command "goimports")
                    (add-hook 'before-save-hook 'lsp-organize-imports nil t)
                    (setq truncate-lines t
                          indent-tabs-mode t
                          tab-width 4
                          ;; lsp-ui-sideline-enable nil
                          ;; lsp-ui-doc-enable nil
                          lsp-gopls-staticcheck t
                          lsp-eldoc-render-all t
                          lsp-gopls-complete-unimported t
                          company-tooltip-limit 20
                          company-idle-delay .3
                          company-echo-delay 0
                          company-begin-commands '(self-insert-command))
                    (defun go-run-save-file ()
                      (interactive)
                      (save-buffer)
                      (go-run))
                    (local-set-key (kbd "C-c C-c") 'go-run-save-file)
                    (local-set-key (kbd "M-.") 'godef-jump)
                    (local-set-key (kbd "M-b") 'pop-tag-mark)
                    (local-set-key (kbd "C-c r w") 'lsp-workspace-restart)
                    (local-set-key (kbd "C-c C-r") 'go-remove-unused-imports)
                    (local-set-key (kbd "C-c C-a") 'go-import-add)
                    (local-set-key (kbd "C-c C-g") 'go-goto-imports)
                    (local-set-key (kbd "C-c C-f") 'gofmt)
                    (local-set-key (kbd "C-c r .") 'lsp-find-definition)
                    (local-set-key (kbd "C-c r ,") 'lsp-find-references)
                    (local-set-key (kbd "C-c r i") 'lsp-find-implementation)
                    (local-set-key (kbd "C-c r j") 'go-guru-definition)
                    (local-set-key (kbd "C-c r d") 'go-guru-describe)
                    (local-set-key (kbd "C-c o i") 'lsp-organize-imports)
                    (local-set-key (kbd "C-c s f") 'gofmt-before-save)
                    (local-set-key (kbd "C-c r r") 'lsp-rename)
                    (local-set-key (kbd "C-c t f") 'go-test-current-test)
                    (local-set-key (kbd "C-c t a") 'go-test-current-file)
                    (lsp)
                    (gofmt-before-save)
                    (go-guru-hl-identifier-mode)
                    (set (make-local-variable 'company-backends) '(company-go))
                    (company-mode)))
  :config
  (progn
    (add-to-list 'auto-mode-alist (cons "\\.go\\'" 'go-mode))))


(use-package go-guru)

(use-package go-eldoc
  :init (lambda ()
          (set-face-attribute 'eldoc-highlight-function-argument nil
                              :underline t :foreground "green"
                              :weight 'bold))
  :config
  (add-hook 'go-mode-hook 'go-eldoc-setup))

(use-package go-complete
  :ensure t
  :config
  (add-hook 'completion-at-point 'go-complete-at-point))

(use-package gorepl-mode
  :hook ((go-mode . flycheck-golangci-lint-setup)))

(use-package go-tag)

(use-package go-gen-test)

(use-package company-go)

(use-package flycheck-golangci-lint)

(use-package go-dlv
  :ensure t)

(use-package gotest
  :ensure t)

Terraform

(use-package hcl-mode)
(use-package terraform-mode)
(use-package terraform-doc)
(use-package company-terraform)

K8S

(use-package kubel
  :after (vterm)
  :config (kubel-vterm-setup))

Desktop-mode restore Buffers

(use-package desktop
  :if window-system
  :straight nil
  :hook ((after-init . desktop-restore)
         (desktop-after-read . desktop-remove))
  :custom
  (desktop-path `(,user-emacs-directory))
  (desktop-dirname user-emacs-directory)
  (desktop-base-file-name "desktop")
  (desktop-base-lock-name "desktop.lock")
  (desktop-save t)
  (desktop-load-locked-desktop t)
  :init
  (defun desktop-remove ()
    (let ((desktop desktop-dirname))
      (desktop-remove)
      (setq desktop-dirname desktop)))
  (defun saved-desktop-p ()
    "Check if desktop exists."
    (file-exists-p (concat desktop-dirname "/" desktop-base-file-name)))
  (defun desktop-restore ()
    "Restore a saved emacs session."
    (interactive)
    (desktop-save-mode t)
    (if (saved-desktop-p)
        (desktop-read)
      (message "No desktop found."))))

Private

(defconst private-dir (expand-file-name "private" user-emacs-directory))
(defconst temp-dir (format "%s/cache" private-dir))

(unless (file-exists-p private-dir)
  (make-directory private-dir :parents))

(unless (file-exists-p temp-dir)
  (make-directory temp-dir :parents))

Alerts

Alert

(use-package alert
  :config
  (setq alert-default-style 'libnotify
        alert-log-messages t))

User configuration

Telegram notifications

(add-to-list 'alert-user-configuration
             '(((:category . "telega"))
               log nil))
(add-to-list
       'alert-user-configuration
       '(((:message . "@ianffcs\\|Ian")
          (:category . "telega"))
         libnotify nil))

Version Control Systems

Ediff

Sane config for ediff which is basically removing noisy highlights, avoiding crazy multi-frames setup, ignoring some whitespaces and windows should be side-by-side.

(use-package ediff
  :init
  (setq ediff-highlight-all-diffs nil)
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (setq ediff-diff-options "-w")
  (setq ediff-split-window-function 'split-window-horizontally))

Magit

(setq project-switch-commands t)

(use-package magit
  :ensure t
  :defer t
  :bind ("C-x g" . magit-status)
  :init
  (setq magit-diff-options (quote ("--word-diff"))
        magit-diff-refine-hunk 'all
        ;;magit-completing-read-function 'magit-ido-completing-read
        ;;highlight individual word and letter changes when hunk diff displays
        magit-diff-refine-hunk t
        ;; don't tell me when magit reverts buffers
        magit-revert-buffers 'silent
        ;; always show the verbose diff in commit windows
        magit-commit-arguments '("--verbose")
        ;; timeout when magit takes a while to call out to git
        magit-process-popup-time 10)
  :config
  (add-to-list 'magit-no-confirm 'stage-all-changes)
)


(use-package git-gutter
  :ensure t
  :init
  (global-git-gutter-mode +1))

(use-package browse-at-remote :ensure t)

(use-package gitignore-templates :ensure t)

Org

Org General confs

(use-package org
  :straight nil
  :init (org-crypt-use-before-save-magic)
  :hook ((org-mode . toggle-word-wrap)
         (org-mode . org-indent-mode)
         (org-mode . turn-on-visual-line-mode)
         (org-mode . (lambda () (display-line-numbers-mode -1)))
         (org-mode . auto-revert-mode))
  :bind (("C-c l" . org-store-link)
         ("C-c a" . org-agenda)
         ("C-c d" . org-decrypt-entry))
  :mode (("\\.org$" . org-mode))
  :config
  (setq
   org-default-notes-files "~/sync/orgfiles/notes.org.gpg"
   org-catch-invisible-edits 'smart ;; or show
   org-export-html-postamble nil
   org-hide-leading-stars t
   org-startup-indented t
   org-display-inline-images t
   org-redisplay-inline-images t
   org-startup-with-inline-images "inlineimages"
    ;org-agenda-files (list "~/sync/orgfiles/life.org.gpg" "~/sync/orgfiles/personal_cal.org.gpg" "~/sync/orgfiles/work_cal.org.gpg")
   org-todo-keywords '((sequence "TODO(t)" "PENDING(p!)" "WAIT(w@)" "VERIFY(v)" "|" "DONE(d!)" "CANCELED(c@)")
                       (sequence "REPORT(r@)" "BUG(b@)" "KNOWNCAUSE(k@)" "|" "FIXED(f!)"))
   org-edit-src-content-indentation 0
   org-src-tab-acts-natively t
   org-src-fontify-natively t
   org-confirm-babel-evaluate nil
   org-support-shift-select 'always
   org-hide-emphasis-markers        t
   org-edit-src-content-indentation 0
   org-src-tab-acts-natively        t
   org-src-fontify-natively         t
   org-src-preserve-indentation     t
   org-file-apps '((auto-mode . emacs)
                   ("\\.mm\\'" . default)
                   ("\\.x?html?\\'" . "/usr/bin/firefox %s")
                   ;;("\\.pdf\\'" . "/usr/bin/zathura %s")
                   )
   org-display-inline-images t
   org-redisplay-inline-images t
   org-startup-with-inline-images "inlineimages"
   org-confirm-elisp-link-function nil
   org-hide-emphasis-markers t
   org-babel-clojure-nrepl-timeout nil
   org-export-allow-bind-keywords t
   org-confirm-babel-evaluate       t
   org-tags-exclude-from-inheritance (quote ("crypt"))
   org-crypt-key "A6A63F72F3FA0BE546769D9013C0FCE929207C95"
   auto-save-default nil)

  (add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)
  (add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images)
  (defun do-org-show-all-inline-images ()
    (interactive)
    (org-display-inline-images t t))
  (global-set-key (kbd "C-c C-x C v")
                  'do-org-show-all-inline-images)

  (use-package ob-restclient)
  (use-package ob-hy)
  (use-package ob-prolog)
  (use-package ob-async
    :init (setq ob-async-no-async-languages-alist '("ipython")))
  (use-package ox-reveal)

  (org-defkey org-mode-map "\C-x\C-e" 'cider-eval-last-sexp)
  (org-defkey org-mode-map "\C-c\C-d" 'cider-doc))

(use-package toc-org
  :after org
  :hook (org-mode . toc-org-enable))

(defun my/org-clock-query-out ()
  "Ask the user before clocking out.
This is a useful function for adding to `kill-emacs-query-functions'."
  (if (and
       (featurep 'org-clock)
       (funcall 'org-clocking-p)
       (y-or-n-p "You are currently clocking time, clock out? "))
      (org-clock-out)
    t)) ;; only fails on keyboard quit or error

;; timeclock.el puts this on the wrong hook!
(add-hook 'kill-emacs-query-functions 'my/org-clock-query-out)
;; organize journal confs after
;;(use-package org-web-tools :ensure t)

Agenda

(require 'org-agenda)

(use-package calendar
  :ensure nil
  :hook (calendar-today-visible . calendar-mark-today)
  :config
  (setq calendar-latitude -23.5475
        calendar-longitude -46.63611
        calendar-location-name "Sao_Paulo, Brazil")
  (setq calendar-holiday-marker t))

;;(load (expand-file-name (concat user-emacs-directory "elisp/brazil-holidays.el")))
;;(setq calendar-holidays holiday-brazil-all)

(when (file-exists-p (concat user-emacs-directory "sensitive/agenda.el"))
  (load (expand-file-name (concat user-emacs-directory "sensitive/agenda.el"))))
(add-hook 'org-mode-hook 'auto-revert-mode)

Appearance

(use-package org-superstar
  :config (progn (add-hook 'org-mode-hook (lambda () (org-superstar-mode 1)))))

(use-package fill-column-indicator
  :config (progn
            (add-hook 'org-mode-hook
                      (lambda ()
                        (setq fci-rule-width 1)
                        (setq fci-rule-color "darkblue")))
            (add-hook 'org-mode-hook 'turn-on-auto-fill)))

Org Alert

(use-package org-alert
  :config (progn
            (setq alert-default-style          'libnotify
                  org-alert-notification-title "*org-mode*"
                  org-alert-interval           21600)
            (org-alert-enable)))

Exports and Org-Babel

Let’s begin by setting up a few things for Babel.

(setq org-export-allow-bind-keywords t)

(use-package ob-go)
(use-package ess) ;; package for languages such as Julia, R
(org-babel-do-load-languages 'org-babel-load-languages
                             '((lisp   . t)
                               (go     . t)
                               (shell  . t)
                               (dot    . t)
                               (js     . t)
                               ;;(julia  . t)
                               (C      . t)
                               (scheme . t)
                               (prolog . t)
                               (python . t)
                               ;;(ein    . t)
                               (emacs-lisp . t)
                               (clojure . t)
                               (hy . y)
                               (restclient . t)
                               (plantuml . t)
                               (sql . t)))

(mapc (lambda (x)
        (add-to-list 'org-babel-tangle-lang-exts x))
      '(("js"      . "js")
        ("gnu-apl" . "apl")))

HTMLize

Configure Htmlize to preferred defaults.

(use-package htmlize
  :config (setq htmlize-output-type 'css))

LaTeX

(require 'ox-latex)
(unless (boundp 'org-latex-classes)
  (setq org-latex-classes nil))

(add-to-list 'org-latex-classes
             '("abntex2"
               "\\documentclass{abntex2}
                  [NO-DEFAULT-PACKAGES]
                  [EXTRA]"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")
               ("\\maketitle" . "\\imprimircapa")))

(add-to-list 'org-latex-classes
             '("standalone"
               "\\documentclass{standalone}
                [NO-DEFAULT-PACKAGES]"))

I also like to use the plain PDF export.

(setq org-latex-pdf-process '("latexmk -shell-escape -bibtex -f -pdfxe -8bit %f"))

Also, for buffer images to scale and look good, we use this:

;;(plist-put org-format-latex-options :scale 1.2)

When using the minted package for source code, make sure that Common Lisp uses highlighting:

(setq org-latex-listings 'minted)
(add-to-list 'org-latex-minted-langs
             '(lisp "common-lisp"))
(add-to-list 'org-latex-packages-alist '("" "minted"))

inputenc configuration for Unicode characters.

(setq org-latex-inputenc-alist '(("utf8" . "utf8x")))

Using mathletters from ucs also helps a lot.

(add-to-list 'org-latex-default-packages-alist
             '("mathletters" "ucs" nil))

Epub

Export Org filex to Epub format.

(use-package ox-epub)

Org-ref

(use-package org-ref
  :config
  (setq reftex-default-bibliography "~/sync/bibliography.bib"
        org-ref-bibliography-notes "~/sync/bibliography/notes.org"
        org-ref-default-bibliography '("~/sync/bibliography/references.bib")
        org-ref-pdf-directory "~/sync/bibliography/bibtex-pdfs/"))

Org Reveal.js

;; (setq org-reveal-mathjax t
;;       org-reveal-root "https://cdn.jsdelivr.net/npm/[email protected]/js/reveal.min.js"
;;       org-re-reveal-root "~/reveal")

(use-package org-re-reveal
  :config (setq org-ref-default-bibliography '("references.bib")
                org-ref-bibliography-entry-format
                '(("article" . "%a, %t, <i>%j %v(%n)</i>, %p (%y). <a href=\"%U\">%U</a>")
                  ("book" . "%a, %t, %u, %y. <a href=\"%U\">%U</a>")
                  ("inproceedings" . "%a, %t, %b, %y. <a href=\"%U\">%U</a>")
                  ("incollection" . "%a, %t, %b, %u, %y. <a href=\"%U\">%U</a>")
                  ("misc" . "%a, %t, %i, %y.  <a href=\"%U\">%U</a>")
                  ("phdthesis" . "%a, %t, %s, %y.  <a href=\"%U\">%U</a>")
                  ("techreport" . "%a, %t, %i, %u (%y).")
                  ("proceedings" . "%e, %t in %S, %u (%y)."))))

(use-package org-ref
  :after org-re-reveal)

(use-package org-re-reveal-ref
  :after org-re-reveal)

(let ((emacs-reveal-path "~/.emacs.d/elpa/emacs-reveal"))
  (when (file-directory-p emacs-reveal-path)
    (add-to-list 'load-path emacs-reveal-path)
    (require 'emacs-reveal)))

;; (require 'oer-reveal-publish)
;; (oer-reveal-setup-submodules t)
;; (oer-reveal-generate-include-files t)
;; (oer-reveal-publish-setq-defaults)

Presentations

I use Epresentation which makes Emacs fullscreen in org.

(use-package epresent)

Org-noter

Org-noter is a tool for writing notes in Org for PDFs, EPUB, DVI, PS, etc. See the documentation here.

(use-package pdf-tools)
(use-package nov)
(use-package djvu)
(use-package org-noter)

Org-roam

(use-package org-roam
  :pin melpa
  :ensure t
  :custom
  (org-roam-directory "~/org-roam/")
  :bind (:map org-roam-mode-map
              (("C-c n l" . org-roam)
               ("C-c n f" . org-roam-find-file)
               ("C-c n g" . org-roam-graph))
         :map org-mode-map
         (("C-c n i" . org-roam-insert))
         (("C-c n I" . org-roam-insert-immediate))))

Deft

(use-package deft
  :after org-roam
  :custom
  (deft-recursive t)
  (deft-use-filter-string-for-filename t)
  (deft-default-extension "org")
  (deft-directory org-roam-directory))

Org-journal

;;(load-sensible-file "journal.el")

(defvar org-journal-loaded nil)

(use-package org-journal
  :after org
  :bind (("C-c T" . org-journal-new-entry)
         ("C-c Y" . journal-file-yesterday))
  :init
  (defun org-journal-load-files ()
    (interactive)
    (when (not org-journal-loaded)
      (setq org-agenda-file-regexp "\\`[^.].*\\.org'\\|[0-9]$")
      (add-to-list 'org-agenda-files org-journal-dir)
      (setq org-journal-loaded t)))
  :config
  (setq org-journal-date-format "%e %b %Y (%A)"
        org-journal-dir "~/sync/orgfiles"
        org-journal-enable-encryption t
        org-journal-file-format "%Y%m%d"
        org-journal-time-format ""))

Org-AI

;; whisper, everything below this point is only needed if you want speech input

(defun rk/get-ffmpeg-device ()
  "Gets the list of devices available to ffmpeg.
The output of the ffmpeg command is pretty messy, e.g.
  [AVFoundation indev @ 0x7f867f004580] AVFoundation video devices:
  [AVFoundation indev @ 0x7f867f004580] [0] FaceTime HD Camera (Built-in)
  [AVFoundation indev @ 0x7f867f004580] AVFoundation audio devices:
  [AVFoundation indev @ 0x7f867f004580] [0] Cam Link 4K
  [AVFoundation indev @ 0x7f867f004580] [1] MacBook Pro Microphone
so we need to parse it to get the list of devices.
The return value contains two lists, one for video devices and one for audio devices.
Each list contains a list of cons cells, where the car is the device number and the cdr is the device name."
  (unless (string-equal system-type "darwin")
    (error "This function is currently only supported on macOS"))

  (let ((lines (string-split (shell-command-to-string "ffmpeg -list_devices true -f avfoundation -i dummy || true") "\n")))
    (cl-loop with at-video-devices = nil
             with at-audio-devices = nil
             with video-devices = nil
             with audio-devices = nil
             for line in lines
             when (string-match "AVFoundation video devices:" line)
             do (setq at-video-devices t
                      at-audio-devices nil)
             when (string-match "AVFoundation audio devices:" line)
             do (setq at-audio-devices t
                      at-video-devices nil)
             when (and at-video-devices
                       (string-match "\\[\\([0-9]+\\)\\] \\(.+\\)" line))
             do (push (cons (string-to-number (match-string 1 line)) (match-string 2 line)) video-devices)
             when (and at-audio-devices
                       (string-match "\\[\\([0-9]+\\)\\] \\(.+\\)" line))
             do (push (cons (string-to-number (match-string 1 line)) (match-string 2 line)) audio-devices)
             finally return (list (nreverse video-devices) (nreverse audio-devices)))))

(defun rk/find-device-matching (string type)
  "Get the devices from `rk/get-ffmpeg-device' and look for a device
matching `STRING'. `TYPE' can be :video or :audio."
  (let* ((devices (rk/get-ffmpeg-device))
         (device-list (if (eq type :video)
                          (car devices)
                        (cadr devices))))
    (cl-loop for device in device-list
             when (string-match-p string (cdr device))
             return (car device))))

(defcustom rk/default-audio-device nil
  "The default audio device to use for whisper.el and outher audio processes."
  :type 'string)

(defun rk/select-default-audio-device (&optional device-name)
  "Interactively select an audio device to use for whisper.el and other audio processes.
If `DEVICE-NAME' is provided, it will be used instead of prompting the user."
  (interactive)
  (let* ((audio-devices (cadr (rk/get-ffmpeg-device)))
         (indexes (mapcar #'car audio-devices))
         (names (mapcar #'cdr audio-devices))
         (name (or device-name (completing-read "Select audio device: " names nil t))))
    (setq rk/default-audio-device (rk/find-device-matching name :audio))
    (when (boundp 'whisper--ffmpeg-input-device)
      (setq whisper--ffmpeg-input-device (format ":%s" rk/default-audio-device)))))

;; example usage:
;; (rk/find-device-matching "FaceTime" :video)
;; (rk/find-device-matching "Macbook Pro Microphone" :audio)
;; (rk/select-default-audio-device)

(use-package org-ai
  :ensure t
  :commands (org-ai-mode
             org-ai-global-mode)
  :init
  (add-hook 'org-mode-hook #'org-ai-mode) ; enable org-ai in org-mode
  (org-ai-global-mode) ; installs global keybindings on C-c M-a
  :config
  (setq org-ai-default-chat-model "gpt-4-32k-0314") ; if you are on the gpt-4 beta:
  (org-ai-install-yasnippets)) ; if you are using yasnippet and want `ai` snippets

(use-package whisper
  :straight  `(whisper :type git :host github :repo "natrys/whisper.el")
  :config
  (setq whisper-model "base"
        whisper-language "pt"
        whisper-translate nil
        whisper-install-directory "/tmp/")
  (when (eq system-type 'darwin)
    (rk/select-default-audio-device "Microfone (MacBook Pro)")
    (when rk/default-audio-device)
    (setq whisper--ffmpeg-input-device (format ":%s" rk/default-audio-device))))

(use-package greader :ensure)
(require 'whisper)
(require 'org-ai-talk)

;; macOS speech settings, optional
(setq org-ai-talk-say-words-per-minute 210)
(setq org-ai-talk-say-voice "Karen")

Dashboard

(use-package dashboard
  :ensure t
  :config
  (dashboard-setup-startup-hook)
  (progn
    (setq initial-buffer-choice (lambda ()
                                  (get-buffer "*dashboard*"))
          dashboard-center-content t
          dashboard-startup-banner 'logo
          dashboard-set-init-info t
          dashboard-set-navigator t
          dashboard-items '((recents  . 5)
                            (bookmarks . 5)
                            (projects . 10)
                            (agenda . 5)
                            (registers . 5)))))

Tramp

(use-package sudo-edit
    :ensure t
    :bind("s-e" . sudo-edit))

(use-package counsel-tramp
  :config (setq tramp-default-method "ssh"))

(setq tramp-backup-directory-alist backup-directory-alist)

Iedit and narrow/widen dwin

; mark and edit all copies of the marked region simultaniously.
(use-package iedit
  :ensure t)

; if you're windened, narrow to the region, if you're narrowed, widen
; bound to C-x n
(defun narrow-or-widen-dwim (p)
"If the buffer is narrowed, it widens. Otherwise, it narrows intelligently.
Intelligently means: region, org-src-block, org-subtree, or defun,
whichever applies first.
Narrowing to org-src-block actually calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer is already
narrowed."
(interactive "P")
(declare (interactive-only))
(cond ((and (buffer-narrowed-p)
            (not p))
       (widen))
      ((region-active-p)
       (narrow-to-region (region-beginning) (region-end)))
      ((derived-mode-p 'org-mode)
       ;; `org-edit-src-code' is not a real narrowing command.
       ;; Remove this first conditional if you don't want it.
       (cond ((ignore-errors (org-edit-src-code))
              (delete-other-windows))
             ((org-at-block-p)
              (org-narrow-to-block))
             (t (org-narrow-to-subtree))))
      (t (narrow-to-defun))))

Try

  • Try is a package that allows you to try out Emacs packages without installing them. If you pass a URL to a plain text .el-file it evaluates the content, without storing the file.
(use-package try
    :ensure t)

Which key

(use-package which-key
         :config
         (which-key-mode))

Keyfreq

(use-package keyfreq
  :ensure t
  :config
  (require 'keyfreq)
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1))

Searchers

Wgrep

(use-package wgrep
  :ensure t)

Ripgrep

(use-package projectile-ripgrep)
(use-package rg
  :ensure t
  :config
  (rg-define-search search-git-root-or-dir
    :query ask
    :format regexp
    :files "everything"
    :dir (let ((vc (vc-root-dir)))
           (if vc
               vc
               default-directory))
          :confirm prefix
          :flags ("--hidden -g !.git"))
;;        :bind ("M-s g" . bk/search-git-root-or-DIR)
)

Occur

Let’s use an occur snippet from (or emacs. It will offer as the default candidate:

  • the current region, if it’s active
  • the current symbol, otherwise
(defun occur-dwim ()
  "Call `occur' with a sane default."
  (interactive)
  (push (if (region-active-p)
            (buffer-substring-no-properties
             (region-beginning)
             (region-end))
          (let ((sym (thing-at-point 'symbol)))
            (when (stringp sym)
              (regexp-quote sym))))
        regexp-history)
  (call-interactively 'occur))

(global-set-key (kbd "M-s o") 'occur-dwim)

Google this

Artur Malabarba has a nice package called google-this which provides a set of functions for querying google from emacs.

(use-package google-this
  :delight google-this-mode
  :config
  (google-this-mode 1))

This package provides a set of functions under the prefix C-c /. The simplest is C-c / RET which prompts you for a search in the minibuffer, with a default search based on the text around the point.

KeysFunction
C-c / SPCgoogle-this-region
C-c / agoogle-this-ray
C-c / cgoogle-this-translate-query-or-region
C-c / egoogle-this-error
C-c / fgoogle-this-forecast
C-c / ggoogle-this-lucky-search
C-c / igoogle-this-lucky-and-insert-url
C-c / mgoogle-maps
C-c / ngoogle-this-noconfirm
C-c / rgoogle-this-cpp-reference
C-c / sgoogle-this-symbol
C-c / tgoogle-this
C-c / wgoogle-this-word
C-c / <return>google-this-search

PDF Tools

(when (not (eq system-type 'darwin))
  (use-package pdf-tools
  :config (progn (pdf-tools-install)
                 ;;(add-hook 'pdf-view-mode-hook 'pdf-view-midnight-minor-mode)
                 (setq pdf-annot-activate-created-annotations t)
                 (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
                 ;; turn off cua so copy works
                 (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))
                 ;; more fine-grained zooming
                 (setq pdf-view-resize-factor 1.1)
                 ;; keyboard shortcuts
                 (define-key pdf-view-mode-map (kbd "h") 'pdf-annot-add-highlight-markup-annotation)
                 (define-key pdf-view-mode-map (kbd "t") 'pdf-annot-add-text-annotation)
                 (define-key pdf-view-mode-map (kbd "D") 'pdf-annot-delete)
                 (add-hook 'pdf-view-mode-hook 'pdf-view-fit-height-to-window)
                 (add-hook 'pdf-view-mode-hook 'auto-revert-mode)))
  ;; initialise
  ;; open pdfs scaled to fit page

  ;; automatically annotate highlights

  ;; use normal isearch
  )

Regex

(use-package pcre2el
  :ensure t
  :config (pcre-mode))

Telega

(use-package telega
  :load-path  "~/telega.el"
  :commands (telega)
  :defer t
  :config (progn
            (telega-notifications-mode 1) ; DBus notifications
            (setq telega-use-images t))
  :hook ((telega-chat-mode-hook
          .
          (lambda () ; completions
            (set (make-local-variable 'company-backends)
                 (append '(telega-company-emoji
                           telega-company-username
                           telega-company-hashtag)
                         (when (telega-chat-bot-p telega-chatbuf--chat)
                           '(telega-company-botcmd))))
            (company-mode 1)))))

nov.el

Nov.el is good for reading EPUB files on Emacs.

Oh, and I also use Olivetti for centering and making it look good.

(use-package nov
  :config (progn
              (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
              (add-hook 'nov-mode-hook
                        (lambda ()
                          (face-remap-add-relative 'variable-pitch
                                                   :family "Liberation Serif"
                                                   :height 1.0)))
              (setq nov-text-width t
                    visual-fill-column-center-text t)
              (add-hook 'nov-mode-hook 'visual-line-mode)
              (add-hook 'nov-mode-hook 'visual-fill-column-mode)))

Paradox

(use-package paradox
  :config (paradox-enable))

IRC

(use-package circe
  :commands circe
  :preface
  (defun my/circe-count-nicks ()
    "Display the number of users connected on the current channel."
    (interactive)
    (when (eq major-mode 'circe-channel-mode)
      (message "%i users are online on %s."
               (length (circe-channel-nicks)) (buffer-name))))

  (defun my/circe-fetch-password (&rest params)
    "Fetch the NickServ password for an username."
    (require 'auth-source)
    (let ((match (car (apply 'auth-source-search params))))
      (if match
          (let ((secret (plist-get match :secret)))
            (if (functionp secret)
                (funcall secret)
              secret))
        (error "[✗] Password not found for %S" params))))

  (defun my/circe-nickserv-password (server)
    "Fetch the NickServ password for the Libera Chat."
    (my/circe-fetch-password :login "ietcd" :machine "irc.libera.chat"))
  :custom
  (circe-default-part-message nil)
  (circe-default-quit-message nil)
  (circe-format-say (format "{nick:+%ss}: {body}" 8))
  (circe-network-options
   '(("Libera Chat"
      :host "irc.libera.chat"
      :nick "ietcd"
      :tls t
      :port 6697
      :server-buffer-name "⇄ Libera Chat"
      :channels (:after-auth "#archlinux" "#bash" "#emacs" "#linux" "#clojure")
      :nickserv-password my/circe-nickserv-password
      )
     ("Hackint Chat"
      :host "irc.hackint.org"
      :nick "ietcd"
      :tls t
      :port 6697
      :server-buffer-name "⇄ Hackint"
      :channels (:after-auth "#milliways"))
     ("Autistici"
      :host "irc.autistici.org"
      :nick "ietcd"
      :tls t
      :port 6697
      :server-buffer-name "⇄ Autistici"
      :channels (:after-auth "#hackit99" "#ai"))
     ))
  (circe-reduce-lurker-spam t)
  (circe-use-cycle-completion t)
  (lui-flyspell-p t)
  :config
  (circe-lagmon-mode)
  (enable-circe-color-nicks)
  (enable-circe-display-images))

(use-package circe-notifications
  :after circe
  :hook (circe-server-connected . enable-circe-notifications))

GNUS

(setq gnus-select-method '(nnnil nil))

(setq gnus-secondary-select-methods
      '((nnimap "Autistici"
        (nnimap-address "mail.autistici.org")
        (nnimap-server-port 143)
        (nnimap-list-pattern ("INBOX" "*"))
        (nnimap-stream ssl)
        (nnir-search-engine imap)
        (nnmail-expiry-target "nnimap+home:[Example]/Trash")
        (nnmail-expiry-wait 'immediate)
        (nnimap-authenticator login)
        (nnimap-authinfo-file "~/.authinfo.gpg")
        (nnimap-expunge-on-close always))

        ;; (nnimap "Gmail"
        ;;         (nnimap-address "imap.gmail.com")
        ;;         (nnimap-server-port 143)
        ;;         (nnimap-server-port 143)
        ;;         (nnimap-list-pattern ("INBOX" "*"))
        ;;         (nnimap-stream ssl)
        ;;         (nnir-search-engine imap)
        ;;         (nnmail-expiry-target "nnimap+home:[Example]/Trash")
        ;;         (nnmail-expiry-wait 'immediate)
        ;;         (nnimap-authenticator login)
        ;;         (nnimap-authinfo-file "~/.authinfo.gpg")
        ;;         (nnimap-expunge-on-close always))
        ))

(setq gnus-asynchronous t
      gnus-use-cache t
      gnus-use-header-prefetch t)

(setq gnus-posting-styles
      '(("ietcd"
         (address "[email protected]")
     (signature "i etc daemon.")
   ("X-Message-SMTP-Method" "smtp smtp.autistici.org 587 [email protected]"))))