Giter Site home page Giter Site logo

bandobo / .emacs.d Goto Github PK

View Code? Open in Web Editor NEW

This project forked from francismurillo/.emacs.d

0.0 1.0 0.0 13.47 MB

My emacs configuration redux

License: GNU General Public License v3.0

HTML 0.14% Emacs Lisp 98.30% Makefile 0.01% Python 1.31% Shell 0.01% CSS 0.24%

.emacs.d's Introduction

Francis Murillo’s Emacs configuration

Introduction

If I Forget

No words can describe my awe with Emacs and continue to do so. A text editor with a lisp interpreter, it’s concept is so simple and sublime. What joy.

I remember starting Emacs seriously at around August of 2015. Before then, I picked it up lightly and thought(not use) about it; but what really drove me to use it is.

Growth

I was using an IDE before and somebody told me that GUIs change but the shell remains the same. I found myself over time exploring keyboard shortcuts, better terminals and Emacs(or maybe vi).

Lightweight

I had a crappy laptop that always needed to be plugged, had a lot dead pixels, and closes when it overheats; I needed something that would work with what I had.

Linux

Moving from Windows to Linux forced me to reevaluate the software I used. Adopting a new philosophy and OS pushed me in the right direction

Whatever the reason might have been. I just want to say I’m a happy Emacs user and I find comfort and joy in hearing other people talk and share about it.

About My Configuration

I use org-babel as my configuration file once I heard you can do so. Splitting the configuration to multiple files was the plan but the way it weaves nicely to documentation immediately drew me in.

You can load this with (org-babel-load-file "/path/to/file") if you need to reload any changes or just take any snippet you want. I do my best to make my configuration copy friendly on different environments.

Or with an function instead

(defun fn/reload-config ()
  "Reload my configuration again"
  (interactive)
  (org-babel-load-file
   (expand-file-name fn/config-file user-emacs-directory)))

(defun fn/dired-emacs-dir ()
  "Quickly visit emacs directory"
  (interactive)
  (dired user-emacs-directory))

Bootstrap

No Byte Compile

Do not byte compile a file.

(setq-local no-byte-compile t)

Lexical Binding

This makes it so that the file that is produced from tangling this file uses lexical scoping and all succeeding files

(setq lexical-binding t)

Package Sources

Add package sources if not present and reload, this should have been added in the init.el but checked here again for completion.

