💾 Archived View for irek.xyz › emacs.el captured on 2021-12-17 at 13:26:06.

View Raw

More Information

⬅️ Previous capture (2021-11-30)

-=-=-=-=-=-=-

;;; My humble Emacs (28.0.50v) configuration -*- lexical-binding:t -*-
;; Last update: 2021-06-13
;;
;; This file is more verbose than my actual config.  For real thing
;; clone repository with "git clone git://irek.xyz/emacs".
;;
;; For full documentation of variable or function use help commands:
;; "C-h v" (`describe-variable') and "C-h f" (`describe-function').
;;
;; Place cursor after closing bracket of `info' function and press
;; "C-x C-e" to open Info page.  To close it press "q".  Examples:
;;
;; (info "(elisp) Comment Tips")        ; Read those Info pages to
;; (info "(emacs) Pages)                ; understand config better

;;; Why not org-mode config?
;;
;; I've started with few big config files maintained with org-mode in
;; spirit of literate programming.  As I got to know Emacs better I
;; have began to reduce init file realizing that instead of another
;; package I can use other workflow or functionality that is build in.
;;
;; My knowledge of help commands grew so the need for writing headings
;; and descriptions become unnecessary.  I don't share config between
;; different computers so that makes it simpler too.
;;
;; After few years I ended up with short single elisp file.


;;; early-init.el (info "(emacs) Early Init File")

(menu-bar-mode -1)   ; Maybe GUI is good for discoverability and fun
(tool-bar-mode -1)   ; to play around but to me it's useless.  Early
(scroll-bar-mode -1) ; Init is good place to disable all of that.

;; Defining path to file in this variable will force Emacs "Easy
;; Customization Interface" to use given file for auto generated code
;; instead of your main init config.
(setq custom-file (concat user-emacs-directory "custom-file.el"))


;;; init.el (info "(emacs) Init File")

;;;; display-time
;;
;; I don't have `display-time-mode' enabled all the time but when I do
;; I like to have it simple and clean.
(setq display-time-24hr-format t)       ; Use 24 hours time format
(setq display-time-default-load-average nil) ; Hide load average

;;;; calendar
(setq calendar-week-start-day 1)        ; Start week with Monday
(setq calendar-date-style 'iso)         ; Use YYYY-MM-DD format

;;;; other random stuff
(setq-default indent-tabs-mode nil)     ; Use spaces over tabs
(setq make-backup-files nil)            ; Avoid creating backup files
(setq-default create-lockfiles nil)     ; I don't care about collisions
                                        ; and ".#" files are messy
(setq dired-maybe-use-globstar t)       ; (info "(emacs) Dired Enter")
(setq isearch-lazy-count t)             ; Show isearch match number
(setq confirm-kill-emacs 'yes-or-no-p)  ; Prompt after C-x C-c
(setq read-buffer-completion-ignore-case t) ; To switch buffer faster

(set-language-environment "UTF-8")      ; Try to use UTF-8
(fset 'yes-or-no-p 'y-or-n-p)       ; Use y/n prompt instead of yes/no

(global-set-key (kbd "<f6>") 'recompile) ; For quick recompile

;; Some commands are disabled so that beginning users cannot use them
;; by accident.  I like to enable them to avoid confirmation prompt.
(put 'narrow-to-region 'disabled nil)
(put 'scroll-left 'disabled nil)
(put 'dired-find-alternate-file 'disabled nil)

;;;; minor-modes
(global-auto-revert-mode t)             ; Reload file after change
(pending-delete-mode t)                 ; Overwrite region by typing
(ffap-bindings)                         ; (info "(emacs) FFAP")

;;;; tab-bar
(setq tab-bar-close-last-tab-choice     ; Disable tab-bar with C-x t 0
      'tab-bar-mode-disable)            ; if you have only one tab
(setq tab-bar-close-button-show nil)    ; Hide GUI close tab button
(setq tab-bar-new-button-show nil)      ; Hide GUI new tab button

;;;; Version Control (VC)

;; Add "node_modules" directory name to list of excluded directories.
;; When working on JavaScript projects I want to ignore "node_modules"
;; directory through all of the Emacs.  This is the best way because
;; `vc-directory-exclusion-list' variable is used by other libraries.
;; Mainly "grep" and "project" libraries.
;;
;; Default value for `grep-find-ignored-directories' is set from this
;; variable and `project-find-file' function use it as well.
(add-to-list 'vc-directory-exclusion-list "node_modules")

(defun my/log-edit-mode-setup ()
  (ispell-change-dictionary "en")     ; Enable flyspell and use "en"
  (flyspell-mode 1))                  ; dictionary in VC log edit mode

(add-hook 'log-edit-mode-hook 'my/log-edit-mode-setup)

;;;; shr
;;
;; Library used to render HTML in Emacs.  Used mainly by `eww' but
;; also by `rmail' mail reader.

;; Overwrite shr functions to avoid raised text.  In eww references to
;; footnotes is often moved slightly up resulting in line height being
;; higher in that line.  In my opinion this looks bad.
(eval-after-load "shr"
  (lambda ()
    (defun shr-tag-sup (dom) (let ((start (point))) (shr-generic dom)))
    (defun shr-tag-sub (dom) (let ((start (point))) (shr-generic dom)))))

;;;; spellcheck toggle
(defun my/spellcheck-toggle ()          ; Enable flyspell-mode and
  (interactive)                         ; toggle between "polish" and
  (flyspell-mode)                       ; "en" dictionaries using
  (ispell-change-dictionary             ; single binding.
   (if (string= ispell-local-dictionary "en") "polish" "en") nil))

(global-set-key (kbd "C-c s") 'my/spellcheck-toggle)

;;;; org-mode
;;
;; Because of calendar, diary and appointments Emacs features I don't
;; use org-mode as heavily as I used to.  Still there are number of
;; variables I like to set.  Mostly for agenda and clocking.
(setq org-agenda-diary-file 'diary-file) ; Avoid using org for diary
(setq org-use-speed-commands t)          ; Be quick or be dead!

;; In practice while you working on something you can invoke agenda
;; with "C-c a" (defined later), see all your tasks and plans, maybe
;; edit something and then (while in agenda buffer) exit with "q" and
;; have all your windows restored to the point before "C-c a".
(setq org-agenda-restore-windows-after-quit t)

;; List of directories with org files containing TODO tasks.
(setq org-agenda-files '("~/org/" "~/company/"))

;; One custom agenda to plan whole week and second to track current
;; day.  While planning the week I like to see not scheduled tasks so
;; I can schedule them if possible.  During the day I also like to see
;; them so maybe I can do some more if time allows.
(setq org-agenda-custom-commands
      '(("d" "Daily plan"
         ((agenda "" ((org-agenda-span 1)))
          (alltodo "" ((org-agenda-todo-ignore-scheduled t)
                       (org-agenda-todo-ignore-deadlines 'all)))))
        ("w" "Weekly plan"
         ((agenda "")
          (alltodo "" ((org-agenda-todo-ignore-scheduled t)))))))

(global-set-key (kbd "C-c a") 'org-agenda) ; Show agenda prompt

;; Show current clocking time instead of sum of all clocked hours,
;; because I work on bigger tasks in 45m intervals.  So each time I
;; start clocking I like to begin with 0m and end around 45m.
(setq org-clock-mode-line-total 'current)

;; To my surprise summary of all logged time using org-clock feature
;; will take into consideration only "this year".  I like to have sum
;; of all clocked hours.
(setq org-clock-display-default-range 'untilnow)

;; This will allow you to evaluate shell scripts inside code block.
(org-babel-do-load-languages 'org-babel-load-languages '((shell . t)))

;;;; rmail (receiving and reading mails)

;; Mails from current year lives inside "inbox" file.  When year ends
;; I rename it (for example to "2020") and create new empty "inbox"
;; file for new year.
(setq rmail-file-name "~/rmail/inbox")  ; Main rmail inbox file

;; Define mailboxes to fetch mails from.  If your "username" contains
;; "@" character then replace it with "%40" because this string can
;; have only single "@" before server domain.
(setq rmail-primary-inbox-list '("imaps://username@server.org"))

;; Emacs use it's build in implementation of "movemail" program but
;; version from "mailutils" have more features.
(setq rmail-movemail-variant-in-use 'mailutils)
(setq rmail-remote-password-required t) ; Ask for pass on first use

;; Enable spam filter and examples of spam rules
(setq rmail-use-spam-filter t)
(setq rsf-definitions-alist
      '(((from . "spam-company-name-1") (action . delete-spam))
        ((from . "spam-company-name-2") (action . delete-spam))))

;;;; SMTP (sending mails)
;;
;; To make authentication work with server you need to create or edit
;; "~/.authinfo" file and add line (replace capitalized letters with
;; proper values):
;;
;; machine SERVER_ADDRESS port PORT login LOGIN password PASSWORD

;; Set sending method and mail composer.  
(setq message-send-mail-function 'message-smtpmail-send-it)
(setq mail-user-agent 'message-user-agent)

(setq user-mail-address "name@server.org")    ; Your mail address
(setq smtpmail-smtp-server "mail.server.org") ; mail server address
(setq smtpmail-stream-type 'ssl)              ; Enable ssl
(setq smtpmail-smtp-service 465)              ; Port
(setq smtpmail-smtp-user user-mail-address)   ; My username is my mail

;; Send every outgoing mail to myself by adding "BCC: name@server.org"
;; header to each message so all messages (sent and received) are in
;; "inbox" file.  This makes it very easy to read whole conversations
;; and archive sent messages.
(setq message-default-headers (concat "BCC: " user-mail-address "\n"))

(defun my/message-mode-setup ()         ; Enable `flyspell-mode' and
  (ispell-change-dictionary "polish")   ; "polish" dictionary in mail
  (flyspell-mode 1))                    ; composer.

(add-hook 'message-mode-hook 'my/message-mode-setup)

;;;; changing (toggle) font size
;;
;; I like to toggle between two font sizes.  For presentations
;; purposes and sometimes to focus on small file portion.
(defvar my/font-size 10.0)

(defun my/font-size-toggle ()
  (interactive)
  (setq my/font-size (if (>= my/font-size 14.0) 10.0 14.0))
  (set-frame-font (font-spec :family "Monospace" :weight 'normal
                             :slant 'normal :size my/font-size)))

(global-set-key (kbd "<f7>") 'my/font-size-toggle)


;;;; packages
;;
;; Because I don't share my config with different machines I don't use
;; "use-package" package.  Also I use few packages and even fewer are
;; configured so this part is short.
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))

;;;; c-mode c-eldoc
(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode)

;;;; modus themes
;;
;; I mostly use default theme but when I go dark side then modus is my
;; weapon of choice.
(setq modus-themes-hl-line 'accented-background)
(setq modus-themes-mode-line 'accented)

;;;; pass
(defun my/pass-get-password (password-path)
  "Get password stored under PASSWORD-PATH in
pass (https://www.passwordstore.org/)."
  (with-temp-buffer
    (shell-command (format "pass %s | head -1" password-path) (buffer-name))
    (string-trim (buffer-string))))

;;;; circe (irc) https://xkcd.com/1782/
;;
;; I used to use powerful "erc" for a while and minimalistic "rcirc"
;; for few years.  I usually like to stick with build in libraries and
;; packages but "circe" is a great balance between those two.
(eval-after-load "circe"
  (lambda ()
    (require 'circe-color-nicks)          ; Load nicks coloring lib
    (setq circe-color-nicks-everywhere t) ; Color nicks in messages
    (enable-circe-color-nicks)            ; Enable coloring

    ;; By default your messages are printed with no nick ("> text").
    ;; But I like to see my nick in conversations so I can easily
    ;; search for my messages.
    (setq circe-format-self-say "<{nick}> {body}")

    ;; If someone change topic it's not always obvious what exactly
    ;; was modified.  With "{topic-diff}" you will see information
    ;; about topic change as a diff.
    (setq circe-format-server-topic "*** Topic change by {userhost}: {topic-diff}")

    ;; Enable flyspell in chat.  Define rules for dictionaries.  Here
    ;; channels that ends with "-pl" will have "polish" dictionary,
    ;; otherwise use "en".
    (setq lui-flyspell-p t)
    (setq lui-flyspell-alist '((".*[\\.-]pl$" "polish") (".*" "en")))

    ;; Log messages.  Define path, load logging module and enable it.
    (setq lui-logging-directory "~/.config/emacs/irc-logs")
    (load "lui-logging" nil t)
    (enable-lui-logging-globally)

    ;; Enable tracking.  It will show line in place you last read
    ;; before switching to other buffer so you can continue reading
    ;; from there.  Binding allows to jump to that place directly.
    (enable-lui-track)
    (define-key circe-mode-map (kbd "C-c C-a") 'lui-track-jump-to-indicator)

    ;; Server connection setup.  Note that ":pass" uses my function
    ;; `my/pass-get-password' to get password.  As a first argument
    ;; `circe' pass value of ":host" and that is path under which I
    ;; have my password.
    (setq circe-network-options
          '(("libera" :host "irc.libera.chat" :port 6697 :tls t :nick "irek"
             :user "irek" :pass my/pass-get-password :reduce-lurker-spam t
             :channels ("#emacs" "#emacs-circe" "#emacsconf" "#emacs-pl"))))
    ))