aboutsummaryrefslogtreecommitdiff
path: root/.emacs.d
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d')
-rw-r--r--.emacs.d/rul-emacs.org569
1 files changed, 409 insertions, 160 deletions
diff --git a/.emacs.d/rul-emacs.org b/.emacs.d/rul-emacs.org
index 1ba5aae..188fc2b 100644
--- a/.emacs.d/rul-emacs.org
+++ b/.emacs.d/rul-emacs.org
@@ -38,25 +38,6 @@ Customization of graphical aspects of Emacs, such as size, panels, etc.
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
-
-;; Avoid initial flash of light.
-(defun prot-emacs-re-enable-frame-theme (_frame)
- "Re-enable active theme, if any, upon FRAME creation.
-Add this to `after-make-frame-functions' so that new frames do
-not retain the generic background set by the function
-`prot-emacs-avoid-initial-flash-of-light'."
- (when-let* ((theme (car custom-enabled-themes)))
- (enable-theme theme)))
-
-(defun prot-emacs-avoid-initial-flash-of-light ()
- "Avoid flash of light when starting Emacs, if needed.
-New frames are instructed to call `prot-emacs-re-enable-frame-theme'."
- (setq mode-line-format nil)
- (set-face-attribute 'default nil :background "#000000" :foreground "#ffffff")
- (set-face-attribute 'mode-line nil :background "#000000" :foreground "#ffffff" :box 'unspecified)
- (add-hook 'after-make-frame-functions #'prot-emacs-re-enable-frame-theme))
-
-(prot-emacs-avoid-initial-flash-of-light)
#+end_src
** Frame configuration
@@ -345,17 +326,6 @@ together, offering a menu on the way.
("=" gofmt :exit t)
("c" go-coverage :exit t))
-;; vterm
-(defhydra hydra-vterm ()
- "zoom"
- ("t" multi-vterm "Open a terminal" :exit t)
- ("d" multi-vterm-dedicated-open "Dedicated" :exit t)
- ("p" multi-vterm-prev "Previous terminal")
- ("n" multi-vterm-next "Next terminal")
- ("r" multi-vterm-rename-buffer "Rename buffer" :exit t)
- )
-
-(global-set-key (kbd "C-c t") 'hydra-vterm/body)
(global-set-key (kbd "C-c m") 'hydra-go/body)
#+end_src
@@ -591,7 +561,9 @@ installs =fontaine=, a software that allows defining font presets.
(small
:default-height 120)
(medium
- :default-height 140)
+ :default-height 150)
+ (wayland-medium
+ :default-height 320)
(large
:default-weight semilight
:default-height 180
@@ -612,10 +584,8 @@ installs =fontaine=, a software that allows defining font presets.
(t
:default-family "Iosevka"
:default-weight regular
- :default-height 140
+ :default-height 150
:variable-pitch-family "Iosevka Aile")))
-
- ;; Set desired style from `fontaine-presets'
(fontaine-set-preset 'medium))
(provide 'rul-fonts)
@@ -650,7 +620,10 @@ Internet radio channels. It requires =mpv= to be installed.
("SomaFM - Metal" . "https://somafm.com/metal.pls")
("SomaFM - Lush" . "https://somafm.com/lush130.pls")
("KCSM Jazz 91" . "http://ice5.securenetsystems.net/KCSM")
- )))
+ ("KSUA 91.5 FM" . "https://stream.radio.co/se776fab22/listen")
+ ))
+ (setq empv-fd-binary "fdfind")
+ )
(provide 'rul-io)
#+end_src
@@ -678,6 +651,8 @@ Emacs can act as Mail User Agent. My preferred package for this is
notmuch-show-text/html-blocked-images nil
)
+ (setq notmuch-draft-folder "current/Drafts")
+
;; Keymaps
(defun rul/capture-mail()
"Capture mail to org mode."
@@ -913,10 +888,14 @@ Specific to the current window's mode line.")
mode-line-front-space
mode-line-buffer-identification
mode-line-front-space
+ mode-line-percent-position
+ mode-line-front-space
rul-modeline-major-mode
prot-modeline-eglot
mode-line-format-right-align
rul-modeline-misc-info
+ mode-line-front-space
+ mode-line-front-space
))
(provide 'rul-modeline)
@@ -979,8 +958,9 @@ My org mode configuration is quite big, so I split it across multiple files.
(global-set-key (kbd "C-c c") #'org-capture)
(global-set-key (kbd "C-c s") #'org-schedule)
-(global-set-key (kbd "<f9>") 'bh/punch-in)
-(global-set-key (kbd "<f10>") 'bh/punch-out)
+(global-set-key (kbd "<f6>") 'org-clock-goto)
+(global-set-key (kbd "<f9>") 'org-clock-in-last)
+(global-set-key (kbd "<f10>") 'org-clock-out)
(global-set-key (kbd "<f12>") 'org-agenda)
;; ORG STATES ;;
@@ -1099,6 +1079,40 @@ My org mode configuration is quite big, so I split it across multiple files.
;; Honor ATTR_ORG attribute. Defaults to image's width if not set.
(setq org-image-actual-width nil)
+(setq org-clock-mode-line-total 'today)
+
+;; org-tempus
+(unless (package-installed-p 'org-tempus)
+ (package-vc-install "https://github.com/rul/org-tempus.git"))
+
+(use-package org-tempus
+ :init
+ (org-tempus-mode 1))
+
+(use-package org-remark-global-tracking
+ ;; It is recommended that `org-remark-global-tracking-mode' be
+ ;; enabled when Emacs initializes. You can set it in
+ ;; `after-init-hook'.
+ :hook after-init
+ :config
+ ;; Selectively keep or comment out the following if you want to use
+ ;; extensions for Info-mode, EWW, and NOV.el (EPUB) respectively.
+ (use-package org-remark-eww :after eww :config (org-remark-eww-mode +1))
+ (use-package org-remark-nov :after nov :config (org-remark-nov-mode +1)))
+
+(use-package org-remark
+ :bind (;; :bind keyword also implicitly defers org-remark itself.
+ ;; Keybindings before :map is set for global-map. Adjust the keybinds
+ ;; as you see fit.
+ ("C-c n m" . org-remark-mark)
+ ("C-c n l" . org-remark-mark-line)
+ :map org-remark-mode-map
+ ("C-c n o" . org-remark-open)
+ ("C-c n ]" . org-remark-view-next)
+ ("C-c n [" . org-remark-view-prev)
+ ("C-c n r" . org-remark-remove)
+ ("C-c n d" . org-remark-delete)))
+
(provide 'rul-org)
#+end_src
@@ -1373,8 +1387,6 @@ Skip project and sub-project tasks, habits, and loose non-project tasks."
(setq org-clock-history-length 23)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
-;; Change tasks to NEXT when clocking in
-(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK")))
;; Save clock data and state changes and notes in the LOGBOOK drawer
@@ -1392,22 +1404,6 @@ Skip project and sub-project tasks, habits, and loose non-project tasks."
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)
-
-(setq bh/keep-clock-running nil)
-
-(defun bh/clock-in-to-next (kw)
- "Switch a task from TODO to NEXT when clocking in.
-Skips capture tasks, projects, and subprojects.
-Switch projects and subprojects from NEXT back to TODO"
- (when (not (and (boundp 'org-capture-mode) org-capture-mode))
- (cond
- ((and (member (org-get-todo-state) (list "TODO"))
- (bh/is-task-p))
- "NEXT")
- ((and (member (org-get-todo-state) (list "NEXT"))
- (bh/is-project-p))
- "TODO"))))
-
(defun bh/find-project-task ()
"Move point to the parent (project) task if any"
(save-restriction
@@ -1419,60 +1415,6 @@ Switch projects and subprojects from NEXT back to TODO"
(goto-char parent-task)
parent-task)))
-(defun bh/punch-in (arg)
- "Start continuous clocking and set the default task to the
-selected task. If no task is selected set the Organization task
-as the default task."
- (interactive "p")
- (setq bh/keep-clock-running t)
- (if (equal major-mode 'org-agenda-mode)
- ;;
- ;; We're in the agenda
- ;;
- (let* ((marker (org-get-at-bol 'org-hd-marker))
- (tags (org-with-point-at marker (org-get-tags-at))))
- (if (and (eq arg 4) tags)
- (org-agenda-clock-in '(16))
- (bh/clock-in-organization-task-as-default)))
- ;;
- ;; We are not in the agenda
- ;;
- (save-restriction
- (widen)
- ; Find the tags on the current task
- (if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4))
- (org-clock-in '(16))
- (bh/clock-in-organization-task-as-default)))))
-
-(defun bh/punch-out ()
- (interactive)
- (setq bh/keep-clock-running nil)
- (when (org-clock-is-active)
- (org-clock-out))
- (org-agenda-remove-restriction-lock))
-
-(defun bh/clock-in-default-task ()
- (save-excursion
- (org-with-point-at org-clock-default-task
- (org-clock-in))))
-
-(defun bh/clock-in-parent-task ()
- "Move point to the parent (project) task if any and clock in"
- (let ((parent-task))
- (save-excursion
- (save-restriction
- (widen)
- (while (and (not parent-task) (org-up-heading-safe))
- (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
- (setq parent-task (point))))
- (if parent-task
- (org-with-point-at parent-task
- (org-clock-in))
- (when bh/keep-clock-running
- (bh/clock-in-default-task)))))))
-
-(defvar bh/organization-task-id "redefine") ;; org-id-get-create
-
;; https://stackoverflow.com/a/10091330
(defun zin/org-agenda-skip-tag (tag &optional others)
"Skip all entries that correspond to TAG.
@@ -1490,48 +1432,6 @@ If OTHERS is true, skip all entries that do not correspond to TAG."
next-headline
nil))))
-(defun bh/clock-in-organization-task-as-default ()
- (interactive)
- (org-with-point-at (org-id-find bh/organization-task-id 'marker)
- (org-clock-in '(16))))
-
-(defun bh/clock-out-maybe ()
- (when (and bh/keep-clock-running
- (not org-clock-clocking-in)
- (marker-buffer org-clock-default-task)
- (not org-clock-resolving-clocks-due-to-idleness))
- (bh/clock-in-parent-task)))
-
-(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append)
-
-;;; Focusing on current work
-
-(global-set-key (kbd "<f5>") 'bh/org-todo)
-(defun bh/org-todo (arg)
- (interactive "p")
- (if (equal arg 4)
- (save-restriction
- (bh/narrow-to-org-subtree)
- (org-show-todo-tree nil))
- (bh/narrow-to-org-subtree)
- (org-show-todo-tree nil)))
-
-(global-set-key (kbd "<S-f5>") 'bh/widen)
-(defun bh/widen ()
- (interactive)
- (if (equal major-mode 'org-agenda-mode)
- (progn
- (org-agenda-remove-restriction-lock)
- (when org-agenda-sticky
- (org-agenda-redo)))
- (widen)))
-
-(defun bh/narrow-to-org-subtree ()
- (widen)
- (org-narrow-to-subtree)
- (save-restriction
- (org-agenda-set-restriction-lock)))
-
;; AGENDA VIEW ;;
;; Do not dim blocked tasks
@@ -1569,9 +1469,7 @@ on a single file.
(progn
(bind-key [remap find-tag] #'godef-jump))
:config
- (add-hook 'go-mode-hook #'yas-minor-mode)
(add-hook 'go-mode-hook 'electric-pair-mode)
- (add-hook 'go-mode-hook 'my-go-mode-hook)
(add-hook 'before-save-hook 'gofmt-before-save))
(use-package go-eldoc
@@ -1598,13 +1496,6 @@ on a single file.
;; Python
(use-package blacken :ensure t :defer t)
-(with-eval-after-load 'lsp-mode
- (lsp-register-client
- (make-lsp-client
- :new-connection (lsp-stdio-connection '("ruff" "server"))
- :activation-fn (lsp-activate-on "python")
- :server-id 'ruff-lsp)))
-(add-hook 'python-mode-hook #'lsp)
;; Terraform
(use-package terraform-mode :ensure t :defer t)
@@ -1622,3 +1513,361 @@ on a single file.
(provide 'rul-prog)
#+end_src
+** The =terminals= module
+TODO
+
+#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-terminals.el"
+(use-package vterm
+ :ensure t
+ :init
+ (setq vterm-always-compile-module t
+ vterm-max-scrollback 100000)
+ :hook
+ (vterm-mode . goto-address-mode)
+ :bind
+ (:map vterm-mode-map
+ ("C-c C-t" . vterm-copy-mode)
+ ("C-l" . vterm-clear))
+ :config
+ (define-key vterm-mode-map (kbd "C-c C-c")
+ (lambda ()
+ (interactive)
+ (vterm-send-string "\C-c")))
+
+ (defun rul/vterm-copy-and-exit (beg end)
+ "Copy region and exit `vterm-copy-mode'."
+ (interactive "r")
+ (kill-ring-save beg end)
+ (vterm-copy-mode -1))
+
+ (define-key vterm-copy-mode-map (kbd "w") #'rul/vterm-copy-and-exit)
+ (define-key vterm-copy-mode-map (kbd "M-w") #'rul/vterm-copy-and-exit))
+
+(use-package multi-vterm
+ :ensure t
+ :after vterm
+ :bind (("C-c t" . multi-vterm))
+ :config
+ (setq vterm-kill-buffer-on-exit t)
+
+ (defvar-local rul/vterm-close-tab-on-kill nil
+ "When non-nil, close this buffer's tab when the vterm buffer is killed.")
+
+ (defun rul/vterm-maybe-close-tab ()
+ "Close the current tab if this vterm buffer was opened in its own tab."
+ (when rul/vterm-close-tab-on-kill
+ (tab-close)))
+
+ (defun rul/vterm-new-tab ()
+ "Create a new tab and open a new vterm."
+ (interactive)
+ (tab-new)
+ (multi-vterm)
+ (setq-local rul/vterm-close-tab-on-kill t)
+ (add-hook 'kill-buffer-hook #'rul/vterm-maybe-close-tab nil t))
+
+ ;; Inside vterm buffers, make C-c t spawn a new tab + vterm
+ (define-key vterm-mode-map (kbd "C-c t") #'rul/vterm-new-tab)
+ (define-key vterm-mode-map (kbd "C-S-t") #'rul/vterm-new-tab))
+
+(provide 'rul-terminals)
+#+end_src
+
+** The =vc= module
+TODO
+
+#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-vc.el"
+;;; rul-vc.el --- Version control configuration -*- lexical-binding: t; -*-
+
+(setq vc-follow-symlinks nil)
+
+(use-package magit
+ :ensure t
+ :bind (("C-c g s" . magit-status)
+ ("C-c g F" . magit-pull-from-upstream)
+ ("C-c g b" . magit-blame))
+ :hook (git-commit-setup . rul/git-commit-setup)
+ :config
+ (defun rul/git-commit-setup ()
+ "Enable useful text modes for Git commit buffers."
+ (flyspell-mode 1)
+ (auto-fill-mode 1))
+
+ (defun rul/magit-status-save-window-config (&rest _)
+ "Save current window configuration before invoking `magit-status'."
+ (window-configuration-to-register :magit-fullscreen))
+
+ (defun rul/magit-status-single-window (&rest _)
+ "Display `magit-status' in a single window."
+ (delete-other-windows))
+
+ (advice-add 'magit-status :before #'rul/magit-status-save-window-config)
+ (advice-add 'magit-status :after #'rul/magit-status-single-window))
+
+(with-eval-after-load 'project
+ (add-to-list 'project-switch-commands
+ '(magit-project-status "Magit" "m")))
+
+(provide 'rul-vc)
+;;; rul-vc.el ends here
+#+end_src
+
+** The =wm= module
+TODO
+
+#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-wm.el"
+;;;; window.el
+;; Inspiration: https://christiantietze.de/posts/2022/12/updated-org-mode-agenda-display-buffer-alist/
+(defun rul/display-buffer-org-agenda-managed-p (buffer-name action)
+ "Determine whether BUFFER-NAME is an org-agenda managed buffer."
+ (with-current-buffer buffer-name
+ (or (derived-mode-p 'org-mode 'org-agenda-mode)
+ (member (buffer-file-name) (org-agenda-files)))))
+
+;; Side window for dictionary
+(setq switch-to-buffer-obey-display-actions t)
+(add-to-list 'display-buffer-alist
+ '("^\\*Dictionary\\*" display-buffer-in-side-window
+ (side . bottom)
+ (window-height . 12)
+ ))
+
+;;;; tab-bar.el
+(let ((map global-map))
+(define-key map (kbd "C-<next>") 'tab-bar-switch-to-next-tab)
+(define-key map (kbd "C-<prior>") 'tab-bar-switch-to-prev-tab)
+(define-key map (kbd "<f8>") 'tab-bar-mode))
+
+(setq tab-bar-format
+ '(tab-bar-format-tabs
+ ;; tab-bar-format-align-right
+ ;; tab-bar-format-global
+ ))
+
+(setq tab-bar-new-tab-to 'rightmost)
+(setq tab-bar-close-button-show nil)
+(set-face-attribute 'tab-bar nil :height 0.8)
+
+;; I've moved to a frame oriented workflow, so I no longer use tabs.
+;; (tab-bar-mode 1)
+
+;; Pop-up buffers
+;; https://protesilaos.com/codelog/2024-09-19-emacs-command-popup-frame-emacsclient/
+(defun prot-window-delete-popup-frame (&rest _)
+ "Kill selected selected frame if it has parameter `prot-window-popup-frame'.
+Use this function via a hook."
+ (when (frame-parameter nil 'prot-window-popup-frame)
+ (delete-frame)))
+
+(defmacro prot-window-define-with-popup-frame (command)
+ "Define interactive function which calls COMMAND in a new frame.
+Make the new frame have the `prot-window-popup-frame' parameter."
+ `(defun ,(intern (format "prot-window-popup-%s" command)) ()
+ ,(format "Run `%s' in a popup frame with `prot-window-popup-frame' parameter.
+Also see `prot-window-delete-popup-frame'." command)
+ (interactive)
+ (let ((frame (make-frame '((prot-window-popup-frame . t)))))
+ (select-frame frame)
+ ;; Placeholder for frame, otherwise it'll get autoclosed.
+ (switch-to-buffer " prot-window-hidden-buffer-for-popup-frame")
+ (condition-case nil
+ (call-interactively ',command)
+ ((quit error user-error)
+ (delete-frame frame))))))
+
+(declare-function org-capture "org-capture" (&optional goto keys))
+(defvar org-capture-after-finalize-hook)
+
+;;;###autoload (autoload 'prot-window-popup-org-capture "prot-window")
+(prot-window-define-with-popup-frame org-capture)
+
+(add-hook 'org-capture-after-finalize-hook #'prot-window-delete-popup-frame)
+
+(use-package olivetti
+ :ensure t
+ :defer t
+ :config
+ (setq olivetti-body-width 100))
+
+(use-package logos
+:ensure t
+:config
+
+;; If you want to use outlines instead of page breaks (the ^L)
+(setq logos-outlines-are-pages t)
+(setq logos-outline-regexp-alist
+ `((emacs-lisp-mode . "^;;;+ ")
+ (org-mode . "^\\*+ +")
+ (markdown-mode . "^\\#+ +")
+ ))
+
+;; These apply when `logos-focus-mode' is enabled. Their value is
+;; buffer-local.
+(setq-default logos-hide-mode-line t
+ logos-hide-buffer-boundaries t
+ logos-hide-fringe t
+ logos-variable-pitch nil
+ logos-buffer-read-only nil
+ logos-scroll-lock nil
+ logos-olivetti t
+ olivetti-body-width 100
+ )
+
+
+(let ((map global-map))
+ (define-key map [remap narrow-to-region] #'logos-narrow-dwim)
+ (define-key map [remap forward-page] #'logos-forward-page-dwim)
+ (define-key map [remap backward-page] #'logos-backward-page-dwim)
+ (define-key map (kbd "<f7>") #'logos-focus-mode))
+)
+
+(use-package beframe
+ :ensure t
+ :hook (after-init . beframe-mode)
+ :config
+ (setq beframe-functions-in-frames '(project-prompt-project-dir))
+ (setq beframe-global-buffers nil)
+ (define-key global-map (kbd "C-c b") beframe-prefix-map)
+
+ ;;Integration with Consult
+ (defvar consult-buffer-sources)
+ (declare-function consult--buffer-state "consult")
+
+ (with-eval-after-load 'consult
+ (defface beframe-buffer
+ '((t :inherit font-lock-string-face))
+ "Face for `consult' framed buffers.")
+
+ (defun my-beframe-buffer-names-sorted (&optional frame)
+ "Return the list of buffers from `beframe-buffer-names' sorted by visibility.
+With optional argument FRAME, return the list of buffers of FRAME."
+ (beframe-buffer-names frame :sort #'beframe-buffer-sort-visibility))
+
+ (defvar beframe-consult-source
+ `( :name "Frame-specific buffers (current frame)"
+ :narrow ?F
+ :category buffer
+ :face beframe-buffer
+ :history beframe-history
+ :items ,#'my-beframe-buffer-names-sorted
+ :action ,#'switch-to-buffer
+ :state ,#'consult--buffer-state))
+
+ (add-to-list 'consult-buffer-sources 'beframe-consult-source)))
+
+(defun kill-project-buffers-and-close-frame ()
+ (interactive)
+ (project-kill-buffers)
+ (delete-frame (selected-frame)))
+
+(define-key global-map (kbd "C-x p K") 'kill-project-buffers-and-close-frame)
+
+(add-hook 'text-mode-hook 'context-menu-mode)
+
+(defun my-context-menu (menu click)
+ "My context menu"
+ (define-key-after menu [dictionary-lookup]
+ '(menu-item "Dict" dictionary-search-word-at-mouse
+ :help "Look up in dictionary"))
+ menu)
+
+;; hook into context menu
+(add-hook 'context-menu-functions #'my-context-menu)
+
+(provide 'rul-wm)
+#+end_src
+
+** The =write= module
+TODO
+
+#+begin_src emacs-lisp :tangle "rul-lisp/packages/rul-write.el"
+;;;; `dictionary'
+(setq dictionary-server "localhost"
+ dictionary-default-popup-strategy "lev"
+ dictionary-create-buttons nil
+ dictionary-use-single-buffer t)
+(define-key global-map (kbd "C-c d") #'dictionary-lookup-definition)
+
+(use-package denote
+ :ensure t
+ :hook (dired-mode . denote-dired-mode)
+ :bind
+ (("C-c n n" . denote)
+ ("C-c n r" . denote-rename-file)
+ ("C-c n l" . denote-link)
+ ("C-c n b" . denote-backlinks))
+ :config
+ (denote-rename-buffer-mode 1)
+ (setq denote-infer-keywords t)
+ (setq denote-sort-keywords t)
+ (setq denote-file-type 'org)
+ (setq denote-excluded-directories-regexp nil)
+ (setq denote-allow-multi-word-keywords nil)
+ (setq denote-link-fontify-backlinks t)
+ (setq denote-rename-no-confirm t)
+
+ (let ((map global-map))
+ (define-key map (kbd "C-c n j") #'denote-journal-new-or-existing-entry)
+ (define-key map (kbd "C-c n n") #'denote)
+ (define-key map (kbd "C-c n f") #'denote-open-or-create)
+ (define-key map (kbd "C-c n i") #'denote-link)
+ (define-key map (kbd "C-c n r") #'denote-rename-file)
+ )
+)
+
+(use-package electric
+ :init
+ (setq electric-quote-replace-double t)
+ :hook
+ (message-mode . electric-quote-local-mode))
+
+(use-package message
+ :hook
+ (message-mode . my/message-mode-setup))
+
+(defun my/message-mode-setup ()
+ (setq fill-column 72
+ sentence-end-double-space nil)
+ (auto-fill-mode 1))
+
+;; Flycheck
+(use-package flycheck
+ :ensure t
+ :config
+
+(flycheck-define-checker proselint
+ "A linter for prose."
+ :command ("proselint" source-inplace)
+ :error-patterns
+ ((warning line-start (file-name) ":" line ":" column ": "
+ (id (one-or-more (not (any " "))))
+ (message) line-end))
+ :modes (text-mode markdown-mode gfm-mode org-mode))
+
+(add-to-list 'flycheck-checkers 'proselint)
+
+;; TODO: docker run --rm -p 8010:8010 erikvl87/languagetool
+(use-package flycheck-languagetool
+ :ensure t
+ :hook (message-mode . flycheck-languagetool-setup)
+ :init
+ (setq flycheck-languagetool-url "http://localhost:8010")
+))
+
+;; Flyspell
+(defcustom flyspell-delayed-commands nil
+ "List of commands that are \"delayed\" for Flyspell mode.
+After these commands, Flyspell checking is delayed for a short time,
+whose length is specified by `flyspell-delay'."
+ :group 'flyspell
+ :type '(repeat (symbol)))
+
+(setq ispell-dictionary "en")
+(setq flyspell-default-dictionary "en")
+
+(setq flyspell-issue-welcome-flag nil)
+(setq-default ispell-list-command "list")
+
+(provide 'rul-write)
+#+end_src
+
nihil fit ex nihilo