Моя конфигурация Emacs Nickey Emacs Configuration
;; _ ________ ;; / | / / ____/___ ___ ____ ___________ ;; / |/ / __/ / __ `__ \/ __ `/ ___/ ___/ ;; / /| / /___/ / / / / / /_/ / /__(__ ) ;; /_/ |_/_____/_/ /_/ /_/\__,_/\___/____/
Я давно использую org-mode
для формирования файла инициализации Emacs, периодически переписывая его с нуля и перенося в него только самое необходимое из предыдущей версии. Раньше я комментировал все на английском языке, но в сети и так полно примеров на английском, так что пусть пока будет на русском.
Так как недавно я перебрался с Gnome на i3wm, я стал использовать emacs-daemon и терминальную версию редактора, так что наведение красоты в этот раз пока сюда не попало (кое-что, тем не менее, уже добавлено).
Вот конфигурации других людей, в которых я когда-то почерпнул что-то интересное (их, вообще-то, было много больше, но остальных сейчас не припомню). Порядок - алфавитный:
- Bozhidar Batsov GitHub
- Dawid Eckert GitHub
- Diego Zamboni GitHub Blog
- Mike Zamansky GitHub
- Sacha Chua GitHub Blog
Этот файл также доступен в моем блоге и на GitHub.
Запуск и инициализация
Персональная информация
Требуется, как минимум, для работы с почтой.
(setq user-full-name "Nikolay Brovko" user-mail-address "i@nickey.ru")
Установка пакетного менеджера straight.el
Давно руки чесались его попробовать, а теперь он мне нужен, чтобы подтягивать свои мелкие пакеты из git-репозиториев. Для этих целей необязательно было выбирать именно его, но а почему нет, собственно?
Код установки - копипаста из README проекта.
(defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage))
Настройка репозиториев и use-package
Используем Elpa
, Melpa
, Melpa Stable
и Org
.
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/") ("melpa-stable" . "https://stable.melpa.org/packages/") ("org" . "https://orgmode.org/elpa/")))
Загружаем пакет use-package
, предварительно установив, если необходимо.
(unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (require 'use-package)
Установка библиотек
Когда требуется быстро набросать функцию, автоматизирующую то или иное действие, наличие этих библиотек под рукой сильно облегчает жизнь.
- dash.el A modern list api for Emacs. No 'cl required.
- s.el The long lost Emacs string manipulation library.
- f.el Modern API for working with files and directories.
(dolist (library '(dash dash-functional s f)) (eval `(use-package ,library :ensure t)))
Переопределение custom-file
Дабы не захламлять .emacs
автоматически генерируемым мусором, перенаправляем его в другом месте.
(setq custom-file "~/.emacs.d/custom.el") (when (file-exists-p custom-file) (load custom-file))
Сохранение пути к конфигу
Дабы иметь возможность удобно обращаться к другим файлам в репозитории и открывать конфиг по горячим клавишам, запомним, где что лежит.
(setq n-nemacs-file (or buffer-file-name load-file-name) n-nemacs-dir (f-dirname n-nemacs-file))
Отключение бекапов и мусора возле рабочих файлов
Переносим все создаваемые редактором временные файлы и бекапы в ~/.emacs.d/backups/
. Локфайлы - выключаем.
(setq backup-directory-alist '((".*" . "~/.emacs.d/backups/"))) (setq auto-save-file-name-transforms '((".*" "~/.emacs.d/backups/" t))) (setq create-lockfiles nil)
Заменяем yes-or-no-p
на y-or-n-p
повсеместно
Жизнь слишком коротка, чтобы писать yes
или no
.
Так и не решил, относить это к инициализации или рабочему процессу, пока пусть будет здесь…
(fset #'yes-or-no-p #'y-or-n-p)
Не показывать стартовый экран
Не знаю, скольким людям он пригодился, как по мне - вещь не особенно полезная.
(setq inhibit-startup-screen 't)
Шрифт в GUI
Все таки периодически запускаю emacs в GUI, поэтому нужно установить фонт.
На ноуте экран меньше, поэтому определяем разрешение и для ноута устанавливаем меньший размер шрифта.
(let* ((default-font-family "JetBrains Mono") (default-font-size (if (< (x-display-pixel-width ":0") 1920) 11 13)) (default-font (format "%s %s" default-font-family default-font-size))) (if (functionp #'set-default-font) (set-default-font default-font) (set-frame-font default-font)) (add-to-list 'default-frame-alist `(font . ,default-font)))
Тема Dracula
(use-package dracula-theme :ensure t :config (load-theme 'dracula t))
Сокрытие верхнего меню, тулбара и скроллбара
Сначала оставил менюбар, чтобы проще было находить границы окна, но во-первых, он выбивается из темы оформления, а во-вторых, границы окна лучше выделить средствами оконного менеджера, так что опять скрываю.
Тулбар и скроллбар скрываю за компанию - в терминальной версии редактора его все равно нет.
(menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1)
Системный буфер обмена
Поскольку я использую терминальную версию Emacs, kill-ring редактора и системный clipboard ничего друг о друге не знают. Пакет xclip
решает эту проблему с помощью одноименной утилиты для командной строки.
(use-package xclip :ensure t :config (xclip-mode 1))
Diminish
для сокрытия минорных режимов
Зачастую случается так, что минорных режимов набирается с десяток, и в итоге они сжирают все место в модлайне. Чтобы скрывать очевидные режимы (например, включенные глобально - типа Undo Tree), используем Diminish
.
(use-package diminish
:ensure t)
all-the-icons
для отображения иконок
Наводит красоты в дашборде, treemacs и т. д.
(use-package all-the-icons
:ensure t)
Включим также отображение иконок в dired
.
(use-package all-the-icons-dired :ensure t :hook (dired-mode . all-the-icons-dired-mode))
Dashboard
в качестве стартового экрана
Полезно, чтобы утром быстро войти в курс дела, что делал вчера.
(use-package dashboard :ensure t :config (setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")) dashboard-startup-banner (f-join n-nemacs-dir "nemacs.png") dashboard-center-content t dashboard-set-init-info nil dashboard-set-heading-icons t dashboard-set-file-icons t) (dashboard-setup-startup-hook))
Рабочий процесс
Пробелы вместо табуляции
Не слушаем Ричарда Хендрикса и беспощадно ставим пробелы вместо табуляции.
(setq-default indent-tabs-mode nil
tab-width 4)
Удаление слова перед курсором как в bash
Я так и не понял, что удаляет Emacs по умолчанию по нажатию C-w
, но меня это не устраивает. Надо либо удалять выделенную область, либо слово перед курсором.
(defun n-kill-region-or-backward-word () (interactive) (call-interactively (if (use-region-p) #'kill-region #'backward-kill-word))) (global-set-key (kbd "C-w") #'n-kill-region-or-backward-word)
Выравнивание значений при присваивании (по символу равенства)
Я стараюсь держать символы равенства выровненными там, где это не нарушает стандарта кодирования языка или проекта. Пример ниже
foo = "bar"; hello = "world"; foobar = "baz";
(defun align-to-equals (begin end) "Align region to equal signs" (interactive "r") (align-regexp begin end "\\(\\s-*\\)=" 1 1 )) (global-set-key (kbd "M-n M-=") #'align-to-equals)
Editorconfig
Используем editorconfig для управления кодировкой, размером и стилем отступов и т. д.
(use-package editorconfig :ensure t :diminish editorconfig-mode :config (editorconfig-mode 1))
Отключение сворачивания по C-z
В терминале C-z
отправляет приложение в фоновый режим, что в случае с емаксом, который сам терминал открыть может, доставляет только лишние неудобства при случайном нажатии. Кто-то предпочитает назначить на это сочетание отмену последнего действия, мне же будет спокойнее, если оно вообще ничего делать не будет.
(global-set-key (kbd "C-z") #'ignore)
Переключение буферов по C-x C-b
bs-show
начал использовать еще в первые дни использования Emacs, с тех пор чего только не перепробовал, последней попыткой был helm-buffers-list
, но как по мне, это менее удобно, чем открыть список буферов, в котором обычно не более 5-10 штук и клавишами n
и p
выбрать нужный.
(global-set-key (kbd "C-x C-b") #'bs-show)
Перемещение по буферу с помощью Ace Jump
Использовать клавиши навигации - контрпродуктивно! Ace Jump
оцениваешь, попользовавшись им пару дней и поломав привычку перемещаться по тексту линейно.
(use-package ace-jump-mode :ensure t :bind (("C-c SPC" . #'ace-jump-mode)))
Переключение между окнами с помощью Ace Window
В общем-то схожий с Ace Jump
воркфлоу для переключения между окнами. Просто переназначаем C-x o
, который по дефолту используется для переключения на следующее окно. Поскольку правая рука после нажатия C-x o
находится в позиции u i o p
, используем эти клавиши в качестве шорткатов для окон.
(use-package ace-window :ensure t :bind ("C-x o" . #'ace-window) :config (setq aw-keys '(?u ?i ?o ?p ?j ?k ?l ?m) aw-ignore-current t))
Подсветка парных скобок
Для лисповых языков, да и не только, переоценить эту функцию очень сложно…
(show-paren-mode 1)
С помощью переменной show-paren-style
можно установить способ подсветки:
'expression
всё выражение между парными скобками'parenthesis
только сами скобки'mixed
смешанный вариант - в случае, если парная скобка находится в области видимости экрана, будут подсвечены только скобки, в противном случае - все выражение.
Сниппеты с yasnippet
Современные языки и фреймворки, вроде как, сильно сократили количество бойлерплейт-кода. Но, во-первых, не до нуля, а во-вторых, не все.
Добавляем директорию yas-snippets
в список директорий для поиска сниппетов. Поскольку она добавляется в начало списка, она же будет путем сохранения для сниппетов, добавляемых с помощью yas-new-snippet
.
Раньше каталог назывался просто snippets
, но это имя конфликтует с каталогом, создаваемым пакетом yasnippet-snippets
по пути ~/.emacs.d/
.
(use-package yasnippet :ensure t :diminish yas-minor-mode :config (progn (add-to-list 'yas-snippet-dirs (f-join n-nemacs-dir "yas-snippets")) (yas-global-mode 1)))
Чтобы не создавать все сниппеты руками, подключаем пакет yasnippet-snippets
, в который входит множество готовых сниппетов для большого количества мажорных режимов.
(use-package yasnippet-snippets :ensure t :after yasnippet)
Автодополнение скобок, кавычек, etc
Раньше я использовал autopair
, но сейчас заглянул к нему в репозиторий и как-то там безрадостно. Случайно наткнулся на smartparens
, его и буду пробовать - время покажет.
(use-package smartparens :ensure t :diminish smartparens-mode :config (progn (require 'smartparens-config) (smartparens-global-mode 1)))
Автокомплит с company
Сам по себе он мне без надобности, пользуюсь только с LSP, и то не всегда.
(use-package company
:ensure t)
Для красивых скриншотов добавлю еще иконки в буфер автокомплита.
(use-package company-box :ensure t :hook (company-mode . company-box-mode))
Управление git-репозиторием с Magit
Magit
- пожалуй, лучшая реализация интерфейса к git-репозиторию из всех, что мне попадались.
(use-package magit :ensure t :bind (("C-x g" . #'magit-status)))
ediff
создает дополнительный фрейм, что доставляет проблемы с фокусом и компоновкой окон на тайловых оконных менеджерах. Отключаем такое поведение.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
При использовании GPG-агента возникает проблема с использованием демона. Устанавливаем переменную окружения SSH_AUTH_SOCK
вручную.
(when-let ((ssh-auth-sock (s-trim (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh-auth-sock))
Writeroom
для работы над текстами
Если в процессе кодинга информация вроде имени открытого файла, текущей git-ветки, положения в документе идут строго на пользу, то при работе над постами в блог, документацией и tex-документами, она только мешает. Writeroom
отображает только текущий буфер, прячет модлайн, ограничивает текст по ширине и смещает его в центр окна (не путать с выравниванием по центру). Вкупе с переводом окна в фулл-скрин и увеличением шрифта это сильно помогает сосредоточиться на тексте.
(use-package writeroom-mode :ensure t :bind ("M-n M-w" . #'writeroom-mode))
Treemacs
дерево каталогов а-ля Sublime, VSCode, etc
Вообще говоря, я как-то привык жить без него, но почему бы и нет?
(use-package treemacs :ensure t :bind ("M-n M-n" . #'treemacs))
Проверка орфографии
flyspell
встроен в Emacs и использует утилиту aspell. Словари надо установить руками, средствами операционной системы
(use-package flyspell
:hook ((org-mode-hook . flyspell-mode)
(text-mode-hook . flyspell-mode)
(markdown-mode-hook . flyspell-mode)))
Untabify для всего буфера
По дефолту untabify работает для выделенной области или текущей строки, что неудобно, когда нужно заменить табы на пробелы во всем буфере.
(defun untabify-buffer () (interactive) (untabify (point-min) (point-max)))
Нормализация вертикальных отступов
Когда я вижу оставленные вертикальные отступы по 10 строк в коде, мне хочется отправиться домой к автору коммита для разъяснительной беседы. Ну и для недопущения подобного у себя, удобно использовать в before-save-hook
.
(defun group-empty-lines () (interactive) (save-excursion (replace-regexp "^\n\n*$" "" nil (point-min) (point-max) t)))
Режимы для различных языков программирования и разметки
За пару месяцев их набирается полтора-два десятка, так что буду добавлять по мере использования.
LSP
Language Server Protocol. Позволяет подтащить специфичные для языка фичи без реализации их средствами самого Emacs.
(use-package lsp-mode :ensure t) (use-package lsp-ui :ensure t) (use-package company-lsp :ensure t) (use-package lsp-treemacs :ensure t)
Лиспы
lispy-mode
Paredit не развивается, пробую вместо него сабж
(use-package lispy :ensure t :diminish lispy-mode :hook ((emacs-lisp-mode . lispy-mode) (scheme-mode . lispy-mode)))
geiser
для Scheme
(lambda ())
как(λ ())
Так код выглядит веселее и компактнее
(use-package prog-mode :hook ((emacs-lisp-mode scheme-mode) . prettify-symbols-mode))
Web-mode
для верстки
Незаменимая вещь для работы с html, php, twig и прочими html-подобными файлами. Умеет расставлять отступы, автоматически закрывает открываемые теги, комментирует-раскомментирует блок, переименовывает тег и многое другое.
(use-package web-mode :ensure t :config (progn (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode)) (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode)) (add-to-list 'auto-mode-alist '("\\.twig\\'" . web-mode)) (add-to-list 'web-mode-engines-alist '("php" . "\\.php\\'"))))
PHP
Тут и добавить нечего - пользуем php-mode
для работы с php-кодом. Требования невысоки - нормальная подсветка синтаксиса, автоматические отступы, открытие документации.
По умолчанию использовать стиль psr-2
.
(use-package php-mode :ensure t :config (add-hook 'php-mode-hook #'php-enable-psr2-coding-style))
JavaScript
Вообще говоря, js2
это минорный, а не мажорный режим, но и выносить его за пределы JavaScript-раздела смысла нет.
(use-package js2-mode :ensure t :config (add-hook 'js-mode-hook #'js2-minor-mode))
VALA
В последнее время редактировал и писал много кода на Vala и, похоже, в будущем еще предстоит, поэтому решил перенести из локального конфига в глобальный.
(defun lsp-register-vala-backend () "Register vala-language-server-alpha lsp backend" (add-to-list 'lsp-language-id-configuration '(vala-mode . "vala")) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection "vala-language-server") :major-modes '(vala-mode) :server-id 'vala-language-server))) (defun n-vala-mode-hook () (setq indent-tabs-mode nil) (setq require-final-newline t) (c-set-style "vala") (add-hook 'before-save-hook #'untabify-buffer t t) (add-hook 'before-save-hook #'delete-trailing-whitespace t t) (add-hook 'before-save-hook #'group-empty-lines t t)) (use-package vala-mode :ensure t :hook (vala-mode . lsp) (vala-mode . n-vala-mode-hook) :config (lsp-register-vala-backend))
У меня нет времени заняться и оживить vala-mode самостоятельно, а авторы на него немного забили. По c-style самым близким к тому, что нужно, оказался psr2 от php-mode, его и используем.
(c-add-style "vala" (list (if (assoc "psr2" c-style-alist) "psr2" "linux")))
Т. к. в Vala принято использовать Meson для сборки проекта, подключение соответствующего режима положу сюда.
(use-package meson-mode :ensure t) (use-package meson-build :ensure t :straight (meson-build :type git :repo "https://git.nickey.ru/nickey/meson-build.el")) (defun meson-build-set-keys () "Hook setting buffer-local Vala and Meson specific keybindings" (local-set-key (kbd "C-c C-c") #'compile) (local-set-key (kbd "C-c C-r") #'meson-build-run-project) (local-set-key (kbd "C-c C-t") #'meson-build-run-tests) (local-set-key (kbd "C-c C-g") #'meson-build-run-gdb) (local-set-key (kbd "C-c b") #'meson-build-set-project-bin)) (add-hook 'meson-mode-hook #'meson-build-set-compile-command) (add-hook 'meson-mode-hook #'meson-build-set-keys) (add-hook 'vala-mode-hook #'meson-build-set-compile-command) (add-hook 'vala-mode-hook #'meson-build-set-keys)
Еще неплохо было бы автоматически вставлять GNU/GPL заголовок в каждый файл, если лицензия применима для текущего проекта.
(defun n-locate-dominating-file (file name) (when-let (dir (locate-dominating-file file name)) (f-join dir name))) (defun n-is-gpl-project (path) (when-let (copying-file (or (n-locate-dominating-file path "COPYING") (n-locate-dominating-file path "LICENSE"))) (with-temp-buffer (insert-file-contents copying-file) (search-forward "GNU GENERAL PUBLIC LICENSE" nil t)))) (defun insert-gpl-header () (when-let (file (buffer-file-name)) (when (and (not (file-exists-p file)) (n-is-gpl-project file)) (when-let (snippet (yas-lookup-snippet "gpl3" major-mode t)) (yas-minor-mode 1) (yas-expand-snippet snippet))))) (add-hook 'vala-mode-hook #'insert-gpl-header t)
YAML
Довольно часто приходится редактировать YAML в различных конфигах. Опять же, от режима требуется, разве что, подсветка синтаксиса и сохранение отступов.
(use-package yaml-mode
:ensure t)
Markdown
README.md
- наше все.
(use-package markdown-mode
:ensure t)
Жизнедеятельность
Самоорганизация
Установка свежего org-mode
Устанавливаем свежую версию org-mode
c дополнениями из официального репозитория.
(use-package org-plus-contrib :ensure t :defer t)
Всегда включаем перенос по словам в длинных строках для org-mode (практика показала, что выключать его приходится многократно реже, чем включать).
(add-hook 'org-mode-hook 'visual-line-mode)
Подключаем полезности из contrib.
(require 'org-checklist) (require 'org-habit)
Настройка шаблонов для org-capture
org-capture
это крайне полезная штука, позволяющая быстро делать заметки и комментарии из любого места, сохраняя их в указанных местах. В моем случае org-capture вызывается командой C-c c
.
(global-set-key (kbd "C-c c") #'org-capture)
Мои org-файлы обычно лежат в папке ~/.cloud/org
, которая, в свою очередь, ведет в NextCloud облако.
(setq n-org-files-dir "~/.cloud/org" n-org-inbox (f-join n-org-files-dir "inbox.org") n-org-projects (f-join n-org-files-dir "projects.org") n-org-calendar (f-join n-org-files-dir "calendar.org") n-org-someday (f-join n-org-files-dir "someday.org") n-org-logbook (f-join n-org-files-dir "logbook.org.gpg"))
(setq org-default-notes-file n-org-inbox)
Шаблоны, которые я использую:
i
inbox Попадает во Входящие для последующего разбора, схоже с GTD.l
logbook Используется для фиксации различных событий и мыслей в шифрованном файле, отдаленно напоминает дневник, только не дневник.
(setq n-capture-templates-dir (f-join n-nemacs-dir "org-templates"))
(setq org-capture-templates `(("i" "Plain inbox entry" entry (file+headline ,n-org-inbox "Входящие") (file ,(f-join n-capture-templates-dir "inbox-plain.org"))) ("l" "Logbook entry" entry (file+datetree+prompt ,n-org-logbook) (file ,(f-join n-capture-templates-dir "logbook.org")))))
Настройка org-refile
После того, как заметки попали в Inbox, их периодически нужно разбирать, раскладывая по соответствующим разделам и файлам. Для этого служит механизм org-refile
. Настроим целевые файлы, в которые возможен перенос. Сам Inbox по понятным причинам в этот список не входит.
(setq org-refile-targets `((,n-org-projects . (:maxlevel . 2)) (,n-org-calendar . (:maxlevel . 2)) (,n-org-someday . (:maxlevel . 2))))
Настройка org-agenda
Когда в заметках наведен порядок, хотелось бы в удобоваримом виде получить список дел на день, неделю или без привязки к календарю. Для этого есть org-agenda
. Указываем файлы, из которых нужно собирать заметки и назначаем клавиши вызова.
(setq org-agenda-files (list n-org-inbox n-org-projects n-org-calendar))
(global-set-key (kbd "C-c a") #'org-agenda)
Настройка org-archive
Удаление выполненных или отмененных дел - плохая практика т. к. иногда (не так уж редко) бывает нужно уточнить, что именно было сделано, когда, если отменено - то почему и т. д. Короче говоря, айтишники тяжело расстаются с метаинформацией. Поэтому вместо удаления лучше использовать org-archive
, который позволяет перемещать ставшие ненужными заметки или деревья в отдельный файл, добавляя к ним информацию о дате архивирования, предыдущем местонахождении и др.
Чтобы файл не мозолил глаза, я использую скрытый файл .archive.org
, а заметки в нем раскладываются по разделам с именами файлов, из которых они были перемещены.
(setq org-archive-location (f-join n-org-files-dir ".archive.org::** Из файла %s"))
Метод помидора (pomidor)
По правде сказать, я не так часто пользуюсь этим методом, но иногда все же пользуюсь. Поэтому пусть будет на готове.
(use-package pomidor :ensure t :bind (("M-n M-p" . #'pomidor)) :config (setq pomidor-play-sound-file #'ignore alert-default-style 'libnotify pomidor-graph-char 10074))
Почта (Gnus
)
Вообще, для работы с почтой я использую neomutt. Но поскольку я подписан на множество списков рассылки, где часто присылают код, либо самому приходится отправлять фрагменты кода, сразу использовать редактор бывает очень удобно.
Извлечением почты у меня занимается offlineimap, каждые две минуты по крону забирающий почту с сервера по IMAP и аккуратно складывающий ее в папку ~/.mail
в формате Maildir. Помимо того, что это позволяет более полноценно работать с почтой, выбирая инструмент под задачу (иногда просто шелл), так появляется возможность разбирать почту из оффлайна - для десктопа так себе достижение, а для ноутбука бывает очень полезно.
(setq gnus-select-method '(nnmaildir "nickey" (directory "~/.mail")))
Ну а поскольку можно разбирать почту в оффлайне, почему бы ее в оффлайне не писать? Я использую msmtp для отправки почты. В пакете с msmtp идут скрипты msmtp-enqueue.sh
, msmtp-listqueue.sh
и msmtp-runqueue.sh
для работы с очередью отправки. Использую msmtp-enqueue для отправки почты, а msmtp-runqueue запускается по крону для отправки почты.
(setq message-send-mail-function #'message-send-mail-with-sendmail sendmail-program "~/.local/bin/msmtp-enqueue")
По умолчанию Gnus начинает хозяйничать в домашней папке и создавать в ней папки Mail
и News
. Спрячем их в глубинах ~/.emacs.d
.
(setq message-directory "~/.emacs.d/mail/" gnus-directory "~/.emacs.d/news/" nnfolder-directory "~/.emacs.d/mail/archive/")
Недавно я отказался от использования Disqus, равно как и любых других видов обратной связи на сайте.
Если вам есть что сказать по поводу прочитанного - можете написать на мою основную электронную почту i@nickey.ru, на данный момент это самый надежный способ связаться со мной.