;;; +casing.el --- Word-case-twiddling things -*- lexical-binding: t; -*-

;;; Code:

(require 'thingatpt)

;;;###autoload
(defun +upcase-dwim (arg)
  "Upcase words in the region, or upcase word at point.
If the region is active, this function calls `upcase-region'.
Otherwise, it calls `upcase-word' on the word at point (using
`thingatpt'), and the following ARG - 1 words."
  (interactive "*p")
  (if (use-region-p)
      (upcase-region (region-beginning) (region-end) (region-noncontiguous-p))
    (let ((following (1- arg))
          (word-bound (save-excursion
                        (skip-chars-forward "^[:word:]")
                        (bounds-of-thing-at-point 'word))))
      (when (and (car word-bound) (cdr word-bound))
        (upcase-region (car word-bound) (cdr word-bound))
        (goto-char (cdr word-bound))
        (upcase-word following)))))

;;;###autoload
(defun +downcase-dwim (arg)
  "Downcase words in the region, or downcase word at point.
If the region is active, this function calls `downcase-region'.
Otherwise, it calls `downcase-word' on the word at point (using
`thingatpt'), and the following ARG - 1 words."
  (interactive "*p")
  (if (use-region-p)
      (downcase-region (region-beginning) (region-end) (region-noncontiguous-p))
    (let ((following (1- arg))
          (word-bound (save-excursion
                        (skip-chars-forward "^[:word:]")
                        (bounds-of-thing-at-point 'word))))
      (when (and (car word-bound) (cdr word-bound))
        (downcase-region (car word-bound) (cdr word-bound))
        (goto-char (cdr word-bound))
        (downcase-word following)))))

;;;###autoload
(defun +capitalize-dwim (arg)
  "Capitalize words in the region, or capitalize word at point.
If the region is active, this function calls `capitalize-region'.
Otherwise, it calls `capitalize-word' on the word at point (using
`thingatpt'), and the following ARG - 1 words."
  (interactive "*p")
  (if (use-region-p)
      (capitalize-region (region-beginning) (region-end) (region-noncontiguous-p))
    (let ((following (1- arg))
          (word-bound (save-excursion
                        (skip-chars-forward "^[:word:]")
                        (bounds-of-thing-at-point 'word))))
      (when (and (car word-bound) (cdr word-bound))
        (capitalize-region (car word-bound) (cdr word-bound))
        (goto-char (cdr word-bound))
        (capitalize-word following)))))

;; Later on, I'll add repeat maps and stuff in here...

(defvar +casing-map (let ((map (make-sparse-keymap)))
                      (define-key map "u" #'+upcase-dwim)
                      (define-key map (kbd "M-u") #'+upcase-dwim)
                      (define-key map "l" #'+downcase-dwim)
                      (define-key map (kbd "M-l") #'+downcase-dwim)
                      (define-key map "c" #'+capitalize-dwim)
                      (define-key map (kbd "M-c") #'+capitalize-dwim)
                      map)
  "Keymap for case-related twiddling.")

(define-minor-mode +casing-mode
  "Enable easy case-twiddling commands."
  :lighter " cC"
  :global t
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "M-c") +casing-map)
            map))

(provide '+casing)
;;; +casing.el ends here
