Files
emacs-doom/config.el
Martin Sukany b77864b6da update
2026-02-07 14:11:08 +01:00

239 lines
9.1 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
;; --------------------------------------------------
;; Theme / UI
;; --------------------------------------------------
(setq doom-theme 'tango-dark
display-line-numbers-type t
doom-font (font-spec :family "JetBrains Mono" :size 14)
doom-variable-pitch-font nil)
;; --------------------------------------------------
;; macOS / UX
;; --------------------------------------------------
(setq mouse-autoselect-window t
focus-follows-mouse t
select-enable-clipboard t
select-enable-primary t
inhibit-splash-screen t)
;; --------------------------------------------------
;; Completion (Company) minimum, bezpečné
;; --------------------------------------------------
(after! company
(setq company-idle-delay 0.1
company-minimum-prefix-length 2
company-selection-wrap-around t
company-tooltip-limit 14
company-show-numbers t
company-require-match nil)
;; Spolehlivé vyvolání v TTY
(map! :i "C-." #'company-complete
:n "C-." #'company-complete))
;; --------------------------------------------------
;; Robustní file completion "kdekoliv pod kurzorem"
;; Funguje i v Markdown odkazu [x](./tady), protože neřeší kontext jen token okolo pointu.
;; --------------------------------------------------
(defun martin/complete-file-name-at-point ()
"Doplň název souboru kolem kurzoru pomocí standardní file completion tabulky.
Funguje v libovolném textu, včetně Markdown linků (např. [x](./...))."
(interactive)
(let* ((stop-chars '(?\s ?\t ?\n ?\r ?\" ?\' ?\( ?\) ?\[ ?\] ?\< ?\> ?\{ ?\} ?, ?;))
(start (save-excursion
(while (and (> (point) (point-min))
(let ((c (char-before)))
(and c (not (memq c stop-chars)))))
(backward-char))
(point)))
(end (save-excursion
(while (and (< (point) (point-max))
(let ((c (char-after)))
(and c (not (memq c stop-chars)))))
(forward-char))
(point))))
;; Pokud nejsme "na tokenu", vezmi aspoň start=end=point (doplň odtud)
(when (= start end)
(setq start (point) end (point)))
(let ((completion-category-defaults nil)
(completion-category-overrides '((file (styles basic partial-completion)))))
(completion-in-region start end #'completion-file-name-table))))
;; Globální klávesa (funguje všude, i v TTY)
(map! :i "C-c f" #'martin/complete-file-name-at-point
:n "C-c f" #'martin/complete-file-name-at-point)
;; V Markdownu snížíme prefix, ať to jde hned po `./`
(after! markdown-mode
(add-hook 'markdown-mode-hook (lambda () (setq-local company-minimum-prefix-length 1)))
(add-hook 'gfm-mode-hook (lambda () (setq-local company-minimum-prefix-length 1))))
;; --------------------------------------------------
;; Copilot
;; --------------------------------------------------
(use-package! copilot
:hook (prog-mode . copilot-mode)
:bind (:map copilot-completion-map
("<tab>" . copilot-accept-completion)
("TAB" . copilot-accept-completion)
("C-TAB" . copilot-accept-completion-by-word)
("C-<tab>" . copilot-accept-completion-by-word)))
;; --------------------------------------------------
;; Org
;; --------------------------------------------------
(setq org-directory "~/org/")
(after! org
(setq org-default-notes-file (expand-file-name "inbox.org" org-directory))
(setq org-agenda-files (list org-directory
(expand-file-name "projects" org-directory)
(expand-file-name "notes" org-directory)))
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "WAIT(w@/!)" "|" "DONE(d!)" "CANCELLED(c@)")))
(setq org-log-done 'time)
(setq org-refile-targets '((org-agenda-files :maxlevel . 5))
org-outline-path-complete-in-steps nil
org-refile-use-outline-path 'file)
(defun my/project-org-file ()
"Return path to ./project.org in current Projectile project, if it exists."
(when-let ((root (projectile-project-root)))
(let ((f (expand-file-name "project.org" root)))
(when (file-exists-p f) f))))
(defun my/org-agenda-project ()
"Open Org agenda restricted to current project's project.org."
(interactive)
(let ((org-agenda-files (delq nil (list (my/project-org-file)))))
(if org-agenda-files
(org-agenda nil "a")
(user-error "No project.org found in this project"))))
(setq org-capture-templates
'(("i" "Inbox task" entry
(file "inbox.org")
"* TODO %?\n%U\n%a\n")
("n" "Note" entry
(file+headline "inbox.org" "Notes")
"* %?\n%U\n%a\n")
("p" "Project task" entry
(file "inbox.org")
"* TODO %? :project:\n%U\n%a\n"))))
;; --------------------------------------------------
;; Dired
;; --------------------------------------------------
(after! dired
(put 'dired-find-alternate-file 'disabled nil)
(map! :map dired-mode-map
"RET" #'dired-find-alternate-file
"^" #'dired-up-directory))
;; --------------------------------------------------
;; PlantUML (server) — TVOJE PŮVODNÍ ČÁST
;; --------------------------------------------------
(add-to-list 'auto-mode-alist '("\\.puml\\'" . plantuml-mode))
(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode))
(after! plantuml-mode
(setq plantuml-default-exec-mode 'server
plantuml-server-url "https://www.plantuml.com/plantuml"
plantuml-output-type "svg"
plantuml-verbose t))
(defun my/plantuml-encode-hex (text)
"PlantUML HEX encoding: ~h + hex(UTF-8 bytes)."
(let* ((utf8 (encode-coding-string text 'utf-8 t)))
(concat "~h"
(apply #'concat
(mapcar (lambda (b) (format "%02x" b))
(append utf8 nil))))))
(defun my/plantuml-fix-png-header (file)
"Odstraní vše před PNG signaturou (řeší \\n před 89 50 4E 47)."
(let ((sig (unibyte-string #x89 ?P ?N ?G ?\r ?\n #x1a ?\n)))
(with-temp-buffer
(set-buffer-multibyte nil)
(insert-file-contents-literally file)
(goto-char (point-min))
(unless (looking-at (regexp-quote sig))
(let ((pos (search-forward sig nil t)))
(unless pos (user-error "PNG signature nenalezena"))
(delete-region (point-min) (- pos (length sig)))
(let ((coding-system-for-write 'binary))
(write-region (point-min) (point-max) file nil 'silent)))))))
(defun my/plantuml-render-server (type)
"Render aktuální .puml přes PlantUML server do PNG nebo SVG."
(interactive (list (completing-read "Type: " '("png" "svg") nil t "png")))
(unless buffer-file-name (user-error "Otevři .puml jako soubor"))
(let* ((text (buffer-substring-no-properties (point-min) (point-max)))
(encoded (my/plantuml-encode-hex text))
(server (string-remove-suffix "/" plantuml-server-url))
(url (format "%s/%s/%s" server type encoded))
(out (concat (file-name-sans-extension buffer-file-name) "." type)))
(url-copy-file url out t)
(when (string-equal type "png")
(my/plantuml-fix-png-header out))
(message "PlantUML uložen: %s" out)
out))
(after! plantuml-mode
(define-key plantuml-mode-map (kbd "C-c C-p")
(lambda () (interactive) (my/plantuml-render-server "png")))
(define-key plantuml-mode-map (kbd "C-c C-s")
(lambda () (interactive) (my/plantuml-render-server "svg"))))
;; --------------------------------------------------
;; PATH fix for MacTeX
;; --------------------------------------------------
(setenv "PATH" (concat "/Library/TeX/texbin:" (getenv "PATH")))
(add-to-list 'exec-path "/Library/TeX/texbin")
;; --------------------------------------------------
;; Python
;; --------------------------------------------------
(setq python-shell-interpreter "python3")
(after! org
(setq org-babel-python-command "python3")
(require 'ob-python))
;; --------------------------------------------------
;; Low-vision základ
;; --------------------------------------------------
;; Větší font + pohodlnější řádkování
(setq doom-font (font-spec :family "JetBrains Mono" :size 20) ;; zkus 1824
doom-variable-pitch-font (font-spec :family "SF Pro Text" :size 20))
(setq-default line-spacing 0.25) ;; 0.200.35 dle chuti
;; Jednoduché zvětšení/zmenšení textu kdykoliv
(map! :n "C-=" #'text-scale-increase
:n "C--" #'text-scale-decrease
:n "C-0" #'text-scale-set
:i "C-=" #'text-scale-increase
:i "C--" #'text-scale-decrease
:i "C-0" #'text-scale-set)
;; Automaticky ukládej org soubory po refilingu a změnách
(add-hook 'org-after-refile-insert-hook #'save-buffer)
(add-hook 'org-after-todo-state-change-hook #'save-buffer)
(add-hook 'org-capture-after-finalize-hook #'save-buffer)
(run-with-idle-timer
300 t
(lambda ()
(save-some-buffers t (lambda ()
(derived-mode-p 'org-mode)))))