armacs/customsrc/words.org

9.1 KiB
Raw Permalink Blame History

Word Smithing

Auto Complete

Using company-mode for all my auto completion needs.

Like this idea of being able to easily insert math symbols based on LaTeX keywords. Start typing a backslash.

  (use-package company
    :ensure t
    :init
    (setq company-dabbrev-ignore-case t
          company-show-numbers t)
    (add-hook 'after-init-hook 'global-company-mode)
    :config
    (add-to-list 'company-backends 'company-math-symbols-unicode)
    :bind ("C-:" . company-complete)  ; In case I don't want to wait
    :diminish company-mode)
    (defun check-expansion ()
    (save-excursion
    (if (looking-at "\\_>") t
    (backward-char 1)
    (if (looking-at "\\.") t
    (backward-char 1)
    (if (looking-at "->") t nil)))))
    
    (defun do-yas-expand ()
    (let ((yas/fallback-behavior 'return-nil))
    (yas/expand)))
    
    (defun tab-indent-or-complete ()
    (interactive)
    (if (minibufferp)
    (minibuffer-complete)
    (if (or (not yas/minor-mode)
    (null (do-yas-expand)))
    (if (check-expansion)
    (company-complete-common)
    (indent-for-tab-command)))))
    (global-set-key [tab] 'tab-indent-or-complete)
    (use-package company-web
    :ensure t)
    (define-key web-mode-map (kbd "C-'") 'company-web-html)

    ;; emmet integration
    (custom-set-faces
'(company-preview
((t (:foreground "darkgray" :underline t))))
'(company-preview-common
((t (:inherit company-preview))))
'(company-tooltip
((t (:background "lightgray" :foreground "black"))))
'(company-tooltip-selection
((t (:background "steelblue" :foreground "white"))))
'(company-tooltip-common
((((type x)) (:inherit company-tooltip :weight bold))
 (t (:inherit company-tooltip))))
'(company-tooltip-common-selection
((((type x)) (:inherit company-tooltip-selection :weight bold))
 (t (:inherit company-tooltip-selection)))))