(defconst fn/package-archives
  `(("gnu" "http://elpa.gnu.org/packages/" 10)
    ("org" "http://orgmode.org/elpa/" 0 )
    ("melpa" "http://melpa.org/packages/" 20))
  "List of my packages")

(mapc
 (lambda (package-archive)
   (pcase-let ((`(,id ,location ,priority) package-archive))
     (unless (assoc-default id package-archives)
       (add-to-list 'package-archives (cons id location))
       (add-to-list 'package-archive-priorities (cons id priority)))))
 fn/package-archives)

Package Manager

The package manager of this whole configuration

(require 'use-package)

(setq use-package-verbose t
   use-package-check-before-init t
   use-package-minimum-reported-time 0.025
   use-package-always-defer t
   use-package-always-defer-install nil)

(defun fn/remove-byte-compiled-files ()
  "Remove byte compiles from emacs directory"
  (interactive)
  (shell-command
   (format "cd '%s' && find . -name '*.elc' -type f | xargs rm -f"
           (expand-file-name user-emacs-directory))))

Org Src

Configuration for using the tangling nature of this configuration

(setq org-confirm-babel-evaluate nil
      org-src-fontify-natively t
      org-src-tab-acts-natively t)

Constants

Some constants to work with

(defconst fn/minute-per-second 60
  "Obviously converting minutes to seconds")

(defconst fn/cache-dir-name ".cache"
  "Place every moving file in this directory")

(defconst fn/cache-dir (expand-file-name fn/cache-dir-name user-emacs-directory)
  "Every cached or moving file should be here like with Spacemacs")

(make-directory fn/cache-dir t)


(defconst fn/setting-dir-name ".setting"
  "Just like `fn/cache-dir-name' but for my persistent setting.")

(defconst fn/setting-dir (expand-file-name fn/setting-dir-name user-emacs-directory)
  "Just like `fn/cache-dir' but for persistent settings.")

(make-directory fn/setting-dir t)


(defconst fn/lib-dir-name "lib"
  "External non-standard files directory")

(defconst fn/lib-dir (expand-file-name fn/lib-dir-name user-emacs-directory)
  "External library directory")

(make-directory fn/lib-dir t)


(defconst fn/system-dir-name "system"
  "System library dependencies directory")

(defconst fn/system-dir (expand-file-name fn/system-dir-name user-emacs-directory)
  "System library for external files.")

(make-directory fn/system-dir t)


(defconst fn/font-dir-name "fonts"
  "Font dependencies directory")

(defconst fn/font-dir (expand-file-name fn/font-dir-name fn/system-dir)
  "External font directory.")

(make-directory fn/font-dir t)


(defconst fn/conf-dir-name "conf"
  "Config dependencies directory")

(defconst fn/conf-dir (expand-file-name fn/conf-dir-name fn/system-dir)
  "External conf directory.")

(make-directory fn/conf-dir t)



(defconst fn/extra-dir-name "extra"
  "Anything under the sun you can put here")

(defconst fn/extra-dir (expand-file-name fn/extra-dir-name user-emacs-directory)
  "Anything under the sun directory")

(make-directory fn/extra-dir t)


(defconst fn/custom-module-dir-name "modules"
  "Custom elisp packages directory name")

(defconst fn/custom-module-dir (expand-file-name fn/custom-module-dir-name fn/library-dir)
  "Custom elisp packages directory")

(make-directory fn/custom-module-dir t)

(defconst fn/custom-script-dir-name "scripts"
  "Custom elisp script directory name")

(defconst fn/custom-script-dir (expand-file-name fn/custom-script-dir-name fn/library-dir)
  "Custom elisp script directory")


(make-directory fn/custom-script-dir t)

(add-to-list 'load-path fn/custom-script-dir)

Basic Setup

Basic configurations anyone can do for vanilla Emacs

Customization

Basis for configuration

;; Don't really care about custom file
(setq custom-file (expand-file-name "custom-file.el" fn/cache-dir))


(defgroup fn nil
  "My namespace for customizing my configuration")


;;* Custom Prefixes
;; Anything that just calls normal commands
;; Binding: C-c n
(define-prefix-command 'fn-standard-prefix-map)

;; Anything that I worked experimentally on
;; Binding: C-c m
(define-prefix-command 'fn-custom-prefix-map)

;; Anything that is important while I am working on something
;; Binding: C-c C-m / C-c C-n / C-c b / C-C C-b
(define-prefix-command 'fn-work-prefix-map)


(defun fn/make-prefixed-keymap (key &optional base-keymap)
  "Make a sparse keymap that is already prefixed by KEY.
It also accepts a BASE-KEYMAP if you are prefixing an existing key map."
  (let* ((prefixed-keymap (make-sparse-keymap))
         (target-keymap (or base-keymap
                            prefixed-keymap)))
    (define-key target-keymap key prefixed-keymap)
    prefixed-keymap))


;;* Custom Key Sequences
(defconst fn/standard-key-sequence (kbd "C-c n")
  "My standard key sequence.")

(defconst fn/custom-key-sequence (kbd "C-c m")
  "My custom key sequence.")

(defconst fn/work-key-sequence (kbd "C-c C-m")
  "My work key sequence.")

(defun fn/make-work-keymap (&optional base-keymap)
  "Just `fn/make-prefixed-keymap` with `fn/work-key-sequence`."
  (fn/make-prefixed-keymap fn/work-key-sequence base-keymap))


(global-set-key (kbd "C-c n") fn-standard-prefix-map)
(global-set-key (kbd "C-c m") fn-custom-prefix-map)

Startup

Everything related to the startup state

(defconst fn/gc-cons-threshold (* 256 1024 1024)
  "A high limit for garbage colection.")

(setq gc-cons-threshold fn/gc-cons-threshold) ;; High memory for Emacs

(defvar fn/my-lightning (concat
                         (propertize
                          " MY LIGHTNING "
                          'face '(:background "#ff1e02" :foreground "#110200"
                                              :box (:line-width 0 :color "#ff1e02")))
                         "...")
  "A reference to continue?987654321.
May I accept the lightning.")

(defvar fn/my-prayer (format "%s %s"
                             fn/my-lightning
                             (concat
                              (propertize
                               " MY PRAYER "
                               'face '(:background "#ffffff" :foreground "#121212"
                                                   :box (:line-width 0 :color "#ffffff")))
                              "..."))
  "The closing message for garbage collection.
May I be lift up.")

(setq garbage-collection-messages nil) ;; My lightning... my prayer

(defun fn/continue-gc (orig-gc &rest args)
  "Wrap some message with ORIG-GC."
  (let ((start-time (current-time)))
    (if (or (minibuffer-prompt) (current-message))
        (apply orig-gc args)
      (prog2
          (message fn/my-lightning)
          (apply orig-gc args)
        (message "%s %s"
                 fn/my-prayer
                 (format "(%.4fs)"
                         (float-time (time-subtract (current-time) start-time))))))))

(advice-add 'garbage-collect :around #'fn/continue-gc)


;; Since the limit is high, it might never gc. So if I am idle, do some cleanup.
(run-with-idle-timer 30 t #'garbage-collect)

(setq inhibit-startup-screen t ;; No need for the awesome startup screen.
      initial-scratch-message nil)

Environment

Some environment configuration.

(set-language-environment "UTF-8") ;; UTF-8 should be the enivorment

(setq visible-bell t) ;; Visual bell for me since audio is a bit more distractive

(fset 'yes-or-no-p 'y-or-n-p) ;; Y or N

Backups

Backups are good, just annoying when things are good

(defconst fn/backup-dir-name "backups/"
  "Backup directory name")

(defconst fn/backup-dir (expand-file-name fn/backup-dir-name fn/cache-dir)
  "Backup directory")


(defconst fn/auto-save-dir-name "auto-save-list/"
  "Auto save directory name")

(defconst fn/auto-save-dir (expand-file-name fn/auto-save-dir-name fn/cache-dir)
  "Auto save directory")


(setq auto-save-timeout 15
      auto-save-list-file-name fn/auto-save-dir

      delete-old-versions t
      version-control t
      vc-make-backup-files t
      backup-by-copying t
      kept-new-versions 10
      kept-old-versions 50

      backup-directory-alist `(("." . ,fn/backup-dir))

      auto-save-list-file-prefix fn/auto-save-dir
      auto-save-file-name-transforms `((".*" ,fn/auto-save-dir t)))

History

Save minibuffer history

(defconst fn/savehist-file-name "savehist"
  "Save history file name")

(defconst fn/savehist-file (expand-file-name fn/savehist-file-name fn/cache-dir)
  "Save history file")


(setq savehist-file fn/savehist-file

      history-length t
      history-delete-duplicates t

      savehist-save-minibuffer-history t
      savehist-additional-variables (list 'kill-ring
                                          'search-ring
                                          'regexp-search-ring))

(savehist-mode t)


(setq bookmark-file (expand-file-name "bookmarks" fn/cache-dir)
      bookmark-default-file (expand-file-name "bookmarks-default" fn/cache-dir))

(add-to-list
 'display-buffer-alist
 (cons
  (rx bos "*Bookmark List*" eos)
  (cons 'display-buffer-same-window (list))))

Editing

Some editing configurations

(setq whitespace-line-column 10000 ;; No line too long font locking please

      ;; C-M-a should go to the beginning of a sentence
      sentence-end-double-space nil

      require-final-newline t)

;; I like tabs but they should just be converted to spaces for equality
(setq-default indent-tabs-mode nil)

(add-hook 'makefile-mode 'indent-tabs-mode)

Bookmark

Bookmark configuration

(setq bookmark-default-file (expand-file-name "bookmarks" fn/cache-dir)
   bookmark-save-flag t)

Search

You must have this setup, it’s like butter and you’re the bread.

(defconst fn/default-search-whitespace-regexp search-whitespace-regexp
  "Store the default whitespace option")

(setq search-highlight t)

;; This ignores whitespace when searching
(setq-default search-whitespace-regexp ".*?")


(defun fn/isearch-forward-normally ()
  "This custom command does i-search without the whitespace skips,
   the vanilla behavior"
  (interactive)
  (let ((search-whitespace-regexp fn/default-search-whitespace-regexp))
    (isearch-forward)))


(defun fn/isearch-backward-normally ()
  "Ditto with fn/isearch-foward-normally except backwards."
  (interactive)
  (let ((search-whitespace-regexp fn/default-search-whitespace-regexp))
    (isearch-backward)))

Coding

Some programming configuration that make sense

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

;; Please indent after newline to maintain sanity
(global-set-key (kbd "RET") 'newline-and-indent)


(make-variable-buffer-local
 (defvar fn/whitespace-cleanup-on-save t
   "When non-nil, delete trailing whitespace on save"))

(add-to-list 'safe-local-variable-values '(fn/whitespace-cleanup-on-save))

(defun fn/delete-trailing-whitespace-on-save ()
  "Delete trailing whitespace on save."
  (when fn/whitespace-cleanup-on-save
    (with-current-buffer (current-buffer)
      (message "Deleting trailing whitespace in %s" (current-buffer))
      (delete-trailing-whitespace (point-min) (point-max)))))

;; (add-hook 'before-save-hook 'fn/delete-trailing-whitespace-on-save)

(defun fn/disable-delete-trailing-whitespace-on-save ()
  "Disable `fn/delete-trailing-whitespace-on-save' for a specific mode."
  (setq-local fn/whitespace-cleanup-on-save nil))

(add-hook 'makefile-mode-hook 'fn/disable-delete-trailing-whitespace-on-save t)


(temp-buffer-resize-mode t)

(setq compilation-window-height 10
      compilation-scroll-output 'first-error
      compilation-ask-about-save nil)

Mouse

I better be a cat

(mouse-avoidance-mode 'cat-and-mouse)

Shell

Some minor shell enhancement

(setq comint-input-ignoredups t)

Request

Some basic configuration with url.

(with-eval-after-load 'url
  (setq url-configuration-directory
        (expand-file-name "url" fn/cache-dir)))

Others

Some other configurations that I can’t classify yet

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

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program "chromium")

Commands

Unlock some commands I need

(put 'narrow-to-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)

Local Variables

Allow safe local variables

(setq enable-local-variables :safe)

(add-to-list 'safe-local-variable-values '(major-mode))
(add-to-list 'safe-local-variable-values '(auto-save-default))
(add-to-list 'safe-local-variable-values  '(backup-inhibited . t))
(add-to-list 'safe-local-variable-values '(epa-file-encrypt-to))

Dependencies

Everything needed to support this more complex configurations

dash

Functionally elisp

(use-package dash
  :ensure t
  :defer t)

(use-package dash-functional
  :ensure t
  :after dash)

async

Not really builtin but should be

(use-package async
  :ensure t
  :defer t)

s

A string library, everyone needs that

(use-package s
  :ensure t)

f

File manipulation library for Emacs

(use-package f
  :ensure t)

promise

Something to help with package configuration

(defconst fn/promise-package-dir (expand-file-name "promise/" fn/custom-module-dir)
  "Promise package location")

(use-package promise
  :load-path fn/promise-package-dir
  :demand t
  :config
  (defmacro fn/use-function (name function &rest body)
    (let ((function-name-var (make-symbol "function-name")))
      `(let ((,function-name-var ,(symbol-name name)))
         (message "Checking function %s" ,function-name-var)
         (if (not (fboundp (quote ,function)))
             (message "Function does not exist")
           (message "Loading function %s" ,function-name-var)
           ,@body
           (message "Configured function %s" ,function-name-var)))))

  (put 'fn/use-function 'lisp-indent-function 'defun)


  (defmacro fn/use-feature (name features &rest body)
    "The equivalent for `use-package' but for combining features as promises."
    (let ((now-var (make-symbol "now"))
        (elapsed-var (make-symbol "elapsed"))
        (feature-name-var (make-symbol "feature-name")))
      `(promise-then
        (apply #'promise-all-features (list ,@(if features
                                           (mapcar (lambda (feature) (list 'quote feature)) features)
                                         (list (list 'quote 'use-package)))))
        (lambda (loaded-features)
          (let ((,feature-name-var ,(symbol-name name))
              (,now-var (current-time)))
            (message "Loading feature package %s" ,feature-name-var)
            ,@body
            (let ((,elapsed-var (float-time (time-subtract (current-time) ,now-var))))
              (if (> ,elapsed-var ,use-package-minimum-reported-time)
                  (message
                   "Configuring feature package %s ... done (%.3fs)"
                   ,feature-name-var
                   ,elapsed-var)
                (message
                 "Configuring feature package %s... done"
                 ,feature-name-var))
              nil))))))

  (put 'fn/use-feature 'lisp-indent-function 'defun)
)

unicode-fonts

Unicode is an required aesthetic

(use-package pcache ;; Required by unicode-fonts
  :ensure t
  :init
  ;; Mentioned here to redirect directory
  (setq pcache-directory (expand-file-name "pcache/" fn/cache-dir)))

(use-package unicode-fonts
  :ensure t
  :demand t
  :config
  (unicode-fonts-setup))

persistent-soft

Nice to have some persistence.

(use-package persistent-soft
  :ensure t
  :demand t
  :config
  (defconst fn/persistence-location "custom-persistence"
    "My persistence location.")

  (defvar fn/persistence-managed-symbols (list)
    "Managed persistent symbols.")


  (defun fn/persistence-store (key value)
    "Just a wrapper for `persistent-soft-store' with KEY and VALUE,
location is defined by `fn/-persistence-location'."
    (persistent-soft-store key value fn/persistence-location))

  (defun fn/persistence-fetch (key)
    "Another wrapper for `persistent-soft-fetch' with KEY,
and location is defined by `fn/custom-persistence-file'."
    (persistent-soft-fetch key fn/persistence-location))

  (defun fn/persistence-flush ()
    "Store all symbols in `fn/persistence-managed-symbols' before Emacs closes."
    (mapc
     (lambda (symbol)
       (ignore-errors
         (fn/persistence-store symbol (symbol-value symbol))))
     fn/persistence-managed-symbols))

  (add-hook 'kill-emacs-hook #'fn/persistence-flush)

  (defun fn/persistence-manage-symbol (symbol)
    (set symbol (fn/persistence-fetch symbol))
    (push symbol fn/persistence-managed-symbols)))

exec-path-from-shell

The path variable from the shell is need to run commands

(defconst fn/exec-path-from-shell-package-dir
  (expand-file-name "exec-path-from-shell/" fn/custom-module-dir)
  "Exec package dir")

(use-package exec-path-from-shell
  :ensure t
  :load-path fn/exec-path-from-shell-package-dir
  :demand t
  :if (not (eq system-type 'windows-nt)) ;; Sorry Windows
  :config
  (setq exec-path-from-shell-variables
        (list
         "PATH" "MANPATH"
         "PROMPT" "PS1"

         "JAVA_HOME" "ECLIPSE_HOME")
        exec-path-from-shell-arguments
        (list
         "-l" "-i"))

  (exec-path-from-shell-initialize))

htmlize

My custom library for exporting.

(defconst fn/htmlize-package-dir
  (expand-file-name "htmlize/" fn/custom-module-dir)
  "Htmlize package dir")

(use-package htmlize
  :ensure t
  :defer t)

log4e

Nice logging library

(unless noninteractive
  (use-package log4e
    :ensure t
    :demand t
    :config
    (log4e:deflogger
      "chat"
      ">>> %t \n%m\n<<<"
      "%F %H:%M:%S"
      (list (cons 'info "info")))

    (chat--log-enable-logging)


    (defface fn/chat-server-name  '((t (:weight bold :height 0.9)))
      "Chat server name face")

    (defface fn/chat-channel-name  '((t (:weight ultra-bold :height 1.1)))
      "Chat server  name face")

    (defface fn/chat-chatter-name  '((t (:underline t :weight semi-bold :height 1.0)))
      "Chat sender name face")

    (defface fn/chat-message  '((t (:weight thin :height 1.0)))
      "Chat message face")


    (defun fn/chat-propertize (text style)
      "Add extra coloring with TEXT and STYLE."
      (let ((new-text (substring text)))
        (add-face-text-property
         0
         (length new-text)
         style
         nil
         new-text)
        new-text))


    (defun fn/prettify-word (word)
      "Prettify word if possible."
      (if (fboundp 'text-candy-candied-word)
          (text-candy-candied-word word)
        word))

    (defun fn/chat-log (server channel chatter message)
      "Log SERVER, CHANNEL, CHATTER and MESSAGE."
      (unless (string-empty-p message)
        (let* ((out
             (string-trim-right
              (format "[%s/%s] %s: %s"
                      (fn/chat-propertize (fn/prettify-word server) 'fn/chat-server-name)
                      (fn/chat-propertize (fn/prettify-word channel) 'fn/chat-channel-name)
                      (fn/chat-propertize chatter 'fn/chat-chatter-name)
                      (fn/chat-propertize message 'fn/chat-message)))))
          (chat--log-info out)
          out)))

    (defun fn/chat-log-open ()
      "Open chat log."
      (interactive)
      (chat--log-open-log))


    (defconst fn/chat-log-file (expand-file-name ".chat-log.txt.gpg" fn/cache-dir)
      "My chat log file.")

    (defun fn/chat-log-clear ()
      "Clear chat log."
      (interactive)
      (chat--log-clear-log))

    (defun fn/chat-log-flush (&optional retain)
      "Save log for posterity.  If RETAIN is non-nil, do not clear the log."
      (ignore-errors
        (save-window-excursion
          (fn/chat-log-open) ;; NOTE: Error might result if the log isn't populated yet.
          (let ((new-log
                 (with-current-buffer log4e--log-buffer-chat
                   (buffer-substring-no-properties (point-min) (point-max))))
                (file (find-file-noselect fn/chat-log-file)))
            (with-current-buffer file
              (end-of-buffer)
              (newline)
              (insert new-log)
              (save-buffer))
            (unless retain
              (fn/chat-log-clear))
            nil))))

    (defun fn/chat-log-flush-before-clear (&rest args)
      "Save the log before clearing."
      (fn/chat-log-flush t))

    ;; (advice-add 'chat--log-clear-log :before #'fn/chat-log-flush-before-clear)
    ;; (add-hook 'kill-emacs-hook #'fn/chat-log-flush)


    (fn/use-feature log4e-mode--mode-icon
      (all-the-icons)
      (fn/add-major-mode-icon
       'log4e-mode
       (list 'all-the-icons-octicon "clippy" :v-adjust 0.0)))))

auto-compile

Automatic compilation of package files

(use-package auto-compile
  :ensure t
  :hook (emacs-lisp-mode . auto-compile-mode)
  :config
  (auto-compile-on-load-mode)
  (auto-compile-on-save-mode))

all-the-icons

Making Emacs more modern.

Sadly, this has to be placed here because fn/use-feature cannot load it properly.

(defconst fn/all-the-icon-font-dir (expand-file-name "all-the-icons-font" fn/custom-module-dir)
  "All the icon font library.")

(defconst fn/all-the-icon-font-families
  (list
   (cons "FontAwesome" "fontawesome.ttf")
   (cons "Weather Icons" "weathericons.ttf")
   (cons "file-icons" "file-icons.ttf")
   (cons "github-octicons" "octicons.ttf")
   (cons "all-the-icons" "all-the-icons.ttf"))
  "The font available.")

(fset 'fn/add-major-mode-icon 'ignore)

(unless noninteractive
  (use-package all-the-icons
    :ensure t
    :demand t
    :config
    (defun fn/add-major-mode-icon (main-mode icon-config)
      "Add icon mapping to major mode given MAIN-MODE, ICON-CONFIG."
      (add-to-list
       'all-the-icons-mode-icon-alist
       (append (list main-mode) icon-config)))

    (fn/add-major-mode-icon
     'makefile-mode
     (list 'all-the-icons-faicon "wrench" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'special-mode
     (list 'all-the-icons-faicon "birthday-cake" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'fundamental-mode
     (list 'all-the-icons-faicon "pencil" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'compilation-mode
     (list 'all-the-icons-faicon "cog" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'process-menu-mode
     (list 'all-the-icons-faicon "list" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'package-menu-mode
     (list 'all-the-icons-octicon "package" :v-adjust 0.0))

    (fn/add-major-mode-icon
     'outline-mode
     (list 'all-the-icons-faicon "list-ul" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'conf-unix-mode
     (list 'all-the-icons-faicon "code" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'edmacro-mode
     (list 'all-the-icons-faicon "pause-circle" :v-adjust -0.1))


    (defun fn/check-installed-font-families ()
      "Check if `fn/all-the-icon-font-families' is intalled."
      (mapc
       (lambda (pair)
         (pcase-let ((`(,family . ,_) pair))
           (unless (member family (font-family-list))
             (message "The %s is not installed, you might want it installed." family))))
       fn/all-the-icon-font-families))

    (defun fn/install-font-families-locally ()
      "Install all-the-icons fonts in the `~/.local/share/fonts' folder.
Tested on Arch Linux."
      (interactive)
      (let ((local-font-folder (expand-file-name "~/.local/share/fonts/")))
        (make-directory local-font-folder t)
        (mapcar
         (lambda (font-file)
           (copy-file font-file local-font-folder t))
         (directory-files fn/all-the-icon-font-dir  t ".ttf"))

        (when (executable-find "fc-cache")
          (shell-command "fc-cache"))))

    (add-hook 'after-init-hook 'fn/check-installed-font-families)))

Optional

Dependencies that aren’t really required

(use-package org-jekyll-blogger
  :load-path fn/custom-script-dir
  :defer t)

(use-package prodigy-set
  :load-path fn/custom-script-dir
  :defer t)

(use-package text-candy
  :load-path fn/custom-script-dir
  :defer 5)

(use-package xpm
  :load-path fn/custom-script-dir
  :defer t)

Assumptions

These are assumptions I have of my setup externally. After this section, everything is free.

Checking for missing executables.

(defvar fn/missing-executables (list)
  "Executables that could not be found.")

(defun fn/record-executable (orig-fun executable)
  "Record executable is missing."
  (lexical-let ((result (funcall orig-fun executable)))
    (prog1
        result
      (unless result
        (add-to-list 'fn/missing-executables executable)))))

(advice-add 'executable-find :around #'fn/record-executable)

(defun fn/notify-missing-executables ()
  "Notify executables that are missing through `fn/missing-executables'."
  (when fn/missing-executables
    (message "You're missing some executables: %s" fn/missing-executables)))

(add-hook 'after-init-hook #'fn/notify-missing-executables t)


(defmacro fn/use-executables (name executables &rest body)
  "Like with `use-package' but used in checking for executables."
  `(progn
       (message "Checking executable set %s" ,(symbol-name name))
       (if (not (and ,@(mapcar
                    (lambda (executable)
                      `(executable-find ,(symbol-name executable)) )
                    executables)))
           (message "Missing executable set %s" ,(symbol-name name))
         ,@body)
       (quote ,executables)))

(put 'fn/use-executables 'lisp-indent-function 'defun)


(fn/use-executables bootstrap-check
  (emacs git tmux)
  nil)

(fn/use-executables downloader-check
  (wget curl rsync)
  nil)

(fn/use-executables secure-check
  (tor polipo)
  nil)

(fn/use-executables browser-check
  (w3m firefox chromium)
  nil)

Terminator

Shell related aspect

shell

Some configurations on the terminal

(setq async-shell-command-buffer 'new-buffer)

(fn/use-feature shell-mode--mode-icon
  (all-the-icons)
  (fn/add-major-mode-icon
   'shell-mode
   (list 'all-the-icons-faicon "terminal" :v-adjust 0.0)))

sh

More things for sh-mode

(use-package company-shell
  :ensure t
  :after (shell company)
  :hook (sh-mode . company-mode)
  :config
  (add-to-list 'company-backends 'company-shell))

term

An enhancement for term

(use-package term
  :bind (:map fn-standard-prefix-map
              ("x t" . ansi-term))
  :config
  (defadvice term-sentinel (around ansi-term-kill-buffer (proc msg))
    (if (memq (process-status proc) '(signal exit))
        (let ((buffer (process-buffer proc)))
          ad-do-it
          (kill-buffer buffer))
      ad-do-it))
  (ad-activate 'term-sentinel)

  ;; Set the term program and ask for a name
  (defadvice ansi-term (before ansi-term-force-shell)
    (interactive (list (getenv "SHELL")
          (let ((term-name (string-trim (read-from-minibuffer "Name the term buffer: "))))
            (if (string-empty-p term-name) nil term-name)))))
  (ad-activate 'ansi-term)


  (add-hook 'term-mode-hook 'goto-address-mode)
  (add-hook 'term-exec-hook
            '(lambda ()
               (set-buffer-process-coding-system 'utf-8-unix 'utf-8-unix))))

eshell

Another enhancement for the shell

(use-package eshell
  :bind (:map fn-standard-prefix-map
              ("x e" . eshell))
  :config
  (defun fn/eshell-prompt-function ()
    "My eshell prompt function."
    (concat " λ "))

  (setq eshell-highlight-prompt nil
     eshell-hist-ignoredups t
     eshell-directory-name (expand-file-name "eshell" fn/cache-dir)
     eshell-prefer-lisp-functions t
     eshell-prompt-function #'fn/eshell-prompt-function))

Autocompletion

We got completion here

(use-package pcomplete
  :ensure t
  :after eshell)

(use-package pcmpl-git
  :ensure t
  :after pcomplete)

(use-package pcmpl-pip
  :ensure t
  :after pcomplete)

(use-package pcomplete-extension
  :ensure t
  :after pcomplete)

direnv

Env per directory. (Want to hack this with Emacs)

(fn/use-executables direnv-check
  (direnv)
  (use-package direnv
    :ensure t
    :unless noninteractive
    :demand t
    :config
    (direnv-mode)))

prodigy

Living in the shell requires some genius

(defconst fn/prodigy-map (fn/make-prefixed-keymap (kbd "P") fn-standard-prefix-map)
  "My custom prodigy map.")

(defconst fn/prodigy-command-dir (expand-file-name "prodigy-command/" fn/custom-module-dir)
  "My custom command dir.")

(add-to-list 'exec-path fn/prodigy-command-dir)

(use-package prodigy
  :ensure t
  :bind (:map fn/prodigy-map
              ("P" . prodigy))
  :defer t
  :commands (fn/prodigy-define-service)
  :config
  ;; Alias this command so that it can be adviced
  (fset 'fn/prodigy-define-service 'prodigy-define-service)

  ;; Display prodigy buffers on the same windowx
  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*prodigy*" eos)
    (cons 'display-buffer-same-window (list))))

  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*prodigy-" (* anything))
    (cons 'display-buffer-same-window (list))))

  ;; Service restart shiv
  (defun prodigy-find-service-by-buffer (&optional buffer)
    "Find `prodigy' service based on BUFFER name."
    (let* ((this-prodigy-buffer-name (buffer-name buffer))
           (service (-find
                     (lambda (service)
                       (string= (prodigy-buffer-name service)
                                this-prodigy-buffer-name))
                     (prodigy-services))))
      service))

  (defun prodigy-restart-view ()
    "Restart a `prodigy-view-mode' buffer."
    (interactive)
    (-if-let (service (prodigy-find-service-by-buffer))
        (prodigy-with-refresh
         (prodigy-restart-service service))
      (error "Current buffer is not a prodigy view buffer.")))

  (define-key prodigy-view-mode-map (kbd "C-c r") #'prodigy-restart-view)

  (fn/use-feature prodigy-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'prodigy-mode
     (list 'all-the-icons-faicon "cogs" :v-adjust -0.1))

    (fn/add-major-mode-icon
     'prodigy-view-mode
     (list 'all-the-icons-faicon "cog" :v-adjust -0.1))))

Prodigy Cleanup

Ensure when Emacs closes, kill all processes

(fn/use-feature prodigy-auto-kill
  (prodigy)
  (defvar fn/prodigy-processes (list)
    "List of processes to kill when closing.")

  (defun fn/prodigy-kill-processes ()
    "Kill all processes started by `prodigy'"
    (interactive)
    (mapc
     (lambda (process)
       (when (process-live-p process)
         (kill-process process)))
     fn/prodigy-processes)
    (prog1
        fn/prodigy-processes
      (setq fn/prodigy-processes nil)))

  (defun fn/prodigy-add-to-processes (service &rest _args)
    "Add SERVICE process to `fn/prodigy-processes'."
    (setq fn/prodigy-processes (cl-remove-if-not #'process-live-p fn/prodigy-processes))
    (lexical-let ((process (plist-get service :process)))
      (when (process-live-p process)
        (add-to-list 'fn/prodigy-processes process))))

  (advice-add 'prodigy-start-service :after #'fn/prodigy-add-to-processes)

  (add-hook 'kill-emacs-hook #'fn/prodigy-kill-processes))

Customized Prodigy

A dependency to customize prodigy, giving the command fn/prodigy-define-service.

(fn/use-feature prodigy-custom
  (prodigy)
  (defmacro fn/prodigy-with-buffer (&rest body)
    "Execute BODY within an exisiting prodigy buffer."
    `(progn
       (when (prodigy-buffer)
         (with-current-buffer (prodigy-buffer)
           ,@body))))

  (defun fn/prodigy-refresh ()
    "Refresh prodigy buffer."
    (ignore-errors
      (fn/prodigy-with-buffer
       (prodigy-refresh)
       (prodigy-goto-first-line))))


  (defun fn/prodigy-switch-to-process-buffer (service)
    "Just an wrapper for said function with SERVICE. If there is a prefix argument, it will stop it instead."
    (if current-prefix-arg
        (if (prodigy-service-stopping-p service)
            (message "Service already stopping")
          (message "Stopping %s service." (plist-get service :name))
          (prodigy-stop-service service t))
      (if (prodigy-service-started-p service)
          (prodigy-switch-to-process-buffer service)
        (message "Starting %s service." (plist-get service :name))
        (prodigy-start-service service (apply-partially #'prodigy-switch-to-process-buffer service)))))


  (defun fn/prodigy-prepared-switch-to-process-buffer (service)
    "Another wrapper to make specific functions for viewing SERVICE."
    (lexical-let* ((service-name (plist-get service :name))
        (command-name (or (plist-get service :bind-command-name)
                         (symbol-name (gensym "prodigy-view-"))))
        (prefix "fmpv/")
        (function-symbol (intern (format "%s%s" prefix command-name)))
        (service service))
      (fset function-symbol
            `(lambda ()
               ,(format "A prodigy view function for %s" service-name)
               (interactive)
               (fn/prodigy-switch-to-process-buffer (quote ,service))))
      function-symbol))

  (defun fn/prodigy-define-service-binder (orig-fun &rest args)
    "When creating a service, check for a `:bind' keyword to
create an automatic keybinding for it."
    (let ((result (apply orig-fun args)))
      (prog1
          result
        (lexical-let* ((service (car result))
            (name (plist-get service :name))
            (bind (plist-get service :bind))
            (bind-map (or (plist-get service :bind-map) global-map)))
          (when bind
            (message "Creating binding for %s" name)
            (define-key bind-map bind (fn/prodigy-prepared-switch-to-process-buffer service)))))))

  (advice-add 'fn/prodigy-define-service :around #'fn/prodigy-define-service-binder)


  ;; :on-stop and :on-start property
  (defun fn/prodigy-stop-service (service &rest args)
    "Like `prodigy-stop-service' but also checks for
     `:on-stop' which runs before it."
    (lexical-let ((on-stop (prodigy-service-or-first-tag-with service :on-stop)))
      (when (functionp on-stop)
        (apply on-stop (list :service service)))))

  (defun fn/prodigy-start-service (service &rest args)
    "Like `prodigy-start-service' but also checks for
     `:on-start' which runs after it."
    (lexical-let ((on-start (prodigy-service-or-first-tag-with service :on-start)))
      (when (functionp on-start)
        (apply on-start (list :service service)))))

  (defun fn/prodigy-define-service-on-start-and-stopper (orig-fun &rest args)
    "When creating a service, check and persist `:on-stop' and
    `:on-start' property."
    (let ((result (apply orig-fun args)))
      (prog1
          result
        (lexical-let* ((service (car result))
            (on-stop (plist-get args :on-stop))
            (on-start (plist-get args :on-start)))
          (when (functionp on-stop)
            (nconc service (list :on-stop on-stop)))
          (when (functionp on-start)
            (nconc service (list :on-start on-start)))))))

  (advice-add 'prodigy-stop-service :after #'fn/prodigy-stop-service)
  (advice-add 'prodigy-start-service :after #'fn/prodigy-start-service))

Service Tags

Some commands that can be refactored out

(fn/use-feature prodigy-command-tags
  (prodigy)
  (fn/use-executables prodigy-polipo
    (polipo)
    (prodigy-define-tag
      :name 'polipo
      :cwd user-emacs-directory
      :command "polipo"
      :stop-signal 'kill
      :kill-process-buffer-on-stop t
      :ready-message "\\.*Established listening socket on \\.*")

    (defun fn/prodigy-create-polipo-conf (file options)
      "Update FILE with polipo OPTIONS."
      (with-temp-file file
        (insert
         (string-join
          (mapcar
           (lambda (pair)
             (pcase-let ((`(,key . ,value) pair))
               (format
                "%s = %s"
                key
                (typecase value
                  (symbolp (symbol-name value))
                  (numberp (number-to-string value))
                  (stringp (format "\"%s\"" value))))))
           options)
          "\n")))))

  (fn/use-executables prodigy-tor
    (tor)
    (prodigy-define-tag
      :name 'tor
      :cwd user-emacs-directory
      :command "tor"
      :stop-signal 'kill
      :kill-process-buffer-on-stop t
      :ready-message ".*Bootstapped 100.*")


    (defun fn/prodigy-create-tor-conf (file options)
      "Update FILE with tor OPTIONS."
      (with-temp-file file
        (insert
         (string-join
          (mapcar
           (lambda (pair)
             (pcase-let ((`(,key . ,value) pair))
               (format
                "%s %s"
                key
                (typecase value
                  (symbolp (symbol-name value))
                  (numberp (number-to-string value))
                  (stringp value)))))
           options)
          "\n")))))

  (fn/use-executables prodigy-privoxy
    (privoxy)
    (prodigy-define-tag
      :name 'privoxy
      :cwd user-emacs-directory
      :command "privoxy"
      :stop-signal 'kill
      :kill-process-buffer-on-stop t
      :ready-message "\\.*Listening on port \\.*")

    (defun fn/prodigy-create-privoxy-conf (file options)
      "Update FILE with privoxy OPTIONS."
      (with-temp-file file
        (insert
         (string-join
          (mapcar
           (lambda (pair)
             (pcase-let ((`(,key . ,value) pair))
               (format
                "%s %s"
                key
                (typecase value
                  (symbolp (symbol-name value))
                  (numberp (number-to-string value))
                  (stringp value)))))
           options)
          "\n")))))

  (fn/use-executables prodigy-jekyll
    (jekyll)
    (prodigy-define-tag
      :name 'jekyll
      :command "jekyll"
      :args (list "serve")
      :stop-signal 'kill
      :kill-process-buffer-on-stop t))

  (fn/use-executables prodigy-npm
    (npm)
    (prodigy-define-tag
      :name 'npm
      :command "npm"
      :args `("run start")
      :stop-signal 'kill
      :kill-process-buffer-on-stop t))

  (fn/use-executables prodigy-offlineimap
    (offlineimap)
    (defcustom fn/prodigy-offlineimap-state-change-hook (list)
      "`offlineimap' state change hook.
Possible values are `error', `synced' and `ready'.")

    (defvar fn/prodigy-offlineimap-current-state nil
      "The state of parsing `offlineimap'. Not to be used directly.")

    (defun fn/prodigy-offlineimap-state-change-listener (&rest args)
      "Just notify me when the offlineimap has something new"
      (lexical-let ((output (plist-get args :output))
                    (service (plist-get args :service)))
        (pcase output
          ((pred (string-match-p "OfflineIMAP"))
           (prodigy-set-status service 'ready)
           (run-hook-with-args 'fn/prodigy-offlineimap-state-change-hook service 'ready))
          ((and (guard (not fn/prodigy-offlineimap-current-state))
                (pred (string-match-p "Copy message")))
           (setq fn/prodigy-offlineimap-current-state t))
          ((and (guard fn/prodigy-offlineimap-current-state)
                (pred (string-match-p "Finished account")))
           (run-hook-with-args 'fn/prodigy-offlineimap-state-change-hook service 'synced)
           (setq fn/prodigy-offlineimap-current-state nil)))))

    (prodigy-define-tag
      :name 'offlineimap
      :command "offlineimap"
      :on-output 'fn/prodigy-offlineimap-state-change-listener))

  (fn/use-executables prodigy-mbsync
    (mbsync)
    (defconst fn/mbsync-daemon-command "mbsync-daemon"
      "Wrappd `mbsync' as a daemon.")

    (defconst fn/mbsync-slave-pattern
      (rx line-start
          "slave: "
          (group-n 1 (one-or-more digit))
          " messages, "
          (group-n 2 (one-or-more digit))
          " recent" line-end))

    (defcustom fn/prodigy-mbsync-state-change-hook (list)
      "`mbsync' state change hook.
Possible values are `error', `synced' and `ready'.")

    (defun fn/prodigy-mbsync-state-change-listener (&rest args)
      "Listen on `mbsync' output for state changes."
      (lexical-let ((output (plist-get args :output))
                    (service (plist-get args :service)))
        (pcase output
          ((pred (string-prefix-p "Starting daemon"))
           (prodigy-set-status service 'ready)
           (run-hook-with-args 'fn/prodigy-mbsync-state-change-hook service 'ready))
          ((pred (string-prefix-p "Error:"))
           (run-hook-with-args 'fn/prodigy-mbsync-state-change-hook service 'error))
          ((pred (string-match fn/mbsync-slave-pattern))
           (let ((recent (match-string 2 output)))
             (when (> (string-to-number recent) 0)
               (run-hook-with-args 'fn/prodigy-mbsync-state-change-hook service 'synced)))))))

    (prodigy-define-tag
      :name 'mbsync
      :command fn/mbsync-daemon-command
      :args `("-V" "-a")
      :on-output 'fn/prodigy-mbsync-state-change-listener))

  (fn/use-executables prodigy-mpd
    (mpd)
    (prodigy-define-tag
      :name 'mpd
      :cwd user-emacs-directory
      :command "mpd"
      :stop-signal 'kill
      :args `("--no-daemon")
      :kill-process-buffer-on-stop t)

    (defun fn/prodigy-create-mpd-conf (file options)
      "Update FILE with mpd OPTIONS."
      (with-temp-file file
        (insert
         (string-join
          (mapcar
           (lambda (pair)
             (pcase-let ((`(,key . ,value) pair))
               (format
                "%s %s"
                key
                (if (listp value)
                    (format
                     "{\n%s\n}"
                     (string-join
                      (mapcar
                       (lambda (pair)
                         (pcase-let ((`(,key . ,value) pair))
                           (format
                            "%s %s"
                            key
                            (format "\"%s\"" value))))
                       value)
                      "\n"))
                  (format "\"%s\"" value)))))
           options)
          "\n"))))))

Service Sets

Services are grouped together, starting and stopping together or in sequence.

(use-package prodigy-set
  :load-path fn/custom-script-dir
  :after prodigy
  :config
  nil)

procred

Similarly, manage processes.

(use-package proced
  :ensure t
  :defer t
  :bind (:map fn-standard-prefix-map
              ("C-M-p p" . proced)))

emamux

Work better with tmux

(fn/use-executables emamux-check
  (tmux)
  (use-package emamux
    :ensure t
    :defer 1
    :config
    (shell-command "tmux -2 -C new -s emamux")))

multi-term

Emacs and term

(use-package multi-term
  :ensure t
  :defer t)

docker

Containers eh?

(fn/use-executables docker-check
  (docker)
  (use-package docker
    :ensure t
    :defer t
    :commands (docker-images docker-containers docker-volumes docker-networks docker-machines)
    :config
    nil))

Something to edit Dockerfile

(use-package dockerfile-mode
  :ensure t
  :mode (("Dockerfile\\'" . dockerfile-mode)))

vagrant

Vagrant tools

(use-package vagrant
  :ensure t
  :defer t
  :config
  nil)

memory-usage

Nice to know if my baby is getting to fat to quick

(use-package memory-usage
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("m" . memory-usage)))

Editor

Anything to do with editing in Emacs

Environment

visual-line

Visual lines make more sense than the hard lines, what you see is what you get. Besides, I use syntax motions

(fn/use-feature visual-line-mode
  nil
  (global-visual-line-mode t)
  (diminish 'visual-line-mode))

auto-fill

Useful mode when writing, keeps things under 80 characters.

(fn/use-feature auto-fill-mode
  nil
  (add-hook 'text-mode-hook 'turn-on-auto-fill)
  (diminish 'auto-fill-function)
  (setq-default fill-column 72))

auto-revert

The more generic revert

(fn/use-feature auto-revert
  nil
  (global-auto-revert-mode t)

  (setq global-auto-revert-non-file-buffers t
        auto-revert-verbose nil)

  (diminish 'auto-revert-mode))

autorevert

Enhancement for log reading

(use-package autorevert
  :diminish auto-revert-mode
  :mode (("\\.log\\'" . auto-revert-tail-mode)));

Editing

hungry-delete

Very useful default delete functionality

(use-package hungry-delete
  :ensure t
  :diminish hungry-delete-mode
  :bind (:map fn-standard-prefix-map
              ("C-d C-d" . hungry-delete-forward)
              ("C-d DEL" . hungry-delete-backward)))

expand-region

Another great feature for marking

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

multiple-cursors

This functions does not get too much attention

(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . mc/edit-lines)
         ("C->" . mc/mark-next-like-this)
         ("C-<" . mc/mark-previous-like-this)
         ("C-c C-<" . mc/mark-all-like-this)))

undo-tree

Visualizing undo like vi

(use-package undo-tree
  :ensure t
  :defer t
  :diminish undo-tree-mode
  :bind (:map fn-standard-prefix-map
              ("C-_" . undo-tree-visualize)))

glasses

I don’t like the camelCase convention so I make it more like Emacs.

(unless noninteractive
  (with-eval-after-load 'glasses
    (setq glasses-separator "~")))

Completion

hippie-exp

Hippie expand rocks

(use-package hippie-exp
  :bind (("M-/" . hippie-expand))
  :config
  (setq hippie-expand-try-functions-list
     '(
          try-expand-dabbrev
          try-expand-dabbrev-all-buffers
          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))

  (fn/use-feature hippie-ggtags
    (ggtags)
    (add-to-list 'hippie-expand-try-functions-list 'ggtags-try-complete-tag)))

company

A replacement for autocomplete.

(use-package company
  :ensure t
  :unless noninteractive
  :demand t
  :diminish company-mode
  :defines company-backends
  :init
  (add-hook 'prog-mode-hook 'company-mode)
  :config
  (global-set-key (kbd "TAB") #'company-indent-or-complete-common)

  (setq company-idle-delay (/ 60.0)
        company-minimum-prefix-length 3

        company-begin-commands (list 'self-insert-command))

  (setq company-show-numbers t
        company-tooltip-limit 20
        company-tooltip-align-annotations t)

  (setq company-dabbrev-time-limit 0.001
        company-dabbrev-code-time-limit 0.001
        company-dabbrev-downcase nil)

  (setq company-backends (list))

  (add-to-list 'company-backends 'company-capf)
  (add-to-list 'company-backends 'company-dabbrev)
  (add-to-list 'company-backends 'company-elisp)

  (defun fn/combine-backends (backend new-backend)
    "Combine BACKEND with NEW-BACKEND."
    (if (and (listp backend) (member new-backend backend))
        backend
      (let* ((list-backend (if (consp backend)
                               backend
                             (list backend)))
             (with-backend (if (member ':with list-backend)
                               list-backend
                             (append list-backend '(:with)))))
        (append with-backend (list new-backend)))))

  (defun fn/append-to-backends (new-backend)
    "Append NEW-BACKEND to company."
    (setq company-backends
          (mapcar
           (lambda (backend)
             (fn/combine-backends backend new-backend))
           company-backends)))

    (setq company-show-numbers t
          company-tooltip-limit 20
          company-tooltip-align-annotations t)

    (setq company-dabbrev-time-limit 0.001
          company-dabbrev-code-time-limit 0.001
          company-dabbrev-downcase nil)


    (setq company-backends (list))

    (add-to-list 'company-backends 'company-capf)
    (add-to-list 'company-backends 'company-dabbrev)
    (add-to-list 'company-backends 'company-elisp)

    (defun fn/combine-backends (backend new-backend)
      "Combine BACKEND with NEW-BACKEND."
      (if (and (listp backend) (member new-backend backend))
          backend
        (let* ((list-backend (if (consp backend)
                                 backend
                               (list backend)))
               (with-backend (if (member ':with list-backend)
                                 list-backend
                               (append list-backend '(:with)))))
          (append with-backend (list new-backend)))))

    (defun fn/append-to-backends (new-backend)
      "Append NEW-BACKEND to company."
      (setq company-backends
            (mapcar
             (lambda (backend)
               (fn/combine-backends backend new-backend))
             company-backends)))

    (setq fn/company-prog-backends (list 'company-dabbrev-code))

    (defun fn/backend-with-prog ()
      (fn/append-to-backends 'company-keywords)))

yasnippet

Snippet system along with autocomplete is awesome

(use-package yasnippet
  :ensure t
  :unless noninteractive
  :diminish yas-minor-mode
  :disabled t
  :bind (:map fn-standard-prefix-map
              ("y" . yas-new-snippet))
  :hook (prog-mode . yas-minor-mode)
  :init
  (setq-default yas-snippet-dirs
                `(,(expand-file-name "snippets" fn/extra-dir)))
  :config
  (setq yas/root-directory (expand-file-name "snippets" fn/extra-dir)
        yas--default-user-snippets-dir yas/root-directory
        yas-snippet-dirs `(,yas/root-directory))

  (make-directory yas--default-user-snippets-dir t)

  (setq yas-verbosity 3)

  (push 'yas-hippie-try-expand hippie-expand-try-functions-list)

  (defun fn/add-company-yasnippet ()
    "Add yasnippet to company backends"
    (fn/append-to-backends 'company-yasnippet))

  (add-hook 'after-init-hook 'fn/add-company-yasnippet)

  (yas-reload-all))

Ergonomic

Things to assist in managing Emacs

Jump

Things to jump around with

recentf

Accessing the files recently

(unless noninteractive
  (use-package recentf
    :bind (("C-x C-r" . recentf-open-files))
    :config
    (setq recentf-save-file (expand-file-name "recentf" fn/cache-dir)

       recentf-max-menu-items 1000
       recentf-max-saved-items 1000

       recentf-exclude '("TAGS" ".*-autoloads\\.el\\'"))

    (recentf-mode t))

  (use-package recentf-ext
    :ensure t
    :after recentf))

bookmark+

Enhancement for normal bookmarking

(defconst fn/bookmark+-module-dir (expand-file-name "bookmark+/" fn/custom-module-dir)
  "Archived `bookmark+' packages.")

(unless noninteractive
  (use-package bookmark+
    :load-path fn/bookmark+-module-dir
    :defer t
    ;; :commands ()
    :config
    nil))

Windows

Anything related to window management

desktop

Managing buffers the Emacs way.

(defconst fn/desktop-map (fn/make-prefixed-keymap (kbd "d") fn-standard-prefix-map)
  "My custom desktop bookmarked map.")

(use-package desktop
  :defer t
  :config
  (defconst fn/desktop-dir (expand-file-name "desktop/" fn/cache-dir)
    "My desktop dir")

  (make-directory fn/desktop-dir t)

  (setq desktop-path (list fn/desktop-dir)
     desktop-dirname fn/desktop-dir
     desktop-base-file-name "blank"
     desktop-base-lock-name ".desk-lock"
     desktop-save 'if-exists

     desktop-restore-eager 15
     desktop-lazy-idle-delay 10
     desktop-lazy-verbose t)

  (desktop-save-mode)

  (fn/use-feature bookmarked-desktop
    (bookmark+)
    (define-key fn/desktop-map (kbd "s") 'bmkp-set-desktop-bookmark)

    (setq bmkp-desktop-default-directory fn/desktop-dir
       bmkp-desktop-jump-save-before-flag t)))

(use-package desktop+
  :ensure t
  :after desktop
  :bind (:map fn/desktop-map
              ("s" . desktop+-create)
              ("l" . desktop+-load))
  :config
  (setq desktop+-base-dir fn/desktop-dir))

workgroups

Saving window state is very helpful specially when you move a lots

(use-package workgroups2
  :ensure t
  :defer t
  :bind (("C-c w w" . workgroups-mode))
  :init
  (setq wg-prefix-key (kbd "C-c w")
     wg-session-file (expand-file-name "workgroups" fn/cache-dir))

  (add-hook 'after-init-hook #'workgroups-mode)
  :config
  (setq wg-morph-on nil

     wg-mode-line-display-on nil

     wg-mess-with-buffer-list nil

     wg-buffer-auto-association-on nil
     wg-undoify-window-configuration-change nil

     wg-buffer-local-variables-alist (list)

     wg-restore-frame-position nil
     wg-restore-scroll-bars nil
     wg-restore-margins nil

     wg-restore-point t
     wg-restore-point-max t

     wg-restore-mark nil
     wg-restore-window-dedicated-p nil
     wg-remember-frame-for-each-wg nil

     wg-load-last-workgroup nil

     wg-emacs-exit-save-behavior           'save
     wg-workgroups-mode-exit-save-behavior 'save)

  (defun fn/wg-session-list-buffers (&optional frame)
    "Get the current session buffers."
    (-reject
     (-compose
      (-partial #'s-starts-with-p " ")
      #'buffer-name)
     (funcall wg-buffer-list-function frame)))

  (defun fn/list-to-hash-table (xs)
    "Convert XS to a hash table with equality comparison."
    (let ((table (make-hash-table)))
      (mapc (lambda (x) (puthash x t table)) xs)
      table))

  (defun fn/wg-switch-to-buffer ()
    "Switch buffer with my custom workgroup."
    (interactive)
    (lexical-let* ((session-buffers (fn/wg-session-list-buffers))
        (buffer-table (fn/list-to-hash-table session-buffers))
        (predicate
         (lambda (buffer-pair)
           (when (consp buffer-pair)
             (lexical-let* ((buffer (cdr buffer-pair)))
               (gethash buffer buffer-table nil)))))
        (buffer (read-buffer
                 "Switch to session buffer: "
                 nil
                 t
                 predicate)))
      (switch-to-buffer buffer)))

  (defun fn/wg-create-workgroup ()
    "Create a blank workgroup."
    (interactive)
    (let ((current-prefix-arg t))
      (call-interactively #'wg-create-workgroup)))

  (define-key wg-prefixed-map (kbd "b") #'fn/wg-switch-to-buffer)
  (define-key wg-prefixed-map (kbd "s") #'wg-switch-to-workgroup)

  (run-with-idle-timer 0 nil (lambda  ()
                             (define-key workgroups-mode-map
                               (vector 'remap 'wg-create-workgroup)
                               #'fn/wg-create-workgroup)))


  (defun fn/wg-cleanup ()
    "Some cleanup with workgroups since it becomes really slow speciall with `execute-extended-command' with `smex'."
    (wg-perform-session-maintenance))

  (add-hook 'wg-after-switch-to-workgroup-hook 'fn/wg-cleanup)
  (add-hook 'wg-after-switch-to-workgroup-hook 'garbage-collect)

  ;; Performance
  ;; Limit tracked buffers
  (defcustom fn/wg-buf-list-limit 500
    "The maximal number of buffers that should tracked if `fn/wg-limit-add-buffer-to-buf-list' is enabled.")

  (defun fn/wg-limit-add-buffer-to-buf-list (&rest args)
    "Limit the buffers tracked by `wg-add-buffer-to-buf-list' based on `fn/wg-buf-list-limit'."
    (when (fboundp 'wg-buf-list)
      (when (>= (length (wg-buf-list)) fn/wg-buf-list-limit)
        (nbutlast (wg-buf-list)))))

  (advice-add 'wg-add-buffer-to-buf-list :after #'fn/wg-limit-add-buffer-to-buf-list)

  ;; Golden Ratio fix
  (fn/use-feature workgroups-golden-ratio
    (workgroups2 golden-ratio)
    (defun fn/workgroups-switch-disable-golden-ratio (orig-fun &rest args)
      (if (not golden-ratio-mode)
          (apply orig-fun args)
        (prog2
            (golden-ratio-mode -1)
            (apply orig-fun args)
          (golden-ratio-mode +1))))

    (advice-add 'wg-switch-to-workgroup :around #'fn/workgroups-switch-disable-golden-ratio))

  ;; Multi frame fix
  (defun fn/wg-delete-other-frames (&rest args)
    "Remove other frames on exit since it causes a `PickelError'."
    (delete-other-frames))

  (advice-add 'wg-save-session-on-exit :before #'fn/wg-delete-other-frames))

workgroup-layouts

Hooks for each workgroup

(use-package workgroups-layout
  :load-path fn/custom-script-dir
  :defer t
  :after (workgroups2)
  :commands (workgroups-layout-mode)
  :config
  (workgroups-layout-mode)

  (defvar fn/workgroups-layout-icons (list)
    "An list of workgroup config icons, taken from `all-the-icons' mode line.")

  (defun fn/workgroups-layout-define-workgroup-config-icon (workgroup icon-family icon-function icon-name &rest args)
    "Just like with `all-the-icons' mode line, this is for workgroup config with
ICON-FAMILY, ICON-FUNCTION, ICON-NAME and ARGS."
    (let ((workgroup-name (wg-workgroup-name workgroup)))
      (add-to-list
       'fn/workgroups-layout-icons
       (append
        (list
         workgroup-name
         icon-family
         icon-function
         icon-name)
        args))))

  (defun fn/workgroups-layout-workgroup-icon ()
    "Return icon for workgroup as defined for `fn/workgroups-layout-icons' list"
    (-if-let* ((current-workgroup-name (workgroups-layout-current-workgroup-name))
               (result (assoc current-workgroup-name fn/workgroups-layout-icons)))
        (let* ((icon-result (cdr result))
               (icon-font-function (car icon-result))
               (icon-function (cadr icon-result))
               (icon-args (cddr icon-result)))
          (propertize
           (format " %s " (apply icon-function icon-args))
           'help-echo (format "Workgroup: `%s`" current-workgroup-name)
           'face
           (list
            :family (funcall icon-font-function))))
      nil)))

e2wm

Specific layouts for Emacs

(use-package e2wm
  :ensure t
  :defer t
  :config
  (fn/use-feature e2em-disable-golden-ratio
    (e2wm golden-ratio)
    (defun fn/e2wm-disable-golden-ratio ()
      "Disable `golden-ratio-mode' when layout is managed."
      (golden-ratio-mode -1))

    (add-hook 'e2wm:pre-start-hook #'fn/e2wm-disable-golden-ratio)))

winner

You got to have those window configuration

(unless noninteractive
  (use-package winner
    :ensure t
    :config
    (winner-mode t)))

window-numbering

A must to navigate through windows with numbers.

(use-package window-numbering
  :ensure t
  :unless noninteractive
  :demand t
  :config
  (window-numbering-mode t)

  (global-set-key (kbd "M-`") #'other-frame)

  (when (require 'dash)
    (defun fn/get-window-by-number (window-number)
      "Get window by WINDOW-NUMBER."
      (-find
       (lambda (window)
         (= (window-numbering-get-number window) window-number))
       (window-list)))

    (defun fn/swap-windows (this-window that-window)
      "Swap THIS-WINDOW and THAT-WINDOW"
      (let ((this-buffer (window-buffer this-window))
            (that-buffer (window-buffer that-window)))
        (unless (eq this-buffer that-buffer)
          (set-window-buffer this-window that-buffer)
          (set-window-buffer that-window this-buffer))))

    (defun fn/swap-with-numbered-window (window-number)
      "Swap with current window with numbered window."
      (interactive "NWhat window number? ")
      (let ((this-window (selected-window))
            (that-window (fn/get-window-by-number window-number)))
        (if (null that-window)
            (message "Window %s does not exist"
                     window-number)
          (fn/swap-windows this-window that-window)
          (select-window-by-number window-number))))))

window-layout

Making window layouts

(use-package window-layout
  :ensure t
  :config
  (fn/use-feature window-numbered-layout
    (window-numbering)
    (require 'dash)

    (defvar fn/current-window-layout nil
      "The current window layout.")

    (defun fn/window-numbering-assign-func ()
      "Window number assignment based on the current window layout."
      (ignore-errors
        (lexical-let ((this-window (selected-window)))
          (when (wlf:wset-p fn/current-window-layout)
            (let ((layout-index
                 (-find-index
                  (lambda (winfo) (eq (wlf:window-window winfo) this-window))
                  (wlf:wset-winfo-list fn/current-window-layout))))
              (if layout-index
                  layout-index
                nil))))))

    (setq window-numbering-assign-func 'fn/window-numbering-assign-func)))

golden-ratio

Makes windows large enough to see.

(use-package golden-ratio
  :ensure t
  :demand t
  :unless noninteractive
  :diminish golden-ratio-mode
  :bind (("C-c q" . golden-ratio)
         :map fn-standard-prefix-map
         ("q" . golden-ratio-mode))
  :config
  (golden-ratio-mode t)

  (run-with-idle-timer 3 nil #'golden-ratio-mode)

  (setq split-width-threshold nil
        golden-ratio-adjust-factor 1.0)

  ;; Frame entry exit fix
  (add-hook 'focus-in-hook #'golden-ratio)
  (add-hook 'focus-out-hook #'golden-ratio)

  (with-eval-after-load 'workgroups2
    ;; When switching workgroups, make sure the screen is rationed correctly
    (add-hook 'wg-after-switch-to-workgroup-hook #'golden-ratio))

  (with-eval-after-load 'window-numbering
    (defun fn/golden-ratio-after-select-window-by-number (&rest args)
      (golden-ratio))

    (advice-add
     #'select-window-by-number
     :after
     #'fn/golden-ratio-after-select-window-by-number)))

uniquify

Nicer naming convention

(unless noninteractive
  (use-package uniquify
    :if (version<= "24.3.1" emacs-version)
    :demand t
    :config
    (setq uniquify-buffer-name-style 'post-forward-angle-brackets)))

Interface

Anything related to buffers

projectile

Must have a project finder when using a project.

(use-package projectile
  :ensure t
  :defer 1
  :unless noninteractive
  :diminish projectile-mode
  :bind (("C-c p p" . projectile-switch-project)
         ("C-c p f" . projectile-find-file)
         ("C-c p d" . projectile-find-dir))
  :init
  (setq projectile-cache-file (expand-file-name "projectile.cache" fn/cache-dir)
        projectile-known-projects-file (expand-file-name "projectile-bookmarks.eld" fn/cache-dir)
        projectile-keymap-prefix (kbd "C-c p"))
  :config
  (defun fn/find-project-root ()
    "Visit project root."
    (interactive)
    (dired (projectile-project-root)))

  (define-key projectile-command-map (kbd "C-r") #'fn/find-project-root)

  (setq projectile-switch-project-action #'fn/find-project-root)

  (projectile-mode)
  (setq projectile-indexing-method 'native
        projectile-enable-caching t
        projectile-enable-idle-timer nil)

  (setq projectile-sort-order 'modification-time)

  (add-to-list 'projectile-project-root-files "config.xml"))

Per-Project Config

Use projectile to load per project config via .project.el and .project-locals.el

(with-eval-after-load 'projectile
  (defconst fn/project-file ".project.el"
    "Project configuration file")

  (defconst fn/project-local-file ".project-locals.el"
    "Project local setting file")

  (defconst fn/project-init-files `(,fn/project-file ,fn/project-local-file)
    "Project init files")

  (defun fn/load-project-file ()
    "Loads the `fn/project-file' for a project.
  This is run once after the project is loaded signifying project setup."
    (interactive)
    (when (projectile-project-p)
      (let* ((current-project-root (projectile-project-root))
             (project-init-file (expand-file-name fn/project-file current-project-root)))
        (when (file-exists-p project-init-file)
          (message "Loading project init file for %s" (projectile-project-name))
          (condition-case ex
              (load project-init-file t)
            ('error
             (message
              "There was an error loading %s: %s"
              project-init-file
              (error-message-string ex))))))))

  (defun fn/load-project-local-file ()
    "Loads the `fn/project-local-file' for a project.
  This is run for every time a file in a project is opened signifying per-file setup."
    (interactive)
    (when (projectile-project-p)
      (let* ((current-project-root (projectile-project-root))
             (project-local-init-file (expand-file-name fn/project-local-file current-project-root)))
        (when (and (file-exists-p project-local-init-file)
                   (not (member (buffer-file-name) fn/project-init-files)))
          (message
           "Loading project local file for %s on %s"
           (projectile-project-name)
           (buffer-name))
          (condition-case ex
              (load project-local-init-file t)
            ('error
             (message
              "There was an error loading %s: %s"
              project-local-init-file
              (error-message-string ex))))))))

  (defun fn/find-project-file ()
    "Find the project's `.project.el'."
    (interactive)
    (when (projectile-project-p)
      (let* ((current-project-root (projectile-project-root))
             (project-file (expand-file-name fn/project-file current-project-root)))
        (find-file project-file))))

  (defun fn/find-project-locals-file ()
    "Find the project's `.project-locals.el'."
    (interactive)
    (when (projectile-project-p)
      (let* ((current-project-root (projectile-project-root))
             (project-locals-file (expand-file-name fn/project-local-file current-project-root)))
        (find-file project-locals-file))))


  ;; Safety Loader
  (defvar fn/checked-projects (list)
    "Projects that are trusted with loading `fn/project-init-files' or not.")

  (defvar fn/loaded-projects (list)
    "Projects that have been loaded by `fn/load-project-file'.")

  (unless (fboundp 'file-attribute-modification-time)
    (defun file-attribute-modification-time (attributes)
      "The last access time of ATTRIBUTES"
      (nth 5 attributes)))

  (defun fn/trust-project ()
    "Trust current project."
    (interactive)
    (if (not (projectile-project-p))
        (message ("Not in a project."))
      (let* ((project-root (projectile-project-root))
             (project-entry (assoc project-root fn/checked-projects)))
        (if project-entry
            (progn
              (setcdr
               project-entry
               (plist-put
                (cdr project-entry)
                :trusted
                t)))
          (add-to-list
           'fn/checked-projects
           (list project-root
                 :last-modification-time (file-attribute-modification-time (file-attributes project-root))
                 :project-root project-root
                 :trusted t)))
        (message "Project %s trusted" project-root))))

  (defun fn/safe-project-p (project-root)
    "Check if PROJECT-ROOT can be trusted."
    (let* ((last-modification-time
            (file-attribute-modification-time (file-attributes project-root)))
           (safe-project-properties
            (or (cdr (assoc project-root fn/checked-projects))
                (let* ((base-properties
                        (list :last-modification-time last-modification-time
                              :project-root project-root))
                       (trusted
                        (yes-or-no-p
                         (format "Do you ultimately trust the project at %s?" project-root)))
                       (new-properties
                        (plist-put base-properties :trusted trusted)))
                  new-properties))))
      (prog1
          (plist-get safe-project-properties :trusted)
        (add-to-list 'fn/checked-projects
                     (cons project-root  safe-project-properties)))))

  (defun fn/safe-load-project-file ()
    "Safety wrapper around `fn/load-project-file' with `fn/safe-project-p'."
    (if (not (projectile-project-p))
        (message "Not in a project.")
      (let ((project-root (projectile-project-root))
            (project-name (projectile-project-name)))
        (when (not (member project-root fn/loaded-projects))
          (if (not (fn/safe-project-p project-root))
              (message "Project script for %s is not trusted." project-name)
            (fn/load-project-file)
            (add-to-list 'fn/loaded-projects project-root))))))

  (defun fn/safe-load-project-local-file ()
    "Safety wrapper around `fn/load-project-local-file' with `fn/safe-project-p'."
    (if (not (projectile-project-p))
        (message "Not in a project.")
      (let ((project-root (projectile-project-root))
            (project-name (projectile-project-name)))
        (if (not (fn/safe-project-p project-root))
            (message "Project local script for %s is not trusted." project-name)
          (fn/load-project-local-file)))))


  ;; Project root script should run before project file script
  (add-hook 'find-file-hook #'fn/safe-load-project-file t)
  (add-hook 'find-dired-hook #'fn/safe-load-project-file t)
  (add-hook 'dired-mode-hook #'fn/safe-load-project-file t)

  (add-hook 'find-file-hook #'fn/safe-load-project-local-file t)
  (add-hook 'find-dired-hook #'fn/safe-load-project-local-file t)
  (add-hook 'dired-mode-hook #'fn/safe-load-project-local-file t)

  (when (require 'savehist)
    (add-to-list 'savehist-additional-variables 'fn/checked-projects)))

Completion System

Fix for the completion system being removed each time an upgrade is completed.

(with-eval-after-load 'projectile
  (cl-defun projectile-completing-read (prompt choices &key initial-input action)
    "Present a project tailored PROMPT with CHOICES."
    (let ((prompt (projectile-prepend-project-name prompt))
          res)
      (setq res
            (cond
             ((eq projectile-completion-system 'ido)
              (ido-completing-read prompt choices nil nil initial-input))
             ((eq projectile-completion-system 'default)
              (completing-read prompt choices nil nil initial-input))
             ((eq projectile-completion-system 'helm)
              (if (and (fboundp 'helm)
                       (fboundp 'helm-make-source))
                  (helm :sources
                        (helm-make-source "Projectile" 'helm-source-sync
                          :candidates choices
                          :action (if action
                                      (prog1 action
                                        (setq action nil))
                                    #'identity))
                        :prompt prompt
                        :input initial-input
                        :buffer "*helm-projectile*")
                (user-error "Please install helm from \
https://github.com/emacs-helm/helm")))
             ((eq projectile-completion-system 'ivy)
              (if (fboundp 'ivy-read)
                  (ivy-read prompt choices
                            :initial-input initial-input
                            :action (prog1 action
                                      (setq action nil))
                            :caller 'projectile-completing-read)
                (user-error "Please install ivy from \
https://github.com/abo-abo/swiper")))
             (t (funcall projectile-completion-system prompt choices))))
      (if action
          (funcall action res)
        res))))

helm

The revolutionary package to find

(use-package helm
  :ensure t
  :unless noninteractive
  :defer 3
  :diminish helm-mode
  :bind (("M-x" . helm-M-x)
         ("C-c f" . helm-recentf)
         ("C-h a" . helm-apropos)
         ("C-h r" . helm-info-emacs)
         ("C-x b" . helm-mini)
         ("C-x C-f" . helm-find-files)
         ("M-s o" . helm-occur)
         ("M-s i" . helm-imenu)
         ("C-c C-/" . helm-dabbrev))
  :config
  (require 'helm-config)

  (helm-mode t)

  ;; core & utils
  (setq helm-yank-symbol-first t

        helm-mode-fuzzy-match nil

        helm-su-or-sudo "sudo"

        helm-input-idle-delay (/ 1 60.0) ;; 60fps
        helm-exit-idle-delay (/ 1 60.0)  ;; ditto

        helm-echo-input-in-header-line nil ;; If the theme does not block it

        helm-split-window-default-side 'same

        helm-debug-root-directory fn/cache-dir)

  ;; files & command
  (setq helm-ff-file-name-history-use-recentf t
        helm-ff-auto-update-initial-value t

        helm-M-x-always-save-history t)

  ;; adaptive
  (setq helm-adaptive-history-file (expand-file-name "helm-adaptive-history" fn/cache-dir)
        helm-adaptive-history-length 100)

  (helm-adaptive-mode t))

helm-projectile

A nice assist for projectile

(defconst fn/helm-projectile-package-dir (expand-file-name "helm-projectile/" fn/custom-module-dir)
  "My custom helm projectile package")

(fn/use-feature helm-projectile
  (helm)
  (require 'dash)
  (require 'dash-functional)
  (require 's)
  (require 'f)

  (defconst fmc/completion-buffer-name "*Hacker Helm Completions"
    "Just a constant name for the completion buffer")


  (defface fmc/completion-label  '((t (:weight bold :height 1.1)))
    "Label face")

  (defface fmc/completion-delimiter '((t (:weight light :height 0.9)))
    "Delimiter face")

  (defface fmc/completion-description '((t (:weight extra-light :height 0.9)))
    "Description face")


  (defconst fmc/reverse-notation-separator ".."
    "My reversed separator")

  (defconst fmc/completion-separator ">>"
    "My completion separator")

  (defun fmc/uniquify-project-paths (project-paths)
    "Customize how projectile files and more are displayed"
    (lexical-let*
        ((fn-notation
          (lambda (path)
            (lexical-let ((fn-pieces (f-split path)))
              (string-join (reverse fn-pieces) fmc/reverse-notation-separator))))
         (relative-parent-path
          (lambda (path relative-path)
            (lexical-let
                ((split-path (f-split path))
                 (split-relative-path (f-split relative-path)))
              (string-join
               (-drop-last (length split-relative-path) split-path)
               (f-path-separator)))))

         (as-pair
          (lambda (ish)
            (if (listp ish)
                ish (cons ish ish))))
         (map-car
          (lambda (f pair)
            (cons (funcall f (car pair))
                  (cdr pair))))
         (pair-as-label
          (lambda (pairs)
            (lexical-let*
                ((display-formatter
                  (lambda (name description)
                    (format "%-s %s %-s"
                            (propertize name 'font-lock-face 'fmc/completion-label)
                            (propertize fmc/completion-separator 'font-lock-face 'fmc/completion-delimiter)
                            (propertize description 'font-lock-face 'fmc/completion-description)))))
              (lambda (pair)
                (lexical-let*
                    ((unique-path (car pair))
                     (full-path (cdr pair))
                     (parent-path
                      (funcall relative-parent-path
                               full-path
                               unique-path))

                     (display-name
                      (funcall fn-notation unique-path))
                     (display-description
                      (funcall fn-notation parent-path))

                     (display-label
                      (funcall display-formatter
                               display-name
                               display-description)))
                  (cons display-label (cdr pair)))))))
         (uniquify-paths
          (lambda (paths)
            ;; Ideally, this is just f-uniquify-alist but there is a minor contrivance
            (lexical-let*
                ((is-dir
                  (lambda (path)
                    (string-equal (f-path-separator)
                                  (s-right 1 path))))

                 (swap-pair (lambda (pair)
                              (cons (cdr pair) (car pair))))
                 (map-pair
                  (lambda (f pair)
                    (cons (funcall f  (car pair)) (funcall f (cdr pair)))))

                 (remove-last-separator
                  (lambda (text)
                    (s-left (1- (length text)) text)))
                 (add-separator
                  (lambda (text)
                    (concat text (f-path-separator)))))
              (mapcar (-compose
                       swap-pair)
                      (if (-any is-dir paths)
                          ;; Remove separator, uniquify and add separator back
                          ;; Weird performance shiznit
                          (funcall
                           (-compose
                            (-partial #'mapcar (-partial map-pair add-separator))
                            #'f-uniquify-alist
                            (-partial #'mapcar remove-last-separator))
                           paths)
                        (f-uniquify-alist paths))))))
         (refined-paths  (funcall uniquify-paths project-paths)))
      (mapcar (-compose
               (funcall pair-as-label refined-paths)
               as-pair)
              refined-paths)))

  (defun fmc/custom-helm-completion (prompt choices)
    "Just a custom helm completion for projection"
    (prog1
        (helm-comp-read prompt (fmc/uniquify-project-paths choices)
                        :buffer fmc/completion-buffer-name
                        :must-match t)
      (kill-buffer fmc/completion-buffer-name)))

  (setq projectile-completion-system #'fmc/custom-helm-completion))

helm-smex

smex is faster than helm-M-x

(defconst fn/smex-module-dir (expand-file-name "smex/" fn/custom-module-dir)
  "Archived `smex' packages.")

(defconst fn/helm-smex-module-dir (expand-file-name "helm-smex/" fn/custom-module-dir)
  "Archived `helm-smex' packages.")

(unless noninteractive
  (use-package smex
    :load-path fn/smex-module-dir
    :demand t
    :config
    (setq smex-save-file (expand-file-name "smex-items" fn/cache-dir)
          smex-history-length 100)))

(use-package helm-smex
  :load-path fn/helm-smex-module-dir
  :after helm
  :bind (("M-x" . helm-smex))
  :config
  (setq helm-smex-show-bindings t
        smex-history-length (or helm-adaptive-history-length smex-history-length)))

helm-flx

Flex matching is strong

(use-package helm-flx
  :ensure t
  :after helm
  :config
  (helm-flx-mode t))

ivy

A lighter and faster library than helm that uses the minibuffer instead of a separate window.

(use-package ivy
  :ensure t
  :disabled t
  :bind (("M-x" . counsel-M-x))
  :config
  (setq ivy-use-virtual-buffers t))

Help

Helper functions ere

command-log

A command log when needed

(unless noninteractive
  (use-package command-log-mode
    :ensure t
    :diminish command-log-mode
    :demand t
    :config
    (global-command-log-mode t)))

keyfreq

Nice to know what key’s I press the most

(use-package keyfreq
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("K" . keyfreq-show))
  :config
  (keyfreq-mode t)
  (keyfreq-autosave-mode t)

  (setq keyfreq-file (expand-file-name "keyfreq" fn/cache-dir)
        keyfreq-file-lock (expand-file-name "keyfreq.lock" fn/cache-dir)))

which-key

A mnemonic for key bindings

(unless noninteractive
  (use-package which-key
    :ensure t
    :diminish which-key-mode
    :demand t
    :config
    (which-key-mode t)
    (which-key-setup-side-window-bottom)

    (setq which-key-idle-delay 0.8

       which-key-separator ""
       which-key-unicode-correction 3

       which-key-prefix-prefix ""
       which-key-show-prefix 'top
       which-key-echo-keystrokes nil

       which-key-show-remaining-keys nil

       which-key-sort-order 'which-key-description-order)


    (defun fn/which-key-prefix-command-replacement (kb)
      "My custom label for prefix command."
      (cons (car kb)
         (format
          "/Σ-%2d/"
          (let ((which-key--current-prefix
               (apply #'vector (listify-key-sequence (kbd (car kb))))))
            (length (which-key--get-current-bindings))))))


    ;; Mode Highlighting
    (require 's)

    ;; NOTE: Avoid changing height since it destroys the layout
    (defface fn/which-key-active-mode-face '((t . (:underline t :foreground "#dddddd")))
      "Face for active modes."
      :group 'fn)

    (defface fn/which-key-inactive-mode-face '((t . (:underline t :foreground "#444444")))
      "Face for inactive modes."
      :group 'fn)

    (defun fn/which-key-highlight-modes ()
      "Add active and inactive modes to `which-key-highlighted-command-list'."
      (message "Updating which-key mode highlighting.")
      (mapc
       (lambda (command-option)
         (when (and (consp command-option)
                  (s-ends-with-p "-mode$" (car command-option)))
           (setcdr command-option 'fn/which-key-inactive-mode-face)))
       which-key-highlighted-command-list)
      (mapc
       (lambda (minor-mode)
         (lexical-let* ((mode-name (symbol-name minor-mode))
             (mode-regex (concat mode-name "$"))
             (command-option
              (assoc mode-regex which-key-highlighted-command-list)))
           (unless command-option
             (setq command-option
                (cons mode-regex 'italic))
             (push command-option which-key-highlighted-command-list))
           (when (consp command-option)
             (setcdr command-option
                     (if (and (boundp minor-mode)
                            (symbol-value minor-mode))
                         'fn/which-key-active-mode-face 'fn/which-key-inactive-mode-face
                       )))))
       minor-mode-list)


      (lexical-let* ((generic-mode-regex ".*-mode$")
          (command-option (assoc generic-mode-regex which-key-highlighted-command-list)))
        (unless command-option
          (add-to-list 'which-key-highlighted-command-list
                       (cons generic-mode-regex
                          'fn/which-key-inactive-mode-face)
                       t))))

    (advice-add 'which-key--init-buffer :before #'fn/which-key-highlight-modes)
    (add-hook 'after-init-hook #'fn/which-key-highlight-modes t)


    ;; Namespace Highlighting
    (defface fn/which-key-personal-namespace-face '((t . (:foreground "#9b59b6")))
      "Face for my personal namespace."
      :group 'fn)

    (add-to-list 'which-key-highlighted-command-list
                 (cons "^f.*/" 'fn/which-key-personal-namespace-face))


    ;; Customized prefix display
    (add-to-list 'which-key-replacement-alist
                 (cons (cons nil "Prefix Command")
                    #'fn/which-key-prefix-command-replacement))))

which-function

Likewise with key and functions

(unless noninteractive
  (fn/use-feature which-function
    nil
    (which-function-mode t)))

eldoc

Nice to have the documentation at any time in the buffer.

(use-package eldoc
  :diminish eldoc-mode
  :init
  (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)

  (add-hook 'org-mode-hook 'turn-on-eldoc-mode))

helm-descbinds

Another way to check bindings

(use-package helm-descbinds
  :ensure t
  :after helm
  :bind (("C-h b" . helm-descbinds))
  :config
  (setq helm-descbinds-window-style 'same))

helm-describe-modes

A nice way to describe the current modes

(use-package helm-describe-modes
  :ensure t
  :after helm
  :config
  (global-set-key [remap describe-mode] #'helm-describe-modes))

Profiler

Some things to help debug Emacs performance

(use-package profiler
  :if (not noninteractive)
  :init
  (defun fn/profiler-start ()
    "Start profiler with `cpu+mem'"
    (profiler-start 'cpu+mem))

  (add-hook 'after-init-hook #'fn/profiler-start)
  :commands (profiler-start profiler-report profiler-stop))

Packages

Anything to manage packages

paradox

The package management improvement

(use-package paradox
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("p" . paradox-list-packages))
  :init
  (setq package-gnupghome-dir (expand-file-name "gnupg" fn/cache-dir))
  :config
  (setq paradox-github-token t)

  (with-eval-after-load 'all-the-icons
    (fn/add-major-mode-icon
     'paradox-menu-mode
     (list 'all-the-icons-octicon "package" :v-adjust 0.0))))

elpa-mirror

Just in case things are down.

(use-package elpa-mirror
  :ensure t
  :demand t
  :config ;; Configuration in personal.el
  ;; Configure `elpamr-default-output-directory'

  (require 'rx)
  (require 's)

  (defconst fn/backup-file-pattern
    (rx line-start
        (group-n 1 (one-or-more anything))
        "-"
        (group-n 2 (one-or-more (or digit ".")))
        "."
        (group-n 3 (one-or-more anything))
        line-end)
    "The `elpamr' backup file pattern.")

  (defun fn/update-bootstrapped-packages ()
    "Update `fn/bootstrap-packages' with files from `elpamr-default-output-directory'."
    (interactive)
    (let* ((raw-backup-package-files
            (mapcar #'file-name-nondirectory
                    (with-temp-buffer
                      (setq default-directory elpamr-default-output-directory)
                      (append
                       (file-expand-wildcards
                        (expand-file-name  "*.tar"))
                       (file-expand-wildcards
                        (expand-file-name  "*.el"))))))
           (backup-packages
            (mapcar (lambda (raw-backup-package-file)
                      (car (s-match-strings-all fn/backup-file-pattern raw-backup-package-file)))
                    raw-backup-package-files))
           (bootstrap-packages
            (mapcar (lambda (bootstrap-package)
                      (cons
                       (file-name-base (cdr bootstrap-package))
                       (cdr bootstrap-package)))
                    fn/bootstrap-packages)))
      (mapc
       (lambda (package)
         (pcase-let ((`(,package-file ,package-name _ ,package-extension) package))
           (let ((found-package (assoc-string package-name bootstrap-packages)))
             (when found-package
               (copy-file
                (expand-file-name package-file elpamr-default-output-directory)
                (expand-file-name (cdr found-package) fn/bootstrap-dir)
                t)
               (message "Updating bootstrapped package %s from %s"
                        package-name
                        package-file)))))
       backup-packages))))

Artist

Visual aesthetics is also a functional thing as well

Font

I like fixed font specially DejaVu Mono

(defconst fn/primary-font-name "DejaVu Sans Mono"
  "My ideal font.")

(unless (member fn/primary-font-name (font-family-list))
  (message "Hey, you're favorite font isn't installed. You can find a copy in %s and get good." fn/font-dir))


(defconst fn/secondary-font-name "Courier"
  "My backup font.")


(defconst fn/primary-font-size 8
  "My ideal font size.")


(cond
 ((member fn/primary-font-name (font-family-list))
  (set-frame-font (format "%s-%s" fn/primary-font-name fn/primary-font-size) t t))
 ((member fn/secondary-font-name (font-family-list))
  (set-frame-font (format "%s-%s" fn/secondary-font-name fn/primary-font-size) t t))
 (t
  (message "Darn it, you have no ideal font set.")))


Screen

I prefer no clutter in my screen so I disable majority of the niceties.

(defun fn/optimize-visual-space ()
  (let ((try-set-mode (lambda (mode value)
                        (when (fboundp 'mode)
                          (mode value)))))
    (funcall try-set-mode 'tooltip-mode -1)
    (funcall try-set-mode 'tool-bar-mode -1)
    (funcall try-set-mode 'menu-bar-mode -1)
    (funcall try-set-mode 'fringe-mode 0)))

(fn/optimize-visual-space)

Theme

I like dark themes, my eyes respond better to it

My chosen themes

(use-package apropospriate-theme
  :ensure t)

(use-package base16-theme
  :ensure t)

(defconst fn/tronsesque-package-dir (expand-file-name "tronesque/" fn/custom-module-dir)
  "Tronesque package dir")

(use-package tronesque-theme
  :load-path fn/tronsesque-package-dir
  :demand t)

(use-package material-theme
  :ensure t)

Load the theme if it is a terminal or desktop.

(load-theme 'tronesque t)
(tronesque-mode-line)

Aesthetic

Somewhat more aesthetic than functional

rainbow-mode

Just to view hex quicker.

(use-package rainbow-mode
  :ensure t
  :hook (prog-mode . rainbow-mode)
  :commands (rainbow-mode)
  :bind (:map fn-standard-prefix-map
              ("R" . rainbow-mode))
  :config
  nil)

whitespace

Got to love that whitespace display

(unless noninteractive
  (fn/use-feature global-whitespace
    nil
    (add-hook 'after-init-hook 'global-whitespace-mode)
    (diminish 'global-whitespace-mode)))

hl-line

Highlight the current line

(use-package hl-line
  :diminish hl-line-mode
  :init
  (global-hl-line-mode t))

Screensaver

When idle time hits

fireplace

Warm and cozy feeling

(use-package fireplace
  :bind (:map fn-standard-prefix-map
              ("F" . fireplace))
  :ensure t
  :defer t
  :config
  (fn/use-feature fireplace-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'fireplace-mode
     (list 'all-the-icons-faicon "fire" :v-adjust -0.0))))

zone

I love to zone out from time to time.

(defconst fn/zone-animation-dir (expand-file-name "custom-zone/" fn/custom-module-dir)
  "Custom zone animation directory")

(unless noninteractive
  (use-package zone
    :ensure t
    :commands zone
    :defer fn/minute-per-second
    :config
    (defconst fn/zone-idle-time (* fn/minute-per-second 5)
      "Time for zone to zone")

    (zone-when-idle fn/zone-idle-time)

    (defvar fn/zoning-out-p nil
      "Are we zoning yet?")

    (defun fn/focused-zone (orig-zone &rest args)
      "Only show one window while zoning."
      (save-window-excursion
        (delete-other-windows)
        (setq fn/zoning-out-p t)
        (prog1
            (apply orig-zone args)
          (setq fn/zoning-out-p nil))))

    (advice-add #'zone :around #'fn/focused-zone)


    ;; Garbage collect after zoning
    (advice-add #'zone :after #'garbage-collect)

    ;; Update mode line if there is.
    (advice-add #'zone :before #'force-mode-line-update)

    (setq zone-programs (list))))

;; Custom zone
(use-package zone-end-of-buffer
  :load-path fn/zone-animation-dir
  :after zone
  :config
  (add-to-list 'zone-programs 'zone-end-of-buffer))

(use-package zone-waves
  :load-path fn/zone-animation-dir
  :after zone
  :config
  (add-to-list 'zone-programs 'zone-waves))

;; Packaged zones
(defconst fn/zone-matrix-dir (expand-file-name "zone-matrix" fn/custom-module-dir)
  "My zone matrix dir.")

(use-package zone-matrix
  :load-path fn/zone-matrix-dir
  :after zone
  :config
  (add-to-list 'zone-programs 'zone-matrix)

  (setq zmx-update-time (/ 30.0)
     zmx-update-speed-factor (/ 60.0)))

(use-package zone-nyan
  :ensure t
  :after zone
  :config
  (add-to-list 'zone-programs 'zone-nyan))


(use-package zone-sl
  :ensure t
  :after zone
  :config
  (add-to-list 'zone-programs 'zone-sl))

Coding

Whatever pertains to coding

Scratch

Making scratch behave better.

(unless noninteractive
  (use-package scratch
    :ensure t
    :demand t))

(use-package scratch-ext
  :ensure t
  :after scratch
  :config
  (setq scratch-ext-log-directory (expand-file-name ".scratch" fn/cache-dir)))

Focus Mode

Seems like a good mode

(use-package focus
  :ensure t
  :defer t
  :bind (:map fn-standard-prefix-map
              ("f" . focus-mode))
  :config
  nil)

font-lock

Syntax highlighting is a requirement

(global-font-lock-mode t)

(setq font-lock-support-mode 'jit-lock-mode)
(setq font-lock-maximum-decoration t)

rainbow-delimeter

Visual aid helps with very nested code

(use-package rainbow-delimiters
  :ensure t
  :defer t
  :init
  (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)
  :config
  (set-face-attribute 'rainbow-delimiters-depth-1-face nil :foreground "dark orange")
  (set-face-attribute 'rainbow-delimiters-depth-2-face nil :foreground "deep pink")
  (set-face-attribute 'rainbow-delimiters-depth-3-face nil :foreground "chartreuse")
  (set-face-attribute 'rainbow-delimiters-depth-4-face nil :foreground "deep sky blue")
  (set-face-attribute 'rainbow-delimiters-depth-5-face nil :foreground "yellow")
  (set-face-attribute 'rainbow-delimiters-depth-6-face nil :foreground "orchid")
  (set-face-attribute 'rainbow-delimiters-depth-7-face nil :foreground "spring green")
  (set-face-attribute 'rainbow-delimiters-depth-8-face nil :foreground "sienna1"))

color-identifiers-mode

Make things easier to see

(use-package color-identifiers-mode
  :ensure t
  :defer t
  :diminish color-identifiers-mode
  )

show-paren

Also a vital thing to keeping things highlighted

(show-paren-mode t)

(setq show-paren-style 'expression)

Display Buffer

My modification on display-buffer.

(progn
  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*Process List*" eos)
    (cons 'display-buffer-same-window (list))))

  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*Help*" eos)
    (cons 'display-buffer-same-window (list))))

  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*Async Shell Command*")
    (cons 'display-buffer-same-window (list))))

  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*shell" (* anything) "*")
    (cons 'display-buffer-same-window (list)))))

Mode Line

The mode line customization.

(use-package moder
  :load-path fn/custom-script-dir
  :unless noninteractive
  :demand t
  :config
  nil)

Organizer

Making Emacs more of an organization tool.

alert

Since Emacs doesn’t have dialog boxes, it is sufficient to have fringe or message alerts.

(use-package alert
  :ensure t
  :unless noninteractive
  :commands (alert fn/alert-color)
  :config
  (setq alert-default-style 'libnotify
        alert-log-messages t)

  (defun fn/alert-log-open ()
    "Open alert log."
    (interactive)
    (if (fboundp 'alert--log-open-log)
        (alert--log-open-log)
      (error "No alert logs yet")))

  ;; HACK: Bug #30 in alert to allow default style override
  (alert-add-rule)

  (defun* fn/alert-color (message &rest args &key color &allow-other-keys)
    "A custom alert that focuses on defining a fringe with COLOR key
with a hex value."
    (lexical-let* ((hex-color (replace-regexp-in-string "#" "" color))
                   (hex-symbol-name (format "alert-color--%s" hex-color))
                   (hex-symbol (or (intern-soft hex-symbol-name)
                                   (intern hex-symbol-name))))

      (unless (cdr (assoc hex-symbol alert-log-severity-functions))
        (add-to-list 'alert-log-severity-functions
                     (cons hex-symbol #'alert--log-trace)))

      (unless (cdr (assoc hex-symbol alert-severity-colors))
        (add-to-list 'alert-severity-colors (cons hex-symbol color)))

      (lexical-let ((color-properties
                     (list
                      :style 'fringe
                      :severity hex-symbol))
                    (colorless-properties
                     (cl-reduce
                      (lambda (val props)
                        (if (equal :color val)
                            (cdr props)
                          (cons val props)))
                      args
                      :from-end t
                      :initial-value (list))))
        (apply #'alert
               (append
                (list message)
                color-properties
                colorless-properties)))))

  (defun fn/alert-fringe-notify-message (info)
    "Log `fringe' style with `message'.
This is to support `fn/alert-color' if the color flash needs a
reminder."
    (message (plist-get info :message)))

  (advice-add 'alert-fringe-notify :after #'fn/alert-fringe-notify-message))

epa

Encryption is needed when working with sensitive files for personal or work.

;; Reference: http://conornash.com/2014/03/transparently-encrypt-org-files-in-emacs/

(use-package epa-file
  :demand t
  :config
  (epa-file-enable)

  (defun fn/backup-each-save-filter (filename)
    (let ((ignored-filenames '("\\.gpg$"))
          (matched-ignored-filename nil))
      (mapc
       (lambda (x)
         (when (string-match x filename)
           (setq matched-ignored-filename t)))
       ignored-filenames)
      (not matched-ignored-filename)))

  (setq backup-each-save-filter-function 'fn/backup-each-save-filter)

  (add-to-list 'auto-mode-alist (cons "\\.org\\.gpg\\'" 'org-mode)))

org

This makes more than a editor

Primarily I use org-drill and org-journal

(use-package org
  :ensure t
  :bind (("C-c l" . org-store-link)
         ("C-c a" . org-agenda)
         ("C-c h" . helm-org-in-buffer-headings)
         ("C-c c" . org-capture))
  :config
  (setq org-id-locations-file (expand-file-name "org-id-locations" fn/cache-dir))

  (setq org-catch-invisible-edits 'show)

  (add-to-list 'savehist-additional-variables 'org-insert-link-history)

  ;; Same windowed
  (defun fn/org-switch-to-buffer-other-window (&rest args)
    "This is an hacked form of `org-switch-to-buffer-other-window' to make it open in the same window."
    (org-no-popups
     (apply #'switch-to-buffer args)))

  (fset 'org-switch-to-buffer-other-window #'fn/org-switch-to-buffer-other-window)

  (defun fn/org-ignore-delete-other-windows (orig-fun &rest args)
    "Advice ORIG-FUN to ignore `delete-other-windows'"
    (prog2
        (advice-add 'delete-other-windows :override #'ignore)
        (apply orig-fun args)
      (advice-remove 'delete-other-windows #'ignore))))

(use-package org-plus-contrib
  :ensure t
  :after org
  :config
  nil)

org-src

Configuration for org-src

(fn/use-feature org-src
  (org)
  (setq org-src-window-setup 'current-window)

  (defun fn/org-src-inhibit-save-window-configuration ()
    "Disable org-src from saving the window configuration"
    ;; HACK: This uses an internal variable, might be unstable
    (setq org-src--saved-temp-window-config nil))

  (add-hook 'org-src-mode-hook #'fn/org-src-inhibit-save-window-configuration))

(fn/use-feature org-src-alert
  (org alert)
  nil)

(fn/use-feature org-todo
  (org)
  (setq org-todo-keywords
        `((sequence "TODO(t)" "PENDING(p)" "WAITING(w)" "|" "DONE(d)" "CANCELLED(c)")
          (sequence "EVENT(e)" "|" "ACCEPT(a)" "DECLINE(D)" )))

  (setq org-todo-keyword-faces
        ;; Color pattern from: http://stackoverflow.com/questions/12707492/add-custom-markers-to-emacs-org-mode
        '(("TODO" :background "#e74c3c" :foreground "#000000" :weight bold :box (:line-width 2 :style released-button))
          ("WAITING" :background  "#3498db" :foreground "#000000" :weight bold :box (:line-width 2 :style released-button))
          ("PENDING" :background "#f1c40f" :foreground "#000000" :weight bold :box (:line-width 2 :style released-button))
          ("DONE" :background "#2ecc71" :foreground "#000000" :weight bold :box (:line-width 2 :style released-button))
          ("CANCELLED" :background "lime green" :foreground "black" :weight bold :box (:line-width 2 :style released-button)))))

(fn/use-feature org-src-desktop
  (org desktop)
  (add-to-list 'desktop-modes-not-to-save 'org-src-mode))


(fn/use-feature org-src-edit
  (org)
  (require 'dash)
  (make-variable-buffer-local
   (defvar fn/org-babel-get-src-block-info-mapper nil
     "A mapper for `org-babel-get-src-block-info'. Useful in manipulating its value"))


  (add-to-list 'safe-local-variable-values (cons 'fn/org-babel-get-src-block-info-mapper t))

  (defun fn/org-babel-get-src-block-info-mapper (orig-fun &rest args)
    "Maps over `org-babel-get-src-block-info' if `fn/org-babel-get-src-block-info-mapper' is present."
    (let ((value (apply orig-fun args)))
      (funcall
       (if (null fn/org-babel-get-src-block-info-mapper)
           'identity fn/org-babel-get-src-block-info-mapper)
       value)))

  (defun fn/org-info-file-to-tangle-mapper (info)
    "Defaults an empty `:tangle' option to its `:file' parameter which may be manipulated by `:output-dir'."
    (let* ((null-or-no-p
         (lambda (value) (if (or (null value) (string= value "no")) nil value)))
        (params (nth 2 info))
        (tangle-param
         (funcall null-or-no-p (cdr (assoc :tangle params))))
        (file-param
         (funcall null-or-no-p (cdr (assoc :file params))))
        (new-tangle-param
         (if (and file-param (null tangle-param)) file-param nil)))
      (if new-tangle-param
          (-replace-at 2 (cons (cons :tangle new-tangle-param) params) info)
        info)))

  (advice-add 'org-babel-get-src-block-info :around 'fn/org-babel-get-src-block-info-mapper))

org-capture

More configurations for the capture

(fn/use-feature org-capture
  (org)
  nil ;; Configuration in personal.el
  )

org-agenda

More configuration for org-agenda

(fn/use-feature org-agenda
  (org)
  (setq org-agenda-span 14 ;; Fortnight
        org-agenda-window-setup 'current-window)

  ;; More at personal.el

  (defun fn/org-todo-entries ()
    "Get all entries from `org-todo-list' as cons pairs of id and text.
Useful for linking TODO entries."
    (save-window-excursion
      (org-todo-list 0)
      (let ((entries (list))
            (entry nil)
            (current-point (point)))
        (org-agenda-next-item 1)
        (while (/= (point) current-point)
          (setq current-point (point))
          (call-interactively 'org-store-link) ;; Trick agenda in storing the link into `org-stored-links'
          (setq entry (car org-stored-links))
          (push (cons (cadr entry) (car entry)) entries)
          (org-agenda-next-item 1))
        entries)))

  (defun fn/org-insert-completing-todo-link ()
    "Select a todo item to link.
Uses `fn/org-todo-entries' as the collection."
    (interactive)
    (let* ((entries (fn/org-todo-entries))
           (description (completing-read "Select a TODO entry: " ;; Bug in completing read?
                                         entries ;; Does not work if the todos are not unique, rare.
                                         nil
                                         t))
           (link (car (assoc-string description entries))))
      (org-insert-link nil link description)))

  (with-eval-after-load 'org-capture
    (define-key org-capture-mode-map (kbd "C-c m l") #'fn/org-insert-completing-todo-link))

  (define-key org-mode-map (kbd "C-c m l") #'fn/org-insert-completing-todo-link)

  (advice-add 'org-agenda-get-restriction-and-command :around #'fn/org-ignore-delete-other-windows))

org-refile

Some refiling actions perhaps?

(fn/use-feature org-archive
  (org)
  (setq org-log-refile 'time
        org-refile-targets nil))

org-archiving

Archiving is needed to avoid bloating.

(fn/use-feature org-refile
  (org)
  (when (boundp 'fn/org-dir))

  (defun fn/org-archive-done-agenda-tasks ()
    "Archive done agenda tasks."
    (message "Archiving done agenda tasks.")
    (org-map-entries
     (lambda ()
       (when (org-entry-is-done-p)
         (org-archive-subtree)))
     t 'agenda)
    (org-save-all-org-buffers))

  ;; Archive done tasks on load
  (add-hook
   'after-init-hook
   (apply-partially 'run-with-idle-timer 0 nil 'fn/org-archive-done-agenda-tasks)))

org-journal

Having a journal is good

(unless noninteractive
  (use-package org-journal
    :ensure t
    :after org
    :bind (:map fn-standard-prefix-map
                ("j" . org-journal-new-entry)) ;; C-c j conflicts with normal org-mode
    :config
    (setq org-journal-date-format "%Y-%b-%d %a" ;; YYYY-MMM-DD DAY
          org-journal-time-format "%T ") ;; HH:MM:SS and the space is required

    (setq org-journal-file-format "%Y-%m-%d.journal.org.gpg") ;; Encryption via epa
    (setq org-journal-find-file 'find-file)

    (defun fm/insert-private-file-headers ()
      (interactive)
      (add-file-local-variable-prop-line 'backup-inhibited t)
      (add-file-local-variable-prop-line 'auto-save-default nil)
      (goto-char (point-max)))

    (defun fm/insert-org-gpg-headers ()
      (interactive)
      (add-file-local-variable-prop-line
       'epa-file-encrypt-to (list "[email protected]"))
      (fm/insert-private-file-headers))

    (defun fmj/insert-summary-block ()
      "Insert summary block at point, this is pretty much #+BEGIN_SRC except summary"
      (interactive)
      (let ((summary-block
             (string-join (list "#+BEGIN_SUMMARY"
                                "Something happened but I was too lazy to write it down"
                                "#+END_SUMMARY")
                          "\n")))
        (insert (concat summary-block "\n"))))

    (defun fmj/insert-org-journal-headers ()
      (interactive)
      (fm/insert-org-gpg-headers)

      (end-of-visual-line)
      (newline-and-indent)

      (when (string-match "\\(20[0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)"
                          (buffer-name))
        (let ((year  (string-to-number (match-string 1 (buffer-name))))
              (month (string-to-number (match-string 2 (buffer-name))))
              (day (string-to-number (match-string 3 (buffer-name))))
              (datim nil))
          (setq datim (encode-time 0 0 0 day month year))

          (insert "#+STARTUP: content\n")
          (insert (format-time-string
                   "#+TITLE: Journal Entry - %Y-%b-%d %a\n" datim))

          (fmj/insert-summary-block)


          (insert (format-time-string
                   "* %Y-%b-%d %a" datim)))))

    (auto-insert-mode t)
    (setq auto-insert-query t) ;; Don't ask, just put it in there
    (add-hook 'find-file-hook 'auto-insert)

    (add-to-list 'auto-insert-alist '(".*\.org\.gpg\\'" . fm/insert-org-gpg-headers))
    (add-to-list 'auto-insert-alist '(".*\.private.org\\'" . fm/insert-private-file-headers))
    (add-to-list 'auto-insert-alist '(".*\.journal.org.gpg\\'" . fmj/insert-org-journal-headers))

    (fn/use-feature org-journal-mode--mode-icon
      (all-the-icons)
      (fn/add-major-mode-icon
       'org-journal-mode
       (list 'all-the-icons-faicon "pencil-square-o" :v-adjust 0.0)))))

org-reveal

A nice presentation framework

(unless noninteractive
  (defconst fn/org-reveal-module-dir (expand-file-name "~/Modules/reveal.js")
    "reveal.js directory")

  (fn/use-feature ox-reveal
    (org)
    (use-package ox-reveal
      :ensure t
      :if (file-exists-p fn/org-reveal-module-dir)
      :demand t
      :config
      (setq org-reveal-root (format "file:///%s" fn/org-reveal-module-dir))

      (defun fnr/tangle-buffer ()
        "Tangle current file via ox-reveal"
        (interactive)
        (let* ((current-file (buffer-file-name))
               (target-file (replace-regexp-in-string ".org" ".js" current-file))
               (target-lang "javascript"))
          (org-babel-tangle-file current-file target-file target-lang)))

      (defun fnr/export-buffer ()
        "Export current file via ox-reveal"
        (interactive)
        (message "Exporting %s" (buffer-file-name))
        (org-reveal-export-to-html nil))

      (defun fnr/reveal-export-buffer-on-save ()
        "Auto reveal export buffer on save"
        (interactive)
        (message "Adding hook to auto-export")
        (add-hook 'after-save-hook 'fnr/export-buffer t t))

      (define-minor-mode fn-reveal-editing-mode
        "Some editing enhancement when editing org-reveal files"
        :lighter " FnReveal"
        :init-value nil
        :global nil
        :keymap (let* ((map (make-sparse-keymap)))
                  (define-key map (kbd "C-c b C-p") 'fnr/tangle-buffer)
                  (define-key map (kbd "C-c b C-e") 'fnr/export-buffer)
                  map)))))

org-clock

Configuration for org-clock

(fn/use-feature org-clock
  (org)
  (setq org-log-done 'time)

  (defun fn/clock-todo-change ()
    "A nice little hook that clocks in when a todo is change to PENDING"
    (let ((new-state org-state))
      (pcase new-state
        ("PENDING" (org-clock-in))
        (_ nil))))

  (add-hook 'org-after-todo-state-change-hook #'fn/clock-todo-change))

org-drill

Flash cards are a must

(unless noninteractive
  (fn/use-feature org-drill
    (org)
    (use-package org-drill
      :after org
      :bind (:map fn-standard-prefix-map
                  ("D" . org-drill))
      :demand t
      :config
      (add-to-list 'org-modules 'org-drill)

      ;; More at personal.el
      )))

org-mobile

Mobile org document

(unless noninteractive
  (when (boundp 'fn/org-dir)
    (fn/use-feature org-mobile
      (org)
      (defconst fn/org-mobile-directory (expand-file-name "mobile" fn/org-dir)
        "My org mobile directory")

      (defconst fn/org-mobile-inbox-directory (expand-file-name "mobile-pull" fn/org-dir)
        "My org mobile directory")


      (setq org-mobile-directory  fn/org-mobile-directory
         org-mobile-inbox-for-pull fn/org-mobile-inbox-directory

         org-mobile-files (list
                           fn/org-todo-file
                           fn/org-event-file
                           ))

      (global-set-key (kbd "C-c n o p") #'org-mobile-push)
      (global-set-key (kbd "C-c n o l") #'org-mobile-pull))))

org-helm

Using helm to navigate org-mode.

(fn/use-feature org-helm-completing-read
  (helm org)
  ;; Thanks to :
  ;; https://gist.githubusercontent.com/alphapapa/a3433c54a631b693ba9d/raw/f4f2462c8ccff7352037a12b720e5ccccaf94a7e/helm-org-tag-completion.el
  (add-to-list 'helm-completing-read-handlers-alist '(org-capture . fq/org-completing-read-tags))
  (add-to-list 'helm-completing-read-handlers-alist '(org-set-tags . fq/org-completing-read-tags))

  (defun fq/org-completing-read-tags (prompt coll pred req initial hist def inh)
    (if (not (string= "Tags: " prompt))
        ;; Not a tags prompt.  Use normal completion by calling
        ;; `org-icompleting-read' again without this function in
        ;; `helm-completing-read-handlers-alist'
        (let ((helm-completing-read-handlers-alist (rassq-delete-all
                                                    'fj/org-completing-read-tags
                                                    helm-completing-read-handlers-alist)))
          (org-icompleting-read prompt coll pred req initial hist def inh))
      ;; Tags prompt
      (let* ((initial (and (stringp initial)
                           (not (string= initial ""))
                           initial))
             (curr (when initial
                     (org-split-string initial ":")))
             (table (org-uniquify
                     (mapcar 'car org-last-tags-completion-table)))
             (table (if curr
                        ;; Remove current tags from list
                        (cl-delete-if (lambda (x)
                                        (member x curr))
                                      table)
                      table))
             (prompt (if initial
                         (concat "Tags " initial)
                       prompt)))
        (concat initial (mapconcat 'identity
                                   (nreverse (fq/helm-completing-read-multiple
                                              prompt table pred nil nil hist def
                                              t "Org tags" "*Helm org tags*" ":"))
                                   ":")))))

  (defun fq/helm-completing-read-multiple (prompt choices
                                                  &optional predicate require-match initial-input hist def
                                                  inherit-input-method name buffer sentinel)
    "Read multiple items with `helm-completing-read-default-1'. Reading stops
when the user enters SENTINEL. By default, SENTINEL is
\"*done*\". SENTINEL is disambiguated with clashing completions
by appending _ to SENTINEL until it becomes unique. So if there
are multiple values that look like SENTINEL, the one with the
most _ at the end is the actual sentinel value. See
documentation for `ido-completing-read' for details on the
other parameters."
    (let ((sentinel (or sentinel "*done*"))
          this-choice res done-reading)
      ;; Uniquify the SENTINEL value
      (while (cl-find sentinel choices)
        (setq sentinel (concat sentinel "_")))
      (setq choices (cons sentinel choices))
      ;; Read choices
      (while (not done-reading)
        (setq this-choice (helm-completing-read-default-1 prompt choices
                                                          predicate require-match initial-input hist def
                                                          inherit-input-method name buffer nil t))
        (if (equal this-choice sentinel)
            (setq done-reading t)
          (setq res (cons this-choice res))
          (setq prompt (concat prompt this-choice ":"))))
      res)))

org-tempo

Assist library when working with code blocks

(with-eval-after-load 'org
  (require 'org-tempo)

  ;;; Bug on first element ("n" "#+BEGIN_NOTES ? #+END_NOTES")
  (setq org-structure-template-alist (cdr org-structure-template-alist)))

flyspell

Having a good spell checker is a must. I use flyspell although I have read issues about it

(fn/use-executables flyspell-check
  (aspell)
  (use-package flyspell
    :ensure t
    :if (not (or (eq system-type 'windows-nt) noninteractive))
    :diminish flyspell-mode
    :hook (org-mode . flyspell-mode)
    :config
    (setq flyspell-default-dictionary "en_US"

          ispell-program-name "aspell"
          ispell-cmd-args  '("--sug-mode=ultra"))))

langtool

Also a good grammar checker.

(fn/use-executables java-langtool
  (java languagetool)
  (use-package langtool
    :ensure t
    :unless noninteractive
    :bind
    (:map fn-standard-prefix-map
          ("C-l c" . langtool-check-buffer)
          ("C-l n" . langtool-goto-next-error)
          ("C-l p" . langtool-goto-previous-error))
    :config
    (setq ;; Taken from `languagetool' script to execute command
     langtool-language-tool-jar
     nil
     langtool-java-classpath
     (string-join
      (cons
       "/usr/share/languagetool"
       (directory-files "/usr/share/java/languagetool" t "\\.*jar"))
      ":")

     langtool-default-language "en"
     langtool-mother-tongue "en"

     langtool-disabled-rules (list))


    (add-to-list 'langtool-disabled-rules "WHITESPACE_RULE")
    (add-to-list 'langtool-disabled-rules "EN_QUOTES")
    (add-to-list 'langtool-disabled-rules "EN_UNPAIRED_BRACKETS")

    (defun fn/langtool-clear-mode-line ()
      "Clear modeline for langtool."
      (interactive)
      (setq mode-line-process (remove '(t langtool-mode-line-message) mode-line-process))
      (force-mode-line-update))

    (defun fn/langtool-check-buffer ()
      "Error handled `langtool-check-buffer'."
      (interactive)
      (condition-case ex
          (progn
            (langtool--cleanup-process)
            (langtool-check-buffer))
        ('error (error-message-string ex))))

    (add-hook 'langtool-noerror-hook #'fn/langtool-clear-mode-line)
    (add-hook 'langtool-error-exists-hook #'fn/langtool-clear-mode-line)))

dired

Directory management for Emacs

(require 'dired-x) ;; Allows multi open marked files

(setq dired-dwim-target t

      dired-listing-switches "-alh"

      dired-recursive-copies 'always ;; Don't ask because I did it
      dired-recursive-deletes 'always

      dired-isearch-filenames t

      dired-copy-preserve-time t)

(dired-async-mode t)

(add-hook 'dired-mode-hook 'dired-hide-details-mode)

(fn/use-feature wdired-mode--mode-icon
  (all-the-icons)
  (fn/add-major-mode-icon
   'wdired-mode
   '(all-the-icons-octicon "diff" :v-adjust 0.0)))

image-dired

Text is not enough, images are important too

(use-package image-dired
  :ensure t
  :unless noninteractive
  :after dired
  :config
  (setq image-dired-dir (expand-file-name "image-dired" fn/cache-dir-name)

        image-dired-gallery-dir image-dired-dir

        image-dired-db-file (expand-file-name ".image-dired_db" image-dired-dir)
        image-dired-temp-image-file (expand-file-name ".image-dired_temp" image-dired-dir)
        image-dired-temp-image-file (expand-file-name ".image-dired_rotate_temp" image-dired-dir)

        image-dired-main-image-directory "~/Pictures"))

tramp

Tramp is too good to pass up

(use-package tramp
  :after eshell
  :config
  (setq tramp-persistency-file-name (expand-file-name "tramp" fn/cache-dir)
        tramp-default-user (getenv "USER")

        tramp-verbose 6)

  ;; Make SSH work faster by reusing connections
  (setq tramp-ssh-controlmaster-options
        "-o ControlMaster=auto -o ControlPath='tramp.%%C' -o ControlPersist=no"))

ledger

Something to keep track of my finances

(fn/use-executables ledger-check
  (ledger)
  (use-package ledger-mode
    :ensure t
    :unless noninteractive
    :config
    (setq ledger-clear-whole-transactions t)

    (add-to-list
     'ledger-reports
     '("monthly expense" "%(binary) -f %(ledger-file) -M reg ^expenses"))
    (add-to-list
     'ledger-reports
     '("weekly expense" "%(binary) -f %(ledger-file) -W reg ^expenses"))

    (fn/use-feature ledger-mode--mode-icon
      (all-the-icons)
      (fn/add-major-mode-icon
       'ledger-mode
       '(all-the-icons-faicon "money" :v-adjust -0.1)))

    (fn/use-feature ledger-report-mode--mode-icon
      (all-the-icons)
      (fn/add-major-mode-icon
       'ledger-report-mode
       '(all-the-icons-faicon "line-chart" :v-adjust -0.1))))

  (use-package flycheck-ledger
    :ensure t
    :hook (ledger-mode . flycheck-mode)
    :config
    (add-to-list 'flycheck-enabled-checkers 'ledger)))

woman

Man pages are nice

(fn/use-executables man-check
  (man)
  (use-package woman
    :ensure t
    :bind (:map fn-standard-prefix-map
                ("C-w" . woman))
    :config
    nil))

Mail

Reading mail in Emacs

(with-eval-after-load 'prodigy
  (prodigy-define-tag
    :name 'imap)

  (when (executable-find "mbsync")
    (defconst fn/imap-mbsync-service-name "imap-mbsync"
      "The IMAP `mbsync' service name.")

    (fn/prodigy-define-service
     :name fn/imap-mbsync-service-name
     :tags '(imap mbsync)

     ;; Custom binding
     :bind-command-name "mbsync"
     :bind-map fn/prodigy-map
     :bind (kbd "g m"))

    (progn
      (require 'alert)

      (defun fn/prodigy-mbsync-state-alert (service state)
        "`mbsync' notify alert."
        ;; Color Palette: http://www.color-hex.com/color-palette/201
        (lexical-let ((service-name (plist-get service :name)))
          (when (string= service-name fn/imap-mbsync-service-name)
            (pcase state
              ('ready (fn/alert-color
                       (format "[mbsync] %s is ready" service-name)
                       :color "#0000ff"))
              ('error (fn/alert-color
                       (format "[mbsync] %s is ready" service-name)
                       :color "#bc4b4b"))
              ('synced (fn/alert-color
                        (format "[mbsync] %s synced an account" service-name)
                        :color "#eeeeee"))))))

      (add-hook
       'fn/prodigy-mbsync-state-change-hook
       #'fn/prodigy-mbsync-state-alert))

    (setq fn/imap-mbsync-service (prodigy-find-service fn/imap-mbsync-service-name)))

  (when (executable-find "offlineimap")
    (defconst fn/imap-offlineimap-service-name "imap-offlineimap"
      "The IMAP `offlineimap' service name.")

    (fn/prodigy-define-service
     :name fn/imap-offlineimap-service-name
     :tags '(imap offlineimap)

     ;; Custom binding
     :bind-command-name "imap"
     :bind-map fn/prodigy-map
     :bind (kbd "g g"))

    (progn
      (require 'alert)

      (defun fn/prodigy-offlineimap-state-alert (service state)
        "`offlineimap' notify alert."
        ;; Color Palette: http://www.color-hex.com/color-palette/201
        (lexical-let ((service-name (plist-get service :name)))
          (when (string= service-name fn/imap-offlineimap-service-name)
            (pcase state
              ('ready (fn/alert-color
                       (format "[offlineimap] %s is ready" service-name)
                       :color "#0000ff"))
              ('error (fn/alert-color
                       (format "[offlineimap] %s has a fetch error. Check out the logs" service-name)
                       :color "#bc4b4b"))
              ('synced (fn/alert-color
                        (format "[offlineimap] %s synced an account" service-name)
                        :color "#eeeeee"))))))

      (add-hook
       'fn/prodigy-offlineimap-state-change-hook
       #'fn/prodigy-offlineimap-state-alert))

    (setq fn/imap-offlineimap-service (prodigy-find-service fn/imap-offlineimap-service-name))))

gnus

The ultimate mail browser, majority of the configuration is in ~/.gnus

(unless noninteractive
  (when (file-exists-p (expand-file-name ".gnus" "~"))
    (use-package gnus
      :bind (:map fn-standard-prefix-map
                  ("g g" . gnus)
                  ("g G" . gnus-other-frame))
      :defer t
      :config
      nil ;; Config at `~/.gnus'
      )))

mu4e

A quick alternative for gnus

(unless noninteractive
  (fn/use-executables mu4e-check
    (mu)
    (defconst fn/mu-package-dir
      "/usr/share/emacs/site-lisp/mu4e/"
      "Installed via Arch Linux mu package")

    (use-package mu4e
      :load-path "/usr/share/emacs/site-lisp/mu4e/"
      :if (file-exists-p "/usr/share/emacs/site-lisp/mu4e/")
      :bind (:map fn-standard-prefix-map
                  ("g m" . mu4e))
      :config

      (setq mu4e-maildir (expand-file-name "Maildir" "~")
            mu4e-get-mail-command "true")

      (shell-command (format  "mu index --maildir=%s" mu4e-maildir))

      (mapc
       (lambda (internal-maildir)
         (let ((maildir (expand-file-name internal-maildir mu4e-maildir)))
           (unless (file-exists-p maildir)
             (make-directory maildir))))
       '("sent" "drafts" "trash"))

      (setq mu4e-sent-messages-behavior 'delete
            mu4e-update-interval 60
            mu4e-index-cleanup nil
            mu4e-index-lazy-check t
            mu4e-headers-results-limit 1000)

      (setq mu4e-completing-read-function 'completing-read
            mu4e-context-policy 'pick-first
            mu4e-compose-context-policy nil
            mu4e-confirm-quit nil)

      (setq mu4e-headers-date-format "%F %H:%M"
            mu4e-view-show-addresses nil
            mu4e-headers-fields '((:date . 25)
                                  (:flags . 6)
                                  (:from . 22)
                                  (:subject . nil)))

      (setq mu4e-attachment-dir (expand-file-name "Downloads" "~"))

      (setq mu4e-hide-index-messages t)

      (setq message-citation-line-format "%N @ %Y-%m-%d %H:%M %Z:\n"
            message-citation-line-function 'message-insert-formatted-citation-line)

      (fn/use-feature restclient-mode--mode-icon
        (mu4e all-the-icons)
        (fn/add-major-mode-icon
         'mu4e-headers-mode
         (list 'all-the-icons-faicon "newspaper-o" :v-adjust -0.1))

        (fn/add-major-mode-icon
         'mu4e-main-mode
         (list 'all-the-icons-faicon "envelope" :v-adjust -0.1))

        (fn/add-major-mode-icon
         'mu4e-compose-mode
         (list 'all-the-icons-faicon "paper-plane" :v-adjust -0.1))

        (fn/add-major-mode-icon
         'mu4e-view-mode
         (list 'all-the-icons-faicon "envelope-o" :v-adjust -0.1)))


      (fn/use-feature mu4e-flyspell
        (mu4e flyspell)
        (add-hook 'mu4e-compose-mode-hook #'flyspell-mode))


      (fn/use-feature org-mu4e
        (org mu4e)
        (setq org-mu4e-link-query-in-headers-mode nil))

      (fn/use-feature mu4e-alert
        (mu4e alert)
        (use-package mu4e-alert
          :ensure t
          :defer t
          :after (mu4e alert)
          :functions (mu4e-alert-enable-notifications)
          :init
          (mu4e-alert-enable-notifications)
          :config
          (setq mu4e-alert-email-notification-types `(count)
                mu4e-alert-style 'libnotify)

          (progn ;; Mail count, along-side mu4e-alert
            (defvar fn/mu4e-current-unread-message-count 0
              "The current `mu4e' unread message count.")

            (defun fn/mu4e-alert--get-mu-unread-mails (orig-fun callback)
              "Just `mu4e-alert--get-mu-unread-mails' but the CALLBACK updating the message count."
              (lexical-let ((callback callback))
                (funcall orig-fun
                         (lambda (mails)
                           (prog1
                               (funcall callback mails)
                             (setq fn/mu4e-current-unread-message-count (length mails)))))))

            (advice-add 'mu4e-alert--get-mu-unread-mails :around #'fn/mu4e-alert--get-mu-unread-mails))))

      (fn/use-executables w3m-check
        (w3m) ;; Use `w3m' to render the pages.
        (setq mu4e-html2text-command "w3m -dump -T text/html"
              mu4e-view-show-images t)))))

wanderlust

Alternative to gnus

(use-package wanderlust
  :ensure t
  :defer t)

smtpmail

Sending mail is just as important

(unless noninteractive
  (use-package smtpmail ;; Requires gnutls for ArchLinux
    :defer t
    :functions (smtpmail-send-it)
    :init
    (setq message-send-mail-function 'smtpmail-send-it)
    :config
    (setq smtpmail-debug-info t)

    (defun fn/smtpmail-gmail-server ()
      "Configure `smtpmail' for `gmail' SMTP server."
      (interactive)
      (setq smtpmail-stream-type 'starttls
         smtpmail-smtp-server "smtp.gmail.com"
         smtpmail-smtp-service 587))

    (defun fn/smtpmail-yandex-server ()
      "Configure `smtpmail' for `gmail' SMTP server."
      (interactive)
      (setq smtpmail-stream-type 'ssl
         smtpmail-smtp-server "smtp.yandex.com"
         smtpmail-smtp-service 465))

    ;; mail.yandex.com is a bit more loose
    ;; (fn/smtpmail-yandex-server)
    ))

emacsshot

Sometimes when you just need proof

(use-package emacsshot
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("C-c w" . emacsshot-snap-window)
              ("C-c f" . emacsshot-snap-frame))
  :config
  (defconst fn/emacsshot-dir (expand-file-name "emacsshot" fn/extra-dir)
    "My screenshot directory")

  (unless (f-exists-p fn/emacsshot-dir)
    (make-directory fn/emacsshot-dir))

  (setq emacsshot-with-timestamp t
        emacsshot-snap-frame-filename (expand-file-name "my-frame.png" fn/emacsshot-dir)
        emacsshot-snap-window-filename (expand-file-name "my-window.png" fn/emacsshot-dir)))

camcorder

Making demonstrations in Emacs is a must. My thanks to this blog post.

(fn/use-executables camcorder-check
  (recordmydesktop)
  (use-package camcorder
    :ensure t
    :unless noninteractive
    :bind (("<f10>" . camcorder-record))
    :config
    (defconst fn/camcorder-dir (expand-file-name "camcorder" fn/extra-dir)
      "My camcorder directory.")

    (make-directory fn/camcorder-dir t)

    (setq camcorder-output-directory fn/camcorder-dir
       camcorder-gif-output-directory fn/camcorder-dir
       camcorder-frame-parameters
       (list (cons 'name "Screencast")
          (cons 'height (max (/ (frame-height) 2) 40 ))
          (cons 'width (max (/ (frame-width) 2) 80 ))
          (cons 'top 20)
          (cons 'left 20)))


    (defvar fn/camcorder-state nil
      "The state of the recording. Possible values are `nil', `recording' and `paused'.")

    (defvar fn/camcorder-start-time nil
      "The start time of a recording.")


    (defun fn/camcorder-state-start ()
      "Set the start state of the recording."
      (setq fn/camcorder-state 'recording
         fn/camcorder-start-time (current-time))

      (select-frame-set-input-focus camcorder-recording-frame))

    (defun fn/camcorder-state-pause ()
      "Set the pause state of the recording."
      (cond
       ((null fn/camcorder-state)
        nil)
       ((eq fn/camcorder-state 'recording)
        (setq fn/camcorder-state 'paused))
       ((eq fn/camcorder-state 'paused)
        (setq fn/camcorder-state 'recording))))

    (defun fn/camcorder-state-stop ()
      "Set the stop state of the recording."
      (setq fn/camcorder-state nil
         fn/camcorder-start-time nil))

    (advice-add 'camcorder-record :after  #'fn/camcorder-state-start)
    (advice-add 'camcorder-pause :before  #'fn/camcorder-state-pause)
    (advice-add 'camcorder-stop :before #'fn/camcorder-state-stop)

    ;; Preload
    (defconst fn/camcorder-demo-file (expand-file-name "camcorder-demo.txt" fn/custom-script-dir)
      "Initial buffer when recording.")

    (defconst fn/camcorder-demo-buffer-name "*Space Channel 5"
      "The name of the demo buffer.")

    (defun fn/camcorder-demo-buffer ()
      "Open a blank special buffer when recording."
      (let ((demo-buffer (find-file fn/camcorder-demo-file)))
        (with-current-buffer demo-buffer
          (switch-to-buffer demo-buffer)
          (rename-buffer fn/camcorder-demo-buffer-name)
          (emacs-lisp-mode))))

    (defconst fn/camcorder-init-file (expand-file-name "camcorder-init.el" fn/custom-script-dir)
      "Init script when recording.")

    (defun fn/camcorder-load-init ()
      "Load camcorder init for test."
      (load fn/camcorder-init-file t))

    (defun fn/camcorder-init ()
      "Load an initial script when recording with a little delay."
      (run-with-idle-timer 1 nil #'fn/camcorder-load-init))

    (defun fn/camcorder-ready-message ()
      "Message when camcorder starts."
      (message "Hey there, space cats! Ulala here, comin' at you from Spaceport 9."))

    (add-hook 'camcorder-mode-hook #'fn/camcorder-demo-buffer t)
    (add-hook 'camcorder-mode-hook #'fn/camcorder-load-init t)
    (add-hook 'camcorder-mode-hook #'fn/camcorder-ready-message t)))

list-processes+

A better way of viewing processes

(defconst fn/list-processes+-module-dir (expand-file-name "list-processes+/" fn/custom-module-dir)
  "Archived `list-processes+' packages.")

(use-package list-processes+
  :load-path fn/list-processes+-module-dir
  :bind (:map fn-standard-prefix-map
              ("M-p" . list-processes+))
  :config
  nil)

Code Monkey

Modes for my programming experiences

Support

Generic support for coding

Whitespace Cleanup

Some nice whitespace cleanup.

(use-package ws-butler
  :ensure t
  :defer t
  :init
  (add-hook 'prog-mode-hook 'ws-butler-mode)
  (add-hook 'org-mode-hook 'ws-butler-mode)
  :config
  nil)

Literate Programming

Enable some literate programming

(fn/use-feature org-literate
  (org)
  (require 'ob-shell))

smartparens

This is as handy as paredit

(use-package smartparens
  :diminish smartparens-mode
  :ensure t
  :init
  (add-hook 'prog-mode-hook 'smartparens-mode)
  :config
  (require 'smartparens-config)

  (define-key smartparens-mode-map (kbd "C-<left>") 'sp-forward-slurp-sexp)
  (define-key smartparens-mode-map (kbd "C-<up>") 'sp-splice-sexp))

flycheck

Syntax checking is very important

(use-package flycheck
  :ensure t
  :unless noninteractive
  :diminish flycheck-mode
  :hook (prog-mode . flycheck-mode)
  :config
  (setq flycheck-highlighting-mode 'lines
        flycheck-check-syntax-automatically '(save mode-enabled 'idle-change)
        flycheck-checker-error-threshold nil))

(use-package flycheck-pos-tip
  :ensure t
  :after flycheck
  :config
  (flycheck-pos-tip-mode t))

(use-package flycheck-status-emoji
  :ensure t
  :after flycheck)

(use-package flycheck-package
  :ensure t
  :after flycheck
  :config
  (flycheck-package-setup))

magit

Enough said, magit is the best git client you can get anywhere.

(fn/use-executables git-check
  (git)
  (use-package magit
    :ensure t
    :if (and (version<= "24.4.4" emacs-version)
             (not noninteractive))
    :bind (("C-c g" . magit-status)
           ("M-g b" . magit-blame))
    :config
    (setq magit-repository-directories (list)
          magit-repository-directories-depth 1
          magit-push-always-verify t)

    (defun fq/display-magit-on-same-buffer (buffer)
      (if magit-display-buffer-noselect
          (magit-display-buffer-traditional buffer)
        (display-buffer-same-window buffer nil)))

    (setq magit-display-buffer-function #'fq/display-magit-on-same-buffer)

    (remove-hook 'magit-pre-display-buffer-hook 'magit-save-window-configuration)

    (add-to-list
     'display-buffer-alist
     (cons
      (rx bos "COMMIT_EDITMSG")
      (cons 'display-buffer-same-window (list))))

    (with-eval-after-load 'projectile
      (make-variable-buffer-local 'magit-git-environment)

      (add-hook 'magit-process-mode-hook #'fn/safe-load-project-local-file)
      (add-hook 'magit-status-mode-hook #'fn/safe-load-project-local-file))

    (with-eval-after-load 'direnv
       (add-to-list 'direnv-non-file-modes 'magit-process-mode))))

(use-package git-timemachine
  :ensure t
  :defer t
  :unless noninteractive
  :bind (("M-g t" . git-timemachine))
  :config
  nil)

magithub

A tool to help with github.

;; Dubious extension for the meantime
(use-package magithub
  :ensure t
  :disabled t
  :defer t
  :after (magit)
  :config
  (magithub-feature-autoinject t))

magit-svn

Support for SVN with the awesome magit interface

(use-package magit-svn
  :ensure t
  :after magit)

Folding

Code folding is helpful

(use-package origami
  :ensure t
  :defer t
  :config
  (add-to-list 'origami-parser-alist '(json-mode . origami-javascript-style-parser)))

gist

GitHub integration with gists

(use-package gist
  :ensure t
  :defer t
  :commands (gist-list gist-buffer-private gist-buffer)
  :config
  (defun fn/ignore-gnutls (orig-fun &rest args)
    "Due to `https://github.com/sigma/gh.el/issues/73', ignore only `gnutls-available-p'
for every relevant command."
    (advice-add 'gnutls-available-p :around #'ignore)
    (apply orig-fun args)
    (advice-remove 'gnutls-available-p #'ignore))

  (advice-add 'gist-list :around #'fn/ignore-gnutls)
  (advice-add 'gist-buffer :around #'fn/ignore-gnutls)
  (advice-add 'gist-buffer-private :around #'fn/ignore-gnutls)

  (advice-add 'gist-list-reload :around #'fn/ignore-gnutls)
  (advice-add 'gist-fetch-current :around #'fn/ignore-gnutls)
  (advice-add 'gist-edit-current-description :around #'fn/ignore-gnutls)
  (advice-add 'gist-kill-current :around #'fn/ignore-gnutls)

  (fn/use-feature gist-list--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'gist-list-mode
     (list 'all-the-icons-octicon "checklist" :v-adjust 0.0))))

pastebin

Paste bin integration

(defconst fn/emacs-pastebin-package-dir (expand-file-name "emacs-pastebin/" fn/custom-module-dir)
  "My emacs pastebin package directory.")

(unless noninteractive
  (use-package neopastebin
    :load-path fn/emacs-pastebin-package-dir
    :bind (:map fn-standard-prefix-map
                ("C-y n" . pastebin-new)
                ("C-y l" . pastebin-list-buffer-refresh))
    :init
    (setq pastebin-data-dir (expand-file-name "pastebin-data" fn/cache-dir))))

ag

The silver searcher is a fine tool

(unless noninteractive
  (fn/use-executables ag-check
    (ag)
    (use-package ag
      :ensure t
      :defer t
      :commands (ag)
      :config
      (setq ag-highlight-search t

            ag-reuse-window t
            ag-reuse-buffers t)

      (add-to-list
       'display-buffer-alist
       (cons
        (rx bos "*ag " (zero-or-more anything) "*" eos)
        (cons 'display-buffer-same-window (list))))

      (fn/use-feature restclient-mode--mode-icon
        (ag all-the-icons)
        (fn/add-major-mode-icon
         'ag-mode
         (list 'all-the-icons-faicon "binoculars" :v-adjust -0.1))))))

With helm

(fn/use-feature helm-ag
  (helm ag)
  (use-package helm-ag
    :ensure t
    :demand t
    :config
    nil))

ripgrep

Allow for ripgrep

(unless noninteractive
  (fn/use-executables ripgrep-check
    (rg)
    (use-package ripgrep
      :ensure t
      :defer t
      :after projectile
      :config
      (add-to-list
       'display-buffer-alist
       (cons
        (rx bos "*ripgrep-search*" eos)
        (cons 'display-buffer-same-window (list))))

      (fn/use-feature ripgrep-mode--mode-icon
        (ripgrep all-the-icons)
        (fn/add-major-mode-icon
         'ripgrep-search-mode
         (list 'all-the-icons-faicon "binoculars" :v-adjust -0.1))))))

dumb-jump

Dump jumping with ag

(use-package dumb-jump
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("C-d g" . dumb-jump-go)
              ("C-d b" . dumb-jump-back)))

ggtags

Jump and go is really a must needed feature

(fn/use-executables global-check
  (ggtags global)
  (use-package ggtags
    :ensure t
    :defer t
    :functions 'ggtags-eldoc-function
    :init
    (defun fn/ggtags-c-like-mode ()
      "Turn on GGTAGS if it is a c like mode"
      (when (derived-mode-p 'c-mode 'c++-mode 'java-mode 'javascript-mode)
        (ggtags-mode t)))

    (add-hook 'prog-mode-hook #'fn/ggtags-c-like-mode)
    :config
    (fn/use-feature eldoc-ggtags
      (eldoc)
      (setq-local eldoc-documentation-function #'ggtags-eldoc-function))

    (use-package helm-gtags
      :ensure t
      :after ggtags
      :config
      nil)))

helm-swoop

Something to speed up searching

(require 'dash)

(use-package helm-swoop
  :ensure t
  :after helm
  :bind (("M-i" . helm-swoop)
         ("C-c M-i" . helm-multi-swoop))
  :config
  (define-key helm-swoop-map (kbd "C-r") 'helm-previous-line)
  (define-key helm-swoop-map (kbd "C-s") 'helm-next-line)
  (define-key helm-multi-swoop-map (kbd "C-r") 'helm-previous-line)
  (define-key helm-multi-swoop-map (kbd "C-s") 'helm-next-line)


  (setq helm-swoop-pre-input-function (-const "")))

(use-package wgrep-helm
  :ensure t
  :after helm
  :config
  (setq wgrep-auto-save-buffer t))

Generic Outline

Generic support for outlining.

(unless noninteractive
  (use-package outline
    :ensure t
    :demand t
    :config
    nil)

  (use-package outline-magic
    :ensure t
    :defer t
    :after (outline)
    :config
    (define-key outline-minor-mode-map (kbd "<C-tab>") 'outline-cycle)))

REST Client

I need REST.

(use-package restclient
  :ensure t
  :defer t
  :mode (("\\.rest\\'" . restclient-mode)
         ("\\.rst\\'" . restclient-mode))
  :config
  (add-hook 'restclient-mode-hook 'whitespace-mode)

  (defun fn/restclient-indent-function ()
    "Thanks to `https://github.com/pashky/restclient.el/issues/85'"
    (require 'js)
    (setq-local indent-line-function 'js-indent-line))

  (add-hook 'restclient-mode-hook 'fn/restclient-indent-function)

  (fn/use-feature restclient-mode--mode-icon
    (restclient all-the-icons)
    (fn/add-major-mode-icon
     'restclient-mode
     (list 'all-the-icons-faicon "arrow-circle-o-up" :v-adjust -0.1)))

  (with-eval-after-load 'smartparens
    (add-hook 'restclient-mode-hook 'smartparens-mode))

  (with-eval-after-load 'paredit
    (add-hook 'restclient-mode-hook 'paredit-mode))

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

  (use-package ob-restclient
    :ensure t
    :after (org restclient)
    :config
    (add-to-list 'org-babel-load-languages '(restclient . t)))

  (with-eval-after-load 'outline
    (defun fn/outline-restclient-setup ()
      "Setup `outline' with `restclient'."
      (outline-minor-mode +1)
      (setq-local outline-regexp "###"))

    (add-hook 'restclient-mode-hook 'fn/outline-restclient-setup)))

smerge

Resolving diffs the nice way.

(use-package smerge-mode
  :defer t
  :config
  (setq smerge-command-prefix "C-c v")

  (progn
    (define-key smerge-mode-map (kbd "n") #'smerge-next)
    (define-key smerge-mode-map (kbd "p") #'smerge-prev)

    (define-key smerge-mode-map (kbd "RET") #'smerge-keep-current)
    (define-key smerge-mode-map (kbd "m") #'smerge-keep-mine)
    (define-key smerge-mode-map (kbd "o") #'smerge-keep-other)

    (define-key smerge-mode-map (kbd "E") #'smerge-ediff)))

YAML

YAML editing

(use-package yaml-mode
  :ensure t
  :defer t)

TOML

TOML editing

(use-package toml-mode
  :ensure t
  :defer t)

JSON

JSON support

(use-package json-mode
  :ensure t
  :defer t
  :mode ("\\.json\\'" . json-mode)
  :config
  (fn/use-executables jsonlint-check
    (jsonlint)
    (fn/use-feature flycheck-json
      (json-mode flycheck)
      (add-to-list 'flycheck-enabled-checkers 'json-jsonlint))))


(use-package json-snatcher
  :ensure t
  :defer t
  :after (json-mode))


(use-package json-reformat ;; Native tool for json formatting
  :ensure t
  :defer t
  :after (json-mode))


(fn/use-executables js-beautify-check
  (js-beautify)  ;; sudo npm -g install js-beautify
  (use-package web-beautify ;; A bit more nodejs
    :ensure t
    :defer t
    :after json-mode))

GraphQL

GraphQL support

(use-package graphql-mode
  :ensure t
  :defer t)

Markdown

Markdown editing

(use-package markdown-mode
  :ensure t
  :defer t
  :config nil)

evalator

Expression building.

(use-package evalator
  :ensure t
  :defer t
  :bind (:map fn-standard-prefix-map
              ("C-e e" . evalator)
              ("C-e x" . evalator-explicit)
              ("C-e r" . evalator-resume)
              ("C-e i" . evalator-insert-equiv-expr))
  :config
  nil)

quick-run

Quickly evaluate regions

(unless noninteractive
  (use-package quickrun
    :ensure t
    :defer t
    :config
    nil))

Tree View

Not merely a tree but a structure.

speedbar is a built-in default.

(unless noninteractive
  (use-package speedbar
    :defer t
    :config
    ;; I prefer the same frame version
    (fn/use-feature speedbar-golden-ratio
      (speedbar golden-ratio)
      (add-to-list 'golden-ratio-exclude-modes 'speedbar-mode))))

(defconst fn/sr-speedbar-extras-dir (expand-file-name "sr-speedbar-extras" fn/custom-module-dir)
  "Some extra `sr-speedbar' scripts.")

(use-package sr-speedbar
  :ensure t
  :defer t
  :bind (:map fn-standard-prefix-map
              ("t o" . sr-speedbar-open)
              ("t t" . sr-speedbar-toggle))
  :after (speedbar)
  :commands (sr-speedbar-open)
  :config
  (setq sr-speedbar-auto-refresh t
        sr-speedbar-right-side t
        sr-speedbar-default-width 15
        sr-speedbar-width 15
        sr-speedbar-max-width 25)

  (fn/use-feature workgroups-speedbar
    (workgroups2 sr-speedbar)
    (add-hook 'wg-before-switch-to-workgroup-hook #'sr-speedbar-close))

  (fn/use-feature projectile-speedbar
    (projectile sr-speedbar)
    (use-package projectile-speedbar
      :ensure t
      :defer t
      :after (projectile sr-speedbar)
      :config
      (remove-hook 'projectile-find-dir-hook 'projectile-speedbar-open-current-buffer-in-tree)
      (remove-hook 'projectile-find-file-hook 'projectile-speedbar-open-current-buffer-in-tree)))

  (use-package sb-imenu
    :load-path fn/sr-speedbar-extras-dir
    :after (sr-speedbar)
    :config
    (setq speedbar-initial-expansion-list-name "sb-imenu")))

rx Converter

I hope the rx syntax can be ported to other languages.

(unless noninteractive
  (use-package pcre2el
    :ensure t
    :defer t
    :commands (rxt-global-mode)
    :config
    nil))

RedMine

Using Redmine in any means necessary.

(use-package org-redmine
  :ensure t
  :defer t
  :config
  ;; Use redmine auth api key
  nil)


(defconst fn/redmine-package-dir (expand-file-name "emacs-redmine" fn/custom-module-dir)
  "My local `redmine' package dir.")

(use-package redmine
  :load-path fn/redmine-package-dir
  :defer t
  :config
  (setq redmine-program (expand-file-name "redmine.py" fn/redmine-package-dir)))

Jira

Need Jira support

(unless noninteractive
  (defconst org-jira-keymap (make-sparse-keymap)
    "Shiv keymap for org-jira")

  (use-package org-jira
    :ensure t
    :defer t
    :bind-keymap ("C-c j" . org-jira-keymap)
    :config
    ;; Project specific configuration
    (setq jiralib-url nil)

    (define-key org-jira-keymap (kbd "p p") 'org-jira-get-projects)
    (define-key org-jira-keymap (kbd "i b") 'org-jira-browse-issue)
    (define-key org-jira-keymap (kbd "i i") 'org-jira-get-issues)
    (define-key org-jira-keymap (kbd "i h") 'org-jira-get-issues-headonly)
    (define-key org-jira-keymap (kbd "i u") 'org-jira-update-issue)
    (define-key org-jira-keymap (kbd "i p") 'org-jira-progress-issue)
    (define-key org-jira-keymap (kbd "i P") 'org-jira-progress-issue-next)
    (define-key org-jira-keymap (kbd "i a") 'org-jira-assign-issue)
    (define-key org-jira-keymap (kbd "i r") 'org-jira-refresh-issue)
    (define-key org-jira-keymap (kbd "i R") 'org-jira-refresh-issues-in-buffer)
    (define-key org-jira-keymap (kbd "i c") 'org-jira-create-issue)
    (define-key org-jira-keymap (kbd "i k") 'org-jira-copy-current-issue-key)
    (define-key org-jira-keymap (kbd "s c") 'org-jira-create-subtask)
    (define-key org-jira-keymap (kbd "s s") 'org-jira-get-subtasks)
    (define-key org-jira-keymap (kbd "c u") 'org-jira-update-comment)
    (define-key org-jira-keymap (kbd "c C") 'org-jira-update-worklogs-from-org-clocks)
    (define-key org-jira-keymap (kbd "t t") 'org-jira-todo-to-jira)
    (define-key org-jira-keymap (kbd "f f") 'org-jira-get-issues-by-fixversion)))

Translate

Google Translate support for those RTL times

(unless noninteractive
  (use-package google-translate
    :ensure t
    :defer t
    :commands (google-translate-at-point google-translate-query-translate fn/google-translate-at-point)
    :config
    (require 'google-translate-default-ui)

    (setq google-translate-default-source-language "en"
          google-translate-default-target-language "ar")

    (setq google-translate-output-destination 'current-buffer)

    (defun fn/google-translate-at-point ()
      "Translate at point while replacing the text."
      (interactive)
      (when (region-active-p)
        (let ((beginning (region-beginning))
              (end (region-end))
              (google-translate-output-destination 'current-buffer))
          (google-translate-at-point)
          (kill-region beginning end))))))

CSV mode

CSV moder

(unless noninteractive
  (use-package csv-mode
    :ensure t
    :defer t
    :config
    nil))

String Inflection

Support for rotating between camel case and what not

(unless noninteractive
  (use-package string-inflection
    :ensure t
    :defer t
    :bind (("C-c C-u" . string-inflection-all-cycle))
    :config
    nil))

EditorConfig

Support editor config for some project.

(use-package editorconfig
  :ensure t
  :hook (prog-mode . editorconfig-mode)
  :config
  nil)

Thesaurus

A little thesaurus help.

(use-package powerthesaurus
  :ensure t
  :commands (powerthesaurus-lookup-word))

PlantUML

Support for making diagrams

(defconst fn/plantuml-file (expand-file-name "plantuml.jar" "~"))
;;; Download link: http://sourceforge.net/projects/plantuml/files/plantuml.jar/download

(when (file-exists-p fn/plantuml-file)
  (use-package plantuml-mode
    :ensure t
    :defer t
    :config
    nil)

  (use-package flycheck-plantuml
    :ensure t
    :after flycheck
    :config
    (flycheck-plantuml-setup))

  (with-eval-after-load 'org
    (require 'ob-plantuml)

    (add-to-list 'org-babel-load-languages '(plantuml . t))
    (setq org-plantuml-jar-path fn/plantuml-file)))

Helper

Specific helper modes

npm

Call npm with Emacs

(fn/use-executables npm-check
  (node npm)
  (use-package npm-mode
    :ensure t
    :defer t
    :bind (:map fn-standard-prefix-map
                ("n" . npm-mode))
    :init
    (setq npm-mode-command-prefix "C-c n n")))

Elisp

Mode

This editor is the mode

(require 'dash)

(defun fn/find-definition-at-point ()
  "This is find-function-at-point and find-variable-at-point meld into one"
  (interactive)
  (-if-let
      (point-pair (cond
                   ((symbolp (variable-at-point))
                    (find-variable-noselect
                     (variable-at-point)
                     nil))
                   ((function-called-at-point) (condition-case ex
                                                   (find-function-noselect (function-called-at-point) t)
                                                 ('error nil)))
                   (t nil)))
      (switch-to-buffer (car point-pair))
    (message "Could not find function or symbol definition or might be builtin")))

(let ((custom-keymap (fn/make-work-keymap emacs-lisp-mode-map)))
  (define-key custom-keymap (kbd "j") #'fn/find-definition-at-point))

Motion

Makes you a good lisp developer and quite addictive to have

(use-package paredit
  :ensure t
  :defer t
  :diminish paredit-mode
  :init
  (add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)
  (add-hook 'ielm-mode-hook #'enable-paredit-mode)
  (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
  (add-hook 'lisp-mode-hook #'enable-paredit-mode)
  (add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode))

(fn/use-feature paredit-eldoc
  (eldoc)
  (eldoc-add-command 'paredit-backward-delete
                     'paredit-close-round))

Refactor

Emacs Lisp refactor mode

(use-package emr
  :ensure t
  :defer t
  :init
  (define-key prog-mode-map (kbd "M-RET") 'emr-show-refactor-menu)
  (add-hook 'prog-mode-hook 'emr-initialize))

Formatter

Not really but nice to have for a lisp language

(use-package elisp-format
  :ensure t
  :defer t
  :disabled t
  :config
  (define-key emacs-lisp-mode-map (kbd "C-c C-f") 'elisp-format-region)

  (make-variable-buffer-local
   (defvar fn/elisp-format-on-save t
     "Enable elisp formatting on save"))

  (defun fn/elisp-format-buffer-on-save ()
    "Format elisp on save"
    (when fn/elisp-format-on-save
      (with-current-buffer (current-buffer)
        (message "Elisp formatting buffer %s" (current-buffer))
        (elisp-format-buffer))))

  (add-hook 'before-save-hook #'fn/elisp-format-buffer-on-save))

Testing

Some testing libraries

(use-package buttercup
  :ensure t
  :defer t)

Project

Some packages to help making packages

(defconst fn/header2-module-dir (expand-file-name "header2/" fn/custom-module-dir)
  "Archived `header2' packages.")

(defconst fn/epl-module-dir (expand-file-name "epl/" fn/custom-module-dir)
  "Archived `epl' packages.")

(use-package epl
  :load-path fn/epl-module-dir
  :demand t)

(use-package cask-mode
  :ensure t
  :defer t)

(fn/use-feature cask-mode--mode-icon
  (all-the-icons)
  (fn/add-major-mode-icon
   'cask-mode
   (list 'all-the-icons-faicon "glass" :v-adjust 0.1)))

(unless noninteractive
  (use-package header2
    :load-path fn/header2-module-dir
    :demand t
    :functions auto-make-header
    :init
    (add-hook 'emacs-lisp-mode-hook 'auto-make-header)))

(use-package overseer
  :ensure t
  :defer t
  :hook (emacs-lisp-mode . overseer-mode)
  :diminish 'overseer-mode)

XML

nxml-mode the default please.

(use-package nxml-mode
  :mode ("\\.xml\\'" . nxml-mode)
  :hook (nxml-mode . company-mode)
  :config
  (defun fn/nxml-prettify-on-save ()
    (when (and (eq major-mode 'nxml-mode)
               (require 'sgml-mode))
      (sgml-pretty-print (point-min) (point-max))))

  (add-hook 'before-save-hook #'fn/nxml-prettify-on-save))

SQL

Client

If enterprise grade support is needed.

(fn/use-executables lein-check
  (lein)
  (use-package ejc-sql
    :ensure t
    :defer t
    :after (sql)
    :functions (ejc-create-connection)
    :commands (ejc-connect)
    :config
    (setq ejc-set-rows-limit 1000
          nrepl-sync-request-timeout 60)))

Literate Programming

Sometimes it’s just easier to get a scratch pad.

(fn/use-feature org-literate-sql
  (org sql)
  (require 'ob-sql) ;; Default

  (use-package ob-sql-mode
    :ensure t
    :defer t
    :after (org sql)
    :config
    nil ;; None yet
    ))

Formatting

Some utility when editing SQL files

(unless noninteractive
  (fn/use-executables ruby-sql-formatter
    (anbt-sql-formatter) ;; gem install anbt-sql-formatter
    (defun fn/sql-beautify-region (beg end)
      "Beautify SQL in region between beg and END."
      (interactive "r")
      (save-excursion
        (shell-command-on-region beg end "anbt-sql-formatter" nil t)))

    (defun fn/sql-beautify-buffer ()
      "Beautify SQL in buffer."
      (interactive)
      (fn/sql-beautify-region (point-min) (point-max))))

  (fn/use-executables python-sql-formatter
    (format-sql) ;; pip install --user format-sql
    (use-package format-sql
      :ensure t
      :defer t
      :commands (format-sql-buffer format-sql-region))))

NoSQL

Literate Programming

I need me some SQL support for NoSQL types

(use-package ob-mongo
  :ensure t
  :defer t
  :after org)

Web

The defacto mode for web development

(use-package web-mode
  :ensure t
  :mode ("\\.html\\'" . web-mode)
  :config
  (setq web-mode-enable-auto-pairing t
        web-mode-enable-auto-closing t
        web-mode-enable-current-element-highlight t
        web-mode-enable-current-column-highlight t))

(use-package company-web
  :ensure t
  :after (company web-mode)
  :config
  (add-to-list 'company-backends 'company-web-html))

(use-package emmet-mode
  :ensure t
  :hook ((web-mode . emmet-mode)
         (css-mode . emmet-mode))
  :config
  (setq emmet-self-closing-tag-style " /")

  (with-eval-after-load 'js2-mode
    (setq emmet-expand-jsx-className? t)))

(use-package sass-mode
  :ensure t
  :defer t
  :config
  nil)

(use-package scss-mode
  :ensure t
  :defer t
  :config
  nil)

JavaScript

Mode

The ultimate JS mode

(use-package js2-mode
  :ensure t
  :interpreter (("node" . js2-mode))
  :mode (("\\.\\(js\\)$" . js2-mode)
         ("\\.\\(jsx\\)$" . js2-jsx-mode))
  :defer t
  :config
  (add-hook 'js-mode-hook 'js2-minor-mode)
  (add-hook 'js2-mode-hook 'subword-mode)
  (add-hook 'js2-jsx-mode-hook 'subword-mode)

  (setq js2-highlight-level 3
        js2-mode-show-parse-errors nil
        js2-mode-show-strict-warnings nil

        js2-include-node-externs t
        js2-include-browser-externs t)

  (fn/use-feature js2-jsx-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'js2-jsx-mode
     (list 'all-the-icons-alltheicon "javascript" :v-adjust 0.1))))

Linter

My linter if you will for JS.

(unless noninteractive
  (fn/use-feature flycheck-eslint-relative
    (flycheck js2-mode)
    ;; Thanks to https://emacs.stackexchange.com/questions/21205/flycheck-with-file-relative-eslint-executable
    (defun fq/use-eslint-from-node-modules ()
      (let* ((root (locate-dominating-file
                    (or (buffer-file-name) default-directory)
                    ".projectile"))
             (eslint (and root
                          (expand-file-name "node_modules/eslint/bin/eslint.js"
                                            root))))
        (when (and eslint (file-executable-p eslint))
          (setq-local flycheck-javascript-eslint-executable eslint))))

    (add-to-list 'flycheck-checkers 'javascript-eslint)
    (add-hook 'flycheck-mode-hook #'fq/use-eslint-from-node-modules)))

Formatter

Formatter for js, choose your poison. I tried the three and still am.

(use-package web-beautify
  :ensure t
  :after js2-mode)

(use-package jsfmt
  :ensure t
  :after js2-mode
  :config
  (let ((custom-keymap (fn/make-work-keymap js2-mode-map)))
    (define-key custom-keymap (kbd "b") #'jsfmt)))

(use-package eslint-fix
  :ensure t
  :after js2-mode
  :config
  (defun fn/eslint-fix-after-save ()
    "Apply eslint fix after save"
    (add-hook 'after-save-hook #'eslint-fix nil t))

  ;; (add-hook 'js2-mode-hook #'fn/eslint-fix-after-save)
  )

REPL

Got to have those REPLs

(use-package nodejs-repl
  :ensure t
  :bind (("C-c C-n C-c" . nodejs-repl-send-buffer)
         ("C-c C-n C-r" . nodejs-repl-send-region)
         ("C-c C-n C-e" . nodejs-repl-send-last-sexp))
  :after js2-mode)

(use-package skewer-mode
  :defer t
  :diminish skewer-mode
  :bind (("C-c K" . run-skewer))
  :ensure t
  :init
  (add-hook 'js2-mode-hook 'skewer-mode)
  (add-hook 'css-mode-hook 'skewer-css-mode)
  (add-hook 'html-mode-hook 'skewer-html-mode))

JSON

JSON support

(use-package json-snatcher
  :ensure t
  :after js2-mode
  :bind (("C-c C-g" . jsons-print-path)))

Literate Programming

Let’s support literate programming for JS

(fn/use-feature org-js2-src
  (org js2-mode)
  (add-to-list 'org-babel-load-languages '(js . t)))

Python

Mode

My favorite programming language, unassuming like Marcy from Peanuts

(fn/use-executables python-check
  (python pip)
  (use-package python
    :ensure t
    :defer t
    :config
    nil))

Formatter

Pep me bro

(use-package py-autopep8
  :ensure t
  :defer t
  :after python)

REPL

Using Ipython for this

(use-package ein
  :ensure t
  :defer t
  :config
  (setq ein:use-auto-complete t
        ein:use-smartrep t))

Autocomplete

The newer Python IDE, Jedi, much easier to grok.

This requires pip and the packages virtualenv.

(use-package jedi
  :ensure t
  :after elpy
  :config
  nil)

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

IDE

Making Python an IDE

(use-package elpy
  :ensure t
  :defer t
  :init
  (add-hook 'python-mode-hook 'elpy-enable)

  (add-hook 'elpy-mode-hook 'flycheck-mode)
  (add-hook 'elpy-mode-hook 'py-autopep8-enable-on-save)
  :config
  (setq elpy-python-command "python"
        elpy-rpc-python-command "python"
        elpy-rpc-backend "jedi")

  (setq elpy-interactive-python-command "ipython")
  (elpy-use-ipython)

  (setq elpy-modules (delq 'elpy-module-flycheck elpy-modules))

  (require 'py-autopep8)
  (add-hook 'elpy-mode-hook 'py-autopep8-enable-on-save))

Project

virtualenv is a must

(use-package python-environment
  :ensure t
  :init
  (setq python-environment-directory (expand-file-name "python-environments" fn/cache-dir)))
(use-package virtualenv
  :ensure t
  :after python)

Or the most updated

(use-package virtualenvwrapper
  :ensure t
  :after python)

Literate Programming

Let’s add a link to org-babel

(fn/use-feature org-python-src
  (org python)
  (add-to-list 'org-babel-load-languages '(python .t)))

Haskell

Mode

The defacto for Haskell development

(fn/use-executables haskell-check
  (ghci)
  (use-package haskell-mode
    :ensure t
    :defer t
    :init
    ;; (add-hook 'haskell-mode-hook 'interactive-haskell-mode)
    (add-hook 'haskell-mode-hook 'haskell-auto-insert-module-template)
    (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode)
    :config
    ;; (require 'haskell-interactive-mode)
    (require 'haskell-process)
    ;; Reset mapping as it does more damage than good
    (setq haskell-cabal-mode-map (make-keymap)
       interactive-haskell-mode-map (make-keymap))

    (define-key haskell-mode-map (kbd "<f8>") 'haskell-navigate-imports)

    (define-key haskell-mode-map (kbd "C-c C-c") 'haskell-compile)
    (define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-compile)

    ;; Haskell bindings
    (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload)
    (define-key haskell-mode-map (kbd "C-`") 'haskell-interactive-bring)
    (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type)
    (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info)
    (define-key haskell-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build)
    (define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
    (define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal)

    ;; Cabal bindings
    ;; (define-key haskell-cabal-mode-map (kbd "C-`") 'haskell-interactive-bring)
    ;; (define-key haskell-cabal-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
    ;; (define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build)
    ;; (define-key haskell-cabal-mode-map (kbd "C-c c") 'haskell-process-cabal)

    ;; Interactive Haskell
    ;; (define-key interactive-haskell-mode-map (kbd "C-c M-.") 'haskell-mode-goto-loc)
    ;; (define-key interactive-haskell-mode-map (kbd "C-c M-t") 'haskell-mode-show-type-at)

    ;; (setq haskell-stylish-on-save t)

    ;; (setq interactive-haskell-mode t)

    (setq haskell-process-suggest-remove-import-lines t
       haskell-process-auto-import-loaded-modules t
       haskell-process-log t
       haskell-process-suggest-hoogle-imports t
       haskell-process-type 'stack-ghci
       haskell-interactive-mode-eval-mode 'haskell-mode)


    (add-hook 'haskell-interactive-mode-hook 'smartparens-mode)
    (fn/use-executables haskell-hoogle-check
      (hoogle)
      (add-hook 'haskell-interactive-mode-hook 'haskell-hoogle-start-server)

      (fn/use-feature helm-hoogle
        (helm haskell-mode)
        (use-package helm-hoogle
          :ensure t
          :demand t)))

    (advice-add 'haskell-process-load-file :after 'haskell-interactive-mode-clear)

    ;; Hoogle
    (define-key haskell-mode-map (kbd "C-c b h") 'hoogle)
    (define-key interactive-haskell-mode-map (kbd "C-c b h") 'hoogle)))

Haskell Process Load Fix

(with-eval-after-load 'haskell-mode
  ;;;  https://github.com/haskell/haskell-mode/pull/1605
  (defun haskell-process-load-complete (session process buffer reload module-buffer &optional cont)
    "Handle the complete loading response. BUFFER is the string of
text being sent over the process pipe. MODULE-BUFFER is the
actual Emacs buffer of the module being loaded."
    (when (get-buffer (format "*%s:splices*" (haskell-session-name session)))
      (with-current-buffer (haskell-interactive-mode-splices-buffer session)
        (erase-buffer)))
    (let* ((ok (cond
                ((haskell-process-consume
                  process
                  "Ok, \\(?:[0-9]+\\) modules? loaded\\.$")
                 t)
                ((haskell-process-consume
                  process
                  "Ok, \\(?:[a-z]+\\) module loaded\\.$") ;; for ghc 8.4
                 t)
                ((haskell-process-consume
                  process
                  "Failed, \\(?:[0-9]+\\) modules? loaded\\.$")
                 nil)
                ((haskell-process-consume
                  process
                  "Ok, modules loaded: \\(.+\\)\\.$")
                 t)
                ((haskell-process-consume
                  process
                  "Failed, modules loaded: \\(.+\\)\\.$")
                 nil)
                (t
                 (error (message "Unexpected response from haskell process.")))))
           (modules (haskell-process-extract-modules buffer))
           (cursor (haskell-process-response-cursor process))
           (warning-count 0))
      (haskell-process-set-response-cursor process 0)
      (haskell-check-remove-overlays module-buffer)
      (while
          (haskell-process-errors-warnings module-buffer session process buffer)
        (setq warning-count (1+ warning-count)))
      (haskell-process-set-response-cursor process cursor)
      (if (and (not reload)
               haskell-process-reload-with-fbytecode)
          (haskell-process-reload-with-fbytecode process module-buffer)
        (haskell-process-import-modules process (car modules)))
      (if ok
          (haskell-mode-message-line (if reload "Reloaded OK." "OK."))
        (haskell-interactive-mode-compile-error session "Compilation failed."))
      (when cont
        (condition-case-unless-debug e
            (funcall cont ok)
          (error (message "%S" e))
          (quit nil))))))

Motion

The paredit for haskell, this weirdly needs exec-path-from-shell to work

(use-package shm
  :ensure t
  :disabled t
  :after haskell-mode
  :init
  (add-hook 'haskell-mode-hook 'structured-haskell-mode)
  :config
  (define-key shm-map (kbd "C-j") 'shm/newline-indent)
  (define-key shm-map (kbd "M-a") 'shm/goto-parent)
  (define-key shm-map (kbd "M-e") 'shm/goto-parent-end)
  (define-key shm-map (kbd "C-+") 'shm/add-operand)
  (define-key shm-map (kbd "M-r") 'shm/raise)
  (define-key shm-map (kbd "M-^") 'shm/delete-indentation)
  (define-key shm-map (kbd "M-k") 'shm/kill)
  (define-key shm-map (kbd "C-y") 'shm/yank)
  (define-key shm-map (kbd "M-k") 'shm/kill-line)


  ;; SHM with interactive-haskell
  (defun fn/shm-interactive-config (&rest args)
    "Setup SHM with interactive-haskell-mode"
    (require 'shm-case-split)
    (define-key shm-map (kbd "C-c C-s") 'shm/case-split))

  (eval-after-load 'haskell-interactive-mode #'fn/shm-interactive-config))

Autocomplete

Company for Haskell

(unless noninteractive
  (fn/use-feature company-haskell
    (haskell-mode company)
    (use-package company-ghc
      :ensure t
      :after company
      :config
      (add-to-list 'company-backends 'company-ghc))

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

Formatter

Formatter for Haskell

(use-package hindent
  :ensure t
  :after haskell-mode
  :init
  (add-hook 'haskell-mode-hook #'hindent-mode)
  :config
  (setq hindent-style "johan-tibell")

  (defun fn/hindent-before-save ()
    "Reformat before saving."
    (interactive)
    (add-hook 'before-save-hook 'hindent-reformat-buffer t t)))

Linter

Syntax checker for Haskell

(fn/use-feature flycheck-haskell
  (flycheck haskell-mode)
  (use-package flycheck-haskell
    :ensure t
    :demand t
    :config
    (flycheck-haskell-setup))

  (use-package flycheck-stack
    :ensure t
    :after flycheck-haskell
    :config
    nil))

Snippets

Easy snippets for Haskell

(unless noninteractive
  (fn/use-feature haskell-snippets
    (yasnippet haskell-mode)
    (use-package haskell-snippets
      :ensure t
      :demand t)))

Build Tools

Maybe stack or hack?

Literate Programming

Literate programming for ease

(defconst fn/ob-haskell-package-dir (expand-file-name "ob-haskell/" fn/custom-module-dir)
  "My ob-haskell package dir.")

(unless noninteractive
  (fn/use-feature org-haskell
    (haskell-mode org)
    (use-package ob-haskell
      :load-path fn/ob-haskell-package-dir
      :disabled t
      :demand t
      :config
      (add-to-list 'org-babel-load-languages '(haskell . t)))

    (defconst fn/haskell-file-extension ".hs"
      "The de facto haskell file extension.")

    (defun fn/add-haskell-file-extension (name)
      "Add the extension of .hs to a file or buffer NAME."
      (if (string/ends-with name fn/haskell-file-extension)
          name (concat name fn/haskell-file-extension)))

    (defvar fn/org-haskell-mode-hook nil
      "Hook when buffer is haskellized.")

    (defun fn/haskellize-buffer-file (&optional buffer)
      "Renames an BUFFER with a .hs extension if it doesn't have one."
      (interactive)
      (with-current-buffer (or buffer (current-buffer))
        (save-buffer)
        (lexical-let ((name (buffer-name))
            (file-name (buffer-file-name)))
          (if (not (and file-name (file-exists-p file-name)))
              (error "Buffer '%s' has no backing file" name)
            (lexical-let ((haskellized-name (fn/add-haskell-file-extension name))
                (haskellized-file-name (fn/add-haskell-file-extension file-name)))
              (cond
               ((get-buffer haskellized-name)
                (error "A buffer named '%s' already exists" haskellized-name))
               ((string-equal name haskellized-name)
                (message "Buffer %s is already haskellized" haskellized-name))
               (t
                (rename-file file-name haskellized-file-name t)
                (rename-buffer haskellized-name)
                (set-visited-file-name haskellized-file-name)
                (set-buffer-modified-p nil)
                (message "Buffer %s is now haskellized" haskellized-name))))))))

    (defun fn/org-haskell-buffer-p (&optional buffer)
      "Check if BUFFER is an org-haskell buffer."
      (with-current-buffer (or buffer (current-buffer))
        (and (eq major-mode 'haskell-mode)
           (fboundp 'org-src-edit-buffer-p)
           (org-src-edit-buffer-p))))

    (defun fn/haskellize-org-haskell-buffer (&rest _)
      "Haskellize org haskell buffer."
      (when (fn/org-haskell-buffer-p)
        (fn/haskellize-buffer-file (current-buffer))
        (run-hooks 'fn/org-haskell-mode-hook)))

    (defun fn/save-org-haskell-buffer (&rest _)
      "Save haskell buffer along with the edit buffer."
      (when (fn/org-haskell-buffer-p)
        (save-buffer)))

    (defun fn/cleanup-org-haskell-buffer (orig-fun &rest args)
      "Cleanup the org-haskell buffer when exiting the edit buffer."
      (lexical-let ((org-haskell-file-name (buffer-file-name))
          (org-haskell-buffer-p (fn/org-haskell-buffer-p)))
        (prog1
            (apply orig-fun args)
          (when (and (file-exists-p org-haskell-file-name) org-haskell-buffer-p)
            (delete-file org-haskell-file-name)))))

    (defun fn/haskell-process-load-or-reload ()
      "Invoke reload process without switching buffers"
      (save-window-excursion
        (haskell-process-load-or-reload))

    (defun fn/haskell-reload-on-save ()
      "Reload interactive haskell process on save."
      (add-hook 'after-save-hook 'fn/haskell-process-load-or-reload t t)))

    ;; (add-hook 'org-src-mode-hook #'fn/haskellize-org-haskell-buffer t)

    ;; (add-hook 'fn/org-haskell-mode-hook 'fn/haskell-process-load-or-reload)
    ;; (add-hook 'fn/org-haskell-mode-hook 'fn/haskell-reload-on-save)

    ;; (advice-add 'org-edit-src-save :before #'fn/save-org-haskell-buffer)
    ;; (advice-add 'org-edit-src-exit :around #'fn/cleanup-org-haskell-buffer)

    (fn/use-feature literate-haskell-hindent
      (haskell-mode hindent)
      ;; (add-hook 'fn/org-haskell-mode-hook 'fn/hindent-before-save)
      )))

Purescript

Mode

A major mode for purescript.

(use-package purescript-mode
  :ensure t
  :config
  nil)

Linter

Flycheck for the win

(use-package flycheck-purescript
  :ensure t
  :after (flycheck purescript)
  :config
  (flycheck-purescript-setup))

IDE

The default IDE support for purescript.

(use-package psc-ide
  :ensure t
  :hook (purescript-mode . psc-ide-mode)
  :config
  (setq psc-ide-use-npm-bin t)

  (add-hook 'purescript-mode-hook #'turn-on-purescript-indentation))

Erlang

Some minor support for working with Erlang

(use-package erlang
  :ensure t
  :defer t
  :config
  nil)

(use-package company-erlang
  :ensure t
  :after (company erlang)
  :init
  (add-hook 'erlang-mode-hook #'company-erlang-init))

Elixir

The dynamic Haskell in my opinion… or was it Python or Ruby

(use-package elixir-mode
  :ensure t
  :defer t
  :hook (elixir-mode . subword-mode)
  :config
  (with-eval-after-load 'all-the-icons
    (fn/add-major-mode-icon
     'elixir-mode
     (list 'all-the-icons-faicon "flask" :v-adjust -0.1))))

(use-package flycheck-credo
  :ensure t
  :after flycheck
  :demand t
  :config
  (flycheck-credo-setup))

(use-package flycheck-mix
  :ensure t
  :after flycheck
  :demand t
  :config
  (flycheck-mix-setup))

(use-package elixir-yasnippets
  :ensure t
  :after elixir-mode
  :config
  nil)

 (use-package alchemist
   :ensure t
   :hook (elixir-mode . alchemist-mode)
   :config
   (setq alchemist-test-status-modeline nil
         alchemist-hooks-compile-on-save t
         alchemist-iex-program-name "iex")

   (with-eval-after-load 'company
     (add-hook 'alchemist-iex-mode-hook 'company-mode)))

Rust

A close C alternative that I can chew on

(use-package rust-mode
  :ensure t
  :config
  (setq rust-format-on-save t))

(use-package racer
  :ensure t
  :after (rust-mode company)
  :hook (rust-mode . racer-mode)
  :config
  (setq racer-cmd (executable-find "racer")))

(use-package cargo
  :ensure t
  :after rust-mode
  :hook (rust-mode . cargo-minor-mode)
  :config
  (setq cargo-process--command-add "install")

  (add-to-list 'cargo-process--no-manifest-commands "Add")

  (defun fn/cargo-test-nocapture-flag (orig-fun &rest args)
    "For test commands, add `--nocapture' and `--quiet' flags."
    (let ((cargo-process--command-flags
           (append cargo-process--command-flags
                   "-- --nocapture --quiet")))
      (apply orig-fun args)))

  (advice-add 'cargo-process--command-test :around #'fn/cargo-test-nocapture-flag)
  (advice-add 'cargo-process-test :around #'fn/cargo-test-nocapture-flag)
  (advice-add 'cargo-process-current-test :around #'fn/cargo-test-nocapture-flag)

  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*Cargo" (* anything))
    (cons 'display-buffer-same-window (list)))))

(use-package flycheck-rust
  :ensure t
  :after flycheck
  :demand t
  :config
  (flycheck-rust-setup))

PHP

Mode

The major mode for PHP

(use-package php-mode
  :ensure t
  :defer t
  :config
  (setq php-mode-coding-style 'psr2
        php-style-delete-trailing-whitespace t)

  (add-hook 'php-mode-hook 'php-enable-default-coding-style))

Completion

The usual completion

(use-package company-php
  :ensure t
  :defer t
  :disabled t
  :after company
  :init
  (add-hook 'php-mode-hook 'company-mode)
  :config
  (add-to-list 'company-backends 'company-ac-php-backend))

Formatter

Formatter via phpcbf

(unless noninteractive
  (fn/use-executables php-formatter-check
    (phpcbf)
    (use-package phpcbf
      :ensure t
      :defer t
      :after (php-mode)
      :config
      (setq phpcbf-standard "PSR2"
            phpcbf-executable "phpcbf")

      (add-hook 'php-mode-hook 'phpcbf-enable-on-save))))

Linter

Flycheck to the rescue

(fn/use-feature flycheck-php
  (flycheck php-mode)
  (fn/use-executables php-linter-check
    (phpcs)
    (setq flycheck-phpcs-standard "PSR2"
          flycheck-php-phpcs-executable "phpcs")

    (add-to-list 'flycheck-enabled-checkers 'php)
    (add-to-list 'flycheck-enabled-checkers 'php-phpcs)))

Ruby

Mode

Built in ruby-mode is enough

Completion

Still using company with robe

(unless noninteractive
  (fn/use-feature company-robe
    (robe company)
    (add-to-list 'company-backends 'company-robe)))

Linter

Integrating rubocop here

(use-package rubocop
  :ensure t
  :init
  (add-hook 'ruby-mode-hook #'rubocop-mode)
  :config
  nil)

(use-package rubocopfmt
  :ensure t
  :init
  (add-hook 'rubocop-mode-hook #'rubocopfmt-mode)
  :config
  (setq rubocopfmt-use-bundler-when-possible nil))

Editing

Some editing tools

(unless noninteractive
  (use-package ruby-tools
    :ensure t
    :init
    (add-hook 'ruby-mode-hook #'ruby-tools-mode)
    :config
    nil))

Project

Ruby has it’s own environment

(use-package projectile-rails
  :ensure t
  :after ruby-mode
  :hook (ruby-mode . projectile-rails-mode)
  :config
  (add-to-list
   'display-buffer-alist
   (cons
    (rx bos "*rails" (* anything))
    (cons 'display-buffer-same-window (list)))))

(use-package ruby-test-mode
  :ensure t
  :hook (ruby-mode  . ruby-test-mode)
  :config
  nil)

Solidity

Block chain development.

(use-package solidity-mode
  :ensure t
  :config
  nil)

(use-package solidity-flycheck
  :ensure t
  :hook solidity
  :config
  nil)

(use-package company-solidity
  :ensure t
  :hook solidity
  :config
  nil)

dotNet

omnisharp

For C# development

(use-package omnisharp
  :ensure t
  :defer t
  :init
  (add-hook 'csharp-mode-hook 'omnisharp-mode)
  :config
  (setq omnisharp-root-dir
        (expand-file-name "~/Fakespace/omnisharp-server"))
  (setq omnisharp-server-executable-path
        (expand-file-name "OmniSharp/bin/Debug/" omnisharp-root-dir)))

LaTeX

LaTeX editing for my files

Mode

Actual mode to do the job

(with-eval-after-load 'latex
  (add-hook 'latex-mode-hook 'flyspell-mode)

  (add-to-list 'TeX-command-list '("XeLaTeX" "%`xelatex%(mode)%' %t" TeX-run-TeX nil t)))

(use-package auctex
  :ensure t
  :defer t
  :init
  (add-hook 'LaTeX-mode-hook 'turn-on-reftex)
  (add-hook 'latex-mode-hook 'turn-on-reftex)
  (setq reftex-plug-into-AUCTex t)
  :config
  (setq TeX-auto-save t
        TeX-parse-self t)

  (setq-default TeX-master nil))

Autocomplete

Autocomplete obviously

(use-package company-auctex
  :ensure t
  :after auctex
  :config
  (company-auctex-init))

Linter

Something similar but for spelling

(fn/use-feature flyspell-auctex
  (flyspell auctex)
  (add-hook 'latex-mode-hook #'flyspell-mode))

REPL

Something like that but rather a preview for every edit

(use-package latex-preview-pane
  :ensure t
  :after auctex
  :config
  (define-key latex-mode-map (kbd "C-c C-p") 'latex-preview-pane-mode))

Git Gutter

Git gutter support for Emacs

(use-package git-gutter
  :ensure t
  :defer t
  :init
  (add-hook 'prog-mode-hook #'git-gutter-mode)
  :commands (git-gutter-mode)
  :bind (("C-x g" . git-gutter:toggle)
         ("C-x n" . git-gutter:next-hunk)
         ("C-x p" . git-gutter:previous-hunk)
         ("C-x v s" . git-gutter:stage-hunk)
         ("C-x v r" . git-gutter:revert-hunk))
  :config
  (setq git-gutter:window-width 1
        git-gutter:modified-sign "/"
        git-gutter:added-sign "+"
        git-gutter:deleted-sign "-"))

Random Was Alone

Anything that just does something useful

redis

Some redis support

(use-package eredis
  :ensure t
  :defer t
  :commands (eredis-connect)
  :config
  (setq main (eredis-connect "localhost" 6379)))

w3m

Web browsing is a must

(fn/use-executables w3m-check
  (w3m)
  (use-package w3m
    :ensure t
    :unless noninteractive
    :defer t
    :bind (:map fn-standard-prefix-map
                ("w w" . w3m)
                ("w s" . w3m-search-new-session)
                ("w e" . w3m-external-view-current-url)
                ("w g" . w3m-goto-url))
    :init
    (setq w3m-search-engine-alist (list))

    (defcustom fn/w3m-ignore-arrived-url-functions (list)
      "Functions that check if the url is saved for privacy."
      :type 'hook)

    (defconst fn/w3m-ignore-arrived-hosts (list)
      "Ignore the urls of the arrived hosts.")

    (defcustom fn/w3m-exclude-ignore-search-engine (list)
      "Exclude search engine from being ignored."
      :type 'list)
    :config
    ;; Main
    (setq w3m-home-page "https://duckduckgo.com"
          w3m-init-file (expand-file-name "emacs-w3m.config" fn/cache-dir)
          w3m-use-cookies nil
          w3m-confirm-leaving-secure-page nil
          w3m-cookie-file (expand-file-name "w3m-cookie" fn/cache-dir))


    (setq w3m-command-arguments (list))


    ;; Tabs
    (setq w3m-add-tab-number t
          w3m-make-new-session nil

          w3m-use-header-line t
          w3m-use-header-line-title t
          w3m-show-graphic-icons-in-header-line nil

          w3m-use-title-buffer-name t)

    ;; Util
    (defun fn/w3m-ignore-search-engine-pages (url &rest args)
      "Ignore search engine pages as defined by `w3m-search-engine-alist'."
      (ignore-errors ;; Ignore special urls such as //:about or whatnot
        (lexical-let* ((url-parts (w3m-parse-http-url url))
                       (url-host (elt url-parts 1)))
          (cl-some
           (lambda (pair)
             (pcase-let ((`(,name ,search-url) pair))
               (lexical-let* ((search-parts (w3m-parse-http-url search-url))
                              (search-host (elt search-parts 1)))
                 (and (not (member name fn/w3m-exclude-ignore-search-engine))
                      (string= search-host url-host)))))
           w3m-search-engine-alist))))

    (defun fn/w3m-ignore-special-pages (url)
      "Ignore special pages such like `about://'."
      (pcase url
        ((pred (string-prefix-p "about://")) t)
        (_ nil)))


    ;; Search Engine
    (require 'w3m-search)

    (setq w3m-search-default-engine "duckduckgo")


    (add-to-list 'w3m-search-engine-alist
                 (list "duckduckgo" "https://duckduckgo.com?q=%s"))
    (add-to-list 'w3m-search-engine-alist
                 (list "youtube" "https://www.youtube.com/results?search_query=%s"))
    (add-to-list 'w3m-search-engine-alist
                 (list "wikipedia" "http://en.wikipedia.org/wiki/Special:Search?search=%s"))


    ;; Proxy
    (require 'w3m-proc)


    ;; Conkeror / Lnum
    (require 'w3m-lnum)

    (add-hook 'w3m-mode-hook #'w3m-lnum-mode t)


    ;; History
    (require 'w3m-hist)

    (setq w3m-y-reuse-history-elements t
          w3m-arrived-file (expand-file-name "w3m-arrived" fn/cache-dir)
          w3m-arrived-db-size 2000
          w3m-keep-cache-size 1500)


    (defun fn/w3m-ignore-arrived-add-url (orig-fun &rest args)
      "Check whether to save the url using `fn/w3m-ignore-arrived-url-functions' as basis.
Each function predicate takes is the same arguments as `w3m-arrived-add'
Good for privacy and cleanliness."
      (if (not (apply #'run-hook-with-args-until-success
                      (append
                       (list 'fn/w3m-ignore-arrived-url-functions)
                       args)))
          (apply orig-fun args)
        (message "Not saving arrived url %s" (car args))
        nil))

    (advice-add 'w3m-arrived-add :around #'fn/w3m-ignore-arrived-add-url)


    (define-minor-mode fn/w3m-private-mode
      "A simple minor mode to indicate private browsing in `w3m'."
      :lighter " w3m-private"
      :init-value nil
      :global t
      :keymap (make-sparse-keymap)
      (defun fn/w3m-ignore-all-arrived-url (&rest args)
        "Ignore all urls when `fn/w3m-private-mode' is active"
        (and (boundp 'fn/w3m-private-mode)
             fn/w3m-private-mode))

      (add-hook 'fn/w3m-ignore-arrived-url-functions #'fn/w3m-ignore-all-arrived-url))

    (defun fn/w3m-ignore-arrived-host (url &rest args)
      "Ignore if url host matches and `fn/w3m-ignore-arrived-hosts'.
Primary check comes from `w3m-parse-http-url' by direct string match."
      (condition-case ex
          (lexical-let* ((parts (w3m-parse-http-url url))
                         (host (elt parts 1)))
            (not (cl-notany
                  (lambda (check-host)
                    (string= check-host host))
                  fn/w3m-ignore-arrived-hosts)))
        ('error
         (message
          "There was an error parsing with fn/w3m-ignore-arrived-host: %s"
          (error-message-string ex)))))

    (add-hook 'fn/w3m-ignore-arrived-url-functions #'fn/w3m-ignore-search-engine-pages)
    (add-hook 'fn/w3m-ignore-arrived-url-functions #'fn/w3m-ignore-arrived-host)


    ;; Bookmarking
    (require 'w3m-bookmark)

    (setq w3m-bookmark-file (expand-file-name "w3m-bookmark.html" fn/setting-dir)
          w3m-bookmark-default-section "Misc")


    ;; Persistent Session
    (require 'w3m-session)

    (setq w3m-session-file (expand-file-name "w3m-session" fn/cache-dir))


    ;; Util
    (defun fn/w3m-new-buffer ()
      "Opens a new, empty w3m buffer.
Thanks to https://www.emacswiki.org/emacs/WThreeMTabs"
      (interactive)
      (w3m-goto-url-new-session "about://"))


    ;; Key (re)binding
    (define-key w3m-mode-map (kbd "q") 'w3m-delete-buffer)
    (define-key w3m-mode-map (kbd "Q") 'w3m-quit)

    (define-key w3m-mode-map (kbd "c") 'w3m-lnum-print-this-url)
    (define-key w3m-mode-map (kbd "f") 'w3m-lnum-follow)

    (define-key w3m-mode-map (kbd "h") 'w3m-history)
    (define-key w3m-mode-map (kbd "H") 'w3m-db-history)

    (define-key w3m-mode-map (kbd "M-p") 'w3m-previous-buffer)
    (define-key w3m-mode-map (kbd "M-n") 'w3m-next-buffer)

    (define-key w3m-mode-map (kbd "i") 'w3m-toggle-inline-image)
    (define-key w3m-mode-map (kbd "I") 'w3m-toggle-inline-images)

    (define-key w3m-mode-map (kbd "t") 'fn/w3m-new-buffer)
    (unbind-key (kbd "t") w3m-lnum-mode-map)

    (define-key w3m-mode-map (kbd "V") 'w3m-bookmark-view)
    (define-key w3m-mode-map (kbd "v") 'w3m-bookmark-add-current-url)

    (define-key w3m-mode-map (kbd "{") 'w3m-previous-buffer)
    (define-key w3m-mode-map (kbd "}") 'w3m-next-buffer)


    (unbind-key "<right>" w3m-mode-map)
    (unbind-key "<left>" w3m-mode-map)

    (unbind-key "<up>" w3m-mode-map)
    (unbind-key "<down>" w3m-mode-map)


    (define-key w3m-mode-map (kbd "S") 'w3m-search-new-session)
    (define-key w3m-mode-map (kbd "s") 'w3m-search)
    (define-key w3m-mode-map (kbd "RET") 'w3m-view-this-url)
    (define-key w3m-mode-map (kbd "M-RET") 'w3m-view-this-url-new-session)


    (define-key w3m-mode-map (kbd ";") #'fn/w3m-fontify-summary)


    (fn/use-feature w3m-mode--mode-icon
      (all-the-icons)
      (fn/add-major-mode-icon
       'w3m-mode
       (list 'all-the-icons-faicon "globe" :v-adjust -0.1)))))

Privacy Proxy

I want w3m to use tor at least.

(with-eval-after-load 'w3m
  (fn/use-executables w3m-privacy-proxy
    (w3m tor polipo privoxy)
    (defcustom fn/w3m-polipo-cache-dir (expand-file-name "polipo-cache" fn/cache-dir)
      "Polipo cache directory."
      :type 'directory)

    (defcustom fn/w3m-tor-cache-dir (expand-file-name "tor-cache" fn/cache-dir)
      "Tor cache directory."
      :type 'directory)

    (defcustom fn/w3m-privoxy-cache-dir (expand-file-name "polipo-cache" fn/cache-dir)
      "Privoxy cache directory."
      :type 'directory)

    (defcustom fn/w3m-privoxy-conf-dir (expand-file-name "privoxy" fn/system-dir)
      "Privoxy conf directory."
      :type 'directory)



    (defcustom fn/w3m-tor-port 18050
      "Tor port"
      :type 'number)

    (defcustom fn/w3m-polipo-port 18123
      "Polipo port"
      :type 'number)

    (defcustom fn/w3m-privoxy-port 18118
      "Polipo port"
      :type 'number)


    (defcustom fn/w3m-polipo-conf-file (expand-file-name "polipo-w3m-conf" fn/cache-dir)
      "Polipo configuration."
      :type 'file)

    (defcustom fn/w3m-tor-conf-file (expand-file-name "tor-w3m-conf" fn/cache-dir)
      "Tor configuration."
      :type 'file)

    (defcustom fn/w3m-privoxy-conf-file (expand-file-name "privoxy-w3m-conf" fn/cache-dir)
      "Privoxy configuration."
      :type 'file)


    (defun fn/w3m-privacy-update-conf ()
      "Create/update `fn/w3m-polipo-conf-file' and `fn/w3m-tor-conf-file' with new
configurations."
      (interactive)
      (make-directory fn/w3m-polipo-cache-dir t)
      (make-directory fn/w3m-tor-cache-dir t)

      (make-directory fn/w3m-privoxy-cache-dir t)
      (make-directory fn/w3m-privoxy-conf-dir t)

      (fn/prodigy-create-polipo-conf
       fn/w3m-polipo-conf-file
       `(("proxyAddress" . "127.0.0.1")
         ("allowedClients" . "127.0.0.1")
         ("diskCacheRoot" . ,fn/w3m-polipo-cache-dir)
         ("proxyPort" . ,fn/w3m-polipo-port)
         ("cacheIsShared" . false)
         ("socksParentProxy" .
          ,(format "%s:%s" "127.0.0.1" fn/w3m-tor-port))
         ("socksProxyType" . socks5)
         ("relaxTransparency" . true)
         ("logSyslog" . false)
         ("logLevel" . 0xFF)
         ("logFile" . "")

         ;; Optional Security Setting
         ("localDocumentRoot" . "")
         ("disableLocalInterface" . true)
         ("disableConfiguration" . true)
         ("dnsUseGethostbyname" . yes)
         ("disableVia" . true)
         ("censorReferer" . maybe)
         ("maxConnectionAge" . 5m)
         ("maxConnectionRequests" . 120)
         ("serverMaxSlots" . 8)
         ("serverSlots" . 2)))

      (fn/prodigy-create-tor-conf
       fn/w3m-tor-conf-file
       `(("SocksPort" . ,fn/w3m-tor-port)
         ("DataDirectory" . ,fn/w3m-tor-cache-dir)
         ("ControlPort" . ,(1+ fn/w3m-tor-port))
         ("DisableDebuggerAttachment" . 0)
         ("Log" . "info")))

      (fn/prodigy-create-privoxy-conf
       fn/w3m-privoxy-conf-file
       `(("confdir" . ,fn/w3m-privoxy-conf-dir)
         ("logdir" . ,fn/w3m-privoxy-cache-dir)

         ("actionsfile" . "match-all.action")
         ("actionsfile" . "default.action")
         ("actionsfile" . "user.action")
         ("filterfile" . "default.filter")

         ("debug" . 13313)
         ("logfile" . "logfile")
         ("listen-address" .
          ,(format "%s:%s" "127.0.0.1" fn/w3m-privoxy-port))
         ("forward" .
          ,(format "/ %s:%s" "127.0.0.1" fn/w3m-polipo-port))

         ("toggle" . 1)
         ("enable-remote-toggle" . 0)
         ("enable-edit-actions" . 0)
         ("enforce-blocks" . 0)
         ("buffer-limit" . 4096)
         ("enable-proxy-authentication-forwarding" . 0)
         ("forwarded-connect-retries" .  0)
         ("accept-intercepted-requests" . 0)
         ("allow-cgi-request-crunching" . 0)
         ("split-large-forms" . 0)
         ("keep-alive-timeout" . 5)
         ("tolerate-pipelining" . 1)
         ("socket-timeout" . 300))))

    (defun fn/w3m-remove-http-proxy-arguments ()
      "Remove http_proxy= from `w3m-command-arguments'."
      (setq w3m-command-arguments ;; Remove added http_proxy arguments
            (cl-reduce  ;; I wish this could be easier
             (lambda (val xs)
               (if (and (string= "-o" val)
                        (or
                         (string-prefix-p "http_proxy="
                                          (or (car xs) ""))
                         (string-prefix-p "https_proxy="
                                          (or (car xs) ""))))
                   (cdr xs)
                 (cons val xs)))
             w3m-command-arguments
             :from-end t
             :initial-value (list))))

    (defun fn/w3m-append-http-proxy-arguments ()
      "Add http_proxy= to `w3m-command-arguments' while removing previous ones."
      (fn/w3m-remove-http-proxy-arguments)
      (setq w3m-command-arguments
            (append w3m-command-arguments
                    (list "-o"
                          (format
                           "http_proxy=http://127.0.0.1:%s/"
                           fn/w3m-privoxy-port))
                    (list "-o"
                          (format
                           "https_proxy=https://127.0.0.1:%s/"
                           fn/w3m-privoxy-port)))))


    (require 'prodigy)
    (require 'prodigy-set)

    (defun fn/w3m-service-start (&rest args)
      "Add http-proxy from `w3m-command-arguments'."
      (when (prodigy-set-started-p fn/w3m-privacy-set)
        (fn/w3m-append-http-proxy-arguments)))

    (defun fn/w3m-service-stop (&rest args)
      "Add http-proxy from `w3m-command-arguments'."
      (fn/w3m-remove-http-proxy-arguments))

    (defun fn/w3m-service-init (&rest args)
      "If both service are stopped, update config before starting."
      (unless (prodigy-set-started-p fn/w3m-privacy-set)
        (fn/w3m-privacy-update-conf)))


    (prodigy-define-tag
      :name 'w3m
      :init #'fn/w3m-service-init
      :on-start #'fn/w3m-service-start
      :on-stop #'fn/w3m-service-stop)


    (defconst fn/w3m-polipo-service-name "w3m-polipo"
      "Polipo prodigy service name.")

    (defconst fn/w3m-tor-service-name "w3m-tor"
      "Tor prodigy service name.")

    (defconst fn/w3m-privoxy-service-name "w3m-privoxy"
      "Privoxy prodigy service name.")


    (fn/prodigy-define-service
     :name fn/w3m-polipo-service-name
     :tags '(w3m polipo)
     :port fn/w3m-polipo-port
     :args (list "-c" fn/w3m-polipo-conf-file))

    (fn/prodigy-define-service
     :name fn/w3m-tor-service-name
     :tags '(w3m tor)
     :port fn/w3m-tor-port
     :args (list "-f" fn/w3m-tor-conf-file))

    (fn/prodigy-define-service
     :name fn/w3m-privoxy-service-name
     :tags '(w3m privoxy)
     :port fn/w3m-privoxy-port
     :args (list "--no-daemon" fn/w3m-privoxy-conf-file))

    (defconst fn/w3m-privacy-set
      (prodigy-set-define-set
       :name "w3m-privacy"
       :strategy 'sequential
       :services `(("w3m-privoxy" . ready)
                   ("w3m-polipo" . ready)
                   ("w3m-tor" . ready)))
      "My privacy set.")

    (prodigy-set-mode t)


    (defun fn/w3m-start-privacy-proxies (&rest args)
      "Start services"
      (interactive)
      (prodigy-set-mode t)
      (prodigy-set-start-set fn/w3m-privacy-set))

    (defun fn/w3m-kill-privacy-proxies (&rest args)
      "Stop special services."
      (interactive)
      (prodigy-set-mode t)
      (prodigy-set-stop-set fn/w3m-privacy-set))


    (add-to-list 'w3m-no-proxy-domains "127.0.0.1")
    (add-to-list 'w3m-no-proxy-domains "localhost")

    (defun fn/w3m-add-current-host-to-no-proxy-domains ()
      "Add current host to `w3m-no-proxy-domains'"
      (interactive)
      (when (eq major-mode 'w3m-mode)
        (lexical-let* ((parts (w3m-parse-http-url w3m-current-url))
                       (host (elt parts 1)))
          (add-to-list 'w3m-no-proxy-domains host t)
          (w3m-reload-this-page))))

    (when (yes-or-no-p "Start privacy proxies for w3m? ")
      (fn/w3m-start-privacy-proxies)
      (message "Delaying a little bit after starting the proxies.")
      (sleep-for 1))))

External Video Player

Hook up vlc and w3m when visiting certain sites

(fn/use-feature w3m-vlc
  (w3m)
  (fn/use-executables w3m-vlc-check
    (vlc)
    (require 'w3m-cookie) ;; Required by `w3m-parse-http-url'

    (defcustom fn/w3m-video-executable "vlc"
      "The executable that can run a network video stream.")

    (defcustom fn/w3m-video-args
      (list
       ;; This skews how the process is managed for vlc
       ;; "--one-instance"
       ;; "--play-and-exit"
       )
      "Extra arguments to run `fn/w3m-video-executable'")

    (defun fn/w3m-video (&optional url)
      "Get image video url."
      (or url (w3m-anchor) w3m-current-url))

    (defun fn/w3m-view-video ()
      "View the video url with `fn/w3m-video-executable'"
      (interactive)
      (let ((url (w3m-url-valid (fn/w3m-video))))
        (if (null url)
            (prog1
                (w3m-message "No video at point")
              nil)
          (lexical-let ((video-process
               (apply #'start-process
                  (append
                   (list
                    (format "%s-%s" "w3m" fn/w3m-video-executable)
                    nil
                    fn/w3m-video-executable)
                   fn/w3m-video-args
                   (list url)))))
            (with-current-buffer (current-buffer)
              (fn/w3m-kill-page-process)

              (setq-local fn/w3m-page-process video-process))))))

    (defun fn/w3m-video-url-p (url)
      "Check if URL is a video."
      (ignore-errors
        (lexical-let* ((pieces (w3m-parse-http-url url))
            (host (elt pieces 1))
            (path (elt pieces 3)))
          (if (or (and (string= host "www.youtube.com")
                    (string-prefix-p "/watch" path)))
              url nil))))

    (defun fn/w3m-view-this-video-external (url)
      "View this video externally"
      (lexical-let ((video-url (fn/w3m-video-url-p (fn/w3m-video))))
        (when
            (and video-url
               (yes-or-no-p
                (format "%s is a video, view it with %s?"
                        video-url fn/w3m-video-executable)))
          (fn/w3m-view-video))))

    (defun fn/w3m-kill-page-process ()
      "Kill the `fn/w3m-page-process' of the current buffer."
      (interactive)
      (with-current-buffer (current-buffer)
        (when (and (boundp 'fn/w3m-page-process)
                 (process-live-p fn/w3m-page-process))
          (kill-process fn/w3m-page-process))

        (setq-local fn/w3m-page-process nil)))

    (defun fn/w3m-auto-kill-page-process (url)
      "If the page has a process, quit it."
      (fn/w3m-kill-page-process))

    (defun fn/w3m-single-page-process (result)
      "If the page process is a singleton, adjust page container accordingly."
      (when result
        (lexical-let ((this-page (current-buffer))
            (active-process nil))
          (mapc
           (lambda (page)
             (with-current-buffer page
               (when (process-live-p fn/w3m-page-process)
                 (setq active-process fn/w3m-page-process))

               (setq-local fn/w3m-page-process nil)))
           (w3m-list-buffers))
          (with-current-buffer this-page
            (setq-local fn/w3m-page-process active-process))))
      result)


    (add-hook 'w3m-display-hook #'fn/w3m-auto-kill-page-process t)
    (add-hook 'w3m-display-hook #'fn/w3m-view-this-video-external t)
    (add-hook 'kill-buffer-hook #'fn/w3m-kill-page-process t)
    ))

Page Summarizer

Hooking up vlc and sumy to aid in reading web pages.

(fn/use-feature w3m-sumy
  (w3m)
  (fn/use-executables w3m-sumy-check
    (sumy)
    (require 'deferred)

    (defcustom fn/w3m-sumy-executable "sumy"
      "The executable that can run a summarize articles.")

    (defcustom fn/w3m-sumy-args
      (list
       "lex-rank"
       "--length" "5")
      "Extra arguments to run `fn/w3m-sumy-executable'")

    (defface fn/w3m-summary '((t (:weight bold :height 1.1 :box (:line-width 2 :color "grey75" :style released-button))))
      "Summary face.")

    (defun fn/w3m-summarize-url (url)
      "Summarize URL for easier comprehension"
      (lexical-let ((url url))
        (deferred:nextc
          (apply
           #'deferred:process-shell
           (append
            (list fn/w3m-sumy-executable)
            fn/w3m-sumy-args
            (if (string-prefix-p "file://" url)
                (list "--file"
                   (concat "\"" (substring-no-properties url (length "file://"))  "\""))
              (list "--url"
                 (concat "\"" url "\"")))))
          (lambda (summary-output)
            (lexical-let ((processed-text (string-trim-right summary-output)))
              (if (string-empty-p processed-text)
                  nil
                (mapcar
                 (lambda (text) (replace-regexp-in-string "\n" " " text))
                 (split-string processed-text "\\\.\n"))))))))

    (defun fn/w3m-fontify-summary ()
      "Fontify summary points."
      (interactive)
      (when (executable-find fn/w3m-sumy-executable)
        (lexical-let ((fontifier
             (lambda (text)
               (let ((inhibit-read-only t)
                   (new-text
                    (string-join
                     (split-string (regexp-quote text) " ") "\n*\s*")))
                 (goto-char (point-min))
                 (while (re-search-forward new-text nil t)
                   (w3m-add-face-property (match-beginning 0) (match-end 0) 'fn/w3m-summary))))))
          (setq-local fn/w3m-fontify-summary (fn/w3m-summarize-url w3m-current-url))

          (with-current-buffer (current-buffer)
            (message "Summarizing %s" w3m-current-url)
            (deferred:nextc
              fn/w3m-fontify-summary
              (lambda (text-points)
                (setq-local fn/w3m-fontify-summary nil)
                (if (null text-points)
                    (message "No summary for %s" (w3m-current-title))
                  (message "Summarizing points on %s" w3m-current-url)
                  (save-excursion
                    (mapc fontifier text-points))
                  (message "Summary on %s:\n%s"
                           (w3m-current-title)
                           (string-join
                            (mapcar
                             (lambda (text-point)
                               (format "* %s" text-point))
                             text-points)
                            "\n")))))))))

    (defun fn/w3m-kill-page-summarizer ()
      "Kill page summarizer."
      (when (and (boundp 'fn/w3m-page-summarizer)
               fn/w3m-page-summarizer
               (deferred-p fn/w3m-page-summarizer))
        (deferred:cancel fn/w3m-page-summarizer))

      (setq-local fn/w3m-page-summarizer nil))


    (defcustom fn/w3m-summarize-ignore-page-functions (list)
      "Functions that check if the url should be summarized.
Each function takes an current URL argument and returns non-nil
when the page should not be summarized."
      :type 'hook)

    (add-to-list 'fn/w3m-exclude-ignore-search-engine "wikipedia")
    (add-to-list 'fn/w3m-exclude-ignore-search-engine "youtube")

    (add-hook 'fn/w3m-summarize-ignore-page-functions #'fn/w3m-ignore-search-engine-pages)
    (add-hook 'fn/w3m-summarize-ignore-page-functions #'fn/w3m-ignore-special-pages)


    (defun fn/w3m-summarize-page ()
      "Summarize page using `sumy' by checking `fn/w3m-summarize-ignore-page-functions'."
      (unless (run-hook-with-args-until-success 'fn/w3m-summarize-ignore-page-functions w3m-current-url)
        (fn/w3m-fontify-summary)))

    (add-hook 'w3m-fontify-before-hook #'fn/w3m-kill-page-summarizer)
    (add-hook 'w3m-fontify-after-hook #'fn/w3m-summarize-page)))

Loading Screen

At attempt to zone out while waiting to render

(fn/use-feature w3m-zone
  (w3m)
  (defun fn/w3m-zone-retrieve (&rest args)
    (with-current-buffer (current-buffer)
      (let ((inhibit-read-only t))
        (erase-buffer)
        (goto-char (point-min)))
      (setq-local fn/w3m-zone-timer
                  (run-at-time
                   (/ 10.0)
                   (/ 30.0)
                   (lambda ()
                     (let ((inhibit-read-only t)
                         (increment (- 6 (random 12))))
                       (unless (boundp 'fn/w3m-zone-counter)
                         (setq-local fn/w3m-zone-counter (+ 20 (random 20))))
                       (setq-local fn/w3m-zone-counter
                                   (+ fn/w3m-zone-counter increment))

                       (setq-local fn/w3m-zone-counter (max fn/w3m-zone-counter 1))

                       (insert
                        (string-join
                         (mapcar
                          (lambda (ch)
                            (cond
                             ((< 0 increment) "\\")
                             ((> 0 increment) "/")
                             (t "-")))
                          (number-sequence 1 fn/w3m-zone-counter))
                         ""))
                       (insert "\n")))))))

  ;; (advice-add 'w3m-retrieve :after #'fn/w3m-zone-retrieve)

  (defun fn/w3m-cancel-zone-render (&rest args)
    (when (and (boundp 'fn/w3m-zone-timer)
             (timerp fn/w3m-zone-timer))
      (cancel-timer fn/w3m-zone-timer))
    (setq-local fn/w3m-zone-counter (+ 20 (random 20)))
    (setq-local fn/w3m-zone-timer nil))

  ;; (advice-add 'w3m-rendering-buffer :before #'fn/w3m-cancel-zone-render)
  )

Auto Bookmarking

Auto bookmark pages when I seem to visit it frequently

(fn/use-feature w3m-auto-bookmarking
  (w3m)
  (defcustom fn/w3m-auto-bookmark-check-functions (list)
    "Functions that check if a function should be auto-bookmarked.
Each function takes the same arguments as `w3m-arrived-add' and
returns non-nil when the url is bookmarked."
    :type 'hook)

  (defcustom fn/w3m-auto-bookmark-handler-functions (list)
    "Functions that handle how a url should be bookmarked.
Each function takes the same arguments as `w3m-arrived-add' and
returns a cons pair where the car is the section and cdr the title
if it handles it. "
    :type 'hook)


  (defvar fn/w3m-url-visit-table (make-hash-table :test 'equal)
    "Record the number of times an url is visited.")

  (defcustom fn/w3m-auto-bookmark-frequent-visit-count 3
    "Number of times a site should be visited before being bookmarked.")

  (defun fn/w3m-auto-bookmark-frequently-visited (url title)
    "Check if url is visited frequently enough."
    (when (eq (gethash url fn/w3m-url-visit-table 'nothing) 'nothing)
      (puthash url 0 fn/w3m-url-visit-table))

    (lexical-let ((counter (gethash url fn/w3m-url-visit-table)))
      (unless (/= -1 counter)
        (puthash url (1+ ) fn/w3m-url-visit-table)))

    (lexical-let ((result (>= (gethash url fn/w3m-url-visit-table) fn/w3m-auto-bookmark-frequent-visit-count)))
      (prog1
          result
        (when result
          (puthash url -1 fn/w3m-url-visit-table)))))

  (add-hook 'fn/w3m-auto-bookmark-check-functions #'fn/w3m-auto-bookmark-frequently-visited)


  (defcustom fn/w3m-auto-bookmark-host-handlers (list)
    "Handle bookmarking by its host.
This is a list of cons where the car is the host of the url and
cdr a function that takes a url and title argument and returns a
cons pair as specified by
`fn/w3m-auto-bookmark-handler-functions'."
    :type 'list)

  (defun fn/w3m-auto-bookmark-host-handler (url title)
    "Handle bookmarking by host as specified `fn/w3m-auto-bookmark-handler'."
    (lexical-let* ((pieces (w3m-parse-http-url url))
        (host (elt pieces 1))
        (host-handler (cdr (assoc host fn/w3m-auto-bookmark-host-handlers))))
      (if host-handler
          (funcall host-handler url title)
        nil)))


  (progn
    (require 's)
    (add-to-list 'fn/w3m-auto-bookmark-host-handlers
                 (cons "github.com"
                    (lambda (url title)
                      (cons "Github"
                         (cadr
                          (s-match "GitHub - \\(.*\\): .*"
                                   title)))))))

  (add-hook 'fn/w3m-auto-bookmark-handler-functions 'fn/w3m-auto-bookmark-host-handler)

  (defun fn/w3m-bookmarked-p (url)
    "Check if URL is already bookmarked."
    (with-current-buffer (find-file-noselect w3m-bookmark-file)
      (goto-char (point-min))
      (search-forward url nil t)))

  (defun fn/w3m-auto-bookmark-arrived-url ()
    "Check whether to auto bookmark a page."
    (when (w3m-arrived-get url 'title) ;; Check if url is not private
      (lexical-let* ((url w3m-current-url)
          (title w3m-current-title))
        (when (and (not (fn/w3m-bookmarked-p url))
                 (run-hook-with-args-until-success
                  'fn/w3m-auto-bookmark-check-functions
                  url title))
          (lexical-let ((pair (run-hook-with-args-until-success
                     'fn/w3m-auto-bookmark-handler-functions
                     url title)))
            (when (and pair (consp pair))
              (pcase-let ((`(,section . ,title) pair))
                (when (yes-or-no-p
                       (format "Bookmark %s on %s as %s? " url section title ))
                  (w3m-bookmark-write-file
                   url
                   (w3m-encode-specials-string title)
                   (w3m-encode-specials-string section))))))))))


  (add-hook 'w3m-fontify-after-hook #'fn/w3m-auto-bookmark-arrived-url))

twittering

Integrating with emacs is very fun via twittering

(use-package twittering-mode
  :ensure t
  :defer t
  :commands (twittering-mode)
  :init
  (setq twittering-auth-method 'oauth)
  (setq twittering-use-master-password t)
  :config
  (twittering-icon-mode t)
  (setq twittering-convert-fix-size 24))

erc

Connecting with the brothers

(use-package erc
  :ensure t
  :defer t
  :bind (:map fn-standard-prefix-map
              ("e q" . erc-quit-server)
              ("e e" . erc))
  :config
  (setq erc-try-new-nick-p t

     ;; Setup for server and such is in personal.el
     erc-prompt-for-password nil

     erc-rename-buffers t
     erc-interpret-mirc-color t

     erc-quit-reason (lambda (&rest args) "I took with me... their lightning and their prayers"))



  (fn/use-feature erc-message-alert
    (alert)
    (require 's)
    (defun fn/erc-notice-p (message)
      "Check if MESSAGE is a notice."
      (s-starts-with-p erc-notice-prefix message))

    (defun fn/erc-get-sender-name (message)
      "Get the sender from the MESSAGE."
      (let ((result (car (s-split-up-to " " message 1))))
        (if (string= result message)
            nil
          (substring-no-properties result 1 -1))))

    (defun fn/erc-get-message (message)
      "Get the message from the MESSAGE."
      (let ((result (cadr (s-split-up-to " " message 1))))
        (if (null result)
            nil
          result)))

    (defun fn/erc-message-alert (message)
      "Just a small unobtrusive notifcation"
      (ignore-errors ;; NOTE: I shall return
        (let ((raw-message (string-trim-right (substring-no-properties message))))
          (when (and (erc-network-name)
                   (erc-default-target)
                   (not (erc-is-message-ctcp-p raw-message))
                   (not (fn/erc-notice-p raw-message)))
            (let ((server (erc-network-name))
                (channel (substring-no-properties (erc-default-target) 1))
                (chatter (fn/erc-get-sender-name raw-message))
                (base-message (fn/erc-get-message raw-message)))
              (fn/alert-color (fn/chat-log server channel chatter base-message)
                              :color  "#3d57b1"
                              :category 'erc))))))

    (add-hook 'erc-insert-pre-hook #'fn/erc-message-alert))

  (fn/use-feature erc-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'erc-mode
     (list 'all-the-icons-faicon "exchange" :v-adjust 0.0))))

jabber

Listen to chat notifications

(use-package jabber
  :ensure t
  :bind (:map fn-standard-prefix-map
              ("J J" . jabber-connect-all)
              ("J c" . jabber-chat-with)
              ("J q" . jabber-disconnect))
  :config
  ;; account set at personal.el

  ;; core
  (setq jabber-auto-reconnect t
     jabber-version-show nil

     jabber-history-enabled t
     jabber-use-global-history nil
     jabber-history-dir (expand-file-name "jabber-history/" fn/cache-dir)

     jabber-backlog-number 40
     jabber-backlog-days 30)

  (defconst fn/jabber-roster-buffer-name "*-jabber-*"
    "My custom name for the jabber buffer")

  ;; chat
  (setq jabber-chat-buffer-format "*-jabber-%n-*")

  ;; history
  (setq jabber-history-enabled t
        jabber-history-dir (expand-file-name "jabber-history" fn/cache-dir))

  ;; mode
  (setq jabber-mode-line-mode t)

  ;; chat states
  (setq jabber-chatstates-confirm nil
     jabber-presence-hooks nil)

  ;; avatar
  (setq jabber-avatar-cache-directory (expand-file-name "jabber-avatar-cache" fn/cache-dir)
        jabber-vcard-avatars-publish nil
        jabber-vcard-avatars-retrieve nil)

  ;; libnotify
  (setq jabber-libnotify-method 'shell
     jabber-libnotify-urgency "high")

  ;; presence
  (setq jabber-alert-presence-message-function nil)


  ;; chat
  (setq jabber-chat-foreign-prompt-format "[%t] %n>"
     jabber-chat-local-prompt-format  "[%t] %n>"
     jabber-groupchat-prompt-format  "[%t] %n>"
     jabber-muc-private-foreign-prompt-format "[%t] %g/%n>")


  ;; alerts
  (setq jabber-alert-message-hooks nil)

  (fn/use-feature jabber-alert-custom
    (alert)
    (defconst fn/jabber-google
      (format "%s%s%s%s%s%s"
              (propertize "g" 'face '(:foreground "#4285f4"))
              (propertize "o" 'face '(:foreground "#ea4335"))
              (propertize "o" 'face '(:foreground "#fbbc05"))
              (propertize "g" 'face '(:foreground "#4285f4"))
              (propertize "l" 'face '(:foreground "#34a853"))
              (propertize "e" 'face '(:foreground "#ea4335")))
      "A nice candy colored google text")

    (defun fn/jabber-message-notify (from buffer text title)
      "Just a small unobtrusive notifcation"
      (let ((chatter (cdr (assoc from jabber-activity-name-alist))))
        (fn/alert-color
         (fn/chat-log fn/jabber-google user-mail-address chatter text)
         :color "#abb2e1"
         :category 'jabber)))

    (add-hook 'jabber-alert-message-hooks #'fn/jabber-message-notify))

  (fn/use-feature jabber-roster-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'jabber-roster-mode
     (list 'all-the-icons-octicon "radio-tower" :v-adjust -0.1)))

  (fn/use-feature jabber-chat-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'jabber-chat-mode
     (list 'all-the-icons-faicon "comments" :v-adjust -0.1)))


  ;; roster
  (setq jabber-roster-show-title nil
        jabber-roster-line-format "%c %-25n %u %-8s  %S"
        jabber-roster-buffer fn/jabber-roster-buffer-name)

  (defun fn/display-jabber-roster-buffer ()
    "Show jabber roster buffer"
    (interactive)
    (display-buffer-same-window (get-buffer fn/jabber-roster-buffer-name) nil)))

slack

Slack is awesome.

(defconst fn/slack-map (fn/make-prefixed-keymap (kbd "s") fn-standard-prefix-map)
  "My custom slack map.")

(use-package slack
  :ensure t
  :defer t
  :bind (:map fn/slack-map
              ("s" . slack-start))
  :config
  (setq slack-request-timeout 60)

  (setq slack-enable-emoji nil
        slack-buffer-emojify nil
        slack-typing-visibility 'never
        slack-prefer-current-team t
        slack-buffer-function #'switch-to-buffer)

  (progn
    ;; Thanks https://github.com/yuya373/emacs-slack/issues/175#issuecomment-300159618
    (defun fn/slack-unread-rooms ()
      "Get unread rooms from slack."
      (let ((team (slack-team-select)))
        (cl-loop for team in (list team)
                 append
                 (with-slots (groups ims channels) team
                   (cl-remove-if
                    #'(lambda (room)
                        (not (< 0 (oref room unread-count-display))))
                    (append ims groups channels))))))

    (defun fn/slack-goto-unread-room ()
      "Quickly visit an unread room in slack."
      (interactive)
      (let ((unread-rooms (fn/slack-unread-rooms)))
        (if (null unread-rooms)
            (error "No unread rooms in slack. Silence is good.")
          (slack-room-create-buffer
           (car unread-rooms)
           (slack-team-find (oref (car unread-rooms) team-id)))))))

  (progn ;; Force subscription
    (defun fn/slack-room-all-subcribedp (_ team)
      "Overrides `slack-room-subscribedp' to always return
      non-nil to force subscription."
      team)

    (advice-add 'slack-room-subscribedp :override #'fn/slack-room-all-subcribedp))

  (fn/use-feature slack-message-flyspell
    (flyspell slack)
    (add-hook 'slack-edit-message-mode-hook #'flyspell-mode))

  (fn/use-feature slack-custom-alert
    (alert)
    (defun fn/slack-message-custom-notifier (message room team)
      "My custom notication for slack given MESSAGE, ROOM and TEAM.
What I do is use the fringe to notify me instead of `libnotify'."
      (when (and (not (slack-message-minep message team))
                 (or (slack-im-p room)
                     (and (slack-group-p room) (slack-mpim-p room))
                     (slack-room-subscribedp room team)
                     (string-match (format "@%s" (plist-get (oref team self) :name))
                                   (or (slack-message-body message team) ""))))
        (let* ((team-name (oref team name))
               (room-name (slack-room-name room))
               (text (slack-message-to-alert message team))
               (user-name (slack-message-sender-name message team))
               (out (fn/chat-log team-name room-name user-name text)))
          (fn/alert-color out
                          :category (intern team-name)
                          :color "#3a417a"))))

    (setq slack-message-custom-notifier #'fn/slack-message-custom-notifier
          slack-message-custom-delete-notifier #'fn/slack-message-custom-notifier))

  (fn/use-feature slack-mode--mode-icon
    (all-the-icons)
    (fn/add-major-mode-icon
     'slack-mode
     (list 'all-the-icons-faicon "commenting-o" :v-adjust 0.0))
    (fn/add-major-mode-icon
     'slack-edit-message-mode
     (list 'all-the-icons-faicon "pencil" :v-adjust 0.0)))

  (progn
    (define-key fn/slack-map (kbd "q") #'slack-ws-close)

    (define-key fn/slack-map (kbd "t") #'slack-change-current-team)

    (define-key fn/slack-map (kbd "b k") #'slack-buffer-kill)
    (define-key fn/slack-map (kbd "b r") #'slack-select-rooms)
    (define-key fn/slack-map (kbd "b c") #'slack-channel-select)
    (define-key fn/slack-map (kbd "b i") #'slack-im-select)
    (define-key fn/slack-map (kbd "b g") #'slack-group-select)
    (define-key fn/slack-map (kbd "b t") #'slack-group-select)

    (define-key fn/slack-map (kbd "u b") #'slack-select-unread-rooms)
    (define-key fn/slack-map (kbd "u u") #'fn/slack-goto-unread-room))

  (progn
    (define-key slack-mode-map (kbd "C-c r r") #'slack-message-remove-reaction)
    (define-key slack-mode-map (kbd "C-c r s") #'slack-message-show-reaction-users)
    (define-key slack-mode-map (kbd "C-c r a") #'slack-message-add-reaction)

    (define-key slack-mode-map (kbd "C-c C-m") #'slack-message-write-another-buffer)

    (define-key slack-mode-map (kbd "C-c m e") #'slack-message-edit)

    (define-key slack-mode-map (kbd "C-c m u") #'slack-room-update-messages))

  (progn
    (define-key slack-edit-message-mode-map (kbd "C-c e m") #'slack-message-embed-mention)
    (define-key slack-edit-message-mode-map (kbd "C-c e c") #'slack-message-embed-channel)))

sx

Stack Exchange api

(use-package sx
  :bind (:map fn-standard-prefix-map
              ("S q" . sx-tab-all-questions)
              ("S i" . sx-inbox)
              ("S o" . sx-open-link)
              ("S u" . sx-tab-unanswered-my-tags)
              ("S a" . sx-ask)
              ("S s" . sx-search))
  :config
  (setq sx-cache-directory (expand-file-name ".sx" fn/cache-dir)))

bbdb

People organization

(use-package bbdb
  :ensure t
  :defer t
  :config
  (bbdb-initialize)
  (add-hook 'gnus-startup-hook 'bbdb-insinuate-gnus))

emms

This controls the music player.

(defconst fn/emms-map (fn/make-prefixed-keymap (kbd "C-p") fn-standard-prefix-map)
  "My custom prodigy map.")

(fn/use-executables emms-player-check
  (vlc mpd)
  (use-package emms
    :ensure t
    :defer t
    :init
    (setq emms-directory (expand-file-name "emms" fn/cache-dir))
    :bind (:map fn/emms-map
                ("C-p" . emms)
                ("p n" . emms-next)
                ("p p" . emms-previous)
                ("p q" . emms-pause)
                ("p s" . emms-start)
                ("p S" . emms-stop))
    :config
    (emms-minimalistic)
    (emms-standard)

    (when (require 'emms-player-simple))

    (setq emms-player-list nil)

    (setq emms-source-file-default-directory (expand-file-name "~/Musicbox/"))

    (setq emms-info-asynchronously nil
          emms-playlist-buffer-name "*Music*")

    (setq emms-playlist-default-major-mode 'emms-playlist-mode)

    (when (require 'emms-mark)
      (add-hook 'emms-playlist-mode-hook #'emms-mark-mode))

    (when (require 'emms-history)
      (emms-history-load))

    (when (require 'emms-browser))

    (when (require 'emms-volume)
      (emms-volume-minor-mode t)

      (setq emms-volume-mode-timeout 1))

    (fn/use-executables emms-mp3info
      (mp3info)
      (add-to-list 'emms-info-functions 'emms-info-mp3info))

    (fn/use-executables emms-ogginfo
      (ogginfo)
      (add-to-list 'emms-info-functions 'emms-info-ogginfo))

    (fn/add-major-mode-icon
     'emms-playlist-mode
     (list 'all-the-icons-faicon "music" :v-adjust -0.1))

    (progn
      (global-set-key (kbd "C-c -") 'emms-volume-mode-plus)
      (global-set-key (kbd "C-c +") 'emms-volume-mode-minus)

      (global-set-key (kbd "C-c n C-e s") 'emms-start)
      (global-set-key (kbd "C-c n C-e S") 'emms-stop))))

MPD Integration

I prefer mpd as a music player as it is more stable.

(fn/use-executables mpd-check
  (mpd)
  (fn/use-feature emms-mpd
    (emms)
    (require 'emms-player-mpd)

    (setq emms-player-mpd-supported-regexp
          (regexp-opt '(".ogg" ".mp3" ".wav" ".mpg" ".mpeg" ".wmv" ".wma"
                        ".mov" ".avi" ".divx" ".ogm" ".asf" ".mkv" "http://" "mms://"
                        ".rm" ".rmvb" ".mp4" ".flac" ".vob" ".m4a" ".flv" ".ogv" ".pls")))

    (add-to-list 'emms-info-functions 'emms-info-mpd)
    (add-to-list 'emms-player-list 'emms-player-mpd))

  (fn/use-feature prodigy-emms-mpd
    (prodigy emms)
    (defcustom fn/emms-mpd-cache-dir (expand-file-name "emms-mpd" fn/cache-dir)
      "Emms cache directory."
      :type 'directory)

    (defcustom fn/emms-mpd-config-file (expand-file-name "mpd.conf" fn/emms-mpd-cache-dir)
      "Mpd config file"
      :type 'file)

    (defcustom fn/emms-mpd-port 38700
      "Mpd port config file"
      :type 'number)

    (defun fn/emms-mpd-update-conf (&rest args)
      "Create/update `fn/emms-mpd-config-file' with new
configurations."
      (interactive)
      (make-directory fn/emms-mpd-cache-dir t)

      (setq emms-player-mpd-server-port nil
            emms-player-mpd-server-name (expand-file-name "socket" fn/emms-mpd-cache-dir))

      (fn/prodigy-create-mpd-conf
       fn/emms-mpd-config-file
       `(("music_directory" . ,(expand-file-name emms-source-file-default-directory))
         ("playlist_directory" . ,(expand-file-name "Playlist"))
         ("connection_timeout" . 30)
         ("state_file" . ,(expand-file-name "state" fn/emms-mpd-cache-dir))
         ("pid_file" . ,(expand-file-name "pid" fn/emms-mpd-cache-dir))
         ("sticker_file" . ,(expand-file-name "sticker.sql" fn/emms-mpd-cache-dir))
         ("port" . ,fn/emms-mpd-port)
         ("bind_to_address" . ,emms-player-mpd-server-name)
         ("audio_output" . (("type" . "pulse")
                            ("name" . "My PULSE Device")))
         ("database" . (("plugin" . "simple")
                        ("path" . ,(expand-file-name "db" fn/emms-mpd-cache-dir)))))))

    (defun fn/emms-mpd-on-start (&rest args)
      "On start of mpd server.."
      (setq emms-volume-change-function 'emms-volume-mpd-change)
      (emms-player-mpd-connect)
      (emms-cache-set-from-mpd-all))

    (defun fn/emms-mpd-on-stop (&rest args)
      "On stop of mpd server."
      (setq emms-volume-change-function 'emms-volume-mpd-change)
      (emms-player-mpd-disconnect))

    (defconst fn/emms-mpd-service-name "emms-mpd"
      "Emms mpd prodigy service name.")

    (fn/prodigy-define-service
     :name fn/emms-mpd-service-name
     :tags '(mpd emms)
     :init #'fn/emms-mpd-update-conf
     :on-start #'fn/emms-mpd-on-stop
     :on-stop #'emms-player-mpd-disconnect
     :args `("--no-daemon"
             "--stderr"
             "--verbose"
             ,fn/emms-mpd-config-file)

     :bind-name "emms-mpd"
     :bind-map fn/prodigy-map
     :bind (kbd "m m"))

    (prodigy-start-service (prodigy-find-service fn/emms-mpd-service-name))))

Scripts

Clean Home

Make sure my Emacs home is clean

(require 'f)

(defconst fn/user-emacs-home-files
  (list
   "bootstrap"
   "bootstrapper.el"
   ".cache"
   ".setting"
   "config.el"
   "config.org"
   "extra"
   "system"
   ".git"
   ".gitignore"
   "init.el"
   "init-standard.el"
   "LICENSE"
   "lib"
   "personal.el"
   ".projectile"
   ".project-locals.el"
   "README.org")
  "Known Emacs home files")


(defun fn/clean-user-emacs-home ()
  "Make sure Emacs only has the following files as specified by `fn/user-emacs-home-files'"
  (interactive)
  (message "Cleaning emacs home.")
  (mapc
   (lambda (home-file)
     (unless (member home-file fn/user-emacs-home-files )
       (message "Deleting trash file %s" home-file)
       (f-delete (expand-file-name home-file user-emacs-directory) t)))
   (mapcar ;; You can use `directory-files' but you have to filter `.' and `..'
    'f-filename
    (append
     (f-files user-emacs-directory)
     (f-directories user-emacs-directory))))
  (message "All clean."))

(add-hook 'after-init-hook 'fn/clean-user-emacs-home)

Custom Emacs

Bootstrap different configurations of Emacs for reviewing expert configurations and trying different modes

Configurable

Let’s bootstrap from different configurations dynamically

(defun fn/bootstrap-from-dir ()
  (interactive)
  (setq new-home (read-directory-name "What Emacs config would you like to boot?" "~"))
  (fn/bootstrap-new-emacs new-home))


(defvar fn/previous-bootstrap-dir nil)

(defun fn/store-bootstrap-dir (new-home)
  "Store previously bootstrap directory"
  (setq fn/previous-bootstrap-dir new-home))

(advice-add 'fn/bootstrap-new-emacs :after 'fn/store-bootstrap-dir)


(defun fn/bootstrap-previous ()
  "Bootstrap the previously chosen one, `fn/previous-bootstrap-dir'"
  (interactive)
  (fn/bootstrap-new-emacs fn/previous-bootstrap-dir))

Itself

Load another copy of this configuration for vanity sake I suppose?

(defun fn/bootstrap-itself ()
  (interactive)
  (fn/bootstrap-new-emacs nil))

Experimental

Just a random build for myself

(setq fn/experimental-home "~/.fmacs.d/")

(defun fn/bootstrap-experimental ()
  (interactive)
  (fn/bootstrap-new-emacs fn/experimental-home))

Spacemacs

The love child of Emacs and Vim, what does it hold?

(setq fn/spacemacs-home "~/Modules/.spacemacs.d/")

(defun fn/bootstrap-spacemacs ()
  (interactive)
  (fn/bootstrap-new-emacs fn/spacemacs-home))

Quick Config Tangler

I don’t need to tangle the whole file. Maybe just one block if I can.

(require 'f)

(random t)

(defun fn/random-uuid ()
  ;; Thanks to http://ergoemacs.org/emacs/elisp_generate_uuid.html
  "Generate a random UUID.
Example of a UUID: 1df63142-a513-c850-31a3-535fc3520c3d

WARNING: this is a simple implementation. The chance of generating the same UUID is much higher than a robust algorithm."
  (interactive)
  (format "%04x%04x-%04x-%04x-%04x-%06x%06x"
          (random (expt 16 4))
          (random (expt 16 4))
          (random (expt 16 4))
          (random (expt 16 4))
          (random (expt 16 4))
          (random (expt 16 6))
          (random (expt 16 6))))


(defconst fn/tangled-config-file (f-swap-ext fn/config-file "el")
  "The tangled config file.")


(defun fn/get-code-block-id ()
  "Get code block id at point."
  (interactive)
  (cdr (assoc fn/code-block-id-symbol (nth 2 (org-babel-get-src-block-info)))))

(defun fn/get-code-block-previous-id ()
  "Get previous code block id at point."
  (interactive)
  (condition-case ex
      (save-excursion
        (org-babel-goto-src-block-head)
        (org-babel-previous-src-block)
        (fn/get-code-block-id))
    ('error nil)))

(defun fn/get-code-block-next-id ()
  "Get next code block id at point."
  (interactive)
  (condition-case ex
      (save-excursion
        (org-babel-goto-src-block-head)
        (org-babel-next-src-block)
        (fn/get-code-block-id))
    ('error nil)))

(defun fn/get-code-block-code ()
  "Get src code at point."
  (interactive)
  (nth 1 (org-babel-get-src-block-info)))

(defun fn/generate-code-block-id ()
  "Generate code block id for block."
  (interactive)
  (if (fn/get-code-block-id)
      nil
    (save-excursion
      (org-babel-goto-src-block-head)
      (end-of-line)
      (insert " ")
      (let ((id (symbol-name fn/code-block-id-symbol)))
        (insert
         (format "%s %s"
                 id
                 (fn/random-uuid)))
        id))))

(defun fn/generate-code-block-ids (&optional buffer)
  "Generate block ids for current BUFFER."
  (interactive)
  (save-excursion
    (beginning-of-line)
    (condition-case ex
        (while t
          (org-babel-next-src-block)
          (fn/generate-code-block-id))
      ('error nil))))

(defun fn/find-code-block (&optional block-id)
  "Find code block with equivalent BLOCK-ID."
  (interactive)
  (let ((id (or block-id
             (fn/get-code-block-id))))
    (unless id
      (error "No code block id."))

    (let ((block-start (format fn/code-block-start-format id)))
      (condition-case ex
          (with-current-buffer (find-file fn/tangled-config-file)
            (goto-char (point-min))
            (search-forward block-start)
            (beginning-of-line)
            (switch-to-buffer (current-buffer)))
        ('error (message "Cannot find block id: %s" (error-message-string ex)))))))

(defun fn/update-code-block (&optional block-id)
  "Update or add code block with equivalent BLOCK-ID."
  (interactive)
  (let ((id (or block-id
             (fn/get-code-block-id)))
      (code (fn/get-code-block-code)))
    (let ((block-start (format fn/code-block-start-format id))
        (block-end (format fn/code-block-end-format id))
        (tangle-buffer (find-file-noselect fn/tangled-config-file)))
      (cond
       ((condition-case ex
            (with-current-buffer tangle-buffer
              (beginning-of-buffer)
              (search-forward block-start)
              (beginning-of-line)
              (forward-line)

              (command-execute #'set-mark-command)
              (search-forward block-end)
              (beginning-of-line)
              (kill-region (region-beginning) (region-end))
              (open-line 1)
              (command-execute #'set-mark-command)

              (insert code)
              (insert "\n")
              (save-buffer)
              t)
          ('error nil))
        'update)
       ((condition-case ex
            (let* ((previous-id (fn/get-code-block-previous-id))
                (previous-block-end (format fn/code-block-end-format previous-id)))
              (with-current-buffer tangle-buffer
                (beginning-of-buffer)
                (search-forward previous-block-end)
                (beginning-of-line)
                (next-line)
                (insert "\n")
                (insert block-start)
                (insert "\n")
                (insert code)
                (insert "\n")
                (insert block-end)
                (insert "\n")
                (insert "\n")
                (save-buffer)
                t))
          ('error nil))
        'add)
       ((condition-case ex
            (let* ((next-id (fn/get-code-block-next-id))
                   (next-block-start (format fn/code-block-start-format next-id)))
              (with-current-buffer tangle-buffer
                (beginning-of-buffer)
                (search-forward next-block-start)
                (beginning-of-line)
                (previous-line)
                (insert "\n")
                (insert block-start)
                (insert "\n")
                (insert code)
                (insert "\n")
                (insert block-end)
                (insert "\n")
                (insert "\n")
                (save-buffer)
                t))
          ('error nil))
        'add)
       (t
        (error "Trouble of updating code block"))))))

(defun fn/check-duplicate-code-block-id ()
  "Check current buffer for duplicate ids."
  (interactive)
  (let ((id-table (make-hash-table))
      (same-ids (list))
      (current-id))
    (save-excursion
      (beginning-of-buffer)
      (condition-case ex
          (while t
            (org-babel-next-src-block)
            (setq current-id (fn/get-code-block-id))
            (if (gethash current-id id-table nil)
                (push current-id same-ids)
              (puthash current-id t id-table)))
        ('error nil)))
    same-ids))

(defcustom fn/org-edit-src-exit-hook nil
  "Hook when running edit exit."
  :type 'hook
  :group 'fn)

(defun fn/org-edit-src-exit-hook-run (&rest args)
  "Run `fn/org-edit-src-exit-hook'."
  (run-hooks 'fn/org-edit-src-exit-hook))

(advice-add 'org-edit-src-exit :after #'fn/org-edit-src-exit-hook-run)

Window Layouts

Split the windows into a nice four panel division. This works even well with golden-ratio.

(require 'dash)

(defconst fmw/empty-buffer "*unchained buffer*"
  "A buffer to represent an empty one")

(defun fmw/remap-window-buffers (buffer-remapper)
  "Reassigns the windows with new buffers taking a remapper function over the old ones"
  (lexical-let* ((current-buffers (mapcar 'window-buffer (window-list)))
                 (empty-buffer (if (get-buffer fmw/empty-buffer)
                                   (get-buffer fmw/empty-buffer)
                                 (generate-new-buffer fmw/empty-buffer)))
                 (new-buffers (funcall buffer-remapper current-buffers)))
    (mapc (lambda (pair)
            (pcase-let ((`(,current-buffer . ,current-window) pair))
              (when current-window
                (set-window-buffer current-window
                                   (if current-buffer current-buffer
                                     empty-buffer))))
            )
          (-zip-fill nil new-buffers (window-list)))))

(defun fmw/restore-buffers (window-movement)
  "Restore buffers after doing a window layout"
  (lexical-let ((mover window-movement))
    (fmw/remap-window-buffers (lambda (old-buffers)
                                (funcall window-movement)
                                old-buffers))))

(defun fmw/rotate-window-buffers (arg)
  "Rotate the buffers from window to the next like a clock"
  (interactive "P")
  (lexical-let ((rotation (if arg arg 1)))
    (fmw/remap-window-buffers (lambda (old-buffers)
                                (-rotate rotation old-buffers)))))

(defun fmw/four-part-horizontal-window-layout ()
  "Split the frame into four windows horizontally. I use this when I'm working in a project where the
   - upper left serves the main file
   - upper right serves as a secondary file
   - lower left serves as auxilliary or task buffer
   - lower right serves a project buffer"
  (interactive)
  (fmw/restore-buffers (lambda ()
                         (setq golden-ratio-mode t)
                         (delete-other-windows)
                         (split-window-vertically)
                         (split-window-horizontally)
                         (other-window 2)
                         (split-window-horizontally)
                         (other-window 2))))

(defun fmw/four-part-vertical-window-layout ()
  "Unlike with the =fn/four-way-horizontal-layout=, I use this more oftenly on dired to make file moving easier
   (and probably more)"
  (interactive)
  (fmw/restore-buffers (lambda ()
                         (setq golden-ratio-mode t)
                         (delete-other-windows)
                         (split-window-vertically)
                         (split-window-horizontally)
                         (other-window 2)
                         (split-window-horizontally)
                         (other-window 2))))

(defun fmw/three-part-left-window-layout ()
  "Like =fn/four-way-horizontal-layout= but fits a smaller screen namely my Raspberry Pi."
  (interactive)
  (fmw/restore-buffers (lambda ()
                         (setq golden-ratio-mode t)
                         (delete-other-windows)
                         (split-window-horizontally)
                         (other-window 1)
                         (split-window-vertically)
                         (other-window 2))))

(defun fmw/three-part-vertical-window-layout ()
  "An layout seen at a meetup, seems interesting to work with.
   However, this is disables golden-ration-mode to maintain the delicate origami folds"
  (interactive)
  (fmw/restore-buffers (lambda ()
                         (setq golden-ratio-mode nil)
                         (delete-other-windows)
                         (lexical-let* ((total-width (frame-width))
                                        (one-third-fold  (/ total-width 3)))
                           ;; Split the right window by a third, negative arguments huh.
                           (split-window-horizontally (- one-third-fold))
                           (split-window-horizontally (- one-third-fold))))))

(defun fmw/four-part-equal-vertical-window-layout ()
  "This is for my music conversion but not that mind blowing to do"
  (interactive)
  (fmw/restore-buffers (lambda ()
                         (setq golden-ratio-mode nil)
                         (delete-other-windows)

                         (split-window-horizontally)
                         (split-window-horizontally)
                         (other-window 2)

                         (split-window-horizontally)
                         (other-window 2))))

Utility Commands

Some commands to get me here and there

(defun fn/insert-date ()
  "Insert time at point, useful when you want to put a date.
   TODO: Would be useful if you can change formats too"
  (interactive)
  (let ((time-format "%Y-%m-%d"))
    (insert (format-time-string time-format))))

(defun fn/save-and-kill-buffer ()
  "Save and kill the buffer in one command"
  (interactive)
  (call-interactively 'save-buffer)
  (call-interactively 'kill-this-buffer))


(defun fn/dired-parent ()
  "Quick command to go to parent dired of buffer immediately"
  (interactive)
  (dired ".."))

Sensitive Mode

When editiing gpg or sensitve files, I would like to avoid backing it up so here is a minor mode to do so.

(define-minor-mode fq/sensitive-mode
  "For sensitive files like password lists.
It disables backup creation and auto saving.

With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode."
  ;; The initial value.
  nil
  ;; The indicator for the mode line.
  " Sensitive"
  ;; The minor mode bindings.
  nil
  (if (symbol-value fq/sensitive-mode)
      (progn
        ;; disable backups
        (set (make-local-variable 'backup-inhibited) t)
        ;; disable auto-save
        (if auto-save-default
            (auto-save-mode -1)))
                                        ;resort to default value of backup-inhibited
    (kill-local-variable 'backup-inhibited)
                                        ;resort to default auto save setting
    (if auto-save-default
        (auto-save-mode 1))))

(add-to-list 'auto-mode-alist '("\\.gpg\\'" . fq/sensitive-mode))

Dired Shortcuts

Some shortcuts with the common folder

(defun fn/dired-download-dir ()
  "Just a quick shortcut to my directory folder"
  (interactive)
  (dired "~/Downloads"))

(defun fn/dired-mountain-dir ()
  "Just a quick shortcut to my mounting folder"
  (interactive)
  (dired "~/Mountain"))

(defun fn/dired-fakespace-dir ()
  "Just a quick shortcut to my temp workspace folder"
  (interactive)
  (dired "~/Fakespace"))

(defun fn/dired-home-dir ()
  "Quickly visit home directory"
  (interactive)
  (dired "~"))

(defun fn/dired-lib-dir ()
  "Quickly visit library directory"
  (interactive)
  (dired fn/lib-dir))

(defun fn/dired-module-dir ()
  "Quickly visit modules library"
  (interactive)
  (dired "~/Modules"))

Performance Indicator

Check if Emacs is running fast.

(run-at-time nil 60 #'force-mode-line-update)

(fn/use-feature frame-delay
  nil
  (require 'deferred)

  (defvar fn/-previous-time (current-time)
    "Previous time recording.  Not to be used directly.")

  (defvar fn/current-frame-delay 0.0
    "Fps recording.")

  (defun fn/record-frame-delay ()
    "Record frame delay."
    (prog1
        (let* ((now (current-time))
               (time-diff
                (float-time (time-subtract now fn/-previous-time))))
          (setq fn/current-frame-delay time-diff)
          (force-mode-line-update))
      (fn/-mark-time)))

  (defun fn/-mark-time ()
    "Mark the previous time for use"
    (setq fn/-previous-time (current-time)))

  (run-with-idle-timer 0 t #'fn/record-frame-delay)

  (add-hook 'pre-command-hook #'fn/-mark-time))

(unless (eq system-type 'windows-nt) ;; Windows requires powershell just to poll it. WTF!?
  (require 'deferred)

  (fn/use-executables cpu-check
    (grep awk)
    (fn/use-feature cpu-usage
      (deferred)
      (defvar fn/current-cpu-usage 0.0
        "Cpu recording.")

      (defconst fn/cpu-usage-command "grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage}'")

      (defun fn/record-cpu-usage ()
        "Record cpu usage."
        (deferred:error
          (deferred:nextc
            (deferred:process-shell
              fn/cpu-usage-command)
            (lambda (value)
              (setq fn/current-cpu-usage (string-to-number value))))
          (lambda ()
            (setq fn/cpu-timer
               (cancel-timer fn/cpu-timer))

            (makunbound 'fn/current-cpu-usage)
            (message "Error with CPU monitor, shutting it down"))))

      (defvar fn/cpu-timer nil
        "A cpu timer if you ever want to quit it.")

      (defun fn/start-cpu-monitor ()
        "Start cpu monitor"
        (interactive)

        (when (timerp fn/cpu-timer)
          (cancel-timer fn/cpu-timer))

        (setq fn/cpu-timer
           (run-with-idle-timer 1 t #'fn/record-cpu-usage)))

      (fn/start-cpu-monitor)))

  (fn/use-executables memory-check
    (free grep awk)
    (fn/use-feature memory-usage
      (deferred)
      (defvar fn/current-memory-usage 0.0
        "Memory recording.")

      (defconst fn/memory-usage-command
        "free | grep Mem | awk '{print $3/$2 * 100.0}'")

      (defun fn/record-memory-usage ()
        "Record memory usage."
        (deferred:error
          (deferred:nextc
            (deferred:process-shell
              fn/memory-usage-command)
            (lambda (value)
              (setq fn/current-memory-usage (string-to-number value))))
          (lambda ()
            (setq fn/memory-timer
               (cancel-timer fn/memory-timer))

            (makunbound 'fn/current-memory-usage)
            (message "Error with RAM monitor, shutting it down"))))

      (defvar fn/memory-timer nil
        "A memory timer.")

      (defun fn/start-memory-monitor ()
        "Start memory monitor."
        (interactive)
        (when (timerp fn/memory-timer)
          (cancel-timer fn/memory-timer))

        (setq fn/memory-timer
           (run-with-idle-timer 1 t #'fn/record-memory-usage)))

      (fn/start-memory-monitor)))

  (fn/use-executables battery-check
    (acpi awk)
    (fn/use-feature battery-usage
      (deferred)
      (defvar fn/current-battery-usage 0.0
        "Battery usage.")

      (defconst fn/battery-usage-command "acpi -b | awk -F , '{print substr( $2, 1 , length($2) - 1) / 100}'"
        "Battery usage command.")

      (defun fn/record-battery-usage ()
        "Record battery usage."
        (deferred:error
          (deferred:nextc
            (deferred:process-shell
              fn/battery-usage-command)
            (lambda (value)
              (setq fn/current-battery-usage (string-to-number value))))
          (lambda ()
            (setq fn/battery-timer
               (cancel-timer fn/battery-timer))

            (makunbound 'fn/current-battery-usage)
            (message "Error with Battery monitor, shutting it down"))))

      (defvar fn/battery-timer nil
        "A battery timer.")

      (defun fn/start-battery-monitor ()
        "Start the battery monitor."
        (interactive)
        (when (timerp fn/battery-timer)
          (cancel-timer fn/battery-timer))

        (setq fn/battery-timer
           (run-with-idle-timer 1 t #'fn/record-battery-usage)))

      (fn/start-battery-monitor))))

Create media diary

A personal script to bundle my journal, recordings and images into one org file. Not to be consumed by anyone else

(require 's)


(defun fmd/get-document-property (key &optional selected-buffer)
  "Get the property of the document which starts with #+PROPERTY"
  (with-current-buffer (if selected-buffer selected-buffer (buffer-name))
    (lexical-let* ((property-regex (format "\#\\+%s:\s+\\(.*\\)" key))
                   (property-match (s-match property-regex (buffer-substring-no-properties (point-min) (point-max))))
                   (property (if property-match (cadr property-match)
                               nil)))
      property)))

(defun fmd/get-document-block-property (key &optional selected-buffer)
  "Like with fmd/get-document-property but finds a block summary #+BEGIN_key #+END_key"
  (with-current-buffer (if selected-buffer selected-buffer (buffer-name))
    (lexical-let* ((property-regex (format "#\\+BEGIN_%s\n\\([\0-\377[:nonascii:]]*\\)\n#\\+END_%s" key key))
                   (property-match (s-match property-regex (buffer-substring-no-properties (point-min) (point-max))))
                   (property (if property-match (s-trim (cadr property-match))
                               nil)))
      property)))


(defun fmd/get-title (&optional selected-buffer)
  "Get the #+TITLE value of the current buffer"
  (fmd/get-document-property "TITLE" selected-buffer))

(defun fmd/get-summary (&optional selected-buffer)
  "Get the #+BEGIN_SUMMARY section of the buffer"
  (fmd/get-document-block-property "SUMMARY" selected-buffer))


(defconst fmd/md-root "~/Mountain/diary/media-diary/compile/"
  "The media diary directory")

(defconst fmd/md-compile-date-filter (expand-file-name ".date" fmd/md-root)
  "The media diary directory")


(defconst fmd/md-summary-file-name "media-diary.org"
  "The media diary directory")

(defconst fmd/md-summary-file (expand-file-name  "media-diary.org" fmd/md-root)
  "The media diary directory")

(defconst fmd/md-title "Media Diary"
  "Main header of the file")

(defconst fmd/md-note-title "Notes"
  "Note header of the file")

(defconst fmd/md-journal-title "Journal"
  "Journal header of the file")

(defconst fmd/md-media-title "Media"
  "Journal header of the file")


(defconst fmd/md-datetime-format "%b. %d, %Y"
  "Time format for the compilation")

(defconst fmd/md-audio-datetime-format "%b. %d, %Y %T : Recording"
  "Audio time format for the compilation")

(defconst fmd/md-photo-datetime-format "%b. %d, %Y %T : Photograph"
  "Photo format for the compilation")

(defconst fmd/md-summary-default-text "Something profound happened but I forgot like Dory"
  "The default text to be displayed")

(defconst fmd/md-journal-summary-default-text "Looks like I forgot to write something this day"
  "The default text to be displayed")


(defconst fmd/md-journal-dir-name "journal"
  "The journal directory source")

(defconst fmd/md-audio-dir-name "audio"
  "The audio directory source")

(defconst fmd/md-photo-dir-name "photo"
  "The photo directory source")


(defconst fmd/md-photo-extension "jpg"
  "The photo file extension")

(defconst fmd/md-audio-extension "mp3"
  "The audio file extension")


(defconst fmd/md-journal-dir (expand-file-name fmd/md-journal-dir-name fmd/md-root)
  "The journal directory")

(defconst fmd/md-audio-dir (expand-file-name fmd/md-audio-dir-name fmd/md-root)
  "The audio directory")

(defconst fmd/md-photo-dir (expand-file-name fmd/md-photo-dir-name fmd/md-root)
  "The audio directory")

(defun fmd/parse-file-parts (file)
  "Parse the file name compatible for the media diary file"
  (lexical-let* ((file-regex  "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)?_?\\([0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{2\\}+\\)?\\( - \\)?\\(.+\\)?\\.\\(.+\\)")
                 (filename (file-name-nondirectory file))
                 (file-matches (s-match-strings-all file-regex filename))
                 (file-match (car file-matches)))
    (message filename)
    (lexical-let* ((file-date (nth 1 file-match))
                   (file-time (nth 2 file-match))
                   (file-title (nth 4 file-match))
                   (file-extension (nth 5 file-match)))
      (lexical-let* ((parts (list))
                     (time-part (if file-time (s-replace "-" ":" file-time)
                                  "00:00:00"
                                  ))
                     (date-raw (concat file-date " " time-part))
                     (datetime-part (apply 'encode-time (parse-time-string date-raw))))
        (setq parts (plist-put parts 'datetime datetime-part))
        (setq parts (plist-put parts 'title file-title))
        (setq parts (plist-put parts 'extension file-extension))
        parts))))


(defun fmd/insert-org-header (header)
  "Insert header"
  (org-insert-heading t nil t)
  (insert header))

(defun fmd/insert-org-subheader (subheader)
  "Insert subheader"
  (end-of-buffer)
  (org-insert-heading t nil t)
  (insert subheader)
  (org-demote))

(defun fmd/insert-org-link (link title)
  "Insert link"
  (end-of-buffer)
  (org-insert-heading t)
  (org-insert-link nil link title))

(defun fmd/insert-document-option (key value)
  "Insert document file option"
  (insert (format "#+%s: %s\n" key value)))

(defun fmd/insert-file-headers (start-date)
  "Insert default file headers"
  (interactive)
  (fm/insert-org-gpg-headers)

  (end-of-visual-line)
  (newline)

  (fmd/insert-document-option "TITLE" (format "Media Diary of %s"
                                              (format-time-string "%b. %Y" start-date)))
  (fmd/insert-document-option "DATE" (format-time-string "%Y-%m" start-date))
  (fmd/insert-document-option "STARTUP" "content")
  (fmd/insert-document-option "OPTIONS" "toc:nil"))


(defun fmd/filter-files (directory prefix extension)
  "Get the files based on prefix and extension"
  (directory-files directory nil
                   (format-message "%s-.*\\.%s$" prefix extension)))

(defun fmd/once (f)
  "Invoke a function only once, useful inside a loop"
  (lexical-let ((g f)
                (is-invoked nil))
    (lambda (&rest args)
      (if is-invoked nil
        (progn
          (setq is-invoked t)
          (apply g args))))))


(defun fmd/compile-media-diary ()
  "Compile the media diary, the diary must be compiled first with the shell script"
  (interactive)
  (lexical-let* ((md-prefix (s-trim (shell-command-to-string
                                     (format "cat %s" fmd/md-compile-date-filter))))
                 (md-start-date
                  (lexical-let ((start-date-text (format "%s-01 00:00:00" md-prefix)))
                    (apply 'encode-time (parse-time-string start-date-text)))))
    (lexical-let* ((render-header
                    (lambda ()
                      (fmd/insert-file-headers md-start-date)
                      (fmd/insert-org-header fmd/md-title)))
                   (render-note-section
                    (lambda ()
                      (fmd/insert-org-subheader fmd/md-note-title)
                      (newline-and-indent)
                      (insert fmd/md-summary-default-text)))
                   (render-journal-section
                    (lambda ()
                      (fmd/insert-org-subheader fmd/md-journal-title)
                      (lexical-let* ((journal-files (fmd/filter-files fmd/md-journal-dir md-prefix "org"))
                                     (demote-first (fmd/once (lambda () (org-demote)))))
                        (mapc (lambda (journal-file-name)
                                (lexical-let* ((journal-file (expand-file-name journal-file-name fmd/md-journal-dir))
                                               (journal-piece (fmd/parse-file-parts journal-file-name))
                                               (journal-time (plist-get journal-piece 'datetime))
                                               (journal-base-title (format-time-string fmd/md-datetime-format journal-time))
                                               (journal-title
                                                (lexical-let ((journal-buffer (find-file-noselect journal-file)))
                                                  (prog1
                                                      (fmd/get-title journal-buffer)
                                                    (kill-buffer journal-buffer))))
                                               (journal-summary
                                                (lexical-let ((journal-buffer (find-file-noselect journal-file)))
                                                  (prog1
                                                      (fmd/get-summary journal-buffer)
                                                    (kill-buffer journal-buffer))))
                                               (journal-full-title
                                                (format "%s - %s" journal-base-title journal-title)))
                                  (fmd/insert-org-link (concat "file:" fmd/md-journal-dir-name "/" journal-file-name)
                                                       journal-full-title)
                                  (funcall demote-first)

                                  (newline-and-indent)
                                  (insert (or journal-summary fmd/md-journal-summary-default-text))

                                  (org-set-property "CREATED_ON"
                                                    (format-time-string "%F %T" journal-time))))
                              journal-files))))
                   (render-media-section
                    (lambda ()
                      (fmd/insert-org-subheader fmd/md-media-title)

                      (lexical-let* ((photo-files (fmd/filter-files fmd/md-photo-dir md-prefix fmd/md-photo-extension))
                                     (audio-files (fmd/filter-files fmd/md-audio-dir md-prefix fmd/md-audio-extension))
                                     (media-files
                                      (sort (append photo-files audio-files)
                                            (lambda (left right)
                                              (lexical-let* ((result
                                                              (compare-strings
                                                               (file-name-sans-extension left) nil nil
                                                               (file-name-sans-extension right) nil nil
                                                               nil)))
                                                (if (booleanp result) t
                                                  (if (> result 0) nil t))))))
                                     (demote-first (fmd/once (lambda () (org-demote)))))

                        (intern-soft "photo")
                        (intern-soft "audio")

                        (mapc (lambda (media-file)
                                (lexical-let* ((media-piece (fmd/parse-file-parts media-file) )
                                               (media-time (plist-get media-piece 'datetime))
                                               (media-title (plist-get media-piece 'title))
                                               (media-extension (plist-get media-piece 'extension))
                                               (media-type (if (string-equal media-extension fmd/md-audio-extension)
                                                               'audio 'photo))
                                               (media-time-format (if (eq media-type 'audio)
                                                                      fmd/md-audio-datetime-format
                                                                    fmd/md-photo-datetime-format))
                                               (media-dir-name (if (eq media-type 'audio)
                                                                   fmd/md-audio-dir-name fmd/md-photo-dir-name))
                                               (media-base-title (format-time-string media-time-format media-time))
                                               (media-full-title (if media-title (format "%s - %s" media-base-title media-title)
                                                                   media-base-title)))
                                  (fmd/insert-org-link (concat "file:" media-dir-name "/" media-file)
                                                       media-full-title)
                                  (funcall demote-first)
                                  (org-set-property "CREATED_ON"
                                                    (format-time-string "%F %T" media-time))))
                              media-files)))))

      (find-file fmd/md-summary-file)

      (funcall render-header)
      (funcall render-note-section)
      (funcall render-journal-section)
      (funcall render-media-section)

      (beginning-of-buffer)
      (org-set-startup-visibility)
      (save-buffer)

      (fmd/build-media-diary-html))))

(defun fmd/build-media-diary-html ()
  "Build the current diary as an html org project"
  (interactive)
  (org-publish
   (list "fmd-html"
         :base-directory fmd/md-root
         :base-extension "org"
         :publishing-directory fmd/md-root
         :recursive t
         :publishing-function 'org-html-publish-to-html
         :html-extension "html"
         :headline-levels 4
         :section-numbers nil
         :with-toc nil)
   t))

Open standard buffers

Nice to see the standard buffers

(defun fn/open-message-buffer ()
  (interactive)
  (switch-to-buffer "*Messages*"))

Open config file

This is just a convenience to open this config file

(defun fn/find-config-file ()
  (interactive)
  (find-file (expand-file-name "config.org" user-emacs-directory)))

Insert relative path

Makes it easier to insert relative paths

(require 'f)


(defconst fn/relative-same-node "."
  "Represents the same node on a path.")

(defconst fn/relative-parent-node ".."
  "Represents the parent node on a path.")

(defun fn/relative-parent-node-thunk (&rest args)
  "Always returns `fn/relative-parent-node'."
  fn/relative-parent-node)

(defun fn/relative-path (source-path target-path)
  "An attempt to compute the relative path from SOURCE-PATH to TARGET-PATH."
  (letrec ((recurser
       (lambda (upward-nodes downward-nodes parent-node)
         (cond
          ((and (null upward-nodes) (null downward-nodes))
           (string-join
            (list fn/relative-same-node parent-node)
            (f-path-separator)))
          ((null (car upward-nodes))
           (string-join
            (append (list fn/relative-same-node)
                    downward-nodes)
            (f-path-separator)))
          ((null (car downward-nodes))
           (string-join
            (append (mapcar #'fn/relative-parent-node-thunk upward-nodes)
                    (list parent-node))
            (f-path-separator)))
          ((string-equal (car upward-nodes)
                         (car downward-nodes))
           (funcall recurser
              (cdr upward-nodes)
              (cdr downward-nodes)
              (car upward-nodes)))
          (t
           (lexical-let* ((up-nodes (or (mapcar #'fn/relative-parent-node-thunk (cdr upward-nodes))
                            (list fn/relative-same-node)))
               (down-nodes downward-nodes))
             (string-join
              (append up-nodes down-nodes)
              (f-path-separator))))))))
    (funcall recurser (f-split source-path) (f-split target-path) fn/relative-same-node)))

(defun fn/insert-relative-file-path (arg)
  "Insert the relative file path of a source file to a target file.
If prefix ARG is present, select the source file."
  (interactive "P")
  (let* ((source-path
       (cond
        (arg
         (car (find-file-read-args "Find source file: " t) ))
        ((buffer-file-name)
         (buffer-file-name))
        (t (error "Source file does not have a file name."))))
      (target-path (car (find-file-read-args "Find target file: " t))))
    (insert (fn/relative-path source-path target-path))))

A quick DSL makes me feel good.

(use-package magin
  :load-path fn/custom-script-dir
  :defer 1
  :config
  (magin-write-to-project
   `(delimited
     (context
      (comment "Base files")
      (file ,(format "%s.el" (file-name-base fn/config-file)))
      (file ,(format "%s.el" (file-name-base fn/personal-file))))

     (context
      (comment "Base directory")
      (dir ".cache")
      (dir "extra"))

     (context
      (comment "Project specific")
      (file "working-config.org")

      (file ,(format "%s.el" (file-name-base fn/config-backup-file))))

     (context
      (comment "Library")
      (path
       "lib"
       (context
        (dir "sandbox")
        (dir "packages"))
       (include
        (dir "modules")
        (dir "scripts"))))

     (block gtags)
     (block emacs))
   user-emacs-directory)
  nil)

Org-Jekyll Blogger

My blogging script

(defconst fn/org-jekyll-blogger-map (fn/make-prefixed-keymap (kbd "B") fn-standard-prefix-map)
  "My custom org-jekyll-blogger map.")


(use-package org-jekyll-blogger
  :load-path fn/custom-script-dir
  :defer t
  :bind (:map fn/org-jekyll-blogger-map
              ("d" . org-jekyll-blogger-create-draft)
              ("f" . org-jekyll-blogger-find-post)
              ("p" . org-jekyll-blogger-post-draft)))

Custom Buffer Select

I need some keybindings to select buffers quickly.

(defun fn/list-buffers-by (prompt pred)
  "Like `list-buffers' but specialized by a predicate."
  (completing-read
   prompt
   (mapcar
    (lambda (buffer)
      (cons (buffer-name buffer) buffer))
    (buffer-list))
   (lambda (pair)
     (lexical-let* ((buffer (cdr pair)))
       (funcall pred buffer)))))

(defconst fmb/list-buffer-map (fn/make-prefixed-keymap (kbd "B") fn-custom-prefix-map)
  "My list buffer map.")

(defconst fmb/command-prefix "fmb/"
  "My command key prefix.")

(defun fn/define-custom-switch-buffer (command-name key prompt pred)
  "Create a quick list buffer command."
  (lexical-let* ((full-command-name
       (format "%s%s" fmb/command-prefix command-name))
      (command-symbol
       (intern full-command-name))
      (pred pred)
      (command
       `(lambda ()
          ,(format "List buffers with %s" command-name)
          (interactive)
          (switch-to-buffer
           (fn/list-buffers-by ,prompt ,pred)))))
    (fset command-symbol command)
    (define-key fmb/list-buffer-map key command-symbol)))

(defun fn/define-custom-switch-buffer-by-mode (key prompt main-mode)
  "Create a quick list buffer command by mode."
  (fn/define-custom-switch-buffer
   (symbol-name main-mode)
   key prompt
   (lexical-let ((main-mode main-mode))
     (lambda (buffer) (eq (with-current-buffer buffer major-mode) main-mode)))))

(defun fn/define-custom-switch-buffer-by-minor-mode (key prompt sub-mode)
  "Create a quick list buffer command by minor mode."
  (fn/define-custom-switch-buffer
   (symbol-name sub-mode)
   key prompt
   (lexical-let ((sub-mode sub-mode))
     (lambda (buffer)
       (with-current-buffer buffer
         (and (boundp sub-mode) (symbol-value sub-mode)))))))


;; Major Modes
(fn/define-custom-switch-buffer-by-mode "w" "Select a page: " 'w3m-mode)
(fn/define-custom-switch-buffer-by-mode "e" "Select an (e)shell: " 'eshell-mode)
(fn/define-custom-switch-buffer-by-mode "i" "Select an (e)rc channel: " 'erc-mode)

;; Minor Modes
(fn/define-custom-switch-buffer-by-minor-mode "o" "Select a org-source buffer: " 'org-src-mode)

Text-To-Speech

Some contrivances

(fn/use-executables espeak-check
  (espeak)
  (defcustom fn/espeak-executable "espeak"
    "The speech voicer.")

  (defcustom fn/espeak-args (list "-s" "140")
    "The speech voicer args.")

  (defun fn/espeak (text)
    "Speak up."
    (interactive "sWhat do you want to say? ")
    (apply #'start-process
       (append
        (list fn/espeak-executable nil fn/espeak-executable)
        fn/espeak-args
        (list text))))

  (defun fn/espeak-region ()
    "Speak up in the region."
    (interactive)
    (fn/espeak
     (buffer-substring-no-properties (region-beginning) (region-end)))))

GNU Diction Flycheck

A quick definition for diction checking.

(fn/use-executables diction-check
  (diction)
  (fn/use-feature flycheck-diction
    (flycheck)

    (defconst fn/diction-dir (expand-file-name "diction" fn/system-dir)
      "My diction directory.")

    (make-directory fn/diction-dir t)


    (defconst fn/flycheck-diction-file (expand-file-name "en-conf" fn/diction-dir)
      "Diction conf file.")

    (defun fn/flycheck-diction--error-line-parser (raw-line)
      "Parse a line into relevant parts."
      (lexical-let ((file
           (prog2
               (string-match "\\(.*\\):\\([0123456789]+\\):\\(.*\\)" raw-line)
               (match-string-no-properties 1 raw-line)))
          (line
           (prog2
               (string-match "\\(.*\\):\\([0123456789]+\\):\\(.*\\)" raw-line)
               (match-string-no-properties 2 raw-line)))
          (errors
           (lexical-let ((processed-line
                (replace-regexp-in-string "\\[\\[.+\\]\\[.+\\]\\]" "" raw-line))
               (index 0)
               (matches (list)))
             (while (not (null index))
               (setq index (string-match "\\\[\\(.+?\\)\s->\s\\(.+?\\)\\\]" processed-line
                                      (1+ index)))
               (push
                (cons (match-string-no-properties 1 processed-line)
                   (match-string-no-properties 2 processed-line))
                matches))
             matches)))
        (list file (string-to-number line) errors)))

    (defun fn/flycheck-diction--error-parser (output checker buffer)
      "Parser for diction"
      (lexical-let ((result
           (cl-reduce
            (lambda (acc raw-line)
              (if (string-empty-p raw-line)
                  acc
                (pcase-let ((`(,file ,line ,errors)
                             (fn/flycheck-diction--error-line-parser
                              (string-trim raw-line))))
                  (append
                   acc
                   (mapcar
                    (lambda (this-error)
                      (flycheck-error-new
                       :buffer buffer
                       :checker checker
                       :filename file
                       :line line
                       :message (concat (car this-error) " -> " (cdr this-error))
                       :level 'warning))
                    errors)))))
            (split-string (string-trim output) "\n")
            :initial-value (list)
            :end -1 ;; Exclude ending line
            )))
        result))

    (flycheck-define-command-checker 'fn/diction-checker
      "Checking with diction."
      :command `("diction" "-f" ,fn/flycheck-diction-file "-s" "-b" "-d" source)
      :error-parser 'fn/flycheck-diction--error-parser
      :standard-input nil
      :modes 'org-mode)

    (add-to-list 'flycheck-checkers 'fn/diction-checker)))

Open in Sudo

Use tramp to open a file as root

(defun fn/sudo-edit (&optional arg)
  "Edit currently visited file as root.

With a prefix ARG prompt for a file to visit.
Will also prompt for a file to visit if current
buffer is not visiting a file."
  (interactive "P")
  (if (or arg (not buffer-file-name))
      (find-file (concat "/sudo:root@localhost:"
                         (ido-read-file-name "Find file(as root): ")))
    (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))

Clean Async Buffers

Just utilities to remove async buffers.

(progn
  (require 'cl)

  (defun fn/kill-inactive-async-buffers ()
    (interactive)
    (->> (buffer-list)
         (--filter
          (and
           (string-prefix-p
            "*Async Shell Command*"
            (buffer-name it))
           (not (get-buffer-process it))))
         (--map (kill-buffer it))
         (length)
         (message "Killed %s inactive async buffers"))))

Key Bindings

Here is where all the key binding I mapped to

(defun fn/trigger-key (key)
  "Returns a function that triggers the function bound by the key"
  (lexical-let* ((key-trigger key)
      (trigger
       (lambda ()
         (interactive)
         (let ((key-command (key-binding key-trigger)))
           (cond
            (key-command
             (message "Triggering %s" key-command)
             (command-execute key-command))
            (t
             (message "No key bound to %s" key-trigger)))))))
    trigger))


;; Motion
(define-key fn-custom-prefix-map (kbd "b RET") (fn/trigger-key (kbd "C-RET")))
(define-key fn-custom-prefix-map (kbd "b b RET ") (fn/trigger-key (kbd "M-RET")))


;; Keys
(global-set-key (kbd "M-n") (fn/trigger-key (kbd "DEL")))
(global-set-key (kbd "C-c C-x")  (fn/trigger-key (kbd "M-x")))


;; Search
(define-key fn-standard-prefix-map (kbd "C-s") 'fn/isearch-forward-normally)
(define-key fn-standard-prefix-map (kbd "C-r") 'fn/isearch-backward-normally)


;; Buffers
(define-key fn-standard-prefix-map (kbd "k k") 'kill-this-buffer)
(define-key fn-standard-prefix-map (kbd "k C-k") 'fn/save-and-kill-buffer)
(define-key fn-standard-prefix-map (kbd "k &") 'fn/kill-inactive-async-buffers)

;; Windows
(define-key fn-custom-prefix-map (kbd "w h") 'fmw/four-part-horizontal-window-layout)
(define-key fn-custom-prefix-map (kbd "w v") 'fmw/four-part-vertical-window-layout)
(define-key fn-custom-prefix-map (kbd "w t") 'fmw/three-part-left-window-layout)
(define-key fn-custom-prefix-map (kbd "w 3") 'fmw/three-part-vertical-window-layout)
(define-key fn-custom-prefix-map (kbd "w 4") 'fmw/four-part-equal-vertical-window-layout)
(define-key fn-custom-prefix-map (kbd "w r") 'fmw/rotate-window-buffers)

(define-key fn-custom-prefix-map (kbd "w s") 'fn/swap-with-numbered-window)

;; System Buffers
(define-key fn-custom-prefix-map (kbd "b m") 'fn/open-message-buffer)

;; Shell
(define-key fn-standard-prefix-map (kbd "x s") 'shell)


;; Customize
(define-key fn-standard-prefix-map (kbd "C g") 'customize-group)



;; Files
(define-key fn-custom-prefix-map (kbd "b c") 'fn/find-config-file)
(define-key fn-custom-prefix-map (kbd "b o") 'fn/find-main-org-file)
(define-key fn-custom-prefix-map (kbd "b l") 'fn/find-ledger-file)


;; Special Buffers
(define-key fn-custom-prefix-map (kbd "b j") 'fn/display-jabber-roster-buffer)


;; Dired
(define-key fn-custom-prefix-map (kbd "d h") #'fn/dired-emacs-dir)
(define-key fn-custom-prefix-map (kbd "d d") #'fn/dired-download-dir)
(define-key fn-custom-prefix-map (kbd "d M") #'fn/dired-mountain-dir)
(define-key fn-custom-prefix-map (kbd "d f") #'fn/dired-fakespace-dir)
(define-key fn-custom-prefix-map (kbd "d ~") #'fn/dired-home-dir)
(define-key fn-custom-prefix-map (kbd "d l") #'fn/dired-lib-dir)
(define-key fn-custom-prefix-map (kbd "d m") #'fn/dired-module-dir)

(define-key fn-custom-prefix-map (kbd "d ^") #'fn/dired-parent)
(define-key fn-custom-prefix-map (kbd "d c") #'fn/checksum-current-directory)


;; Special
(define-key fn-standard-prefix-map (kbd "l l") #'fn/chat-log-open) ;; From binding above
(define-key fn-standard-prefix-map (kbd "l L") #'fn/chat-log-clear)
(define-key fn-standard-prefix-map (kbd "l a") #'fn/alert-log-open)

(define-key fn-custom-prefix-map (kbd "i p") #'fn/insert-relative-file-path)


;; Espeak
(define-key fn-standard-prefix-map (kbd "M-s s") #'fn/espeak)

;; Functions
(define-key fn-custom-prefix-map (kbd  "r s") 'fn/startup)
(define-key fn-custom-prefix-map (kbd  "r c") 'fn/cleanup)

;; Custom Emacs
(define-key fn-custom-prefix-map (kbd  "e e") 'fn/bootstrap-experimental)
(define-key fn-custom-prefix-map (kbd  "e C-p") 'fn/bootstrap-previous)
(define-key fn-custom-prefix-map (kbd  "e s") 'fn/bootstrap-spacemacs)
(define-key fn-custom-prefix-map (kbd  "e f") 'fn/bootstrap-from-dir)

.emacs.d's People

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.