Skip to content

Latest commit

 

History

History
808 lines (621 loc) · 21.8 KB

emacs-init.org

File metadata and controls

808 lines (621 loc) · 21.8 KB

Initialization

Inspired by this config and config of angrybacon.

Initialize/update package sources

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

Install use-package

(unless (package-installed-p 'use-package)
  (package-install 'use-package))

Install use-package-ensure-system-package

(use-package use-package-ensure-system-package
  :ensure t)

Load custom libraries

Append additional directories to load-path

(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
(add-to-list 'load-path (expand-file-name "org/lisp" "~/"))

Add Romanian standard input method to Emacs

Emacs comes with two input methods for Romanian: romanian-alt-prefix and romanian-prefix. However, I’m more accustomed to Romanian standard keyboard layout so I created a quail package for it. This will be the default input method.

(require 'quail-romanian-standard)
(setq default-input-method 'romanian-standard)

Load utilities library

(require 'rp-utils)

Basic customization

Move generated UI code to a separate file

(setq-default custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (file-exists-p custom-file)
  (load custom-file t))

Hide the startup message

(setq inhibit-startup-message t)

Hide the toolbar

(tool-bar-mode -1)

Hide the scroll bar

(scroll-bar-mode -1)

Change yes or no prompts to y or n

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

Bind F5 key to revert-buffer

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

Wrap long lines

Found on a StackOverflow answer.

(global-visual-line-mode t)

Replace highlighted text

From Emacs manual:

(delete-selection-mode 1)

Save contents of clipboard before killing text

From Reddit comment:

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

Remove scratch message

(setq initial-scratch-message "")

dired tweaks

Set dired-dwim-target

(setq dired-dwim-target t)

Human readable file sizes

From Pragmatic Emacs.

(setq dired-listing-switches "-alh")

End sentences with single space

(setq sentence-end-double-space nil)

Display date and time in mode line

(setq display-time-day-and-date t
      display-time-24hr-format t)
(display-time-mode 1)

Turn off the error bell

(setq ring-bell-function 'ignore)

Delete trailing whitespace on save

(add-hook 'before-save-hook 'delete-trailing-whitespace)

Unbind C-z

(global-unset-key (kbd "C-z"))

Change start day of the week

(setq calendar-week-start-day 1)

Ask for confirmation before exiting Emacs

(unless (daemonp)
  (setq confirm-kill-emacs 'y-or-n-p))

Use Firefox as the default browser when running in Windows Subsystem for Linux

(defun rp/browse-url-firefox(url &rest ARGS)
  "Browse URL using Firefox from Windows when running under WSL.
This function calls `shell-command' to pass
URL to the Firefox browser located at
`/mnt/c/Program\\ Files/Mozilla\\ Firefox/firefox.exe'.

The second argument ARGS is present to maintain compatibility."
  (progn
    (message "Browsing URL [%s] using external Firefox." url)
    (shell-command
     (concat "/mnt/c/Program\\ Files/Mozilla\\ Firefox/firefox.exe "
        url))))

(when (rp/running-on-wsl)
  (progn
    (message "Running under WSL. The browse-url-browser-function will be overwritten.")
    (setq browse-url-browser-function 'rp/browse-url-firefox)))

Change the location of default bookmarks files

(setq bookmark-default-file "~/org/bookmarks"
      eww-bookmarks-directory "~/org/")

Hide the cursor in inactive windows

(setq-default cursor-in-non-selected-windows nil)

Add a margin when scrolling vertically

(setq-default scroll-margin 2)

Set default encoding to UTF-8

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

Store all backup and autosave files in the /tmp directories

Taken from a reddit answer.

(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))

(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

Start Emacs maximized

(add-to-list 'initial-frame-alist
        '(fullscreen . maximized))

Themes

Use SanityInc themes

(use-package color-theme-sanityinc-tomorrow
  :defer t)

Consider all custom themes to be safe

(setq custom-safe-themes t)

Treating all custom themes as being safe seems to be risky. Ideally, I should be able to specify the list of custom themes like this:

(setq custom-safe-themes
      '("76ddb2e196c6ba8f380c23d169cf2c8f561fd2013ad54b987c516d3cabc00216" ;; sanityinc-tomorrow-day
        "04aa1c3ccaee1cc2b93b246c6fbcd597f7e6832a97aaeac7e5891e6863236f9f" ;; sanityinc-tomorrow-night
        "6fc9e40b4375d9d8d0d9521505849ab4d04220ed470db0b78b700230da0a86c1" ;; sanityinc-tomorrow-eighties
        default))

However, for some reason I can’t find right now, specifying the list of custom safe themes doesn’t work — when starting the daemon, I get a prompt whether to load and treat the theme as safe or not, which blocks the startup of the daemon.

Use circadian to switch between dark and light themes

(use-package circadian
  :ensure t
  :after smart-mode-line
  :config
  (if (and
       (bound-and-true-p calendar-latitude)
       (bound-and-true-p calendar-longitude))
      (progn
        (message "Latitude and longitude are set; themes will change according to sunset and sunrise.")
        (setq circadian-themes '((:sunrise . sanityinc-tomorrow-day)
                                 (:sunset . sanityinc-tomorrow-night))))
    (progn
      (message "Latitude and longitude not set; themes will change at 8:00 and 19:30.")
      (setq circadian-themes '(("8:00" . sanityinc-tomorrow-day)
                               ("19:30" . (sanityinc-tomorrow-night sanityinc-tomorrow-eighties))))))
  (add-hook 'circadian-after-load-theme-hook
            #'(lambda (theme)
                (sml/apply-theme 'respectful)))
  (circadian-setup))

Convenience packages

Use ibuffer for buffer list

As specified in the blog post of Mike Zamansky.

(defun rp/setup-ibuffer ()
  (progn
    (message "Setting-up Ibuffer.")
    (ibuffer-auto-mode 1)
    (ibuffer-switch-to-saved-filter-groups "default")))

(use-package ibuffer
  :defer t
  :config
  (progn
    (setq ibuffer-saved-filter-groups
          (quote (("default"
                   ("dired" (mode . dired-mode))
                   ("org" (name . "^.*org$"))
                   ("web" (or (mode . web-mode)
                              (mode . js2-mode)))
                   ("shell" (or (mode . eshell-mode)
                                (mode . shell-mode)))
                   ("programming" (or (mode . python-mode)
                                      (mode . lisp-mode)
                                      (mode . csharp-mode)
                                      (mode . js2-mode)))
                   ("doc-view" (mode . doc-view-mode))
                   ("magit" (name . "^magit[:-].*"))
                   ("latex" (or (mode . latex-mode)
                                (mode . bibtex-mode)))
                   ("emacs" (or (name . "^\\*scratch\\*$")
                                (name . "^\\*Messages\\*$")))
                   ("helm" (mode . helm-major-mode))
                   ("powershell" (mode . powershell-mode))
                   ("ledger" (mode . ledger-mode))
                   ("pdf" (mode . pdf-view-mode))
                   ("XML" (mode . nxml-mode))))))
    ;; Don't show filter groups if there are no buffers in that group
    (setq ibuffer-show-empty-filter-groups nil))
    :bind
    (:map global-map
          ("C-x C-b" . ibuffer))
    :hook
    (ibuffer-mode . rp/setup-ibuffer))

Use expand-region to expand region around the cursor semantically

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

Use smart-mode-line for improving the mode line

For some reason smart-mode-line needs to be loaded before circadian to avoid a mess in the mode-line.

(use-package smart-mode-line
  :hook
  (after-init . smart-mode-line-enable)
  :config
  (setq sml/no-confirm-load-theme t)
  (setq sml/theme 'respectful)
  (sml/setup))

Use nyan-mode for displaying progress in buffer

(use-package nyan-mode
  :after smart-mode-line
  :config
  (nyan-mode 1))

Use ace-window for window switching

From ace-window for easy window switching:

(use-package ace-window
  :defer t
  :bind
  (:map global-map
        ("C-x o" . ace-window))
  :config
  (progn
    (custom-set-faces
     '(aw-leading-char-face
       ((t (:inherit ace-jump-face-foreground :height 3.0)))))))

Use undo-tree for undo ring representation

(use-package undo-tree
  :defer t
  :defer t
  :init
  (progn
    (setq undo-tree-history-directory-alist
          `(("." . ,temporary-file-directory)))
    (global-undo-tree-mode)))

Use which-key for displaying available key chords

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

Use try package to try other packages

(use-package try
  :defer t)

Use beginend for semantic navigation to beginning/end of buffers

(when (version<= "25.3" emacs-version)
  (use-package beginend
    :defer t
    :hook
    (after-init . beginend-global-mode)))

Use atomic-chrome to edit text areas in Emacs

Atomic chrome allows editing text from a text area within browser using Emacs. Since I use Firefox I GhostText extension needs to be installed in Firefox in order for this to work.

(use-package atomic-chrome
  :defer t
  :when (display-graphic-p)
  :config
  (progn
    (setq atomic-chrome-buffer-open-style 'frame
          atomic-chrome-url-major-mode-alist '(("github\\.com" . gfm-mode)
                                               ("reddit\\.com" . markdown-mode)))
    (atomic-chrome-start-server)))

Helm

Install helm

A merge of configuration from Sacha Chua and other various sources.

(use-package helm
  :defer t
  :diminish helm-mode
  :init
  (progn
    (setq helm-candidate-number-limit 100)
    ;; From https://gist.github.com/antifuchs/9238468
    (setq helm-idle-delay 0.0 ; update fast sources immediately (doesn't).
          helm-input-idle-delay 0.01  ; this actually updates things relatively quickly.
          helm-yas-display-key-on-candidate t
          helm-quick-update t
          helm-M-x-requires-pattern nil
          helm-ff-skip-boring-files t)
    ;; Configuration from https://gist.github.com/m3adi3c/66be1c484d2443ff835b0c795d121ee4#org3ac3590
    (setq helm-split-window-in-side-p t ; open helm buffer inside current window, not occupy whole other window
          helm-move-to-line-cycle-in-source t ; move to end or beginning of source when reaching top or bottom of source.
          helm-ff-search-library-in-sexp t ; search for library in `require' and `declare-function' sexp.
          helm-scroll-amount 8)	; scroll 8 lines other window using M-<next>/M-<prior>
    )
  :hook (after-init . helm-mode)
  :bind (:map global-map
         ("C-c h" . helm-mini)
         ("C-h a" . helm-apropos)
         ("C-x b" . helm-buffers-list)
         ("M-y" . helm-show-kill-ring)
         ("M-x" . helm-M-x)
         ("C-x c o" . helm-occur)
         ("C-x c y" . helm-yas-complete)
         ("C-x c Y" . helm-yas-create-snippet-on-region)
         ("C-x c SPC" . helm-all-mark-rings)
         ("C-x C-f" . helm-find-files)
         :map helm-map
         ("TAB" . helm-execute-persistent-action)))

Install helm-swoop

Bindings from Sacha Chua.

(use-package helm-swoop
  :defer t
  :after helm
  :bind
  (("C-S-s" . helm-swoop)
   ("M-i" .  helm-swoop)
   ("M-s s" . helm-swoop)
   ("M-s M-s" . helm-swoop)
   ("M-I" . helm-swoop-back-to-last-point)
   ("C-c M-i" . helm-multi-swoop)
   ("C-c M-I" . helm-multi-swoop-all)))

Install helm-xref

(use-package helm-xref
  :defer t
  :after helm)

Git integration

Utility functions

Define a function to change the spelcheck dictionary to English, and enable the flyspell-mode in order to avoid spelling mistakes in commits.

(defun rp/git-commit-setup()
  "Setup the git commit buffer."
  (progn
    (ispell-change-dictionary "en_US")
    (flyspell-mode 1)))

Install magit

(use-package magit
  :defer t
  :bind (("C-x g" . magit-status))
  :hook (git-commit-setup . rp/git-commit-setup))

Install forge

(use-package forge
  :defer t
  :after magit)

For some reason, forge is unable to generate the token when running under Cygwin. To avoid this issue, just create a Personal Access Token in GitHub settings page and store it in the ~/.authinfo file like this:

machine api.github.com login <username>^forge password <personal token>

Install git-gutter

As found in Git Gutter in Emacs | Ian Y.E. Pan:

(use-package git-gutter
  :hook (prog-mode . git-gutter-mode)
  :config
  (setq git-gutter:update-interval 0.02))

Completion configuration

Use company for completion

From Emacs configuration of angrybacon.

(use-package company
  :defer t
  :config
  (setq-default
   company-idle-delay .2
   company-minimum-prefix-length 1
   company-require-match nil
   company-tooltip-align-annotations t
   company-show-numbers t
   company-show-quick-access t)
  :hook
  (after-init . global-company-mode))

Use company-quickhelp for displaying help in popup window

(use-package company-quickhelp
  :defer t
  :after company
  :bind
  (:map company-active-map
        ("C-c h" . company-quickhelp-manual-begin))
  :init (with-eval-after-load 'company
          (company-quickhelp-mode)))

Markdown related packages

Use markdown-mode for editing markdown-formatted files

As specified in the documentation.

(use-package markdown-mode
  :defer t
  :commands (markdown-mode gfm-mode)
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("LICENSE" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode))
  :init
  (setq markdown-command "multimarkdown"))

Use gh-md to render markdown buffers using Github API

(use-package gh-md
  :defer t)

Various utility packages

Use csv-mode for CSV files

Use an utility function to setup csv-mode

(defun rp/setup-csv-mode()
  (progn
    (display-line-numbers-mode)
    (hl-line-mode)))

Configure csv-mode

(use-package csv-mode
  :defer t
  :config
  (rp/setup-csv-mode))

Use yasnippet for snippets

Configure yasnippet package

(use-package yasnippet
  :defer t
  :hook
  (after-init . yas-global-mode))

Configure the yasnippet-snippets package

(use-package yasnippet-snippets
  :defer t
  :after yasnippet)

Use projectile

Define an utility function which tries to activate a virtual environment if it exists

(defun rp/try-activate-virtual-environment()
  "Try to activate the virtual environment.
The virtual environment is assumed to be located
in directory .venv under projectile root directory."
  (let* ((project-dir (projectile-project-root))
         (venv-dir (concat project-dir ".venv")))
    (if (file-directory-p venv-dir)
        (progn
          (message (format "Activating virtual environment from %s." venv-dir))
          (pyvenv-activate venv-dir)))))

Configure projectile package

When on Cygwin use native indexing for projectile as mentioned in this Quora answer. It’s slower but it does the job.

(use-package projectile
  :defer t
  :bind-keymap
  ("C-c p" . projectile-command-map)
  :config
  (progn
    (when (eq system-type 'cygwin)
      (setq projectile-indexing-method 'native)))
  :hook
  ((magit-mode . projectile-mode)
   (projectile-mode . rp/try-activate-virtual-environment)))

Use helm as the projectile completion system

(use-package helm-projectile
  :defer t
  :hook
  (projectile-mode . helm-projectile-on)
  :config
  (setq projectile-completion-system 'helm))

Use eldoc

(use-package eldoc
  :defer t
  :hook ((emacs-lisp-mode . eldoc-mode)
         (eval-expression-minibuffer-setup . eldoc-mode)
         (lisp-mode-interactive-mode . eldoc-mode)
         (python-mode . eldoc-mode)
         (eshell-mode . eldoc-mode)
         (org-mode . eldoc-mode)))

Use graphviz-dot-mode

(use-package graphviz-dot-mode
  :defer t)

Use pdf-tools

The examle of using use-package for configuring pdf-tools can be found here.

(use-package pdf-tools
  :defer t
  :config
  (pdf-tools-install)
  (setq-default pdf-view-display-size 'fit-page)
  :mode (("\\.pdf" . pdf-view-mode)))

Use ledger-mode

Prerequisites

Requires ledger to be installed:

sudo apt-get install ledger

Setup ledger-mode

Define function to clean buffer when buffer is in ledger-mode

(defun rp/clean-ledger-buffer()
  (when (equal major-mode 'ledger-mode)
    (ledger-mode-clean-buffer)))

Configure ledger-mode

(use-package ledger-mode
  :defer t
  :config
  (progn
    (setq ledger-reconcile-default-commodity "RON")
    (setq ledger-schedule-file "~/org/financial/ledger-schedule.ledger")
    (add-hook 'before-save-hook 'rp/clean-ledger-buffer)))

Use and configure flycheck-ledger

(use-package flycheck-ledger
  :defer t
  :hook (ledger-mode . flycheck-mode))

Use newsticker to read RSS/Atom feeds

(use-package newst-treeview
  :defer t
  :init
  (require 'rp-feeds-urls)
  (setq newsticker-dir "~/org/newsticker/"
        newsticker-frontend 'newsticker-treeview
        newsticker-cache-filename "~/org/newsticker/.newsticker-cache"
        newsticker-retrieval-interval -1
        newsticker-download-logos nil
        newsticker-treeview-treewindow-width 60
        newsticker-url-list rp/newsticker-feeds)
  :config
  (add-hook 'kill-emacs-hook (lambda ()
                               (if (fboundp 'newsticker-treeview-quit)
                                   (newsticker-treeview-quit)))))