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.

140 lines
5.7 KiB

5 years ago
  1. (in-package :swank)
  2. (defvar *application-hints-tables* '()
  3. "A list of hash tables mapping symbols to indentation hints (lists
  4. of symbols and numbers as per cl-indent.el). Applications can add hash
  5. tables to the list to change the auto indentation slime sends to
  6. emacs.")
  7. (defun has-application-indentation-hint-p (symbol)
  8. (let ((default (load-time-value (gensym))))
  9. (dolist (table *application-hints-tables*)
  10. (let ((indentation (gethash symbol table default)))
  11. (unless (eq default indentation)
  12. (return-from has-application-indentation-hint-p
  13. (values indentation t))))))
  14. (values nil nil))
  15. (defun application-indentation-hint (symbol)
  16. (let ((indentation (has-application-indentation-hint-p symbol)))
  17. (labels ((walk (indentation-spec)
  18. (etypecase indentation-spec
  19. (null nil)
  20. (number indentation-spec)
  21. (symbol (string-downcase indentation-spec))
  22. (cons (cons (walk (car indentation-spec))
  23. (walk (cdr indentation-spec)))))))
  24. (walk indentation))))
  25. ;;; override swank version of this function
  26. (defun symbol-indentation (symbol)
  27. "Return a form describing the indentation of SYMBOL.
  28. The form is to be used as the `common-lisp-indent-function' property
  29. in Emacs."
  30. (cond
  31. ((has-application-indentation-hint-p symbol)
  32. (application-indentation-hint symbol))
  33. ((and (macro-function symbol)
  34. (not (known-to-emacs-p symbol)))
  35. (let ((arglist (arglist symbol)))
  36. (etypecase arglist
  37. ((member :not-available)
  38. nil)
  39. (list
  40. (macro-indentation arglist)))))
  41. (t nil)))
  42. ;;; More complex version.
  43. (defun macro-indentation (arglist)
  44. (labels ((frob (list &optional base)
  45. (if (every (lambda (x)
  46. (member x '(nil "&rest") :test #'equal))
  47. list)
  48. ;; If there was nothing interesting, don't return anything.
  49. nil
  50. ;; Otherwise substitute leading NIL's with 4 or 1.
  51. (let ((ok t))
  52. (substitute-if (if base
  53. 4
  54. 1)
  55. (lambda (x)
  56. (if (and ok (not x))
  57. t
  58. (setf ok nil)))
  59. list))))
  60. (walk (list level &optional firstp)
  61. (when (consp list)
  62. (let ((head (car list)))
  63. (if (consp head)
  64. (let ((indent (frob (walk head (+ level 1) t))))
  65. (cons (list* "&whole" (if (zerop level)
  66. 4
  67. 1)
  68. indent) (walk (cdr list) level)))
  69. (case head
  70. ;; &BODY is &BODY, this is clear.
  71. (&body
  72. '("&body"))
  73. ;; &KEY is tricksy. If it's at the base level, we want
  74. ;; to indent them normally:
  75. ;;
  76. ;; (foo bar quux
  77. ;; :quux t
  78. ;; :zot nil)
  79. ;;
  80. ;; If it's at a destructuring level, we want indent of 1:
  81. ;;
  82. ;; (with-foo (var arg
  83. ;; :foo t
  84. ;; :quux nil)
  85. ;; ...)
  86. (&key
  87. (if (zerop level)
  88. '("&rest" nil)
  89. '("&rest" 1)))
  90. ;; &REST is tricksy. If it's at the front of
  91. ;; destructuring, we want to indent by 1, otherwise
  92. ;; normally:
  93. ;;
  94. ;; (foo (bar quux
  95. ;; zot)
  96. ;; ...)
  97. ;;
  98. ;; but
  99. ;;
  100. ;; (foo bar quux
  101. ;; zot)
  102. (&rest
  103. (if (and (plusp level) firstp)
  104. '("&rest" 1)
  105. '("&rest" nil)))
  106. ;; &WHOLE and &ENVIRONMENT are skipped as if they weren't there
  107. ;; at all.
  108. ((&whole &environment)
  109. (walk (cddr list) level firstp))
  110. ;; &OPTIONAL is indented normally -- and the &OPTIONAL marker
  111. ;; itself is not counted.
  112. (&optional
  113. (walk (cdr list) level))
  114. ;; Indent normally, walk the tail -- but
  115. ;; unknown lambda-list keywords terminate the walk.
  116. (otherwise
  117. (unless (member head lambda-list-keywords)
  118. (cons nil (walk (cdr list) level))))))))))
  119. (frob (walk arglist 0 t) t)))
  120. #+nil
  121. (progn
  122. (assert (equal '(4 4 ("&whole" 4 "&rest" 1) "&body")
  123. (macro-indentation '(bar quux (&rest slots) &body body))))
  124. (assert (equal nil
  125. (macro-indentation '(a b c &rest more))))
  126. (assert (equal '(4 4 4 "&body")
  127. (macro-indentation '(a b c &body more))))
  128. (assert (equal '(("&whole" 4 1 1 "&rest" 1) "&body")
  129. (macro-indentation '((name zot &key foo bar) &body body))))
  130. (assert (equal nil
  131. (macro-indentation '(x y &key z)))))
  132. (provide :swank-indentation)