gearnode / emacs.d

My personal emacs configuration

Home Page:https://git.frimin.fr/?p=emacs.d.git;a=summary

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

GNU Emacs configuration file

This repository contains my (Bryan Frimin) Emacs configuration. If you find a bug or have any question, feel free to open a Github issue or to contact me by email. Please note that I do not currently review or accept any contribution.

First change default Emacs memory management, I’ve a modern computer not an Apple II.

(setq read-process-output-max (* 1024 1024)) ; 1MB instead of 4KB
(setq gc-cons-threshold 100000000) ; 100MB instead of 800KB

Use gls instead of ls on BSD system.

(if (eq system-type 'berkeley-unix)
    (progn (setq insert-directory-program "/usr/local/bin/gls")))

Configure font and font size.

(face-spec-set 'default '((t :font "NotoMono Nerd Font")))
(set-face-attribute 'default nil :height 115)

This package is a minor mode to set background color to strings that match color name.

(use-package rainbow-mode
  :straight t
  :config
  (setq rainbow-ansi-colors nil)
  (setq rainbow-x-colors nil))

Add a newline character when visiting or saving a buffer relevance.

(setq mode-require-final-newline 'visit-save)

Keep code file clean.

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

Highligh keywords that are normally used in code comments.

(use-package hl-todo
  :straight t
  :config
  (setq hl-todo-keyword-faces
        '(("TODO"  . "#FF0000")
          ("DEBUG" . "#1E90FF")
          ("XXX"   . "#1E90FF")))
  :hook (prog-mode-hook . hl-todo-mode))

Ensures buffers are updated whenever the file changes. A change can happen externally or by some other tool inside of Emacs.

(setq auto-revert-verbose t)
(global-auto-revert-mode)

The standard line lengh is 80 characters. Having something less allows such things like quoting text, indent, etc.

(setq-default fill-column 72)
(global-display-fill-column-indicator-mode)

Shortcut to avoid typing yes or no each time.

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

Turn off annoying bell.

(setq ring-bell-function 'ignore)

Turns off Indent Tabs mode.

(setq-default indent-tabs-mode nil)

Enable line number mode.

(setq column-number-mode t)

Setting custom file.

(setq custom-file (concat user-emacs-directory "custom.el"))

Enable ANSI color in the compilation mode.

(defun gearnode/compilation-mode-colorize-output ()
  (read-only-mode -1)
  (unwind-protect
      (let ((start compilation-filter-start)
            (end (point)))
        (ansi-color-apply-on-region start end))
    (read-only-mode 1)))

(use-package compilation-mode
  :straight nil
  :init
  (require 'ansi-color)
  :config
  (setq compilation-scroll-output t)
  :hook
  ((compilation-filter-hook . gearnode/compilation-mode-colorize-output)))

Disable menu bar, toolbar and scrollbar.

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

Emacs history and state

This sections contains configuration for Emacs state and history management.

Remember where the cursor is in any given file.

(setq save-place-file "~/.emacs.d/saveplace")
(setq save-place-forget-unreadable-file t)
(save-place-mode 1)

Keep Emacs opened buffers after crash or kill.

(setq desktop-auto-save-timeout 300)
(setq desktop-dirname "~/.emacs.d/")
(setq desktop-base-file-name "desktop")
(setq desktop-files-not-to-save nil)
(setq desktop-globals-to-clean nil)
(setq desktop-load-locked-desktop t)
(setq desktop-missing-file-warning nil)
(setq desktop-restore-eager 0)
(setq desktop-restore-frames nil)
(setq desktop-save 'ask-if-new)
(desktop-save-mode 1)

Ensure Emacs starts in the *scratch* buffer.

(setq initial-buffer-choice t)
(setq inhibit-startup-echo-area-message "gearnode")
(setq inhibit-startup-screen t)
(setq inhibit-startup-buffer-menu t)

Configure Emacs backup files to:

  • not pollute the current working directory with emacs backup files.
  • enable backup on versioned file.
(setq backup-by-copying t)

(setq version-control t)
(setq delete-old-versions t)
(setq kept-new-versions 10)
(setq kept-old-versions 5)

;; By default, Emacs never backs up versioned file.
(setq vc-make-backup-files t)

(setq backup-directory-alist '(("" . "~/.emacs.d/backup/per-save")))

(defun gearnode/force-backup-of-buffer ()
  ;; Make a special "per session" backup at the first save of each
  ;; emacs session.
  (when (not buffer-backed-up)
    ;; Override the default parameters for per-session backups.
    (let ((backup-directory-alist '(("" . "~/.emacs.d/backup/per-session")))
          (kept-new-versions 3))
      (backup-buffer)))
  ;; Make a "per save" backup on each save.  The first save results in
  ;; both a per-session and a per-save backup, to keep the numbering
  ;; of per-save backups consistent.
  (let ((buffer-backed-up nil))
    (backup-buffer)))

(add-hook 'before-save-hook  'gearnode/force-backup-of-buffer)
(setq savehist-file "~/.emacs.d/savehist")
(setq history-length 1000)
(setq history-delete-duplicates t)
(setq savehist-save-minibuffer-history t)
(add-hook 'after-init-hook 'savehist-mode)

Use VS Code theme.

(use-package vscode-dark-plus-theme
  :straight (:host github :repo "ianyepan/vscode-dark-plus-emacs-theme" :branch "master")
  :ensure t
  :config
  (load-theme 'vscode-dark-plus t))

Git

Emacs version control seems nice, but does not wrap Git as Magit do. Because I mainly works with Git I use magit instead of VC.

(use-package magit
  :straight t
  :config
  (setq magit-log-margin '(t "%F %R" magit-log-margin-width t 18))
  :bind
  ("C-c g" . magit-status))

Configure git-commit to follow my commit style

(use-package git-commit
  :config
  (setq git-commit-summary-max-length 50)
  (setq git-commit-known-pseudo-headers
        '("Signed-off-by"
          "Modified-by"
          "Cc"
          "Suggested-by"
          "Reported-by"))
  (setq git-commit-style-convention-checks
        '(non-empty-second-line
          overlong-summary-line)))

PDF

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

Web browser

I do not use Emacs has web browser but use the web browser binding to transform HTML email content in text one.

(use-package w3m
  :straight t
  :config
  (setq w3m-user-agent "42")
  (setq w3m-add-user-agent t)
  (setq w3m-default-save-directory "~/Download")
  (setq w3m-fill-column 72)
  (setq w3m-default-display-inline-images t))

Open link in new Firefox tab.

(setq browse-url-browser-function 'browse-url-firefox)
(setq browse-url-new-window-flag t)
(setq browse-url-firefox-new-window-is-tab t)

GNUS

This section contains my GNUS configuration.

Bind C-c m to open GNUS.

(global-set-key (kbd "C-c m") 'gnus)

Style

A bit of frontend to have cleaner interface.

(setq gnus-use-full-window nil)

(setq gnus-summary-line-format
      (concat "%U%R %~(max-right 17)~(pad-right 17)&user-date;  "
              "%~(max-right 20)~(pad-right 20)f %B%s\n"))

(setq gnus-user-date-format-alist '((t . "%d.%m.%Y %H:%M"))
      gnus-sum-thread-tree-false-root ""
      gnus-sum-thread-tree-indent " "
      gnus-sum-thread-tree-root ""
      gnus-sum-thread-tree-leaf-with-other "├─≻"
      gnus-sum-thread-tree-single-leaf     "└─≻"
      gnus-sum-thread-tree-vertical        "")

(setq gnus-summary-thread-gathering-function
      'gnus-gather-threads-by-subject)

(setq gnus-thread-sort-functions
      '(gnus-thread-sort-by-number
        gnus-thread-sort-by-total-score))

(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

Mailboxes

Configure mailboxes.

(setq user-mail-address "bryan@frimin.fr")
(setq user-full-name "Bryan Frimin")
(setq message-user-fqdn "workstation.frimin.fr")

(setq gnus-select-method '(nnnil nil))
(setq gnus-secondary-select-methods
      '((nntp "news.gwene.org")
        (nnimap "frimin"
                (nnimap-address "imap.frimin.fr")
                (nnimap-server-port 993)
                (nnimap-stream ssl)
                (nnir-search-engine imap)
                (nnimap-inbox "INBOX")
                (nnmail-expiry-target
                 "nnimap+frimin:Trash")
                (nnmail-expiry-wait immediate))
        (nnimap "gmail"
                (nnimap-address "imap.gmail.com")
                (nnimap-server-port 993)
                (nnimap-stream ssl)
                (nnir-search-engine imap)
                (nnmail-expiry-target
                 "nnimap+gmail:[Gmail]/Trash")
                (nnmail-expiry-wait immediate))))

;; Reply to mails with matching email address
(setq gnus-posting-styles
      '((".*"
         (address "Bryan Frimin <bryan@frimin.fr>")
         (signature
          "Bryan Frimin\nhttps://www.frimin.fr\nbryan@frimin.fr")
         ("X-Message-SMTP-Method"
          "smtp smtp.frimin.fr 587 bryan@frimin.fr"))
        ("gmail"
         (address "Bryan Frimin <friminb@gmail.com>")
         ("X-Message-SMTP-Method"
          "smtp smtp.gmail.com 587 friminb@gmail.com"))))

(setq gnus-message-archive-group
      '(("frimin" "nnimap+frimin:Sent")
        ("gmail" "[Gmail]/Sent Mail")
        (".*" "nnimap+frimin:Sent")))

(setq gnus-gcc-mark-as-read t)

Configure SMTP server.

(setq smtpmail-default-smtp-server "smtp.frimin.fr")
(setq smtpmail-smtp-server "smtp.frimin.fr")
(setq smtpmail-stream-type 'starttls)
(setq smtpmail-smtp-service 587)
(setq smtpmail-retries 7)
(setq smtpmail-queue-mail nil)
(setq send-mail-function 'smtpmail-send-it)
(setq message-send-mail-function 'smtpmail-send-it)

Contact

(use-package bbdb
  :ensure t
  :straight t
  :init
  (bbdb-initialize 'gnus)
  (bbdb-initialize 'message)
  :config
  (setq bbdb-offer-save 1) ; save without asking
  (setq bbdb-use-pop-up t) ; allow popups for addresses
  (setq bbdb-electric-p t) ; be disposable with SPC
  (setq bbdb-popup-target-lines 1) ; very small popup
  (setq bbdb-dwim-net-address-allow-redundancy t) ; always use full name
  (setq bbdb-quiet-about-name-mismatches 2) ; shiw name-mismacthes 2 secs
  (setq bbdb-always-add-address t)
  (setq bbdb-file "~/.bbdb"))

Misc

Make GNUS not check for any new newsgroups and stops gnus from trying to filter out outdated newsgroups.

(setq gnus-check-new-newsgroups nil)
(setq gnus-check-bogus-newsgroups nil)

Kill mail buffer after sending an email.

(setq message-kill-buffer-on-exit t)

Don’t deal with HTML news.

(setq mm-discouraged-alternatives '("text/html" "text/richtext"))
(setq mm-text-html-renderer 'w3m)
(setq gnus-blocked-images "ads")

Org

(use-package org
  :straight t
  :ensure org-plus-contrib
  :config
  (setq org-hide-emphasis-markers t)
  (setq org-startup-folded t)
  (setq org-startup-indented t)
  (setq org-startup-with-inline-images t)
  (setq org-ellipsis "")
  (setq org-todo-keywords
        '((sequence "TODO" "WORK" "STOP" "VERIFY" "|" "DONE" "DELEGATED")))
  (setq org-todo-keyword-faces
        '(("TODO" . org-warning)
          ("WORK" . "yellow")
          ("STOP" . "red")
          ("VERIFY" . "orange")
          ("DONE" . "green")
          ("DELEGATED" .  "blue"))))

Use unicode bullet instead of asterix.

(use-package org-superstar
  :straight t
  :config
  (add-hook 'org-mode-hook (lambda () (org-superstar-mode 1)))
  :custom
  (org-superstar-headline-bullets-list '("" "" "" "" "" "" "")))

Customize org appearance.

(require 'color)

(set-face-attribute 'org-block nil
                    :background (color-darken-name
                                 (face-attribute 'default :background) 3))

(set-face-attribute 'org-block-begin-line nil
                    :background (color-darken-name
                                 (face-attribute 'default :background) 3)
                    :foreground "#4d4d4d")

(set-face-underline 'org-ellipsis nil)

Languages

Understand camelCaseWords as many words instead of one long word.

(add-hook 'prog-mode-hook 'subword-mode)

See column for syntax with identation.

(use-package highlight-indent-guides
  :straight t
  :config
  (setq highlight-indent-guides-method 'column)
  :hook
  ((yaml-mode-hook . highlight-indent-guides-mode)))

Autocomplete

Emacs is not compatible by default with LSP.

(use-package lsp-mode
  :straight t
  :commands
  (lsp lsp-deferred)
  :init
  (setq lsp-prefer-flymake nil) ;; use flycheck not flymake
  (setq lsp-log-io t)
  (setq lsp-keymap-prefix "C-c l")
  (setq lsp-headerline-breadcrumb-enable nil))

Install flycheck as lsp mode need it.

(use-package flycheck
  :straight t
  :init (global-flycheck-mode))

Use company as auto complete package.

(use-package company
  :straight t
  :after lsp-mode
  :hook
  (lsp-mode . company-mode)
  :bind
  (:map company-active-map
        ("<tab>" . company-complete-selection))
  (:map lsp-mode-map
        ("<tab>" . company-indent-or-complete-common))
  :custom
  (company-minimum-prefix-length 1)
  (company-idle-delay 0.0))

LSP mode use yasnippet.

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

Configure lsp ui mode

(use-package lsp-ui
  :straight t
  :commands lsp-ui-mode
  :config
  (setq lsp-ui-sideline-show-diagnostics t)
  (setq lsp-ui-sideline-show-hover t)
  (setq lsp-ui-sideline-update-mode t)

  (setq lsp-ui-doc-enable t))

Snippet

(use-package yasnippet
  :straight t
  :config
  (add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets")
  (yas-reload-all)
  (yas-global-mode))

Comment

Basic configuration for the newcomment mode.

  • Replace M-; by C-;
  • Remove comment with C-:
  • Ident comment with M-;
(defun gearnode/comment (&optional arg)
  (interactive "*P")
  (if (use-region-p)
      (comment-dwim arg)
    (save-excursion
      (comment-line arg))))

(use-package newcomment
  :straight nil
  :config
  (setq comment-multi-line t)
  (setq comment-style 'multi-line)
  (setq comment-fill-column nil)
  (setq comment-empty-lines t)
  :bind
  (("C-;" . gearnode/comment)
   ("C-:" . comment-kill)
   ("M-;" . comment-indent)))

Ruby

Enable ruby-mode in various files that are not obvious Ruby files.

(defun gearnode/ruby-hook ()
  (setq-local fill-column 90))

(use-package ruby-mode
  :hook
  (ruby-mode-hook . gearnode/ruby-hook)
  :mode
  (("Gemfile" . ruby-mode)
   ("Rakefile" . ruby-mode)
   ("\\.rake$" . ruby-mode)
   ("\\.rb$" . ruby-mode)
   ("\\.ru$" . ruby-mode)
   ("\\.gemspec$" . ruby-mode)
   ("\\.irbrc$" . ruby-mode)))

Erlang

(defun gearnode/erlang-hook ()
  (setq-local fill-column 78))

(use-package erlang
  :straight t
  :config
  (setq erlang-electric-commands '())
  (setq erlang-man-download-url
        "https://erlang.org/download/otp_doc_man_24.0.tar.gz")
  (setq erlang-indent-level 2)
  :hook
  (erlang-mode-hook . display-fill-column-indicator-mode)
  (erlang-mode-hook . gearnode/erlang-hook)
  (erlang-mode-hook . lsp-deferred)
  :mode
  (("\\.erl$" . erlang-mode)
   ("\\.hrl%" . erlang-mode)
   ("\\.app\\.src$" . erlang-mode)
   ("rebar\\.config" . erlang-mode)
   ("rebar\\.lock" . erlang-mode)))

Reconize escript shebang.

(add-to-list 'interpreter-mode-alist
             '("escript" . erlang-mode))

NGINX

(use-package nginx-mode
  :straight t)

PHP

(use-package php-mode
  :straight t
  :ensure t)

Docker

Support syntax highlighting for Dockerfile file.

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

Markdown

Markdown rich editing support.

(use-package markdown-mode
  :straight t
  :config
  (setq markdown-fontify-code-blocks-natively t)
  :mode
  ("\\.md$"))

Enable editing of code block in indirect buffers using `C-c ‘`

(use-package edit-indirect
  :straight t
  :after markdown-mode)

JSONNET

Support syntax highlighting for JSONNET file.

(use-package jsonnet-mode
  :straight t)

YAML

Support syntax highlighting for YAML files.

(use-package yaml-mode
  :straight t
  :mode
  (("\\.yaml$" . yaml-mode)
   ("\\.yml$" . yaml-mode)))

Shell scripts

Enable sh-mode in various files that are not obvious shell scripts.

(use-package sh-script
  :mode
  (("PKGBUILD" . sh-mode)
   ("Stackfile" . sh-mode)))

Terraform

(use-package terraform-mode
  :straight t
  :config
  (setq terraform-indent-level 4))

Go

(use-package go-mode
  :straight t
  :hook
  (go-mode-hook . lsp-deferred)
  (before-save-hook . gofmt-before-save))

Javascript

(setq js-indent-level 2)

Typescript

(use-package typescript-mode
  :straight t
  :config
  (setq-default typescript-indent-level 2))

Rust

(use-package rust-mode
  :straight t
  :config
  (setq rust-format-on-save t)
  :hook
  (rust-mode-hook . lsp-deferred))

x509 certificates

(use-package x509-mode
  :straight t
  :ensure t)

Search

(use-package rg
  :straight t
  :config
  (rg-enable-default-bindings))

Dired

(require 'dired)

Kill buffers of files/directories that are deleted in dired.

(setq dired-clean-up-buffers-too t)

Always copy directories recursively instead of asking every time.

(setq dired-recursive-copies 'always)

Ask before recursively deleting a directory.

(setq dired-recursive-deletes 'top)

Dired listing switches:

  • -a: Do not ignore entries starting with.
  • -l: Use long listing format.
  • -G: Do not print group names like users.
  • -h: Human-readable sizes like 1K, 234M, etc.
  • -v: Do natural sort .. so the file names starting with . will show up first.
  • -F: Classify filenames by appending * to executables, / to directories, etc.
(setq dired-listing-switches "-alGhvF --group-directories-first")

Project management

Basic projectile configuration.

(use-package projectile
  :straight t
  :init
  (projectile-mode +1)
  :config
  (setq projectile-project-search-path '("~/Workspace"))
  (setq projectile-indexing-method 'alien)
  (setq projectile-sort-order 'access-time)
  (setq projectile-enable-caching t)
  (setq projectile-file-exists-remote-cache-expire (* 10 60))
  :bind
  (:map projectile-mode-map
        ("s-p" . projectile-command-map)
        ("C-c p" . projectile-command-map)))

Incremental completions

(use-package helm
  :straight t
  :ensure t
  :init
  (helm-mode 1)
  :config
  (setq helm-always-two-window nil)
  (setq helm-default-display-buffer-functions '(display-buffer-in-side-window))
  (setq helm-display-buffer-default-height 16)
  (setq helm-buffer-max-length 30)
  (setq helm-boring-buffer-regexp-list
        (list
         "\\*Customize"
         "erlang-ls"
         "magit"
         "lsp"
         "\\*org-src"
         "\\*code-conversion-work\\*"
         "straight"
         "\\*Echo Area"
         "\\*Minibuf"
         "\\*Shell Command Output\\*"
         "\\*helm"
         "\\*godoc "))
  :bind
  (("M-x" . helm-M-x)
   ("C-x C-b" . helm-buffers-list)
   ("C-x C-y" . helm-show-kill-ring)
   ("C-x C-f" . helm-find-files)))

RFC

(use-package rfc-mode
  :straight t
  :config
  (setq rfc-mode-directory (expand-file-name "~/rfc/"))
  :bind
  ("C-c r" . rfc-mode-browse))

TO REFACTOR

(use-package emacs
  :config
  (setq frame-title-format '("%b"))
  (setq echo-keystrokes 0.25)
  (setq default-input-method "greek"))

About

My personal emacs configuration

https://git.frimin.fr/?p=emacs.d.git;a=summary

License:Apache License 2.0


Languages

Language:Emacs Lisp 69.2%Language:YASnippet 30.8%