(defun my-web-mode-hook ()
"Hook for `web-mode'."
 (set (make-local-variable 'company-backends)
      '(company-web-html company-yasnippet company-files)))

(add-hook 'web-mode-hook 'my-web-mode-hook)

;; Enable JavaScript completion between <script>...</script> etc.
(advice-add 'company-tern :before
         #'(lambda (&rest _)
             (if (equal major-mode 'web-mode)
                 (let ((web-mode-cur-language
                       (web-mode-language-at-pos)))
                   (if (or (string= web-mode-cur-language "javascript")
                           (string= web-mode-cur-language "jsx"))
                       (unless tern-mode (tern-mode))
                     (if tern-mode (tern-mode -1)))))))

;; manual autocomplete
(define-key web-mode-map (kbd "M-SPC") 'company-complete)

Take advantage of idle time by displaying some documentation using company-quickhelp project.

  (use-package company-quickhelp
    :ensure t
    :config
    (company-quickhelp-mode 1))

This also requires pos-tip.

Yasnippets

The yasnippet project allows me to create snippets of code that can be brought into a file, based on the language.

  (use-package yasnippet
    :ensure t
    :init
    (yas-global-mode 1)
    :config)
    (add-hook 'after-init-hook 'global-company-mode)
    (global-set-key (kbd "M-/") 'company-complete-common)
    (use-package company-jedi)
    (add-to-list 'company-backends 'company-jedi)
    (add-hook 'python-mode-hook 'jedi:setup)
    (setq jedi:complete-on-dot t)

Note:: the snippets directory contains directories for each mode, e.g. clojure-mode and org-mode.

Spell Checking

Spell checking with FlySpell, which uses the built-in settings of ispell. The ASpell project is better supported than ISpell, and it seems to be better than Hunspell for programming modes.

  brew install aspell

Start for all text modes (but not for log files):

  (use-package flyspell
    :ensure t
    :diminish flyspell-mode
    :init
    (add-hook 'prog-mode-hook 'flyspell-prog-mode)

    (dolist (hook '(text-mode-hook org-mode-hook))
      (add-hook hook (lambda () (flyspell-mode 1))))

    (dolist (hook '(change-log-mode-hook log-edit-mode-hook org-agenda-mode-hook))
      (add-hook hook (lambda () (flyspell-mode -1))))

    :config
    (setq ispell-program-name "/usr/local/bin/aspell"
          ispell-local-dictionary "en_US"
          ispell-dictionary "american" ; better for aspell
          ispell-extra-args '("--sug-mode=ultra" "--lang=en_US")
          ispell-list-command "--list"
          ispell-local-dictionary-alist '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']"
                                        t ; Many other characters
                                        ("-d" "en_US") nil utf-8))))

ASpell automatically configures a personal dictionary at ~/.aspell.en.pws, so no need to configure that.

A possibly nifty feature of aspell is the ability to spellcheck individual words in CamelCase that is used extensively in some code (for details, see this article).

  (use-package flyspell
    :config
    (defun flyspell-detect-ispell-args (&optional run-together)
      "if RUN-TOGETHER is true, spell check the CamelCase words."
      (let (args)
        (setq args (list "--sug-mode=ultra" "--lang=en_US"))
        (if run-together
            (setq args (append args '("--run-together" "--run-together-limit=5" "--run-together-min=2"))))
        args))

    ;; ispell-cmd-args is useless, it's the list of *extra* arguments we will append to the ispell process when "ispell-word" is called.
    ;; ispell-extra-args is the command arguments which will *always* be used when start ispell process
    (setq-default ispell-extra-args (flyspell-detect-ispell-args t))

    (defadvice ispell-word (around my-ispell-word activate)
      (let ((old-ispell-extra-args ispell-extra-args))
        (ispell-kill-ispell t)
        (setq ispell-extra-args (flyspell-detect-ispell-args))
        ad-do-it
        (setq ispell-extra-args old-ispell-extra-args)
        (ispell-kill-ispell t)))

    (defadvice flyspell-auto-correct-word (around my-flyspell-auto-correct-word activate)
      (let ((old-ispell-extra-args ispell-extra-args))
        (ispell-kill-ispell t)
        ;; use emacs original arguments
        (setq ispell-extra-args (flyspell-detect-ispell-args))
        ad-do-it
        ;; restore our own ispell arguments
        (setq ispell-extra-args old-ispell-extra-args)
        (ispell-kill-ispell t)))

    (defun text-mode-hook-setup ()
      ;; Turn off RUN-TOGETHER option when spell check text-mode
      (setq-local ispell-extra-args (flyspell-detect-ispell-args)))

    (add-hook 'text-mode-hook 'text-mode-hook-setup))

According to this essay, we can make a flyspell-goto-previous-error (which really should be added to the official flyspell project):

  (defun flyspell-goto-previous-error (arg)
    "Go to ARG previous spelling error."
    (interactive "p")
    (while (not (= 0 arg))
      (let ((pos (point))
            (min (point-min)))
        (when (and (eq (current-buffer) flyspell-old-buffer-error)
                   (eq pos flyspell-old-pos-error))
          (if (= flyspell-old-pos-error min)
              ;; goto beginning of buffer
              (progn
                (message "Restarting from end of buffer")
                (goto-char (point-max)))
            (backward-word 1))
          (setq pos (point)))

        ;; seek the next error
        (while (and (> pos min)
                    (let ((ovs (overlays-at pos))
                          (r '()))
                      (while (and (not r) (consp ovs))
                        (if (flyspell-overlay-p (car ovs))
                            (setq r t)
                          (setq ovs (cdr ovs))))
                      (not r)))
          (backward-word 1)
          (setq pos (point)))
        ;; save the current location for next invocation
        (setq arg (1- arg))
        (setq flyspell-old-pos-error pos)
        (setq flyspell-old-buffer-error (current-buffer))
        (goto-char pos)
        (if (= pos min)
            (progn
              (message "No more miss-spelled words!")
              (setq arg 0))))))