Конфигурация GNU Emacs

Emacs – текстовый редактор от сообщества GNU. Он расширяется при помощи языка Emacs Lisp и является одним из старейших текстовых редакторов, который используется многими и по сей день. Далее идёт моя конфигурация этого редактора.


Исходный код

About this Emacs configuration

Configuration uses org-mode to tangle its contents to init.el and then be used by emacs. I use guix home for my emacs config on gnu guix system.

If you see :tangle nil it means that snippet is not used anymore, but it is left because it might be valuable in a future for me.

This configuration is available here: https://w96k.dev/emacs.html

The git source code is hosted on Sourcehut: https://git.sr.ht/~w96k/dotfiles/tree/master/item/emacs

The license of emacs config and dotfiles is CC0 which is Public Domain.

Packets

Only needed when I need to install a package from Melpa and not GNU Guix

(require 'package)

(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
                     ("melpa" . "http://melpa.org/packages/")))

(when (< emacs-major-version 27)
  (package-initialize))

(require 'gnutls)

EXWM

(require 'exwm)
(require 'exwm-config)
(exwm-config-example)

Init.el

;; -*- lexical-binding: t -*-

;; Show/Hide errors
;; (setq debug-on-error nil)
;; (setq debug-on-quit nil)

;; Timer
(add-hook 'emacs-startup-hook
            (lambda ()
              (message
               "Emacs ready in %s with %d garbage collections."
               (format "%.2f seconds"
                       (float-time
                        (time-subtract after-init-time before-init-time)))
               gcs-done)))

;; Dont ask when following symlinks
(setq vc-follow-symlinks t)

;; Load your custom settings
(setq custom-file "~/.emacs.d/custom-settings.el")
(load custom-file t)

Meta

About me

;; Information about me
(setq user-full-name "Mikhail Kirillov"
        user-mail-address "w96k@runbox.com")

Configuration

(setq config-dotfiles-path "/home/w96k/projects/dotfiles/emacs/.emacs.d/"
        config-path "~/.emacs.d/"
        config-name ".emacs-config.org")

(defun config-visit ()
  (interactive)
  (find-file (concat config-path config-name)))

(defun config-tangle ()
  (interactive)
  (org-babel-tangle-file (concat config-dotfiles-path config-name))
  ;; Configuration stored in another directory,
  ;; so I need to move files .emacs.d manually
  ;; (rename-file (concat config-dotfiles-path "early-init.el") config-path t)
  (rename-file (concat config-dotfiles-path "init.el") config-path t))

Appereance

Line numbers

Изначально они отключены, но можно вызвать по клавише F7.

(define-key global-map
  (kbd "<f7>") 'display-line-numbers-mode)

(define-key global-map
  (kbd "<f6>") 'whitespace-mode)

Editing

Completion styles

(setq completion-styles '(basic partial-completion emacs22 substring))

Dired

;; Show files in KiB
(use-package dired
  :hook
  (dired-mode . hl-line-mode)
  :config
  (setq dired-listing-switches "-hlap"
        dired-kill-when-opening-new-dired-buffer t)

  (customize-set-variable 'global-auto-revert-non-file-buffers t)
  (global-auto-revert-mode 1))

Linter

I use Flymake and Flycheck

  • Flymake
    (add-hook 'prog-mode-hook 'flymake-mode)
    
    (require 'psalm)
    
    (define-prefix-command 'flymake-map)
    (global-set-key (kbd "C-q") 'flymake-map)
    (define-key flymake-map (kbd "n") 'flymake-goto-next-error)
    (define-key flymake-map (kbd "p") 'flymake-goto-prev-error)
    (define-key flymake-map (kbd "l") 'flymake-show-diagnostics-buffer)
    (define-key flymake-map (kbd "e") 'flymake-show-diagnostic)
    
  • Flycheck
    ;; (require 'psalm)
    
    (when (package-loaded? "flycheck")
    
      (defun flycheck-phanclient-start-daemon ()
        "Start the phan daemon"
        (interactive)
        (let* ((default-directory (php-project-get-root-dir))
                 (phan-executable (or flycheck-phanclient--phan-executable
                                      (if (file-exists-p "vendor/bin/phan")
                                          (concat default-directory "vendor/bin/phan")
                                        (executable-find "phan"))))
                 (cmd (list phan-executable "--daemonize-tcp-port" "4846" "--quick")))
            (apply #'start-process "PhanDaemon" "*phan daemon*" cmd)))
    
      (flycheck-define-checker php-phanclient
        "Phan"
        :command ("phan_client" "-l" source-original "-f" source)
        :error-patterns
        ((warning line-start (or "Parse" "Fatal" "syntax" "Phan") " error" (any ":" ",") " " (message) " in " (file-name) " on line " line line-end))
        :modes (php-mode php+-mode))
    
      (add-to-list 'flycheck-checkers 'php-phanclient)
    
      (flycheck-add-next-checker 'php '(warning . php-phanclient))
    
      (add-hook 'prog-mode-hook 'flycheck-mode))
    

Imenu List

(use-package imenu-list
  :bind
  ("C-x C-d" . imenu-list-smart-toggle)
  :config
  (setq imenu-list-focus-after-activation nil
        imenu-list-auto-resize nil
        imenu-list-mode-line-format '()
        imenu-list-size 0.4))

Version Control System

Модуль VC + Magit.

Operation VC Magit
Project status project-vc-dir (C-x p v) magit-status (C-x g)
Pull vc-update (F, in my case) magit-pull (F p)
New branch vc-retrieve-tag (C-u B s) magit-branch (b c)
Commit vc-next-action (C-x v v) magit-commit (c c)
Rebase shell-command (M-!) + git rebase master magit-rebase (r p)
Push vc-push (P or C-u P) magit-push (P p)
Stash mu-vc-git-stash (z) magit-stash (z)
Log vc-print-root-log (L) magit-log (l l)

https://www.manueluberti.eu//emacs/2021/11/27/vc/

  (setq vc-command-messages t)

  (global-set-key "\C-xvB" 'git-branch-next-action)

  ;; Use magit only when built-in VC fails

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

(use-package git-timemachine :defer t)

Jumps

;; Jumps by highlighting symbols on screen
(use-package avy
  :defer t
  :bind (("M-s M-s"	. avy-goto-char)
         ("M-s s"	. avy-goto-char)
         ("M-s g"	. avy-goto-line)
         ("M-s l"	. avy-goto-char-in-line)
         ("M-s M-l"	. avy-goto-char-in-line)

         ("M-g g"	. avy-goto-line)
         ("M-s M-g"	. avy-goto-line)))

(use-package link-hint
  :defer t
  :bind (("M-s j" . link-hint-open-link)))

;; Jumps to last change
(use-package goto-chg
  :defer t
  :bind (("C-z" . goto-last-change)
         ("M-z" . goto-last-change-reverse)))

;; Jumps using grep and similar tools
(use-package dumb-jump
  :defer t
  :bind (("M-g o" . dumb-jump-go-other-window)
         ("M-g j" . dumb-jump-go)
         ("M-g b" . dumb-jump-back)
         ("M-g q" . dumb-jump-quick-look)
         ("M-g x" . dumb-jump-go-prefer-external)
         ("M-g z" . dumb-jump-go-prefer-external-other-window)))

Проекты

Использую встроенный project.el I use built-in project.el

Ограничение ширины строки

(add-hook 'prog-mode-hook 'display-fill-column-indicator-mode)

;;; Set column width to 79 according to pep8 for python
(add-hook 'python-mode-hook
            (lambda () (set-fill-column 79)))

Ввод парных скобок и кавычек (electric)

;;; Input of pair delimiters
(electric-pair-mode)
(add-hook 'prog-mode-hook 'electric-pair-mode)
(add-hook 'prog-mode-hook 'electric-indent-mode)

Kill-ring

(use-package browse-kill-ring
  :defer t
  :bind ("C-M-y" . browse-kill-ring))

Tags

Для прыжков и поиска функций/классов и т.д.

(setq path-to-ctags "~/.guix-home/profile/bin/ctags")

(defun tags-create (dir-name)
  "Create tags file."
  (interactive "DDirectory: ")
  (shell-command
   (format "%s -f TAGS -e -R %s" path-to-ctags
             (directory-file-name dir-name))))

(defun tags-create-python (dir-name)
  "Create tags with python interpreter"
  (interactive "DDirectory: ")
  (shell-command
   (format "%s -f TAGS -e -R --fields=+l --languages=python --python-kinds=-iv $(python -c \"import os, sys; print(' '.join('{}'.format(d) for d in sys.path if os.path.isdir(d)))\") %s" path-to-ctags
             (directory-file-name dir-name))))  
(use-package ggtags
  :defer t
  :hook
  (c-mode . ggtags-mode))

Дебаггер

(when (package-loaded? "realgud")
  (load "~/.emacs.d/site-lisp/realgud-xdebug/realgud-xdebug.el"))
(when (package-loaded? "geben")
  (setq geben-dbgp-default-port 9003))
  • Автодополнение кода и документация

    По большей части я использую дефолтный Completion Buffer и Corfu

    (when (package-loaded? "corfu")
      (progn
        (setq corfu-preview-current 'nil
                corfu-popupinfo-delay t)
        (corfu-mode 1)
        (corfu-popupinfo-mode 1)
        (defun show-default-completion-buffer ()
            (interactive)
            (corfu-quit)
            (corfu-mode -1)
            (completion-at-point)
            (corfu-mode 1)
            (corfu-popupinfo-mode 1))
        (define-key corfu-map (kbd "M-TAB") 'show-default-completion-buffer)
        (define-key corfu-map (kbd "TAB") 'show-default-completion-buffer)
        (define-key corfu-map (kbd "C-M-i") 'show-default-completion-buffer)      
        (corfu-mode -1)
        (add-hook 'prog-mode-hook 'corfu-mode)
    
        (defun corfu-send-shell (&rest _)
            "Send completion candidate when inside comint/eshell."
            (cond
             ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input))
              (eshell-send-input))
             ((and (derived-mode-p 'comint-mode)  (fboundp 'comint-send-input))
              (comint-send-input))))
    
        (advice-add #'corfu-insert :after #'corfu-send-shell)
    
        (add-hook 'eshell-mode-hook 'corfu-mode)))
    
    
  • Агрессивный дефолтный комплит
    (setq aggressive-completion-delay 0.5)
    (aggressive-completion-mode t)
    

Полнотекстовый поиск

Для выхода из поиска – C-c C-q

(load "deft-autoloads")

(define-key global-map
  (kbd "C-c n s") 'deft)

(setq deft-recursive t
        deft-use-filter-string-for-filename t
        deft-default-extension "org md"
        deft-directory "~/projects/at-w96k/content/digarden")

Визуализирование откатов

При помощи пакета undo-tree

(use-package undo-tree
  :defer t
  :hook
  (prog-mode . undo-tree-mode)
  (org-mode . undo-tree-mode))

Сниппеты

(when (package-loaded? "yasnippet")
  (progn
    (add-hook 'prog-mode-hook #'yas-minor-mode)))

Клиент LSP

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               '((php-mode phps-mode php-ts-mode) . ("/home/w96k/projects/phpactor/bin/phpactor" "language-server" "-vvv"))))

;; (with-eval-after-load 'eglot
;;   (add-to-list 'eglot-server-programs '((php-mode phps-mode) . ("~/projects/phpactor/bin/phpactor" "language-server" "-vvv")))
;;   (add-to-list 'eglot-server-programs '((php-mode phps-mode) . ("intelephense" "--stdio")))

;;   ;; No event buffers, disable providers cause a lot of hover traffic. Shutdown unused servers.
;;   (setq eglot-events-buffer-size 0
;; 	eglot-ignored-server-capabilities '(:hoverProvider
;; 					    :documentHighlightProvider)
;; 	eglot-autoshutdown t))

;; Show all of the available eldoc information when we want it. This way Flymake errors
;; don't just get clobbered by docstrings.        
(add-hook 'eglot-managed-mode-hook
          (lambda ()
            "Make sure Eldoc will show us all of the feedback at point."
            (setq-local eldoc-documentation-strategy
                        #'eldoc-documentation-compose)))

Линтеры

(defun my-php-mode-setup ()
  "My PHP-mode hook."
  (require 'flycheck-phpstan)
  (flycheck-mode t))

(add-hook 'php-mode-hook 'my-php-mode-setup)
;; (add-hook 'php-mode-hook 'flymake-php-load)
 ;; (add-hook 'php-mode-hook 'flymake-phpstan-turn-on)

  ;; (require 'flycheck-phpstan)


;;(add-to-list 'auto-mode-alist '("\\.\\(php\\|phtml\\)\\'" . phps-mode))

;; (phps-mode-flycheck-setup)

;; (setq phps-mode-async-process t)
;; (setq phps-mode-async-process-using-async-el t)

Выделение

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

Сессия

(desktop-save-mode 1)

Скроллинг

(setq scroll-margin 0)

Поиск

  • Isearch
    (with-eval-after-load 'isearch
      (define-key isearch-mode-map "\C-h" 'isearch-delete-char)
      (define-key isearch-mode-map "\C-ch" 'isearch-help-for-help))
    
  • Подсчёт кандидатов
    (use-package anzu
      :config
      (global-anzu-mode t))
    
  • Swiper (не используется)
    (load "swiper-autoloads")
    (global-set-key (kbd "C-s") 'swiper)
    
    (setq swiper-include-line-number-in-search t
            swiper-use-visual-line t
            swiper-stay-on-quit t)
    

Which function

(which-function-mode t)

Подсказка биндов

Пакет Which-key

(load "which-key-autoloads")
(which-key-setup-side-window-right)
(which-key-mode)

(setq which-key-side-window-max-width 0.5
        which-key-show-remaining-keys t
        which-key-max-display-columns 50
        which-key-max-description-length 35
        which-key-sort-order 'which-key-local-then-key-order
        which-key-idle-delay 0.25)

Права суперпользователя

Sudo-edit

(use-package sudo-edit
  :defer t)

Промежуточный код

Показывает собранное состояние будь то собранный куски на ассемблере или байт-код при помощи пакета RMSbolt.

(use-package rmsbolt
  :defer t)

Быстрый запуск программы

;; (when (package-loaded? "quickrun")
;;   (define-key global-map (kbd "C-c C-c") 'quickrun))

Языки программирования

Common Lisp

  • REPL
    (load "sly-autoloads")
    
    (setq sly-lisp-implementations
            '((clisp ("clisp"))
              (cmucl ("cmucl" "-quiet"))
              (sbcl ("/opt/sbcl/bin/sbcl") :coding-system utf-8-unix)))
    

Ruby

(when (package-loaded? "inf-ruby")
  (add-hook 'ruby-mode-hook 'inf-ruby-minor-mode))

(when (package-loaded? "inf-ruby")
  (add-hook 'ruby-mode-hook 'robe-mode))

Scheme

(setq geiser-active-implementations '("guile"))

GO

(use-package go-mode)  		      

Python

  • Автодополнение и линт
    (when (package-loaded? "anaconda-mode")
      (progn
        (add-hook 'python-mode-hook 'anaconda-mode)
        (add-hook 'python-mode-hook 'anaconda-eldoc-mode)))
    
    ;; (when (load "flymake" t)
    ;;   (defun flymake-pylint-init ()
    ;;     (let* ((temp-file (flymake-init-create-temp-buffer-copy
    ;; 		       'flymake-create-temp-inplace))
    ;; 	   (local-file (file-relative-name
    ;; 			temp-file
    ;; 			(file-name-directory buffer-file-name))))
    ;;       (list "epylint" (list local-file))))
    
    ;;   (add-to-list 'flymake-allowed-file-name-masks
    ;; 	       '("\\.py\\'" flymake-pylint-init)))
    
    ;; (add-hook 'python-mode-hook 'flymake-mode)
    
  • Прыжки в функции стандартной библиотеки на си

SML

(add-hook 'sml-mode-hook 'sml-mode)

Java

  • Eglot-java

    For better integration with eclipse.jdt.ls

    (unless (package-installed-p 'eglot-java)
      (package-vc-install "https://github.com/yveszoundi/eglot-java" nil nil 'eglot-java))
    

PHP

  • PHP-Mode

    Необходимо скачать и распаковать мануал PHP (в формате html) в директорию ~/.emacs.d/php-manual/.

    ;; (add-to-list 'load-path "~/.emacs.d/site-lisp/realgud-xdebug/")
    ;; (require 'realgud-xdebug)
    
    ;; (defun init-php-mode ()
    ;;   (eglot-ensure))
    
    (use-package php-mode
      :bind ("C-c h" . 'php-quickhelp-at-point)
      :config
    
      (setq php-manual-path
            "~/projects/php-manual/"
            php-quickhelp-dir "~/projects/php-manual/"
            php-quickhelp--dest "~/projects/php-manual/php_manual_en.json"))
    
    
    ;; (add-hook 'php-mode-hook 
    ;; 		'(lambda ()
    ;; 		   ;; (auto-complete-mode t)
    
    ;; 		   ;; (require 'ac-php)
    ;; 		   (require 'php-quickhelp)
    ;; 		   (require 'company)
    ;; 		   (company-mode t)
    ;; 		   (require 'company-php)
    ;; 		   (require 'company-quickhelp)
    
    ;; 		   (require 'yasnippet)
    ;; 		   (require 'yasnippet-snippets)
    
    ;; 		   (set (make-local-variable 'company-backends)
    ;; 			'((company-ac-php-backend company-dabbrev-code)
    ;; 			  php-quickhelp-company-php
    ;; 			  company-capf company-files))
    
    ;; 		   (company-quickhelp-mode t)
    
    ;; 		   (define-key php-mode-map (kbd "C-M-i") 'company-complete)
    ;; 		   (define-key company-mode-map (kbd "M-TAB") 'company-complete)
    
    ;; 		   ;; (setq ac-sources '(ac-source-php php-quickhelp-company-php))
    ;; 		   ;; (setq eldoc-documentation-function
    ;; 		   ;;       'php-quickhelp-eldoc-func)
    
    ;; 		   (yas-minor-mode t)
    
    ;; 		   ;; (define-key php-mode-map (kbd "C-M-i") 'auto-complete)
    ;; 		   ;; (define-key ac-mode-map (kbd "M-TAB") 'auto-complete)
    
    ;; 		   (define-key php-mode-map (kbd "C-c H")
    ;; 			       'php-local-manual-search)
    
    ;; 		   (define-key php-mode-map (kbd "C-c h") 'php-quickhelp-at-point)
    ;; 		   (define-key company-mode-map (kbd "C-c h") 'php-quickhelp-at-point)
    
    ;; 		   ;; (define-key php-mode-map (kbd "C-c t") 'ac-php-show-tip)
    
    ;; 		   ;; Jump to definition (optional)
    ;; 		   (define-key php-mode-map
    ;; 			       (kbd "M-.") 'ac-php-find-symbol-at-point)
    
    ;; 		   ;; Return back (optional)
    ;; 		   (define-key php-mode-map
    ;; 			       (kbd "M-,") 'ac-php-location-stack-back)))
    ))
    
  • Composer
    (setq composer-executable-bin "~/.bin/composer")
    
  • Flymake PHP
  • REPL
  • LSP сервер

    PHPactor

    (setq phpactor-executable "~/.bin/phpactor")
    (custom-set-variables '(lsp-phpactor-path "~/.bin/phpactor"))
    
    (use-package phpactor :ensure t)
    (use-package company-phpactor :ensure t)
    
    
    
    ;; (with-eval-after-load 'php-mode
    ;;   (define-key php-mode-map (kbd "M-.") #'phpactor-goto-definition)
    ;;   (define-key php-mode-map (kbd "M-?") #'phpactor-find-references))
    
  • Transient меню
    (require 'transient)
    (define-transient-command php-menu ()
      "Php"
      [["Class"
        ("cc" "Copy" phpactor-copy-class)
        ("cn" "New" phpactor-create-new-class)
        ("cr" "Move" phpactor-move-class)
        ("ci" "Inflect" phpactor-inflect-class)
        ("n"  "Namespace" phpactor-fix-namespace)]
       ["Properties"
        ("a"  "Accessor" phpactor-generate-accessors)
        ("pc" "Constructor" phpactor-complete-constructor)
        ("pm" "Add missing props" phpactor-complete-properties)
        ("r" "Rename var locally" phpactor-rename-variable-local)
        ("R" "Rename var in file" phpactor-rename-variable-file)]
      ["Extract"
        ("ec" "constant" phpactor-extract-constant)
        ("ee" "expression" phpactor-extract-expression)
        ("em"  "method" phpactor-extract-method)]
      ["Methods"
        ("i" "Implement Contracts" phpactor-implement-contracts)
        ("m"  "Generate method" phpactor-generate-method)]
      ["Navigate"
        ("x" "List refs" phpactor-list-references)
        ("X" "Replace refs" phpactor-replace-references)
        ("."  "Goto def" phpactor-goto-definition)]
      ["Phpactor"
        ("s" "Status" phpactor-status)
        ("u" "Install" phpactor-install-or-update)]])
    

Языки декларирования

SQL

to install lsp-server called sqls https://emacs-lsp.github.io/lsp-mode/page/lsp-sqls/

;; Empty for now (was using emacsql)
(setq lsp-sqls-server "~/go/bin/sqls")

;; (setq lsp-sqls-workspace-config-path nil)

(setq lsp-sqls-connections
        '(((driver . "mysql") (dataSourceName . "dbuser:mangoworms@tcp(localhost:3306)/profile24"))))

The main way to interact with SQL is using org-mode

(when (package-loaded? "org-sql")
  (setq org-sql-files "~/projects/profile24/org"))

(add-hook 'sql-interactive-mode-hook
          (lambda ()
            (sql-connect "profile24")
            (toggle-truncate-lines t)))

(setq sql-connection-alist
    '((profile24
         (sql-product 'mysql)
         (sql-server "localhost")
         (sql-user "dbuser")
         (sql-password "123456")
         (sql-database "testdb")
         (sql-port 3306))))
  • Sql Viewer
    (unless (package-installed-p 'pg)
      (package-vc-install "https://github.com/emarsden/pg-el" nil nil 'pg))
    (unless (package-installed-p 'pgmacs)
      (package-vc-install "https://github.com/emarsden/pgmacs"))
    
    (use-package pgmacs)
    

Веб шаблоны

  • Web-mode
    (use-package web-mode
      :defer t
      :config
      (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
      (add-to-list 'auto-mode-alist '("\\.twig.html\\'" . web-mode))
      (setq web-mode-markup-indent-offset 2)
      (setq web-mode-enable-auto-pairing t)
      (setq web-mode-enable-css-colorization t)
      (setq web-mode-enable-block-face t)
      (setq web-mode-enable-current-element-highlight t))
    

Org

  • Org-mode
    (use-package org
      :defer t
      :config
      (org-babel-do-load-languages
       'org-babel-load-languages
       '((R . t)
         (ditaa . t)
         (dot . t)
         ;; (php . t)
         (emacs-lisp . t)
         (gnuplot . t)
         (haskell . nil)
         (latex . t)
         ;;(ledger . t)
         (ocaml . nil)
         (octave . t)
         (python . t)
         (ruby . t)
         (screen . nil)
         (shell . t)
         (sql . t)
         (js . t)))
      (setq org-default-notes-file "~/Documents/todo.org"
            system-time-locale "C"
            org-use-speed-commands t
            org-adapt-indentation nil
            org-return-follows-link t
            org-agenda-include-diary t
            org-display-remote-inline-images 'download
            org-agenda-start-with-log-mode t
            org-image-actual-width (list 400)
            org-hide-emphasis-markers t
            org-outline-path-complete-in-steps nil
            org-src-tab-acts-natively t
            org-id-track-globally t
            org-confirm-babel-evaluate nil)
      (setq org-todo-keywords
            (quote ((sequence "TODO(t)"
                              "MIGRATE(m)"
                              "IN PROGRESS(p)" 
                              "DONE(d)")
                    (sequence "BLOCKED(w@/!)"
                              "HOLD(h@/!)" "|"
                              "CANCELLED(c@/!)"
                              "PHONE"
                              "MEETING"
                              "NEED CLARIFICATION(t)"
                              ))))
      (setq org-todo-keyword-faces
            (quote (("TODO" :foreground "red" :weight bold)
                    ("NEXT" :foreground "blue" :weight bold)
                    ("DONE" :foreground "forest green" :weight bold)
                    ("WAITING" :foreground "orange" :weight bold)
                    ("HOLD" :foreground "magenta" :weight bold)
                    ("CANCELLED" :foreground "forest green" :weight bold)
                    ("MEETING" :foreground "forest cyan" :weight bold)
                    ("PHONE" :foreground "blue" :weight bold))))
      :bind
      ("C-c l" . org-store-link)
      ("C-c a" . org-agenda)
      ("C-c c" . org-capture)
      )
    
    (defun org-babel-edit-prep:sql (babel-info)
      (setq-local buffer-file-name (->> babel-info caddr (alist-get :tangle)))
      (setq-local lsp-buffer-uri (->> babel-info caddr (alist-get :tangle) lsp--path-to-uri))
      (setq-local lsp-headerline-breadcrumb-enable nil)
      (lsp))
    
    ;; (global-set-key (kbd "M-f") 'org-metaright)
    ;; (global-set-key (kbd "M-b") 'org-metaleft)
    ;; (global-set-key (kbd "M-p") 'org-metaup)
    ;; (global-set-key (kbd "M-n") 'org-metadown)
    
  • Org-ref
    (load "org-ref-autoloads")
    
    (setq reftex-default-bibliography '("~/Documents/bibliography/references.bib"))
    
    ;; see org-ref for use of these variables
    (setq org-ref-bibliography-notes "~/Documents/bibliography/notes.org"
            org-ref-default-bibliography '("~/Documents/Bibliography/references.bib")
            org-ref-pdf-directory "~/Documents/bibliography/bibtex-pdfs/")
    
  • Org-roam
    (use-package org-roam
      :defer t
      :bind
      ("C-c n l" . org-roam-node-insert)
      ("C-c n b" . org-roam-buffer-toggle)
      ("C-c n f" . org-roam-node-find)
      ("C-c n t t" . org-roam-tag-add)
      ("C-c n t r" . org-roam-tag-remove)
      ("C-c n i" . org-roam-jump-to-index)
      ("C-c n g" . org-roam-graph)
      ("C-c n d" . org-roam-db-build-cache)
      ("C-c n r" . org-roam-node-random)
      ("C-c n j" . org-roam-dailies-find-date)
      :config
      (setq org-roam-directory (file-truename "~/Zettelkasten")
            org-roam-v2-ack t
            org-roam-completion-everywhere t
            org-roam-index-file (concat org-roam-directory "/20210409054712-жизнь.org")
            org-roam-dailies-directory (concat org-roam-directory "journals/"))
    
      (org-roam-db-autosync-mode t))
    
    (defun org-roam-jump-to-index ()
      "Stub of recreating the function from V1"
      (interactive)
      (let
          ((org-roam-index org-roam-index-file))
        (find-file org-roam-index)))
    
    (use-package org
      :defer t
      :config
      (customize-set-variable 'org-link-descriptive t)
    
      (add-to-list 'org-agenda-files
                   "~/Documents/todo.org")
    
      (setq org-directory "~/Documents"
            org-default-notes-file (concat org-directory "/todo.org")))
    

YAML

(use-package yaml-mode
  :defer t)

Коммуникации

Gnus


Telega

(use-package telega
  :bind (("C-c t" . telega-prefix-map)))

Mastodon

(use-package mastodon
  :defer t
  :config
  (setq mastodon-active-user "w96k"
          mastodon-instance-url "https://fosstodon.org/"))

Разное

*Highlight

(use-package highlight
  :defer t)

Минорные твики дефолтного имакса

  • Короткие ответы на вопросы
    (if (boundp 'use-short-answers)
      (setq use-short-answers t)
    (advice-add 'yes-or-no-p :override #'y-or-n-p))
    
  • Не сохранять дубликаты в killring
  • Подсвечивать текущую строку
    (global-hl-line-mode t)
    
  • Автодополнение в echo при M-x и других командах
    (icomplete-mode t)
    
  • Проверять орфографию
    (flyspell-mode t)
    
  • Не спрашивать о несуществующих буферах
    (setq-default confirm-nonexistent-file-or-buffer t)
    
  • Переключение буферов
    (global-set-key (kbd "M-o")  'mode-line-other-buffer)
    
  • Минорные твики
    ;; (setq redisplay-dont-pause t)
    
    (setq select-enable-clipboard t
            select-enable-primary t)
    
    (setq completions-detailed nil)
    
    (setq kill-buffer-delete-auto-save-files t)
    (setq next-error-message-highlight t)
    
    (setq mode-line-compact 'long)
    
    (setq completions-group t)
    
    ;;(set-frame-parameter nil 'internal-border-width 0)
    
    ;; (set-window-buffer nil (current-buffer))
    
    (setq default-directory "~/"
            custom-safe-themes t
            delete-old-versions t
            enable-local-variables t)
    
  • Shell
    (setq ansi-color-for-comint-mode t)
    (setq shell-command-prompt-show-cwd t)
    
  • Переменная PATH в eshell
    (setq exec-path-from-shell-variables
            '("PATH" "MANPATH"))
    
    (when (and (memq window-system '(mac ns x))
                 (not (eq system-type 'berkeley-unix)))
      (exec-path-from-shell-initialize))
    
  • Отображение номера колонки
    (column-number-mode)
    
  • nobreak символы
    (setq nobreak-char-display nil)
    
  • Меню
  • Сохранять временные файлы не в той же директории
    (defvar backup-dir "~/.emacs.d/backups/")
    
    (setq
     backup-by-copying t
     backup-directory-alist
     '(("~/.emacs.d/backups/"))
     version-control nil)
    
  • Календарь

    Делаем начало недели в понедельник.

    (setq calendar-week-start-day 1)
    
  • Вернуться в предыдущий буфер
    (define-key global-map (kbd "C-q C-q") 'previous-buffer)
    (define-key global-map (kbd "C-S-q C-S-q") 'next-buffer)
    
  • Смена раскладки (EN / RU) и поддержка биндов на других языках

    Работает на C-\

    (set-input-method "russian-computer")
    (toggle-input-method)
    
  • Требовать создания последней пустой строки
    (setq require-final-newline t)
    
  • Стирать текст на C-h как в Bash

    И переназначаем старые бинды

    (define-key global-map (kbd "C-h") 'delete-backward-char)
    (define-key global-map (kbd "C-c h") 'help-command)
    
  • Bash completion
    (use-package bash-completion
      :config (bash-completion-setup))
    
  • Поддержка CamelCase в навигации
    (global-subword-mode 1)
    

Браузер

(setq browse-url-browser-function #'eww-browse-url)

(add-hook 'eww-mode-hook
            (lambda ()
              (set-fill-column 80)
              (display-fill-column-indicator-mode)
              (visual-fill-column-mode)))

Tramp

(add-to-list 'tramp-remote-path 'tramp-own-remote-path)

Docker

(use-package docker :defer t)
(use-package docker-compose-mode :defer t)

Debian

Инструменты для работы с пакетным менеджером Debian'а apt'ом и смежными инструментами.

(load "debian-el-autoloads")
(load "dpkg-dev-el-autoloads")

Guix

;; (use-package geiser-guile :defer t)

(use-package guix
  :defer t
  :config
  (setq geiser-guile-binary "guile")
  (with-eval-after-load 'geiser-guile
    (progn
      (add-to-list 'geiser-guile-load-path "~/projects/guix/")))

  (let ((guix-copyright "~/projects/guix/etc/copyright.el"))
    (if (file-exists-p guix-copyright)
        (load-file "~/projects/guix/etc/copyright.el")))

  (setq copyright-names-regexp
        (format "%s <%s>" user-full-name user-mail-address)))

Nix

(use-package nix)

Direnv

(when (package-loaded? "direnv")
    (direnv-mode))

Баг-трекеры

  • Debbugs

PDF

Увеличение/уменьшение шрифта

(defun zoom-in ()
  (interactive)
  (let ((x (+ (face-attribute 'default :height)
                10)))
    (set-face-attribute 'default nil :height x)
    (set-face-attribute 'mode-line nil :height x)
    (set-face-attribute 'mode-line-inactive nil :height x)
    (set-face-attribute 'mode-line-position-face nil :height x)))

(defun zoom-out ()
  (interactive)
  (let ((x (- (face-attribute 'default :height)
                10)))
    (set-face-attribute 'default nil :height x)
    (set-face-attribute 'mode-line nil :height x)
    (set-face-attribute 'mode-line-inactive nil :height x)
    (set-face-attribute 'mode-line-position-face nil :height x)))

(define-key global-map (kbd "C-=") 'zoom-in)
(define-key global-map (kbd "C-+") 'zoom-out)

Автокомплит у yes-or-no

Полный экран

Открывать Emacs на полный экран

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

Фуллскрин

Отображать ровно столько строчек, сколько вмещает экран.

Не работает с native-comp.

(toggle-frame-fullscreen)

(defun fullscreen ()
"Fullscreen."
(interactive)
(x-send-client-message nil 0 nil "_NET_WM_STATE" 32
                         ;; if first parameter is '1', can't toggle fullscreen status
                         '(1 "_NET_WM_STATE_FULLSCREEN" 0)))

Удаление буфера и файла

(defun delete-file-and-buffer ()
  "Kill the current buffer and deletes the file it is visiting."
  (interactive)
  (let ((filename (buffer-file-name)))
    (if filename
          (if (y-or-n-p (concat "Do you really want to delete file " filename " ?"))
              (progn
                (delete-file filename)
                (message "Deleted file %s." filename)
                (kill-buffer)))
        (message "Not a file visiting buffer!"))))

Длинные строки

;; Better support for files with long lines
(setq-default bidi-paragraph-direction 'left-to-right)
(setq-default bidi-inhibit-bpa t)
(global-so-long-mode 1)

Make shebang (#!) file executable when saved

(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)

Enable savehist-mode for command history

(savehist-mode 1)

Ignore case sensitive in completions, search and etc

(setq completion-ignore-case t
        read-buffer-completion-ignore-case t
        read-file-name-completion-ignore-case t)

Make scripts executable automatically

(add-hook 'after-save-hook
            'executable-make-buffer-file-executable-if-script-p)

F1 for M-x shell and F2 for grep

(global-set-key (kbd "<f1>") 'shell)
(global-set-key (kbd "<f2>") 'rgrep)

Hippie expand

(global-set-key [remap dabbrev-expand] 'hippie-expand)

Window Divider

(window-divider-mode t)

Use specific font for major modes

(buffer-face-mode t)

(defun set-normal-font ()
  "Set normal weight font in current buffer"
  (interactive)
  (buffer-face-mode 1)
  (setq buffer-face-mode-face '(:weight normal))
  (buffer-face-mode))

;; Use monospaced font faces in current buffer
(defun set-bold-font ()
  "Sets a bold font in current buffer"
  (interactive)
  (buffer-face-mode 1)
  (setq buffer-face-mode-face '(:weight bold))
  (buffer-face-mode))

(add-hook 'dired-mode-hook 'set-normal-font)
(add-hook 'org-mode-hook 'set-normal-font)
(add-hook 'Info-mode-hook 'set-normal-font)

No rights reserved

2024-10-30 Wed 19:20