* 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