Emacs Is Great!

Table of Contents

This is my Emacs configuration.

Fork on gitlab.

The init.el is being generated from this org-mode file on save so you won't find here a init.el.

1 Some initial settings

Make sure that we are using a coding system that can handle international characters

(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)

2 UI Tweaks

2.1 Menu-bar

Turn off the menu bar. It can still be accessed with F10.

(menu-bar-mode -1)
(tool-bar-mode -1)

2.2 Mode-line

2.2.1 TODO Keep the mode-line clean

Can use delight/diminish to hide minor-modes from the mode line

2.3 Scroll-bars

(scroll-bar-mode -1)

2.4 TODO don't bg unless in terminal.

3 DONE Package Manager / Use Package

3.1 Setting up package-archives and Install use-package

(require 'package)
(add-to-list 'package-archives
             '("melpa-stable" . "https://stable.melpa.org/packages/") t)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)

(package-initialize)
(unless (package-installed-p 'use-package )
  (package-refresh-contents)
  (package-install 'use-package ))

(require 'use-package)

3.2 DONE configure use package

Always ensure packages, so we don't have to specify, this is usually what we want.

(setq use-package-always-ensure t)

3.3 TODO Make packages lazy loading

Right now using package-initialize will add a bunch of auto loaders so we lose the benifits of deffered loading.

3.4 TODO Advanced package management

  • Lazy loading / installing
  • Contribute back to packages
  • Options:
    • Quelpa : works package.el specify other branches
    • Borg : Treats all of your packages as git sub-modules.
    • Straight.el : Works from a init.el configuration ( like use-package ),but clones from the VC and allows to use custom forks. Looks a bit complicated though.

4 Customize

Using a custom file for customization

I want to move my location of customized variables so they don't get over written on tangle and so I can put environment specific settings in there.

(setq custom-file (locate-user-emacs-file "custom.el"))
(if (file-readable-p custom-file)
    (load custom-file))

5 Window Management

5.1 Ace-window

Ace window will let you jump quickly around windows. Use the prefix to switch, and 2x prefix to kill window.

ace-window-display-mode adds the window number to the mode line

(use-package ace-window
  :bind ("M-o" . ace-window)
  :delight
  :config (ace-window-display-mode 1)
)

6 Editing

6.1 TODO pair editing

6.1.1 electric-pair/show-paren

makes inserting pairs easier. built in functions, I turn these off because using smartparens.

(electric-pair-mode 0)
(show-paren-mode 0)

6.1.2 smartparens

Gives some great editing capabilities for pairs, it combines features from other pair editing packages, like paraedit.

(use-package smartparens
  :config (require 'smartparens-config)
  (show-smartparens-global-mode 1)
  (smartparens-global-mode 1)
  (sp-use-paredit-bindings))

6.1.3 expand region

Easily mark logical regions, much easier way to navigate pairs than remembering 100s of bindings for smartparens.

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

6.2 TODO multiple cursors

6.3 Hebrew / Bidirectional text

6.3.1 reordering

Bidirectional automatic reordering hurts performance and is annoying, keep it off to start with, toggle on as needed.

(setq-default bidi-display-reordering nil)

(defun bidi-reordering-toggle ()
  "Toggle bidirectional display reordering."
  (interactive)
  (setq bidi-display-reordering (not bidi-display-reordering))
  (message "bidi reordering is %s" bidi-display-reordering))
  1. Turn on automatically for text-mode.

    Most of the time, text mode will want to guess the right order for bidi text.

    (defun bidi-display-reordering-on ()
      "Sets bidi-display-reordering-on"
      (setq-local bidi-display-reordering t))
    
    (add-hook 'text-mode-hook 'bidi-display-reordering-on)
    

6.3.2 Paragraph direction

By default Emacs tries to guess the Paragraph direction for bidi-text. This ends up with mixed up looking buffers.

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

 (defun bidi-direction-toggle ()
   "Will switch the explicit direction of text for current
buffer. This will set BIDI-DISPLAY-REORDERING to T"
   (interactive "")
   (setq bidi-display-reordering t)
   (if (equal bidi-paragraph-direction 'right-to-left)
       (setq bidi-paragraph-direction 'left-to-right)
     (setq bidi-paragraph-direction 'right-to-left)
     )
   (message "%s" bidi-paragraph-direction))

6.3.3 TODO get printing working

see this mastodon conversation

    @_emacsomancer
About type setting non Roman fonts. 

I have not been able to get Hebrew working. I am exporting from orgmode so that just makes it a bit more
complicated. 
@xahlee
 |   Yisrael Dov :emacs: (@yisraeldov) 2019-03-27 04:40:49
  ------------

@yisraeldov @xahlee You'll probably want to use XeLaTeX or LuaLaTeX. It's easy to set Hebrew or Arabic or the like.
 |   B. Slade :gnu: :emacs: (@_emacsomancer@linuxrocks.online) 2019-03-27 04:44:29
  ------------

@_emacsomancer
Do you have an example of getting it to work with orgmode? I really appreciate it. 

I got emacs to print Hebrew but it comes out backwards, better than nothing. 
@xahlee
 |   Yisrael Dov :emacs: (@yisraeldov) 2019-03-27 06:27:01
  ------------

@yisraeldov Try this:

1) eval/use in your init.el:

(setq org-latex-compiler "xelatex") 

2) Add the following to the header of your org file (or set your default LaTeX packages and header information in
init.el):

#+LATEX_HEADER: \usepackage{fontspec}
#+LATEX_HEADER: \setmainfont{Noto Sans Hebrew}

@xahlee
 |   B. Slade :gnu: :emacs: (@_emacsomancer@linuxrocks.online) 2019-03-27 06:51:38
  ------------

@yisraeldov @xahlee (Or choose some other font in place of 'Noto Sans Hebrew')
 |   B. Slade :gnu: :emacs: (@_emacsomancer@linuxrocks.online) 2019-03-27 06:53:14
  ------------

@yisraeldov @xahlee Hmm... actually you may need a few other packages. Try:


#+LATEX_HEADER: \usepackage{fontspec}
#+LATEX_HEADER: \usepackage{polyglossia}
#+LATEX_HEADER: \setdefaultlanguage{hebrew}
#+LATEX_HEADER: \usepackage{bidi}
#+LATEX_HEADER: \setmainfont{Noto Sans Hebrew}

for headers (I'm not used to working with RtL scripts).

6.4 Autofill

Auto fill will hard wrap lines, good for non-programming modes, so lets turn it on for text modes.

(add-hook 'text-mode-hook 'turn-on-auto-fill)

7 Searching

7.1 Ag mode

Searching using AG, the silver searcher.

Using ripgrep instead:

(use-package ag
:commands (ag)
:config (setq ag-highlight-search t
              ag-group-matches nil
              ))

7.1.1 TODO conditionally enable ag if ripgrep is missing

7.2 Wgrep Mode

Allows editing of grep buffers, great tool for refactoring.

(use-package wgrep)

7.2.1 wgrep-ag

Only seems to work if results are not grouped, ag-group-matches set to nil.

(use-package wgrep-ag
:requires (ag)
)

7.3 Rip Grep

(use-package rg
:commands (rg rg-project rg-dwim ))

You may need to install the ripgrep executable.

I did this on Ubuntu 16.4 like this

curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.10.0/ripgrep_0.10.0_amd64.deb
sudo gdebi ripgrep_0.10.0_amd64.deb

If you are in a newer version of Ubuntu or Debian it is in the repo so use apt-get install ripgrep, otherwise see the instructions above.

8 Spelling/Linting

8.1 Flyspell

(use-package flyspell
  :hook (
         (prog-mode . flyspell-prog-mode)
         (text-mode . flyspell-mode))
)

8.2 Flycheck

(use-package flycheck
  :init
  (defun disable-fylcheck-in-org-src-block ()
    "Disables flychecks that could be problematic in org-mode "
    (setq-local flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
  :hook ((prog-mode . flycheck-mode)
         (org-src-mode . disable-fylcheck-in-org-src-block))
  )

8.2.1 TODO Don't complain about elips code-snippets

9 Org-mode

9.1 Get the newest version of orgmode

(use-package org
  :ensure org-plus-contrib
  :pin org 
  :config 
  <<org-config>>
  )

9.2 Configure org

9.2.1 make fonts nice in code snippets

This will use the native fonts for source code snippets and make your org look cool

(setq org-src-fontify-natively t)

9.2.2 get back easy templates

(require 'org-tempo)

10 Auto-complete

10.1 DONE auto-complete

I currently use auto-complete and it works fine, but it hasn't been updated in a long time

Add to the list ac-sources to get more default auto-complete sources.

 (use-package fuzzy )
  (use-package auto-complete
    :after fuzzy
    :config
    (ac-flyspell-workaround)
    (setq ac-use-fuzzy 1)
    :init
    (ac-config-default)
    (add-to-list 'ac-sources 'ac-source-yasnippet)

)

10.1.1 Get fuzzy matching to work.

Fuzzy matching will only work when you manually call the auto-complete function.

10.2 YA-Snippets

(use-package yasnippet-snippets)

10.3 TODO try company   try

(use-package company)

11 Figlet / Other demo type stuff

11.1 TODO Use figlet to make the banners

11.2 Command Log Mode

Command log mode will show the Emacs commands and key used in a separate buffer. I prefer this to something like screen key because not everyone is going to have the same keys bound to the same commands. Additionally it isn't going to show passwords or spam you with arrows.

(use-package command-log-mode
  :commands (command-log-mode)
  :bind ("C-c o" . clm/toggle-command-log-buffer)
  )

11.3 Screen Shot

Will take a screeshot of the current frame

(defun screenshot-frame ()
  "Takes a screenshot of the current frame. Requires imagemagic. "
  (interactive)
  (let (screenshot-file)
    (setq screenshot-file (format "~/Pictures/screenshot-%s.png" (format-time-string "%FT%H%M%S")))
    (start-process "screenshot" "*screenshot*"
                   "import" "-window" (frame-parameter (selected-frame) 'outer-window-id)
                   (expand-file-name screenshot-file)
                   )
    screenshot-file
    )
  )

12 Projectile

For managing projects (not project management)

(use-package projectile
  :config (projectile-mode 1)
  (use-package counsel-projectile
    :after counsel
    :config (counsel-projectile-mode))
  (setq projectile-project-search-path '("~/Projects"))
  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
  (define-key projectile-mode-map (kbd "C-c C-p") 'projectile-command-map)
  (projectile-register-project-type 'phpspec '("phpspec.yml")
                                  :compile "phpspec run"
                                  :test "phpspec run"
                                  :test-suffix "Spec"
                                  :test-dir "spec/"
                                  :src-dir "src/"))

13 Convenience/Matching

13.1 ivy/counsel

Flx package makes ivy matching better

(use-package flx)

Settings for ivy

(use-package ivy
  :defer 0.1
  :config (ivy-mode)
  (setq ivy-initial-inputs-alist nil)
  (setq ivy-re-builders-alist
        '((t . ivy--regex-fuzzy)))
  :delight
  )

Setting counsel mode

(use-package counsel
  :config (counsel-mode)
  :defer 1
  )

14 Version control / git

14.1 magit

Magit is an interface to git. This is a must have. It is probably the best git interface that exists. Use C-x g to launch.

14.1.1 Installing magit

(use-package magit
  :commands ( magit-status)
  :bind ("C-x g" . magit-status)
  )

14.2 TODO magit forge

(use-package forge
  :after magit
  :config 
  (setq ghub-use-workaround-for-emacs-bug nil) ;; fixies an issue where are workaround breaks gitlab
  (defun forge-create-secret-auth ()
    "Prompts for and creates the git forge secret. Mostly for gitlab."
    (interactive)
    (let*
        (
         (repo (forge-get-repository 'full))
         (host (oref repo apihost))
         (username (ghub--username host  'gitlab))
         (user (concat username "^forge")) 
         token
         )
      (setq token (read-passwd (format "Enter your token for %s @ %s: " username host)))
      (ghub-clear-caches)
      (auth-source-forget-all-cached)
      (secrets-create-item
       "Login" (format "%s @ %s" user host)
       token
       :host host
       :user user
       )
      )
    )
  )

See: https://github.com/magit/ghub/issues/89

14.3 live git info

(use-package diff-hl
:ensure t
:config
(global-diff-hl-mode 1)
(diff-hl-flydiff-mode 1)
(unless (display-graphic-p) (diff-hl-margin-mode 1)) 
(add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh)
)  

14.4 Quicker commits.

Sometimes working with Magit can be too slow. If you want to do a quick, stage,and commit of the current file you can use the built in vc-next-action, by default it is bound to C-x v v.

14.5 Gitlab

14.5.1 gitlab-ci

(use-package gitlab-ci-mode)

14.5.2 gitlab auto complete

(use-package ac-gitlab
  :load-path "lib/ac-gitlab"
  :hook ((git-commit-mode . ac-gitlab-set-up)
         (forge-post-mode . ac-gitlab-set-up)
         (markdown-mode . ac-gitlab-set-up))
  :config
  (add-to-list 'ac-modes 'git-commit-mode)
  (add-to-list 'ac-modes 'forge-post-mode)
  (add-to-list 'ac-modes 'markdown-mode)
  )

15 TODO docker

Highlighting for docker files and dockercompose.yaml

(use-package dockerfile-mode)
(use-package docker-compose-mode)

There is a mode for interacting with docker.

(use-package docker)

16 Rainbow-mode

Show colors for color strings like #fff or red depending on the mode.

(use-package rainbow-mode
:hook (prog-mode . rainbow-mode ))

17 Languages

17.1 Emacs-lisp

17.1.1 TODO litable

Cool looking package that shows live "light-table" results of elisp.

For some reason I can't get it to work

(use-package litable
:commands (litable-mode))

17.2 PHP

You will need to have Composer installed for most of this to work.

17.2.1 PHP-mode

Gives highlighting and other basic php editing stuff.

(use-package php-mode
  :mode (("\\.php\\'" . php-mode))
  :init
  <<php-init>>
  (setq php-mode-coding-style (quote psr2))
  (setq php-search-documentation-browser-function 'eww-browse-url )
  (setq php-style-delete-trailing-whitespace 1)
  :hook ((php-mode. ydl/php-mode-hook-for-ac)
  (php-mode . subword-mode))
)

17.2.2 Linting

  1. Be sure that you have all of the linters installed
    composer global require --prefer-source -n phpmd/phpmd \
     squizlabs/php_codesniffer \
     phpunit/phpunit \
     phpstan/phpstan
    composer global update --prefer-source
    
  2. Set up paths for linters/tools to use the composer version
    (if
        (file-exists-p "~/.config/composer/vendor/bin" )
        (setq flycheck-php-phpcs-executable "~/.config/composer/vendor/bin/phpcs"
              flycheck-php-phpmd-executable "~/.config/composer/vendor/bin/phpmd"
              phpcbf-executable "~/.config/composer/vendor/bin/phpcbf"
              phpunit-program "~/.config/composer/vendor/bin/phpunit")
      (warn "Can't find composer bin directory, some tools might not work")
      )
    
  3. Configure php-codesniffer
    (setq flycheck-phpcs-standard "PSR2")
    
  4. PHP code beautifier

    Keeps our code up to standards when possible

    (use-package phpcbf
      :after php-mode
      :commands (phpcbf)
      :ensure t
      :hook (php-mode . phpcbf-enable-on-save)
      )
    
  5. PHPstan
    (use-package flycheck-phpstan
      :after php-mode
      :config (setq-default phpstan-level "max")
      )
    

17.2.3 PHP auto complete

Getting auto-complete running can be a bit of a challenge

(use-package ac-php
  :after php-mode
  :init (setq ac-php-auto-update-intval 180)
  :commands (ac-php-core-eldoc-setup ac-php-remake-tags ac-php-remake-all-tags)
  :config (defun ydl/php-mode-hook-for-ac ()
            "Sets up ac-php"
            (yas-global-mode t)
            (auto-complete-mode t)
            (setq ac-sources  '(
                        ac-source-php
                        ac-source-words-in-same-mode-buffers
                        ac-source-yasnippet ))
            (ac-php-core-eldoc-setup))
  :bind ((:map php-mode-map
               ;;original bindings
               ("C-]" . ac-php-find-symbol-at-point)
               ("C-t" . ac-php-location-stack-back)
               ;;overwrite the xref bindings
               ("M-." . ac-php-find-symbol-at-point)
               ("M-," . ac-php-location-stack-back)
               ))
  :hook (
         (php-mode . ydl/php-mode-hook-for-ac)
         (php-mode . ac-php-remake-tags)
         (projectile-idle-timer . ac-php-remake-tags)
         )
  )

17.2.4 PHP actor


17.3 SQL

17.3.1 TODO sql repl

17.3.2 TODO sql in orgmode

17.4 Markdown

(use-package markdown-mode)

18 Superfluous eye-candy

18.1 Icons

18.1.1 All-the-icons

(use-package all-the-icons)

first time need to run:

(all-the-icons-install-fonts)
  1. Ivy all-the-icons

    Get some icons in ivy

    (use-package all-the-icons-ivy
    :init (all-the-icons-ivy-setup)
    )
    
  2. Dired all-the-icons

    Adds file icons in dired-mode.

    (use-package all-the-icons-dired
      :hook (dired-mode . all-the-icons-dired-mode))
    

18.2 Color Emoji

You can have emojis in emacs! No need for VS code! :smile:

(use-package emojify
  :config (if (display-graphic-p)
               (setq emojify-display-style 'image)
             (setq emojify-display-style 'unicode)
             )
             (setq emojify-emoji-set "emojione-v2.2.6")
  :init (global-emojify-mode 1))

18.2.1 TODO Auto install custom emojis

There are lots of sites that can use custom emojis, I'd like to dynamically download and install them into emojify.

For example mastodon.

They have an api for fetching emojis.

Emojify has the variable emojify-user-emojis that can be used for adding custom emojis.

For now emojify-logos adds a bit more.

(use-package emojify-logos
:after emojify)

18.2.2 Auto complete emojis

(use-package ac-emoji
  :init (ac-emoji-setup))       

19 TODO Make source code blocks default to emacs-lisp

19.1 YA-Snippets

Turned on yasnippet auto-complete.

19.2 Autocomplete orgmode

(use-package org-ac
  :init (org-ac/config-default))   

19.3 TODO builtin shortcuts

19.4 TODO smartparens

20 TODO Time tracking

20.1 TODO wakatime

pip3 install wakatime

Need to be sure that your API key is set, I set mine in the wakatime config file, .wakatime.cfg.

The documentation says that you will be prompted for API key but I found that wasn't the case.

(use-package wakatime-mode
  :init (global-wakatime-mode))

20.2 TODO Activity watch

You need to have activity watch installed for this

https://github.com/ActivityWatch/activitywatch/releases

(use-package activity-watch-mode
  :init (global-activity-watch-mode))

21 notifications

(use-package notifications
  :config (notifications-notify
           :title "Notifications"
           :body "Notifications enabled"
           :timeout 3000)
)

21.1 Compile finish

(defun notify-after-compile (comp-buffer exit-string)
  "notify when compile is done."
  (notifications-notify :title "compile"
                        :body (concat (buffer-name comp-buffer) " : " exit-string)
                        :timeout 5000
                        )
  )
(add-hook 'compilation-finish-functions 'notify-after-compile)

22 Communication/Internet

22.1 RSS

(use-package elfeed
  :commands (elfeed)
  :bind ((:map elfeed-show-mode-map
               ("p" . browse-url-mpv-open)))
  )

22.2 Mastodon

(use-package mastodon)

Be sure to set mastodon-instance-url

22.3 Web Browsing

Using the w3 browser for better browsing experience .

(use-package w3m
  :config (setq w3m-key-binding 'info) ;; don't use stupid vim bindings
  :commands (w3m))

23 Media

23.1 Video ( You Tube )

23.1.1 Searching YouTube

Using the elfeed method of browsing youtube does not let you search. The package ivy-youtube can search and play. You need to set up ivy-youtube-key with a google api key. I used customize so that it gets stored separately from init.el.

By default it will open the browser, using ivy-youtube-play-at you can use an external application, like mpv.

(use-package ivy-youtube
  :config (setq ivy-youtube-play-at "mpv")
  :commands (ivy-youtube)
  )

23.1.2 Watch media urls with mpv

For this to work correctly you need to have mpv installed.

If you want to watch youtube videos using mpv, you will need to have youtube-dl installed. You can add the option --mark-watched to have it mark the videos as watched, but you will need to have a way to authorise youtube-dl to user your youtube account.

(defun browse-url-mpv-open (url &optional ignored)
  "Pass the specified URL to the \"mpv\" command.
xdg-open is a desktop utility that calls your preferred web browser.
The optional argument IGNORED is not used."
  (interactive (browse-url-interactive-arg "URL: "))
  (call-process "mpv" nil 0 nil url))

23.2 Pdf

23.2.1 pdf-tools

(use-package pdf-tools
  :config (pdf-tools-install)
  )

23.2.2 org-pdf-view

(use-package org-pdfview
  :after org)

(use-package pdfgrep)

24 Financial

24.1 Ledger

(use-package hledger-mode
  :config (add-to-list 'ac-modes 'hledger-mode)
           (add-hook 'hledger-mode-hook
                     (lambda ()
                       (setq-local ac-sources '(hledger-ac-source)))))

(use-package flycheck-ledger
   :pin melpa-stable
   :after flycheck)

25 Local Variables

Author: Yisrael Dov

Created: 2019-06-04 Tue 11:11

Validate