;;; $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" ;; -------------------------------------------------- (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)))) (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)))) (map! :i "C-c f" #'martin/complete-file-name-at-point :n "C-c f" #'martin/complete-file-name-at-point) (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)))) ;; -------------------------------------------------- ;; 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) ;; -------------------------------------------------- (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." (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 ;; -------------------------------------------------- (setq doom-font (font-spec :family "JetBrains Mono" :size 20) doom-variable-pitch-font (font-spec :family "SF Pro Text" :size 20)) (setq-default line-spacing 0.25) (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) (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))))) ;; performance tweak (after! projectile (setq projectile-indexing-method 'alien projectile-enable-caching t))