#+TITLE: Reading and Writing Configuration
#+PROPERTY: header-args :tangle ~/.emacs.d/config.el

* Text and Case

** Convert DOuble capitals to single capitals

#+begin_src elisp :tangle no
  (defun my/dcaps-to-scaps ()
    "Convert word in DOuble CApitals to Single Capitals."
    (interactive)
    (and (= ?w (char-syntax (char-before)))
         (save-excursion
           (and (if (called-interactively-p)
                    (skip-syntax-backward "w")
                  (= -3 (skip-syntax-backward "w"))
                  )
                (let (case-fold-search)
                  (looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]")
                  )
              (capitalize-word 1)
              )
           )
         )
    )
#+end_src

Then, let’s define a minor mode for it to be activated.
#+begin_src elisp :tangle no
  (define-minor-mode my-dubcaps-mode
    "Toggle 'my-dubcaps-mode' and convert words in DOuble CApitals to Single Capitals as you type."
    :init-value nil
    :lighter (" DC")
    (if my-dubcaps-mode
        (add-hook 'post-self-insert-hook #'my/dcaps-to-scaps nil 'local)
      (remove-hook 'post-self-insert-hook #'my/dcaps-to-scaps 'local)))
#+end_src

 Finally, let’s add a hook so that it is on for all the text files Emacs opens.
#+begin_src elisp :tangle no
  (add-hook 'text-mode-hook #'my-dubcaps-mode)  
#+end_src

Also, since we add a minor mode string (it might be useful sometimes), currently I prefer to diminish it.
#+begin_src elisp :tangle no
  (defun my/diminish-dubcaps ()
    (interactive)
    (diminish 'my-dubcaps-mode ""))
  (add-hook 'my-dubcaps-mode-hook 'my/diminish-dubcaps)
#+end_src

* Reading and Writing

** Move correctly over camelCased words

#+begin_src elisp
  (subword-mode)
#+end_src

** Understand the more common sentence with double space

#+begin_src elisp
  (setq sentence-end-double-space nil)
#+end_src

** Join lines into paragraph

#+begin_src elisp
  (defun my/fill-or-unfill-paragraph (&optional unfill region)
    "Fill paragraph (or REGION). With the prefix argument UNFILL, fill it instead."
    (interactive (progn
                   (barf-if-buffer-read-only)
                   (list (if current-prefix-arg 'fill) t)))
    (let ((fill-column (if unfill fill-column (point-max))))
      (fill-paragraph nil region)))

  (bind-key "M-q" 'my/fill-or-unfill-paragraph)
#+end_src

#+begin_src elisp
  (defun my/fill-or-unfill-all-paragraphs (&optional unfill)
  "Fill or unfill all paragraphs in the current buffer.
With the prefix argument UNFILL, fill them instead."
  (interactive (list (if current-prefix-arg 'fill)))
  (let ((fill-column (if unfill fill-column (point-max))))
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
        (fill-paragraph nil t)
        (forward-paragraph)))))

(bind-key "M-Q" 'my/fill-or-unfill-all-paragraphs)
#+end_src

#+begin_src elisp
  (remove-hook 'text-mode-hook #'turn-on-auto-fill)
  (add-hook 'text-mode-hook 'turn-on-visual-line-mode)
#+end_src

** Expand some words with auto-correct

  #+begin_src elisp :tangle no
  (setq save-abbrevs 'silently)
  (setq-default abbrev-mode t)
  #+end_src

** ediff

#+begin_src elisp :tangle no
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (setq ediff-split-window-function 'split-window-horizontally)
#+end_src

** tramp

#+begin_src elisp :tangle no
  (setq tramp-default-method "ssh"
        tramp-backup-directory-alist backup-directory-alist
        tramp-ssh-controlmaster-options "ssh")
#+end_src

** Clean up space
#+begin_src elisp :tangle no
  (bind-key "M-SPC" 'cycle-spacing)
#+end_src

** Transform <a href> links into org links

#+begin_src elisp :tangle no
  (defun my/transform-html-links-to-org ()
  "Transform all HTML <a> links in the current buffer into 'org-mode' links."
  (interactive)
  (goto-char (point-min))
  (while (re-search-forward "<a href=\"\\(.*?\\)\">\\(.*?\\)</a>" nil t)
    (replace-match (org-make-link-string (match-string 1) (match-string 2)))))
#+end_src

** Count words per minute
#+begin_src elisp :tangle no
  (require 'org-clock)
  (defun my/org-entry-wpm ()
    (interactive)
    (save-restriction
      (save-excursion
        (org-narrow-to-subtree)
        (goto-char (point-min))
        (let* ((words (count-words-region (point-min) (point-max)))

               (minutes (org-clock-sum-current-item))
               (wpm (/ words minutes)))
          (message "WPM: %d (words: %d, minutes: %d)" wpm words minutes)
          (kill-new (number-to-string wpm))
          )
        )
      )
    )
#+end_src

** Enable dict mode
  #+begin_src elisp :tangle no
    (setq dictionary-server "automatic")
  #+end_src

** Pick out passive voice and weasel words
#+begin_src elisp :tangle no
  (use-package writegood-mode
    :diminish writegood-mode
    :config
    (progn (add-hook 'text-mode-hook 'writegood-mode))
    )
#+end_src

** Org-babel docker
#+begin_src elisp :tangle no
  (use-package ob-docker-build
    :straight (ob-docker-build :type git :host github :repo "ifitzpat/ob-docker-build")
    :defer t
    :config
    (add-to-list 'org-babel-load-languages '(docker-build . t))
    (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
  )
#+end_src

* Spelling and syntax

** Spell checking

This requires installation of hunspell
#+begin_src bash :tangle no
  sudo apt install hunspell
#+end_src

#+begin_src elisp
  (use-package flyspell
    :config (setq ispell-program-name "hunspell"
                  ispell-default-dictionary "en_US"
                  )
    :diminish (flyspell-mode . "φ")
    :hook (text-mode . flyspell-mode)
    :bind (
           ("M-<f7>" . flyspell-buffer)
           ("<f7>" . flyspell-word)
           ("C-;" . flyspell-auto-correct-previous-word)
           )
    )
#+end_src

** Flyspell correct
#+begin_src elisp :tangle no
  (use-package flyspell-correct
    :after flyspell
    :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))
  )
#+end_src

** Flycheck

Needs external checkers installed

#+begin_src elisp
  (use-package flycheck
    :init (global-flycheck-mode)
    :diminish (flycheck-mode . "")
    :config
    (add-hook 'after-init-hook #'global-flycheck-mode)
    (setq flycheck-emacs-lisp-load-path 'inherit)
    (setq flycheck-emacs-lisp-load-path (concat user-emacs-directory "straight/build"))
    )
#+end_src

** Flycheck bash
#+begin_src bash :tangle no
  sudo apt install devscripts
#+end_src

#+begin_src elisp :tangle no
  (use-package flycheck-checkbashisms
    :config
    (flycheck-checkbashisms-setup)
  )
#+end_src

** Yaml
#+begin_src elisp :tangle no
  (use-package yaml-mode
    :config
    (add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
    (add-to-list 'auto-mode-alist '("\\.yaml\\'" . yaml-mode))
    )
#+end_src

** Docker
#+begin_src elisp :tangle no
  (use-package docker-compose-mode)
#+end_src