* Folding
#+begin_src emacs-lisp
(defun get-indent-point-at-line ()
"Return the column of the first non-whitespace character on current line."
(save-excursion
(beginning-of-line)
(skip-chars-forward " \t")
(current-column)))
(defun get-previous-line-indent-point ()
"Return the column of the first non-whitespace character on the previous
line, or 0 if there is no previous line."
(save-excursion
(if (= (forward-line -1) 0) ; forward-line returns 0 on success
(get-indent-point-at-line)
0)))
(defun wrycode/indent-prose ()
(let ((bol (line-beginning-position))
(eol (line-end-position)))
(if (string-match-p "^[ \t]*$" (buffer-substring bol eol))
;; blank line
(let ((prev-indent (get-previous-line-indent-point))
(current-col (current-column)))
(cond
;; Case 1: Not at previous indent point - move there
((not (= current-col prev-indent))
(delete-region bol eol)
(indent-to prev-indent))
;; Case 2: Already at previous indent point - add one tab
(t
(insert "\t"))))
;; line with text already
(let* ((current-indent (get-indent-point-at-line ))
(prev-indent (get-previous-line-indent-point))
(valid-indent-1 prev-indent)
(valid-indent-2 (+ prev-indent tab-width))
(point-col (current-column))
(point-before-indent (< point-col current-indent))
(moved-something nil))
;; If point is before indent point, move it there
(when point-before-indent
(move-to-column current-indent)
(setq moved-something t))
;; Check if current indent is already valid
(if (and (not moved-something)
(or (= current-indent valid-indent-1)
(= current-indent valid-indent-2)))
'noreturn
;; Sync indent point with previous line if needed
(unless (= current-indent prev-indent)
(save-excursion
(beginning-of-line)
(delete-horizontal-space)
(indent-to prev-indent))
(setq moved-something t))
;; After syncing, if point ended up before new indent, move it
(when (and moved-something (< (current-column) prev-indent))
(move-to-column prev-indent))
;; Return 'noreturn if nothing changed
(if moved-something nil 'noreturn))))))
(add-hook 'text-mode-hook (lambda () (setq-local indent-line-function 'wrycode/indent-prose)) )
(add-hook 'markdown-mode-hook (lambda () (setq-local indent-line-function 'wrycode/indent-prose)) )
(add-hook 'org-mode-hook (lambda () (setq-local indent-line-function 'org-indent-line)) )
#+end_src
* Text manipulation
The ~fill-paragraph~ (~M-q~) command can be useful for formatting long text lines in a pleasing matter. I don't do it in every document, but when I do, I want more columns than the default *:70*.
#+begin_src emacs-lisp
(setq-default fill-column 120)
(use-package expand-region)
(use-package emacs
:bind (
:map text-mode-map
("C-+" . er/expand-region)
("C--" . er/contract-region)
)
)
#+end_src
* Dictionary lookup
#+begin_src emacs-lisp
(use-package dictionary
:bind (("C-c l" . dictionary-lookup-definition))
:config
(setq dictionary-server "dict.org"))
#+end_src
* Grammar checker
Language Tool
#+begin_src emacs-lisp
(use-package langtool
:ensure t
:init
(setq langtool-default-language "de-DE")
(setq langtool-language-tool-jar
(expand-file-name (concat emacsen-dir "/java/LanguageTool/languagetool-commandline.jar"))
)
)
#+end_src
* Spell Checking
As described in "Mastering Emacs" https://www.masteringemacs.org/article/correcting-typos-misspellings-abbrev
, abbreviations are used to correct typos. A list of common typos is loaded according to the language active in the buffer.
#+begin_src emacs-lisp
(add-hook 'text-mode-hook 'abbrev-mode)
#+end_src
#+begin_src emacs-lisp
(require 'ispell)
(setq spellcheck-dir (expand-file-name (concat emacsen-dir "/spelling/")))
(setq ispell-personal-dictionary (expand-file-name (concat spellcheck-dir "ve-dict")))
(setq ispell-local-dictionary "de_DE")
(setq ispell-program-name (executable-find "hunspell"))
(use-package flyspell
:bind ( :map flyspell-mode-map
("C-." . nil)
)
:config
(setq flyspell-abbrev-p t
flyspell-use-global-abbrev-table-p t
flyspell-issue-message-flag nil
flyspell-issue-welcome-flag nil)
:hook ((text-mode . flyspell-mode)
(prog-mode . flyspell-prog-mode)))
(use-package flyspell-correct
:ensure t
:after flyspell
:custom
(flyspell-correct-interface #'flyspell-correct-completing-read))
(defun flyspell-learn-word-at-point ()
"Takes the highlighted word at point -- nominally a misspelling -- and inserts it into the personal/private dictionary, such that it is known and recognized as a valid word in the future."
(interactive)
(let ((current-location (point))
(word (flyspell-get-word)))
(when (consp word)
(flyspell-do-correct
'save nil
(car word)
current-location
(cadr word)
(caddr word)
current-location))))
#+end_src
** UI
#+begin_src emacs-lisp
(use-package consult-flyspell
:config
;; default settings
(setq consult-flyspell-select-function nil
consult-flyspell-set-point-after-word t
consult-flyspell-always-check-buffer nil))
#+end_src
* Pandoc: Conversion of text formats
#+begin_src emacs-lisp
(use-package pandoc :defer t)
(add-hook 'pandoc-mode-hook 'pandoc-load-default-settings)
#+end_src
* Text files
** Completion at Point
#+begin_src emacs-lisp
(defun my/text-mode-hook ()
"My customization for `text-mode'."
(setq-local completion-at-point-functions
(list #'cape-file #'cape-dabbrev #'cape-dict))
)
(add-hook 'text-mode-hook #'my/text-mode-hook)
#+end_src
** Natural Language
*** Create Language Mode
DISCARDED
https://stackoverflow.com/questions/28140668/emacs-abbrev-mode-in-natural-languages
*** Guess Buffer Language
#+begin_src emacs-lisp
(use-package guess-language)
(setq guess-language-languages '(en de))
(setq guess-language-min-paragraph-length 35)
(setq guess-language-langcodes
'((en . ("en_GB" "English" "GB" "English"))
(de . ("de_DE" "German" "D" "German"))))
(add-hook 'text-mode-hook (lambda () (guess-language-mode t)))
(defun my/natural-lang-change-function (lang beginning end)
"change abbreviations and set language for language-tool"
(let ((language (nth 2 (assoc lang guess-language-langcodes)))
)
(cond ((string= language "German")
(progn
(setq-local ispell-local-dictionary "de_DE")
(clear-abbrev-table text-mode-abbrev-table)
(load (expand-file-name (concat emacsen-dir "/abbreviations/umlaute-de.el")))
(load (expand-file-name (concat emacsen-dir "/abbreviations/autocorrect-de.el")))
(setq langtool-default-language "de-DE")
(setq-local cape-dict-file (concat emacsen-dir "/abbreviations/de-words.txt"))
)
)
((string= language "English")
(progn
(setq-local ispell-local-dictionary "en_GB")
(clear-abbrev-table text-mode-abbrev-table)
(load (expand-file-name (concat emacsen-dir "/abbreviations/autocorrect-en.el")))
(setq langtool-default-language "en-GB")
(setq-local cape-dict-file (concat emacsen-dir "/abbreviations/en-words.txt"))
)
)
(t (clear-abbrev-table text-mode-abbrev-table))
)
)
)
(add-hook 'guess-language-after-detection-functions #'my/natural-lang-change-function)
#+end_src
** Org-mode
Use tempel for templates.
*** Mode Setup
#+begin_src emacs-lisp
(use-package org
:bind (
:map org-mode-map (
("M-<left>" . nil)
("M-<right>" . nil)
("C-c a" . org-agenda)
("C-c c" . org-mode-insert-code)
)
)
:custom
(org-return-follows-link t)
(org-src-ask-before-returning-to-edit-buffer nil "??? org-src ???")
(org-src-window-setup 'current-window)
(org-directory (expand-file-name (concat (getenv "HOME") "/gtd/")))
:config
(setq org-cycle-emulate-tab 'exc-hl-bol)
(setq org-time-stamp-custom-formats (quote ("<%m/%d/%y %a %H:%M>" \, "<%m/%d/%y %a>")))
(setq org-read-date-prefer-future 'time)
:init
(defun make-inserter (c) '(lambda () (interactive) (insert-char c)))
(defun zero-width () (interactive) (insert ""))
(defun org-mode-insert-code ()
"Like markdown-insert-code, but for org instead."
(interactive)
(org-emphasize ?~))
(defun org-fold-done-entries ()
"Close/fold all entries marked DONE."
(interactive)
(save-excursion
(goto-char (point-max))
(while (outline-previous-heading)
(when (org-entry-is-done-p)
(hide-subtree)))))
(defun my/org-babel-indent-all ()
"indent all source blocks in buffer"
(interactive)
(org-edit-special)
(indent-buffer)
(org-edit-src-exit))
(defun my/org-babel-indent ()
"indent all source blocks in buffer"
(interactive)
(org-babel-mark-block)
(indent-region (region-beginning) (region-end))
)
(defun my/org-mode-hook ()
;; works out of the box for flyspell
(add-to-list 'ispell-skip-region-alist '(org-property-re))
(add-to-list 'ispell-skip-region-alist '(org-property-drawer-re))
(add-to-list 'ispell-skip-region-alist '(org-clock-drawer-re))
(add-to-list 'ispell-skip-region-alist '(org-logbook-drawer-re))
(add-to-list 'ispell-skip-region-alist '("~" . "~"))
(add-to-list 'ispell-skip-region-alist '("=" . "="))
(add-to-list 'ispell-skip-region-alist '("*" . "*"))
(add-to-list 'ispell-skip-region-alist '("/" . "/"))
)
(defun my/org-hide-done-entries-in-buffer ()
(interactive)
(org-map-entries #'org-fold-hide-subtree
"/+DONE" 'file 'archive 'comment))
:hook ((org-mode . visual-line-mode)
;; (org-mode . my/org-mode-hook)
(org-mode . tempel-setup-capf)
(org-src-mode . display-line-numbers-mode)
)
)
(require 'org-tempo)
#+end_src
**** TODO Additions
Contains unmaintained packages. Used:
- ox-confluence
- ob-tcl
- ob-asymptote
- ob-ledger
#+begin_src emacs-lisp
(use-package org-contrib)
#+end_src
**** Confluence
Export org-documents to Confluence markup.
#+begin_src emacs-lisp
(require 'ox-confluence)
#+end_src
**** More Export Options
#+begin_src emacs-lisp
(use-package ox-pandoc)
#+end_src
**** Babel
#+begin_src emacs-lisp
(require 'ob-asymptote)
(require 'ob-tcl)
(require 'ob-ledger)
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(gnuplot . t)
(asymptote . t)
(python . t)
(tcl . t)
(calc . t)
(julia . t)
(R . t)
(dot . t)
(sql . t)
(awk . t)
(shell . t)
))
(setq org-confirm-babel-evaluate nil
org-src-fontify-natively t
org-src-tab-acts-natively t)
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)
#+end_src
**** Multiple Major Modes in org buffers
#+begin_src emacs-lisp
(use-package poly-org)
#+end_src
**** TODO ELisp Literate Programming
https://github.com/jingtaozf/literate-elisp
*** Visuals
The package *org-modern* makes org-buffers look much cleaner.
#+begin_src emacs-lisp
(use-package org-modern
:config
(setq org-modern-star 'replace)
(setq org-modern-replace-stars '("▼" "▲" "●" "■" "◆" "◉" "▣"))
(setq org-modern-list '("–" "•" "◦" "▪" "▫"))
(setq org-modern-hide-stars " ")
(setq org-modern-fold-stars '(
("▶" . "▼")
("▷" . "▲")
("○" . "●")
("□" . "■")
("◇" . "◆")
("◎" . "◉")
("▱" . "▣")
))
(global-org-modern-mode)
(setq
;; Edit settings
org-auto-align-tags nil
org-tags-column 0
org-catch-invisible-edits 'show-and-error
org-special-ctrl-a/e t
org-insert-heading-respect-content t
;; Org styling, hide markup etc.
org-hide-emphasis-markers t
org-pretty-entities t
;; Agenda styling
org-agenda-tags-column 0
org-agenda-block-separator ?─
org-agenda-time-grid
'((daily today require-timed)
(800 1000 1200 1400 1600 1800 2000)
" ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")
org-agenda-current-time-string
"◀── now ─────────────────────────────────────────────────")
;; Ellipsis styling
(setq org-ellipsis "…")
(set-face-attribute 'org-ellipsis nil :inherit 'default :box nil)
)
#+end_src
*** UI
#+begin_src emacs-lisp
#+end_src
"a" 'org-agenda
"e" 'org-export-dispatch
"t" 'org-hide-block-toggle
"i" 'org-toggle-inline-images
"o" 'org-open-at-point
"b" '(:ignore t :which-key "babel")
"bd" 'org-babel-remove-result
"bx" 'org-babel-execute-src-block
"bX" 'org-babel-execute-and-next
"b/" 'my/org-babel-indent
"bf" 'my/org-babel-indent-all
"c" '(:ignore t :which-key "clock")
"cb" '(org-clock-in :wk "begin/start")
"ce" '(org-clock-out :wk "end/stop")
)
** Markdown
Use GitHub-flavored Markdown.
#+begin_src emacs-lisp
(use-package markdown-mode
:hook (gfm-mode . visual-line-mode)
:bind (:map markdown-mode-map ("C-c C-s a" . markdown-table-align))
:mode ("\\.md$" . gfm-mode))
#+end_src
** Muse
#+begin_src emacs-lisp
(use-package muse :defer t)
#+end_src
** ReST: Python Documentation Markup
"Mastering Emacs" by Mickey Petersen was written in ReST.
See https://www.masteringemacs.org/article/how-to-write-a-book-in-Emacs
#+begin_src emacs-lisp
(use-package rst :defer t)
#+end_src
* GTD
#+begin_src emacs-lisp
;; deutscher Kalender:
(setq calendar-week-start-day 1
calendar-day-name-array
["Sonntag" "Montag" "Dienstag" "Mittwoch"
"Donnerstag" "Freitag" "Samstag"]
calendar-month-name-array
["Januar" "Februar" "März" "April" "Mai"
"Juni" "Juli" "August" "September"
"Oktober" "November" "Dezember"])
#+end_src
#+begin_src emacs-lisp
;; Change task state to STARTED when clocking in
(setq org-clock-out-remove-zero-time-clocks t)
(setq org-clock-out-when-done t)
(setq org-clock-persist (quote history))
#+end_src
** Agenda
#+begin_src emacs-lisp
(setq org-agenda-clock-consistency-checks '(:max-duration "10:00"
:min-duration 0
:max-gap "0:05"
:gap-ok-around ("12:30")
:default-face (:background "Red")
:gap-face (:background "green")))
(setq org-agenda-start-with-log-mode t)
(setq org-agenda-start-with-clockreport-mode t)
(setq org-clock-report-include-clocking-task t)
(setq org-agenda-include-diary t)
(setq org-agenda-window-setup 'reorganize-frame)
(setq org-agenda-span 'week)
(setq org-agenda-files
(list (concat org-directory "studium.org")
(concat org-directory "aufgaben.org")
(concat org-directory "privat.org")
)
)
;; Tasks mit Datum in der Agenda ausblenden, wenn sie bereits erledigt sind:
(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-scheduled-if-done t)
(bind-key "o" #'org-agenda-goto 'org-agenda-mode-map)
#+end_src
* Notes
Based on org-mode
#+begin_src emacs-lisp
(use-package denote)
(setq denote-directory (expand-file-name (concat (getenv "HOME") "/notes/")))
(setq denote-known-keywords '("emacs" "eps" "ivv" "izs" "julia" "statistics" "probability"))
(setq denote-infer-keywords t)
(setq denote-sort-keywords t)
(setq denote-file-type nil) ; Org is the default, set others here
(setq denote-prompts '(title keywords))
(setq denote-date-prompt-use-org-read-date t)
(setq denote-allow-multi-word-keywords t)
(setq denote-date-format nil) ; read doc string
;; By default, we fontify backlinks in their bespoke buffer.
(setq denote-link-fontify-backlinks t)
(add-hook 'dired-mode-hook #'denote-dired-mode)
(defun my-denote-journal ()
"Create an entry tagged 'journal', while prompting for a title."
(interactive)
(denote
(denote-title-prompt)
'("journal")))
(with-eval-after-load 'org-capture
(setq denote-org-capture-specifiers "%l\n%i\n%?")
(add-to-list 'org-capture-templates
'("n" "New note (with denote.el)" plain
(file denote-last-path)
#'denote-org-capture
:no-save t
:immediate-finish nil
:kill-buffer t
:jump-to-captured t)))
#+end_src
define Hydra or better hercules-def
let ((map global-map))
(define-key map (kbd "C-c n j") #'my-denote-journal) ; our custom command
(define-key map (kbd "C-c n n") #'denote)
(define-key map (kbd "C-c n N") #'denote-type)
(define-key map (kbd "C-c n d") #'denote-date)
(define-key map (kbd "C-c n i") #'denote-link) ; "insert" mnemonic
(define-key map (kbd "C-c n r") #'denote-rename-file)
(define-key map (kbd "C-c n R") #'denote-rename-file-using-front-matter))
;; Key bindings specifically for Dired.
let ((map dired-mode-map))
(define-key map (kbd "C-c C-d C-i") #'denote-link-dired-marked-notes)
(define-key map (kbd "C-c C-d C-r") #'denote-dired-rename-marked-files)
(define-key map (kbd "C-c C-d C-R") #'denote-dired-rename-marked-files-using-front-matter))
* Web Presentations with reveal.js
Based on org-mode
#+begin_src emacs-lisp
(use-package org-re-reveal)
(setq org-re-reveal-title-slide nil)
(setq org-re-reveal-mathjax 1)
#+end_src
* TODO Spaced Repetition Learning
Based on org-mode
#+begin_src emacs-lisp
(use-package org-drill
:ensure t
:config
(setq org-drill-add-random-noise-to-intervals-p t)
(setq org-drill-adjust-intervals-for-early-and-late-repetitions-p t)
(setq org-drill-maximum-items-per-session 30)
(setq org-drill-maximum-duration 15) ; minutes
(setq org-drill-hint-separator "||")
(setq org-drill-left-cloze-delimiter "<[")
(setq org-drill-right-cloze-delimiter "]>")
(setq org-drill-learn-fraction 0.25)
)
#+end_src
* Bye
#+begin_src emacs-lisp
;;; text_gtd-setup.el ends here
#+end_src