Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
9.3 KiB

4 years ago
  1. (require 'slime)
  2. (require 'slime-parse)
  3. (require 'slime-autodoc)
  4. (require 'font-lock)
  5. (require 'cl-lib)
  6. ;;; Fontify WITH-FOO, DO-FOO, and DEFINE-FOO like standard macros.
  7. ;;; Fontify CHECK-FOO like CHECK-TYPE.
  8. (defvar slime-additional-font-lock-keywords
  9. '(("(\\(\\(\\s_\\|\\w\\)*:\\(define-\\|do-\\|with-\\|without-\\)\\(\\s_\\|\\w\\)*\\)" 1 font-lock-keyword-face)
  10. ("(\\(\\(define-\\|do-\\|with-\\)\\(\\s_\\|\\w\\)*\\)" 1 font-lock-keyword-face)
  11. ("(\\(check-\\(\\s_\\|\\w\\)*\\)" 1 font-lock-warning-face)
  12. ("(\\(assert-\\(\\s_\\|\\w\\)*\\)" 1 font-lock-warning-face)))
  13. ;;;; Specially fontify forms suppressed by a reader conditional.
  14. (defcustom slime-highlight-suppressed-forms t
  15. "Display forms disabled by reader conditionals as comments."
  16. :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil))
  17. :group 'slime-mode)
  18. (define-slime-contrib slime-fontifying-fu
  19. "Additional fontification tweaks:
  20. Fontify WITH-FOO, DO-FOO, DEFINE-FOO like standard macros.
  21. Fontify CHECK-FOO like CHECK-TYPE."
  22. (:authors "Tobias C. Rittweiler <tcr@freebits.de>")
  23. (:license "GPL")
  24. (:on-load
  25. (font-lock-add-keywords
  26. 'lisp-mode slime-additional-font-lock-keywords)
  27. (when slime-highlight-suppressed-forms
  28. (slime-activate-font-lock-magic)))
  29. (:on-unload
  30. ;; FIXME: remove `slime-search-suppressed-forms', and remove the
  31. ;; extend-region hook.
  32. (font-lock-remove-keywords
  33. 'lisp-mode slime-additional-font-lock-keywords)))
  34. (defface slime-reader-conditional-face
  35. '((t (:inherit font-lock-comment-face)))
  36. "Face for compiler notes while selected."
  37. :group 'slime-mode-faces)
  38. (defvar slime-search-suppressed-forms-match-data (list nil nil))
  39. (defun slime-search-suppressed-forms-internal (limit)
  40. (when (search-forward-regexp slime-reader-conditionals-regexp limit t)
  41. (let ((start (match-beginning 0)) ; save match data
  42. (state (slime-current-parser-state)))
  43. (if (or (nth 3 state) (nth 4 state)) ; inside string or comment?
  44. (slime-search-suppressed-forms-internal limit)
  45. (let* ((char (char-before))
  46. (expr (read (current-buffer)))
  47. (val (slime-eval-feature-expression expr)))
  48. (when (<= (point) limit)
  49. (if (or (and (eq char ?+) (not val))
  50. (and (eq char ?-) val))
  51. ;; If `slime-extend-region-for-font-lock' did not
  52. ;; fully extend the region, the assertion below may
  53. ;; fail. This should only happen on XEmacs and older
  54. ;; versions of GNU Emacs.
  55. (ignore-errors
  56. (forward-sexp) (backward-sexp)
  57. ;; Try to suppress as far as possible.
  58. (slime-forward-sexp)
  59. (cl-assert (<= (point) limit))
  60. (let ((md (match-data nil slime-search-suppressed-forms-match-data)))
  61. (setf (cl-first md) start)
  62. (setf (cl-second md) (point))
  63. (set-match-data md)
  64. t))
  65. (slime-search-suppressed-forms-internal limit))))))))
  66. (defun slime-search-suppressed-forms (limit)
  67. "Find reader conditionalized forms where the test is false."
  68. (when (and slime-highlight-suppressed-forms
  69. (slime-connected-p))
  70. (let ((result 'retry))
  71. (while (and (eq result 'retry) (<= (point) limit))
  72. (condition-case condition
  73. (setq result (slime-search-suppressed-forms-internal limit))
  74. (end-of-file ; e.g. #+(
  75. (setq result nil))
  76. ;; We found a reader conditional we couldn't process for
  77. ;; some reason; however, there may still be other reader
  78. ;; conditionals before `limit'.
  79. (invalid-read-syntax ; e.g. #+#.foo
  80. (setq result 'retry))
  81. (scan-error ; e.g. #+nil (foo ...
  82. (setq result 'retry))
  83. (slime-incorrect-feature-expression ; e.g. #+(not foo bar)
  84. (setq result 'retry))
  85. (slime-unknown-feature-expression ; e.g. #+(foo)
  86. (setq result 'retry))
  87. (error
  88. (setq result nil)
  89. (slime-display-warning
  90. (concat "Caught error during fontification while searching for forms\n"
  91. "that are suppressed by reader-conditionals. The error was: %S.")
  92. condition))))
  93. result)))
  94. (defun slime-search-directly-preceding-reader-conditional ()
  95. "Search for a directly preceding reader conditional. Return its
  96. position, or nil."
  97. ;;; We search for a preceding reader conditional. Then we check that
  98. ;;; between the reader conditional and the point where we started is
  99. ;;; no other intervening sexp, and we check that the reader
  100. ;;; conditional is at the same nesting level.
  101. (condition-case nil
  102. (let* ((orig-pt (point))
  103. (reader-conditional-pt
  104. (search-backward-regexp slime-reader-conditionals-regexp
  105. ;; We restrict the search to the
  106. ;; beginning of the /previous/ defun.
  107. (save-excursion
  108. (beginning-of-defun)
  109. (point))
  110. t)))
  111. (when reader-conditional-pt
  112. (let* ((parser-state
  113. (parse-partial-sexp
  114. (progn (goto-char (+ reader-conditional-pt 2))
  115. (forward-sexp) ; skip feature expr.
  116. (point))
  117. orig-pt))
  118. (paren-depth (car parser-state))
  119. (last-sexp-pt (cl-caddr parser-state)))
  120. (if (and paren-depth
  121. (not (cl-plusp paren-depth)) ; no '(' in between?
  122. (not last-sexp-pt)) ; no complete sexp in between?
  123. reader-conditional-pt
  124. nil))))
  125. (scan-error nil))) ; improper feature expression
  126. ;;; We'll push this onto `font-lock-extend-region-functions'. In past,
  127. ;;; we didn't do so which made our reader-conditional font-lock magic
  128. ;;; pretty unreliable (it wouldn't highlight all suppressed forms, and
  129. ;;; worked quite non-deterministic in general.)
  130. ;;;
  131. ;;; Cf. _Elisp Manual_, 23.6.10 Multiline Font Lock Constructs.
  132. ;;;
  133. ;;; We make sure that `font-lock-beg' and `font-lock-end' always point
  134. ;;; to the beginning or end of a toplevel form. So we never miss a
  135. ;;; reader-conditional, or point in mid of one.
  136. (defvar font-lock-beg) ; shoosh compiler
  137. (defvar font-lock-end)
  138. (defun slime-extend-region-for-font-lock ()
  139. (when slime-highlight-suppressed-forms
  140. (condition-case c
  141. (let (changedp)
  142. (cl-multiple-value-setq (changedp font-lock-beg font-lock-end)
  143. (slime-compute-region-for-font-lock font-lock-beg font-lock-end))
  144. changedp)
  145. (error
  146. (slime-display-warning
  147. (concat "Caught error when trying to extend the region for fontification.\n"
  148. "The error was: %S\n"
  149. "Further: font-lock-beg=%d, font-lock-end=%d.")
  150. c font-lock-beg font-lock-end)))))
  151. (defun slime-beginning-of-tlf ()
  152. (let ((pos (syntax-ppss-toplevel-pos (slime-current-parser-state))))
  153. (if pos (goto-char pos))))
  154. (defun slime-compute-region-for-font-lock (orig-beg orig-end)
  155. (let ((beg orig-beg)
  156. (end orig-end))
  157. (goto-char beg)
  158. (inline (slime-beginning-of-tlf))
  159. (cl-assert (not (cl-plusp (nth 0 (slime-current-parser-state)))))
  160. (setq beg (let ((pt (point)))
  161. (cond ((> (- beg pt) 20000) beg)
  162. ((slime-search-directly-preceding-reader-conditional))
  163. (t pt))))
  164. (goto-char end)
  165. (while (search-backward-regexp slime-reader-conditionals-regexp beg t)
  166. (setq end (max end (save-excursion
  167. (ignore-errors (slime-forward-reader-conditional))
  168. (point)))))
  169. (cl-values (or (/= beg orig-beg) (/= end orig-end)) beg end)))
  170. (defun slime-activate-font-lock-magic ()
  171. (if (featurep 'xemacs)
  172. (let ((pattern `((slime-search-suppressed-forms
  173. (0 slime-reader-conditional-face t)))))
  174. (dolist (sym '(lisp-font-lock-keywords
  175. lisp-font-lock-keywords-1
  176. lisp-font-lock-keywords-2))
  177. (set sym (append (symbol-value sym) pattern))))
  178. (font-lock-add-keywords
  179. 'lisp-mode
  180. `((slime-search-suppressed-forms 0 ,''slime-reader-conditional-face t)))
  181. (add-hook 'lisp-mode-hook
  182. #'(lambda ()
  183. (add-hook 'font-lock-extend-region-functions
  184. 'slime-extend-region-for-font-lock t t)))))
  185. (let ((byte-compile-warnings '()))
  186. (mapc (lambda (sym)
  187. (cond ((fboundp sym)
  188. (unless (byte-code-function-p (symbol-function sym))
  189. (byte-compile sym)))
  190. (t (error "%S is not fbound" sym))))
  191. '(slime-extend-region-for-font-lock
  192. slime-compute-region-for-font-lock
  193. slime-search-directly-preceding-reader-conditional
  194. slime-search-suppressed-forms
  195. slime-beginning-of-tlf)))
  196. (cl-defun slime-initialize-lisp-buffer-for-test-suite
  197. (&key (font-lock-magic t) (autodoc t))
  198. (let ((hook lisp-mode-hook))
  199. (unwind-protect
  200. (progn
  201. (set (make-local-variable 'slime-highlight-suppressed-forms)
  202. font-lock-magic)
  203. (setq lisp-mode-hook nil)
  204. (lisp-mode)
  205. (slime-mode 1)
  206. (when (boundp 'slime-autodoc-mode)
  207. (if autodoc
  208. (slime-autodoc-mode 1)
  209. (slime-autodoc-mode -1))))
  210. (setq lisp-mode-hook hook))))
  211. (provide 'slime-fontifying-fu)