#+TITLE: Конфигурация Emacs #+AUTHOR: Кириллов Михаил #+OPTIONS: toc:nil #+PROPERTY: header-args:elisp :results silent #+STARTUP: showeverything * Вклады Конфигурация составлена из моего кода, а также кода из конфигураций других людей. Их настолько, что все перечислять я не смогу, но оставлю интересные конфигурации других людей, в которые я время от времени заглядываю. * Лицензия Я выступаю против копирайта и интеллектуальной собственности в целом, поэтому стараюсь копирайт избегать. По этой причине свой код распространяю на правах общественного достояния вашей страны. Для этого используется лицензия [[https://creativecommons.org/publicdomain/zero/1.0/][CC0]]. Если кратко, то можете использовать без ограничений вплоть до полной приватизации всего контента. К сожалению за чужие сниппеты не могу ручаться, они распространяются по своим лицензиям и я их не указывал, впрочем всё равно никто это не проверяет и я бы не стал напрягаться из-за авторских прав на конфигурацию текстового редактора. * О конфигурации Минимальная конфигурация Emacs. Пакеты ставлю через Guix или package.el (elpa и melpa), для разделения ответственности использую грамотное программирование при помощи org-mode. Версия Emacs 28+. - В Guix пакет ~emacs-next~ - В FreeBSD пакет ~emacs-devel~ - В Ubuntu [[https://launchpad.net/~kelleyk/+archive/ubuntu/emacs][PPA emacs28]] и пакет ~emacs28-native~ Из программирования поддерживаются /C/, Java, /Python/, /Common Lisp / Scheme/, Haskell, Idris, Ocaml, /Ruby/, PHP, /SML/, SQL, Erlang, редактирование веб-шаблонов и различных форматов конфигураций. Какие-то языки в лучшей мере настроены, какие-то хуже, но есть почти все плюс-минус популярные. Для систем контроля версий использую встроенный /VC/ и в некоторых случаях /Magit/. Для входа в виртуальные среды используется Direnv. Для ведения заметок использую методологию Zettelkasten при помощи org-roam. Для доступа к оффлайн википедии и другим ресурсам Kiwix клиент, который стучится на сервер, который стоит дома. Для коммуникаций клиент для Telegram /telega/, для IRC /erc/ и электронной почты /gnus/, для Mastodon mastodon.el. Для системного администрирования имеют пакеты для работы с Debian, NixOS, Guix. Также есть поддержка Docker, Docker-compose: можно запускать/стопать контейнеры, а также залетать в них через TRAMP. Для установки необходимо установить пакеты Emacs из ~../../guix/user.scm~ и выполнить tangle файла при помощи /M-x org-babel-tangle-file/. В дальнейшем для развёртывания конфигурации можно использовать /M-x config-tangle/ или /M-x config-load/. Данная конфигурация доступна также в сети интернет по адресу, но так как сайт обновляется нечасто, то там может лежать старая версия: https://w96k.dev/emacs.html Исходники конфигурации лежат на Sourcehut: https://git.sr.ht/~w96k/dotfiles/tree/master/item/emacs Распространяется на условиях свободной лицензии [[https://gnu.org/licenses/gpl-3.0.ru.html][GNU GPL v3]], реиспользование одобряется пока распространяется под той же лицензией. * Пакеты Данная конфигурация использует следующие пакеты: - Avy :: Прыжки по тексту - Anaconda :: Поддержка Python - Auctex :: Поддержка Tex и LaTeX - Browse Kill Ring :: Обзор буфера обмена - Haskell Mode :: Поддержка языка Haskell - Idris Mode :: Поддержка языка Idris - Magit :: Интерфейс к git - Gitpatch :: Создание патчей - Goto Cgh :: Переход к последнему изменению в буфере - Debbuge :: Интерфейс debbugs (репорт багов Debian) - Deft :: Полнотекстовый поиск - Direnv :: Изменение окружения при "входе" в директорию - Docker и Docker Compose :: Моды для поддержки контейнерных технологий - Exec Path From Shell :: Синхронизация PATH переменной из шелла - Expand Region :: Семантическое расширение выделения на курсоре - Robe :: Прыжки по определениям Ruby - Geiser :: Repl для языка Scheme - Guix :: Интерфейс к Guix - Org Roam :: Zettelkasten заметки в org-mode - Gnuplot :: Программное рисование графиков - Nix Mode :: Поддержка языка Nix - Pdf Tools :: Рендер PDF файлов в Emacs - PHP Mode :: Поддержка языка PHP - Kiwix :: Чтение скачанных архивов веб-страниц - SML Mode :: Поддержка языка Standard ML - Sly/Slime :: REPL языка Common Lisp - Simple HTTPD :: HTTP Сервер на elisp - Telega :: Интерфейс к Telegram - Treemacs :: Сайдбар для навигации по проекту - Undo Tree :: Визуализация дерева отмен - Yasnippet и Yasnippet Snippets :: Сниппеты для текстов и ЯПов - Web Mode :: Поддержка шаблонов HTML и прочего Следующий блок нужен для тех, кто хочет использовать встроенный пакетный менеджер. Я использую Guix для большей части взаимодействий со сторонним кодом. #+begin_src elisp :tangle nil (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) (progn (package-refresh-contents) (package-install 'avy) (package-install 'php-mode) (package-install 'phps-mode) ;; (package-install 'anzu) (package-install 'anaconda-mode) (package-install 'auctex) ;; (package-install 'rmsbolt) ;; (package-install 'beginend) ;; (package-install 'composer) (package-install 'cinspect) (package-install 'debian-el) (package-install 'dpkg-dev-el) (package-install 'edebug-inline-result) ;;(package-install 'haskell-mode) ;;(package-install 'idris-mode) (package-install 'magit) (package-install 'git-timemachine) (package-install 'git-dwim) (package-install 'gitpatch) (package-install 'goto-chg) (package-install 'debbugs) ;;(package-install 'deft) ;; (package-install 'direnv) (package-install 'dumb-jump) (package-install 'docker) (package-install 'docker-cli) (package-install 'docker-tramp) (package-install 'docker-compose-mode) (package-install 'org-sql) ;;(package-install 'eglot) ;; (package-install 'eglot-java) ;; (package-install 'mastodon) ;; (package-install 'exec-path-from-shell) (package-install 'expand-region) ;; (package-install 'flymake-php) (package-install 'flycheck) (package-install 'flycheck-phpstan) (package-install 'phpactor) ;;(package-install 'robe) (package-install 'geiser) (package-install 'geiser-guile) (package-install 'guix) ;; (package-install 'git-gutter) ;; (package-install 'gnuplot) ;;(package-install 'swiper) ;;(package-install 'sqlite3) (package-install 'org-roam) ;; (package-install 'org-roam-ui) ;; (package-install 'org-download) ;; (package-install 'org-babel-eval-in-repl) ;;(package-install 'ob-php) ;; (package-install 'on-screen) ;;(package-install 'nix-mode) (package-install 'pdf-tools) ;;(package-install 'phpactor) ;; (package-install 'company-quickhelp) ;;(package-install 'ac-php) (package-install 'php-mode) (package-install 'php-quickhelp) (package-install 'phan) ;;(package-install 'php-cs-fixer) ;; (package-install 'company-php) ;;(package-install 'php-eldoc) ;;(package-install 'phps-mode) (package-install 'realgud) ;; (package-install 'realgud-xdebug) ;; (package-install 'kiwix) ;;(package-install 'sml-mode) (package-install 'sly) (package-install 'simple-httpd) (package-install 'sudo-edit) ;;(package-install 'treemacs) (package-install 'undo-tree) ;; (package-install 'yasnippet) ;; (package-install 'yasnippet-snippets) ;; (package-install 'vimrc-mode) ;; (package-install 'flymake-phpcs) ;; (package-install 'flymake-phpstan) ;; (package-install 'no-littering) (package-install 'web-mode) ;; (package-install 'which-key) ;; (package-install 'reverse-im) (package-install 'imenu-list) ;; (package-install 'isearch-mb) (package-install 'visual-fill-column) ;; (package-install 'browse-kill-ring) (package-install 'corfu) ;; (package-install 'inf-ruby) (package-install 'yaml-mode) ;; (package-install 'geben) (package-install 'link-hint) (package-install 'whole-line-or-region) (package-install 'quickrun) ;; (package-install 'psysh) ;; (package-install 'restclient) ) #+end_src *** Ручная компиляция #+begin_src elisp :tangle nil :results nil ;; (native-compile-async "~/.emacs.d/elpa/" 'recursively) (native-compile-async "~/.guix-profile/share/emacs/site-lisp" 'recursively) ;; block until native compilation has finished (while (or comp-files-queue (> (comp-async-runnings) 0)) #+end_src ** Отключаем ненужные загрузки #+begin_src emacs-lisp :tangle nil ;; Disable guix autoloading and x resources loading (setq site-run-file nil) #+end_src ** EXWM #+begin_src emacs-lisp :tangle nil (require 'exwm) (require 'exwm-config) (exwm-config-example) #+end_src ** Редакируем GUI Удаляем ненужные бары, меняем шрифт и модлайн. Использую дефолтный для шрифт DeJavu или недефолтный Agave, так как он является одним из самых интернациональных шрифтов по количеству доступных символов после Unifont. Unifont я не стал использовать, потому что иксы замыливают этот пиксельный шрифт, что делает его использование крайне неприятным. #+begin_src emacs-lisp :tangle nil ;; Change mode-line-modes to show only major mode (defvar mode-line-major-mode (let ((recursive-edit-help-echo "Recursive edit, type C-M-c to get out")) (list (propertize "%[" 'help-echo recursive-edit-help-echo) `(:propertize ("" mode-name) help-echo "Major mode\n\ mouse-1: Display major mode menu\n\ mouse-2: Show help for major mode\n\ mouse-3: Toggle minor modes" mouse-face mode-line-highlight local-map ,mode-line-major-mode-keymap) '("" mode-line-process) (propertize "%n" 'help-echo "mouse-2: Remove narrowing from buffer" 'mouse-face 'mode-line-highlight 'local-map (make-mode-line-mouse-map 'mouse-2 #'mode-line-widen)) (propertize "%]" 'help-echo recursive-edit-help-echo) " ")) "Mode line construct for displaying major and minor modes.") (put 'mode-line-major-mode 'risky-local-variable t) ;; Change mode-line-format (setq-default mode-line-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client mode-line-modified mode-line-remote mode-line-frame-identification ;; long-path mode-line-buffer-identification mode-line-misc-info " " mode-line-major-mode " " vc-mode " " mode-line-position mode-line-end-spaces )) #+end_src #+begin_src emacs-lisp :tangle nil ;; Do not resize the frame at this early stage. (setq frame-inhibit-implied-resize t) (setq use-dialog-box nil) ;;; Disable some gui (scroll-bar-mode -1) (tool-bar-mode -1) (menu-bar-mode -1) ;;(tooltip-mode -1) ;;; Changing emacs default setting through customize (custom-set-variables '(fill-column 72) '(git-gutter:added-sign " ") '(git-gutter:deleted-sign " ") '(git-gutter:modified-sign " ") '(git-gutter:unchanged-sign " ") '(lsp-headerline-breadcrumb-enable nil) '(scroll-bar-mode 'nil) '(scroll-bar-adjust-thumb-portion nil) '(tool-bar-position 'bottom) '(tool-bar-style 'both-horiz)) (custom-set-faces '(default ((t (:height 140 :family "Jetbrains Mono" :embolden t)))) '(region ((t (:background "gray85")))) '(mode-line ((t (:background "grey70" :foreground "grey10")))) '(mode-line-inactive ((t (:inherit mode-line :background "grey90" :foreground "grey20" :box (:line-width (-2 . -2) :color "grey85") :weight light)))) '(mode-line-buffer-id ((t (:weight bold)))) '(mode-line-emphasis ((t (:weight bold)))) '(lsp-modeline-code-actions-face ((t :inherit mode-line :height 100))) '(tool-bar ((t (:background "grey80" :foreground "grey10")))) '(fill-column-indicator ((t (:foreground "grey95")))) '(hl-line ((t (:background "gray95")))) '(fringe ((t (:background "grey87")))) '(header-line ((t (:inherit mode-line :background "grey90")))) '(vertical-border ((t (:foreground "grey90")))) '(window-divider ((t (:foreground "gray90"))))) (set-fringe-style (cons 7 7)) (defun switch-gui () "Disable/enable menu-bar and tool-bar." (interactive) (if menu-bar-mode (progn (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1)) (progn (menu-bar-mode 1) (tool-bar-mode 1) (scroll-bar-mode 1)))) (defun switch-scroll-bar () "Disable/enable scroll-bar." (interactive) (if scroll-bar-mode (scroll-bar-mode -1) (scroll-bar-mode))) (define-key global-map (kbd "") 'switch-gui) (define-key global-map (kbd "") 'switch-scroll-bar) (provide 'early-init) ;;; early-init.el ends here #+end_src ** Инициализируем остальной конфиг Следующие блоки кода выводят в файл init.el. #+begin_src emacs-lisp :tangle init.el ;; -*- lexical-binding: t -*- ;; Show/Hide errors ;; (setq debug-on-error nil) ;; (setq debug-on-quit nil) (require 'package) (package-initialize) (defun package-loaded? (string) (if (or (cl-member string package-activated-list :test #'string=) (ignore-errors (load (concat string "-autoloads")))) t (progn (message (concat "Package " string " is not loaded")) 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) #+end_src * Meta ** Обо мне #+BEGIN_SRC emacs-lisp :tangle init.el ;; Information about me (setq user-full-name "Mikhail Kirillov" user-mail-address "w96k@runbox.com") #+END_SRC ** Конфигурация Базовые функции для манипулирования конфигом в дальнейшем, чтобы не приходилось танглить вручную. #+BEGIN_SRC emacs-lisp :tangle init.el (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)) (defun config-load () (interactive) (org-babel-load-file (concat config-dotfiles-path config-name) t)) #+END_SRC * Внешний вид ** Отображение номера строк и пробелов Изначально они отключены, но можно вызвать по клавише F7. #+BEGIN_SRC emacs-lisp :tangle init.el (define-key global-map (kbd "") 'global-display-line-numbers-mode) (define-key global-map (kbd "") 'whitespace-mode) #+END_SRC * Редактирование ** Файловый менеджер #+BEGIN_SRC emacs-lisp :tangle init.el ;; Show files in KiB (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) #+END_SRC ** Линтер Использую встроенный Flymake и Flycheck *** Flymake #+BEGIN_SRC emacs-lisp :tangle nil ;;(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) #+END_SRC *** Flycheck #+BEGIN_SRC emacs-lisp :tangle nil ;; (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)) #+END_SRC ** Дерево проекта Возможно в дальнейшем откажусь от этого пакета, так как по факту им пользуюсь нечасто. Он предоставляет дерево проектов, как в IDE. #+BEGIN_SRC emacs-lisp :tangle nil (when (package-loaded? "treemacs") (progn (setq treemacs-width 50 treemacs-show-cursor t treemacs-position 'right treemacs-indentation 1 treemacs-tag-follow-mode t treemacs-fringe-indicator-mode nil) (define-key global-map (kbd "C-x C-d") 'treemacs))) #+END_SRC ** Дерево imenu #+begin_src emacs-lisp :tangle init.el ;; (when (package-loaded? "imenu-list") (setq imenu-list-focus-after-activation nil imenu-list-auto-resize nil imenu-list-mode-line-format '() imenu-list-size 0.4) (global-set-key (kbd "C-x C-d") #'imenu-list-smart-toggle) ;; ) #+end_src ** Better Isearch #+begin_src emacs-lisp :tangle nil (when (package-loaded? "isearch-mb") (progn (isearch-mb-mode t) (global-set-key (kbd "C-s") 'isearch-forward-regexp) (global-set-key (kbd "C-r") 'isearch-backward-regexp))) #+end_src ** Система контроля версий Модуль 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/ #+BEGIN_SRC emacs-lisp :tangle init.el (setq vc-command-messages t) (global-set-key "\C-xvB" 'git-branch-next-action) ;; Use magit only when built-in VC fails (when (package-loaded? "magit") (progn (setq magit-refresh-status-buffer nil) (global-set-key (kbd "C-x g") 'magit-status))) (package-loaded? "git-timemachine") #+END_SRC ** Прыжки #+BEGIN_SRC emacs-lisp :tangle init.el (when (package-loaded? "avy") (progn (define-key global-map (kbd "M-s M-s") 'avy-goto-char) (define-key global-map (kbd "M-s s") 'avy-goto-char) (define-key global-map (kbd "M-s g") 'avy-goto-line) (define-key global-map (kbd "M-s l") 'avy-goto-char-in-line) (define-key global-map (kbd "M-s M-l") 'avy-goto-char-in-line) ;; Rewrite default bind to avy (define-key global-map (kbd "M-g g") 'avy-goto-line) (define-key global-map (kbd "M-g M-g") 'avy-goto-line))) (when (package-loaded? "link-hint") (progn (define-key global-map (kbd "M-s j") 'link-hint-open-link))) ;; Прыжок на последнее изменение (when (package-loaded? "goto-chg") (progn (setq glc-default-span 2) (define-key global-map (kbd "C-z") 'goto-last-change) (define-key global-map (kbd "M-z") 'goto-last-change-reverse))) ;; Dumb Jump (when (package-loaded? "dumb-jump") (progn (define-key global-map (kbd "C-.") 'dumb-jump-go))) #+END_SRC ** Проекты Использую встроенный project.el I use built-in project.el ** Ограничение ширины строки #+BEGIN_SRC emacs-lisp :tangle init.el (when (package-loaded? "visual-fill-column") (progn ;;; Column width limit highlighter (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))))) #+END_SRC ** Подсвечивание парных скобок ** Ввод парных скобок и кавычек (electric) #+BEGIN_SRC emacs-lisp :tangle init.el ;;; Input of pair delimiters (electric-pair-mode) (add-hook 'prog-mode-hook 'electric-pair-mode) ;; (add-hook 'prog-mode-hook 'rainbow-identifiers-mode) #+END_SRC ** Kill-ring #+BEGIN_SRC emacs-lisp :tangle nil (when (package-loaded? "browse-kill-ring") (define-key global-map (kbd "C-M-y") 'browse-kill-ring)) #+END_SRC ** Tags Для прыжков и поиска функций/классов и т.д. #+BEGIN_SRC emacs-lisp :tangle nil (setq path-to-ctags "~/.guix-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)))) #+END_SRC ** Дополнение ** Дебаггер #+begin_src emacs-lisp :tangle nil (when (package-loaded? "realgud") (load "~/.emacs.d/site-lisp/realgud-xdebug/realgud-xdebug.el")) #+end_src #+begin_src emacs-lisp :tangle nil (when (package-loaded? "geben") (setq geben-dbgp-default-port 9003)) #+end_src *** Автодополнение кода и документация По большей части я использую дефолтный Completion Buffer и Corfu #+begin_src elisp :tangle nil (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))) #+end_src *** Модификация дефолта #+BEGIN_SRC emacs-lisp :tangle nil (setq completion-styles '(basic partial-completion substring flex emacs22) completion-ignore-case t read-buffer-completion-ignore-case t read-file-name-completion-ignore-case t) #+END_SRC *** Агрессивный дефолтный комплит #+BEGIN_SRC emacs-lisp :tangle nil (setq aggressive-completion-delay 0.5) (aggressive-completion-mode t) #+END_SRC ** Полнотекстовый поиск Для выхода из поиска -- C-c C-q #+begin_src emacs-lisp :tangle nil (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") #+end_src ** Визуализирование откатов При помощи пакета undo-tree #+begin_src emacs-lisp :tangle init.el (when (package-loaded? "undo-tree") (progn (add-hook 'prog-mode-hook #'undo-tree-mode) (add-hook 'org-mode-hook #'undo-tree-mode) (setq undo-tree-auto-save-history nil))) #+end_src ** Сниппеты #+begin_src emacs-lisp :tangle nil (when (package-loaded? "yasnippet") (progn (add-hook 'prog-mode-hook #'yas-minor-mode))) #+end_src ** Клиент LSP #+begin_src emacs-lisp :tangle init.el ;; (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))) #+end_src ** Линтеры #+begin_src emacs-lisp :tangle nil (defun my-php-mode-setup () "My PHP-mode hook." (require 'flycheck-phpstan) (flycheck-mode t)) (add-hook 'php-mode-hook 'my-php-mode-setup) #+end_src #+BEGIN_SRC emacs-lisp :tangle nil ;; (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) #+END_SRC ** Выделение #+BEGIN_SRC emacs-lisp :tangle init.el (when (package-loaded? "expand-region") (global-set-key (kbd "C-=") 'er/expand-region)) #+END_SRC ** Сессия #+BEGIN_SRC emacs-lisp :tangle nil (desktop-save-mode 1) #+END_SRC ** Скроллинг #+BEGIN_SRC emacs-lisp :tangle init.el (setq scroll-margin 0) #+END_SRC ** Поиск *** Isearch #+begin_src emacs-lisp :tangle init.el (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)) #+end_src *** Подсчёт кандидатов #+BEGIN_SRC emacs-lisp :tangle nil (global-anzu-mode t) #+END_SRC *** Swiper (не используется) #+BEGIN_SRC emacs-lisp :result nil :tangle nil (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) #+END_SRC ** Подсказка биндов Пакет Which-key #+begin_src elisp :tangle nil (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) #+end_src ** Права суперпользователя Sudo-edit #+begin_src emacs-lisp (package-loaded? "sudo-edit") #+end_src ** Промежуточный код Показывает собранное состояние будь то собранный куски на ассемблере или байт-код при помощи пакета RMSbolt. #+begin_src emacs-lisp :tangle nil (add-hook 'prog-mode-hook 'rmsbolt-mode) #+end_src ** Быстрый запуск программы #+begin_src emacs-lisp :tangle nil ;; (when (package-loaded? "quickrun") ;; (define-key global-map (kbd "C-c C-c") 'quickrun)) #+end_src * Языки программирования ** Common Lisp *** REPL #+BEGIN_SRC emacs-lisp :tangle nil (load "sly-autoloads") (setq sly-lisp-implementations '((clisp ("clisp")) (cmucl ("cmucl" "-quiet")) (sbcl ("/opt/sbcl/bin/sbcl") :coding-system utf-8-unix))) #+END_SRC ** Erlang #+BEGIN_SRC emacs-lisp :tangle nil (load "erlang-autoloads") #+END_SRC ** Ruby #+BEGIN_SRC emacs-lisp :tangle nil (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)) #+END_SRC ** Scheme #+BEGIN_SRC emacs-lisp :tangle init.el (setq geiser-active-implementations '("guile")) #+END_SRC ** Python *** Автодополнение и линт #+BEGIN_SRC emacs-lisp :tangle nil (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) #+END_SRC *** Прыжки в функции стандартной библиотеки на си ** SML #+BEGIN_SRC emacs-lisp :tangle nil (add-hook 'sml-mode-hook 'sml-mode) #+END_SRC ** PHP *** PHP-Mode Необходимо скачать и распаковать мануал PHP (в формате html) в директорию ~~/.emacs.d/php-manual/~. #+begin_src emacs-lisp :tangle nil ;; (add-to-list 'load-path "~/.emacs.d/site-lisp/realgud-xdebug/") ;; (require 'realgud-xdebug) ;; (defun init-php-mode () ;; (eglot-ensure)) (with-eval-after-load 'php-mode ;; (add-hook 'php-mode-hook #'init-php-mode) ) (when (package-loaded? "php-mode") (progn (add-hook 'php-mode-hook 'php-enable-symfony2-coding-style) (setq lsp-intelephense-php-version "8.1.16") (defvar phpactor-executable "~/.bin/phpactor") (custom-set-variables '(lsp-phpactor-path "~/usr/local/bin/phpactor")) (add-hook 'php-mode-hook '(lambda () ;; (require 'yasnippet) ;; (require 'yasnippet-snippets) (set-fill-column 120) ;; (make-local-variable 'eldoc-documentation-function) ;; (setq eldoc-documentation-function ;; 'phpactor-hover) ;; (yas-minor-mode t) (define-key php-mode-map (kbd "C-c h") 'php-quickhelp-at-point))) (setq php-manual-path "~/php/php-manual/" php-quickhelp-dir "~/php/php-manual/" php-quickhelp--dest "~/.emacs.d/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))) )) #+end_src *** Composer #+begin_src emacs-lisp :tangle init.el (setq composer-executable-bin "~/.bin/composer") #+end_src *** Flymake PHP *** REPL *** LSP сервер PHPactor #+begin_src emacs-lisp :tangle nil (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)) #+end_src *** Transient меню #+begin_src emacs-lisp :tangle nil (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)]]) #+end_src * Языки декларирования ** SQL to install lsp-server called sqls https://emacs-lsp.github.io/lsp-mode/page/lsp-sqls/ #+BEGIN_SRC emacs-lisp :tangle nil ;; 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")))) #+END_SRC The main way to interact with SQL is using org-mode #+begin_src emacs-lisp :tangle nil (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)))) #+end_src ** Веб шаблоны *** Web-mode #+BEGIN_SRC emacs-lisp :tangle init.el (when (package-loaded? "web-mode") (progn (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))) #+END_SRC ** Org *** Org-mode #+BEGIN_SRC emacs-lisp :tangle init.el (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))) (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 "C-c l") 'org-store-link) (global-set-key (kbd "C-c a") 'org-agenda) (global-set-key (kbd "C-c c") 'org-capture) ;; (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) (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)))) #+END_SRC *** Org-ref (не используется) #+begin_src emacs-lisp :tangle nil (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/") #+end_src *** Org-roam #+begin_src emacs-lisp :tangle init.el (when (package-loaded? "org-roam") (progn (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))) (define-key global-map (kbd "C-c n l") 'org-roam-node-insert) (define-key global-map (kbd "C-c n f") 'org-roam-node-find) (define-key global-map (kbd "C-c n b") 'org-roam-buffer-toggle) (define-key global-map (kbd "C-c n t t") 'org-roam-tag-add) (define-key global-map (kbd "C-c n t r") 'org-roam-tag-remove) (define-key global-map (kbd "C-c n i") 'org-roam-jump-to-index) (define-key global-map (kbd "C-c n g") 'org-roam-graph) (define-key global-map (kbd "C-c n d") 'org-roam-db-build-cache) (define-key global-map (kbd "C-c n r") 'org-roam-node-random) (define-key global-map (kbd "C-c n j") 'org-roam-dailies-find-date))) (customize-set-variable 'org-link-descriptive t) #+end_src *** Агенда и Capture #+begin_src emacs-lisp :tangle init.el (add-to-list 'org-agenda-files "~/Documents/todo.org") (setq org-directory "~/Documents" org-default-notes-file (concat org-directory "/todo.org")) #+end_src ** YAML #+begin_src emacs-lisp (package-loaded? "yaml-mode") #+end_src * Коммуникации ** Gnus #+begin_src emacs-lisp :tangle init.el #+end_src ** Telega #+BEGIN_SRC emacs-lisp :tangle init.el (when (package-loaded? "telega") (setq telega-filter-custom-show-folders t telega-chat-fill-column 40 telega-root-fill-column 60 telega-url-shorten-use-images t) (define-key global-map (kbd "C-c t") telega-prefix-map)) #+END_SRC ** Mastodon #+begin_src emacs-lisp :tangle nil (when (package-loaded? "mastodon") (setq mastodon-active-user "w96k" mastodon-instance-url "https://fosstodon.org/")) #+end_src ** LLM #+begin_src emacs-lisp #+end_src * Наука * Разное ** Минорные твики дефолтного имакса *** Короткие ответы на вопросы #+begin_src emacs-lisp :tangle init.el (if (boundp 'use-short-answers) (setq use-short-answers t) (advice-add 'yes-or-no-p :override #'y-or-n-p)) #+end_src *** Не сохранять дубликаты в killring *** Подсвечивать текущую строку #+begin_src emacs-lisp :tangle nil (global-hl-line-mode 1) #+end_src *** Открывать список буферов в отдельном фрейме #+begin_src emacs-lisp :tangle nil (add-to-list 'special-display-buffer-names "*Buffer List*") (setq Buffer-menu-files-only t) #+end_src *** Автодополнение в echo при M-x и других командах #+begin_src emacs-lisp :tangle init.el (icomplete-mode 1) #+end_src *** Проверять орфографию #+begin_src emacs-lisp :tangle init.el (flyspell-mode 1) #+end_src *** Не спрашивать о несуществующих буферах #+BEGIN_SRC emacs-lisp :tangle init.el (setq-default confirm-nonexistent-file-or-buffer t) #+END_SRC *** Переключение буферов #+BEGIN_SRC emacs-lisp :tangle init.el (global-set-key (kbd "M-o") 'mode-line-other-buffer) #+END_SRC *** Минорные твики #+begin_src emacs-lisp :tangle init.el ;; (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 "~/" delete-seleciton-mode t inhibit-startup-message t initial-scratch-message nil custom-safe-themes t delete-old-versions t confirm-kill-processes nil enable-local-variables t) #+end_src *** Shell #+begin_src emacs-lisp :tangle init.el (setq ansi-color-for-comint-mode t) (setq shell-command-prompt-show-cwd t) #+end_src *** Переменная PATH в eshell #+BEGIN_SRC emacs-lisp :tangle nil (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)) #+END_SRC *** Отображение номера колонки #+BEGIN_SRC emacs-lisp :tangle init.el (column-number-mode) #+END_SRC *** nobreak символы #+BEGIN_SRC emacs-lisp :tangle init.el (setq nobreak-char-display nil) #+END_SRC *** Меню *** Сохранять временные файлы не в той же директории #+BEGIN_SRC emacs-lisp :tangle init.el (defvar backup-dir "~/.emacs.d/backups/") (setq backup-by-copying t backup-directory-alist '(("~/.emacs.d/backups/")) version-control nil) #+END_SRC *** Календарь Делаем начало недели в понедельник. #+BEGIN_SRC emacs-lisp :tangle init.el (setq calendar-week-start-day 1) #+END_SRC *** Вернуться в предыдущий буфер #+BEGIN_SRC emacs-lisp :tangle nil (define-key global-map (kbd "C-q C-q") 'previous-buffer) (define-key global-map (kbd "C-S-q C-S-q") 'next-buffer) #+END_SRC *** Смена раскладки (EN / RU) и поддержка биндов на других языках Работает на C-\ #+begin_src elisp :tangle init.el (set-input-method "russian-computer") (toggle-input-method) #+end_src *** Требовать создания последней пустой строки #+begin_src emacs-lisp :tangle init.el (setq require-final-newline t) #+end_src *** Стирать текст на C-h как в Bash И переназначаем старые бинды #+begin_src emacs-lisp :tangle nil (define-key global-map (kbd "C-h") 'delete-backward-char) (define-key global-map (kbd "C-c h") 'help-command) #+end_src *** Поддержка CamelCase в навигации #+begin_src emacs-lisp :tangle init.el (global-subword-mode 1) #+end_src *** Kills #+begin_src emacs-lisp :tangle init.el (define-key global-map (kbd "C-k") 'kill-region) (when (package-loaded? "whole-line-or-region") (whole-line-or-region-global-mode)) (define-key global-map (kbd "C-w") 'backward-kill-word) #+end_src ** Браузер #+begin_src emacs-lisp :tangle nil (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))) #+end_src ** Tramp #+begin_src emacs-lisp :tangle nil (add-to-list 'tramp-remote-path 'tramp-own-remote-path) #+end_src ** Docker #+begin_src emacs-lisp :tangle init.el (package-loaded? "docker") (package-loaded? "docker-compose-mode") #+end_src ** Debian Инструменты для работы с пакетным менеджером Debian'а apt'ом и смежными инструментами. #+begin_src elisp :tangle nil (load "debian-el-autoloads") (load "dpkg-dev-el-autoloads") #+end_src ** Guix #+begin_src emacs-lisp :tangle init.el (package-loaded? "geiser-guile") (package-loaded? "guix") (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)) #+end_src ** Nix #+begin_src emacs-lisp :tangle nil (package-loaded? "nix") #+end_src ** Direnv #+BEGIN_SRC emacs-lisp :tangle nil (when (package-loaded? "direnv") (direnv-mode)) #+END_SRC ** Баг-трекеры *** Debbugs ** PDF ** Увеличение/уменьшение шрифта #+BEGIN_SRC emacs-lisp :tangle nil (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) #+END_SRC ** Автокомплит у yes-or-no ** Полный экран Открывать Emacs на полный экран #+begin_src emacs-lisp :tangle nil (add-to-list 'default-frame-alist '(fullscreen . maximized)) #+end_src ** Фуллскрин Отображать ровно столько строчек, сколько вмещает экран. Не работает с native-comp. #+begin_src elisp :tangle nil (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))) #+end_src ** Удаление буфера и файла #+begin_src elisp :tangle init.el (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!")))) #+end_src ** Длинные строки #+begin_src emacs-lisp :tangle nil ;; 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) #+end_src ** Make shebang (#!) file executable when saved #+begin_src emacs-lisp :tangle init.el (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) #+end_src ** Enable savehist-mode for command history #+begin_src emacs-lisp :tangle init.el (savehist-mode 1) #+end_src ** Ignore case sensitive in completions, search and etc #+begin_src emacs-lisp :tangle init.el (setq completion-ignore-case t) #+end_src