;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- ;; Place your private configuration here! Remember, you do not need to run 'doom ;; sync' after modifying this file! ;; Some functionality uses this to identify you, e.g. GPG configuration, email ;; clients, file templates and snippets. It is optional. ;; (setq user-full-name "John Doe" ;; user-mail-address "john@doe.com") ;; Doom exposes five (optional) variables for controlling fonts in Doom: ;; ;; - `doom-font' -- the primary font to use ;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable) ;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for ;; presentations or streaming. ;; - `doom-symbol-font' -- for symbols ;; - `doom-serif-font' -- for the `fixed-pitch-serif' face ;; ;; See 'C-h v doom-font' for documentation and more examples of what they ;; accept. For example: ;; ;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light) ;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13)) ;; ;; If you or Emacs can't find your font, use 'M-x describe-font' to look them ;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to ;; refresh your font settings. If Emacs still can't find your font, it likely ;; wasn't installed correctly. Font issues are rarely Doom issues! ;; There are two ways to load a theme. Both assume the theme is installed and ;; available. You can either set `doom-theme' or manually load a theme with the ;; `load-theme' function. This is the default: (setq doom-theme 'doom-one) ;; This determines the style of line numbers in effect. If set to `nil', line ;; numbers are disabled. For relative line numbers, set this to `relative'. (setq display-line-numbers-type t) ;; If you use `org' and don't want your org files in the default location below, ;; change `org-directory'. It must be set before org loads! (setq org-directory "~/org/") ;; (setq org-startup-with-inline-images t) ;; (add-hook 'org-mode-hook 'org-display-inline-images) (setq ispell-program-name "hunspell") (setq ispell-dictionary "en_US,ru_RU") (after! ispell (ispell-set-spellchecker-params) (ispell-hunspell-add-multi-dic "en_US,ru_RU")) (defun transform-square-brackets-to-round-ones(string-to-transform) "Transforms [ into ( and ] into ), other chars left unchanged." (concat (mapcar #'(lambda (c) (if (equal c ?\[) ?\( (if (equal c ?\]) ?\) c))) string-to-transform))) (defun get-current-layout () "Получить текущую раскладку клавиатуры для текущего окна с помощью xkb-switch." (string-trim (shell-command-to-string "xkb-switch"))) (defun set-layout (layout) "Установить раскладку клавиатуры для текущего окна с помощью xkb-switch." (shell-command (concat "xkb-switch -s " layout))) (defvar prev-lang "us" "Хранит текущую раскладку перед переключением в insert mode.") (add-hook 'evil-insert-state-entry-hook (lambda () (setq prev-lang (get-current-layout)) (set-layout "us"))) ;; Переключаем на английский в insert mode (add-hook 'evil-insert-state-exit-hook (lambda () (set-layout prev-lang))) ;; Восстанавливаем предыдущую раскладку (setq org-attach-method 'cp) ;; copy file to an attachments dir. (setq org-attach-id-dir "~/org/attachments/") (setq org-adapt-indentation t) (setq org-startup-indented t) (setq org-indent-mode t) (setq org-archive-location "~/org/archive/%s_archive::") (add-hook 'org-mode-hook (lambda () (visual-line-mode 1))) ;; (setq org-agenda-files '("~/org/inbox.org" "~/org/life.org" "~/org/braindump.org")) (setq org-refile-targets '((org-agenda-files :maxlevel . 3))) (setq org-refile-use-cache t) (use-package! org-habit :after org :config (setq org-habit-following-days 7 org-habit-preceding-days 35 org-habit-show-habits t) ) ;; clear cache every 5 minutes (run-with-idle-timer 300 t (lambda () (org-refile-cache-clear) (org-refile-get-targets))) (use-package! org :commands org-refile-cache-clear) (use-package! anki-editor) ;; To open files with .journal extension in hledger-mode (add-to-list 'auto-mode-alist '("\\.journal\\'" . hledger-mode)) ;; Provide the path to you journal file. ;; The default location is too opinionated. (setq hledger-jfile "~/.hledger/2025/all.journal") (setq hledger-currency-string " ") ;;; Auto-completion for account names ;; For company-mode users, ;; (add-to-list 'company-backends 'hledger-company) (use-package! org-roam ;; :ensure nil :custom (org-roam-directory "~/org/roam/") (org-roam-capture-templates '(("d" "default" plain "%?\n\n\n* Key Features\n* Problems\n* Impact\n* Related:\n\n* References:\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags:\n#+date: %U\n")))) (custom-set-faces '((org-roam-link org-roam-link-current) :foreground "#e24888" :underline t)) :config ;; (org-roam-db-autosync-mode) (setq org-roam-completion-everywhere t) (setq org-roam-database-connector 'sqlite-builtin) (setq org-roam-db-node-include-function (lambda () (not (member "ATTACH" (org-get-tags))))) ) (setq org-default-priority ?D) (use-package! org-super-links :bind (("C-c s s" . org-super-links-link) ("C-c s l" . org-super-links-store-link) ("C-c s C-l" . org-super-links-insert-link))) (map! :leader :desc "life" "e l" #'(lambda () (interactive) (find-file "~/org/life.org")) :desc "braindump" "e d" #'(lambda () (interactive) (find-file "~/org/braindump.org")) :desc "inbox" "e i" #'(lambda () (interactive) (find-file "~/org/inbox.org")) :desc "articles" "e a" #'(lambda () (interactive) (find-file "~/org/articles.org")) :desc "notes" "e n" #'(lambda () (interactive) (find-file "~/org/notes.org"))) (setq org-capture-templates '( ("g" "Private" entry (file+headline "~/org/private.org.gpg" "Private") "* %?" :empty-lines 0) ("d" "Braindump" entry (file+headline "~/org/inbox.org" "Inbox") "* [%<%Y-%m-%d>] %?\n:PROPERTIES:\n:ID: %(org-id-new)\n:END:\n" :empty-lines 0) ("p" "Project" entry (file+headline "~/org/life.org" "Projects") "* %?\n:PROPERTIES:\n:ID: %(org-id-new)\n:CREATED: %t\n:END:\n\n** Tasks:\n** Notes:\n** Links:\n" :empty-lines 0) ("n" "Note" entry (file+headline "~/org/notes.org" "2025") "* %?\n:PROPERTIES:\n:ID: %(org-id-new)\n:DATE: %U\n:END:\n" :empty-lines 0) ("j" "Journal Entry" entry (file+datetree "~/org/journal.org") "* Event: %?\n\n %i\n\n From: %a" :empty-lines 1) ("t" "Todo" entry (file+headline "~/org/inbox.org" "Todo") "* TODO [#C] %?\n:PROPERTIES:\n:Created: %T\n:END:\n " :empty-lines 0) ("m" "Meeting" entry (file+datetree "~/org/life.org" "Areas" "Meetings") "* TODO [#A] %? :meeting:%^g\nSCHEDULED: %^T\n:PROPERTIES:\n:Created: %T\n:END:\n" :tree-type week :empty-lines 0) ;; create a flashcard with the content of the Xorg clipboard ("W" "Word" entry (file+headline "~/org/english.org" "Words") "* %x\n** Front\n%x\n** Back\n%^{PROMPT}" :empty-lines 0) ("w" "Selected web capture" entry (file+headline "~/org/inbox.org" "Selected web capture") "* [%<%Y-%m-%d>] [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n:PROPERTIES:\n:ID: %(org-id-new)\n:END:\n Source: %:link\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n%?" :empty-lines 0) ("L" "Unselected web capture" entry (file+headline "~/org/inbox.org" "Web links") "* [%<%Y-%m-%d>] [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]] \n:PROPERTIES:\n:ID: %(org-id-new)\n:END:\n%?" :empty-lines 0))) (setq org-todo-keywords '((sequence "TODO(t)" "STRT(i@/!)" "HOLD(b@)" "CRIT(q@)" "|" "DONE(d!)" "CNCL(c@/!)" ) )) (setq org-todo-keyword-faces '( ("TODO" . (:foreground "GoldenRod" :weight bold)) ("STRT" . (:foreground "Cyan" :weight bold)) ("HOLD" . (:foreground "Red" :weight bold)) ("DONE" . (:foreground "LimeGreen" :weight bold)) ("CRIT" . (:foreground "DarkRed" :weight bold)) ("CNCL" . (:foreground "DimGray" :weight bold)) )) ;; Tags (setq org-tag-alist ' ( ;; context (:startgroup) ("@shop" . ?s) ("@home" . ?h) ("@outdoor" . ?o) ("@any" . ?a) ("@meeting" . ?m) (:endgroup) ;; basic tags (:startgroup) ("chores" . ?C) ("meeting" . ?M) ("finance" . ?F) ("sport" . ?S) ("code" . ?O) ("social" . ?I) ("productivity" . ?P) ("study" . ?U) ("privacy" . ?R) ("family" . ?A) ("travel" . ?T) ("life" . ?L) ("health" . ?H) ("friends" . ?E) ("hobby" . ?B) ("research" . ?G) ("article" . ?I) ("job" . ?J) (:endgroup) ;; Special tags ("CRITICAL" . ?X) ;; other tags ("backend") ("broken_code") ("frontend") ("hike") ("cycle") ("pkm") ("pentest") ("immigration") ("devops") ("pet") ("accomplishment") ("music") ("youtube") ("trash") ("devsecops") ("book") ("movie") ("inbox") )) ;; Tag colors (setq org-tag-faces '( ("@home" . (:foreground "medium MediumPurple" :weight bold)) ("@outdoor" . (:foreground "royalblue1" :weight bold)) ("@shop" . (:foreground "forest green" :weight bold)) ("QA" . (:foreground "sienna" :weight bold)) ("chores" . (:foreground "yellow1" :weight bold)) ("sport" . (:foreground "green yellow" :weight bold)) ("finance" . (:foreground "tomato" :weight bold)) ("privacy" . (:foreground "dark olive green" :weight bold)) ("study" . (:foreground "aquamarine" :weight bold)) ("productivity" . (:foreground "violet" :weight bold)) ("family" . (:foreground "medium violet red" :weight bold)) ("health" . (:foreground "DarkOrange1" :weight bold)) ("code" . (:foreground "snow3" :weight bold)) ("travel" . (:foreground "salmon4" :weight bold)) ("life" . (:foreground "goldenrod1" :weight bold)) ("friends" . (:foreground "plum4" :weight bold)) ("hobby" . (:foreground "SeaGreen1" :weight bold)) ("social" . (:foreground "RoyalBlue1" :weight bold)) ("research" . (:foreground "deep sky blue" :weight bold)) ("meeting" . (:foreground "magenta" :weight bold)) ("CRITICAL" . (:foreground "red1" :weight bold)) ("job" . (:foreground "medium spring green" :weight bold)) ) ) ;; Agenda View "d" (defun air-org-skip-subtree-if-priority (priority) "Skip an agenda subtree if it has a priority of PRIORITY. PRIORITY may be one of the characters ?A, ?B, or ?C." (let ((subtree-end (save-excursion (org-end-of-subtree t))) (pri-value (* 1000 (- org-lowest-priority priority))) (pri-current (org-get-priority (thing-at-point 'line t)))) (if (= pri-value pri-current) subtree-end nil))) (defun air-org-skip-subtree-if-no-priority () "Skip an entry if it has no priority." (let ((priority (org-entry-get (point) "PRIORITY"))) (if (not priority) (save-excursion (org-end-of-subtree t))))) (setq org-agenda-skip-deadline-if-done t) (setq org-agenda-skip-timestamp-if-done t) (setq org-agenda-tag-filter-preset '("-movies" "-book")) (setq org-agenda-skip-function-global '(org-agenda-skip-entry-if 'todo '("CNCL"))) (setq org-agenda-custom-commands '( ;; Daily Agenda & TODOs ("d" "Daily agenda and all TODOs" ;; View 7 days in the calendar view ((agenda "" ((org-agenda-span 7))) ;; Display items with priority A (tags "PRIORITY=\"A\"" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "High-priority unfinished tasks:"))) ;; Display items with priority B (really it is view all items minus A & C) (tags "PRIORITY=\"B\"" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "ALL normal priority tasks:"))) ;; Display items with pirority C (tags "PRIORITY=\"C\"" ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) (org-agenda-overriding-header "Low-priority Unfinished tasks:"))) ) ;; Don't compress things (change to suite your tastes) ((org-agenda-compact-blocks nil))) ;; My Super View ("j" "My Super View" ( (agenda "" ( (org-agenda-remove-tags t) (org-agenda-span 7) (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) ) ) (alltodo "" ( ;; Remove tags to make the view cleaner (org-agenda-remove-tags t) (org-agenda-prefix-format " %t %s") (org-agenda-overriding-header "CURRENT STATUS") ;; Define the super agenda groups (sorts by order) (org-super-agenda-groups '( ;; Filter where tag is CRITICAL (:name "Critical Tasks" :tag "CRIT" :order 0 ) ;; Filter where TODO state is IN-PROGRESS (:name "Currently Working" :todo "STRT" :order 1 ) ;; Filter where TODO state is BLOCKED or where the tag is obstacle (:name "Problems & Blockers" :todo "HOLD" :order 3 ) ;; Filter where tag is meeting and priority is A (only want TODOs from meetings) (:name "Meeting Action Items" :and (:tag "meeting" :priority "A") :order 6 ) ;; Filter where state is TODO and the priority is A and the tag is not meeting (:name "Other Important Items" :and (:todo "TODO" :priority "A" :not (:tag "meeting")) :order 7 ) ;; Filter where state is TODO and priority is B (:name "General Backlog" :and (:todo "TODO" :priority "B") :order 8 ) ;; Filter where the priority is C or less (supports future lower priorities) (:name "Non Critical" :priority<= "C" :order 9 ) ) ) ) ) )) )) ;; Whenever you reconfigure a package, make sure to wrap your config in an ;; `after!' block, otherwise Doom's defaults may override your settings. E.g. ;; ;; (after! PACKAGE ;; (setq x y)) ;; ;; The exceptions to this rule: ;; ;; - Setting file/directory variables (like `org-directory') ;; - Setting variables which explicitly tell you to set them before their ;; package is loaded (see 'C-h v VARIABLE' to look up their documentation). ;; - Setting doom variables (which start with 'doom-' or '+'). ;; ;; Here are some additional functions/macros that will help you configure Doom. ;; ;; - `load!' for loading external *.el files relative to this one ;; - `use-package!' for configuring packages ;; - `after!' for running code after a package has loaded ;; - `add-load-path!' for adding directories to the `load-path', relative to ;; this file. Emacs searches the `load-path' when you load packages with ;; `require' or `use-package'. ;; - `map!' for binding new keys ;; ;; To get information about any of these functions/macros, move the cursor over ;; This will open documentation for it, including demos of how they are used. ;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces, ;; etc). ;; ;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how ;; they are implemented.