Personal emacs config
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.

144 lines
4.7 KiB

  1. ;;; le-lisp.el --- lispy support for Common Lisp. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2014-2015 Oleh Krehel
  3. ;; This file is not part of GNU Emacs
  4. ;; This file is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation; either version 3, or (at your option)
  7. ;; any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; For a full copy of the GNU General Public License
  13. ;; see <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;;
  16. ;;; Code:
  17. (eval-and-compile
  18. (require 'slime nil t)
  19. (require 'sly nil t))
  20. (declare-function slime-output-buffer "ext:slime-repl")
  21. (declare-function slime "ext:slime")
  22. (declare-function slime-current-connection "ext:slime")
  23. (declare-function slime-eval "ext:slime")
  24. (declare-function slime-edit-definition "ext:slime")
  25. (declare-function sly-mrepl--find-buffer "ext:sly-mrepl")
  26. (declare-function sly "ext:sly")
  27. (declare-function sly-current-connection "ext:sly")
  28. (declare-function sly-eval "ext:sly")
  29. (declare-function sly-edit-definition "ext:sly")
  30. (defcustom lispy-use-sly nil
  31. "Whether to use SLY instead of SLIME."
  32. :group 'lispy
  33. :type 'boolean)
  34. (defun lispy--eval-lisp (str)
  35. "Eval STR as Common Lisp code."
  36. (let* ((deactivate-mark nil)
  37. (result (with-current-buffer (process-buffer (lispy--cl-process))
  38. (if lispy-use-sly
  39. (sly-eval `(slynk:eval-and-grab-output ,str))
  40. (slime-eval `(swank:eval-and-grab-output ,str))))))
  41. (if (equal (car result) "")
  42. (cadr result)
  43. (concat (propertize (car result)
  44. 'face 'font-lock-string-face)
  45. "\n\n"
  46. (cadr result)))))
  47. (defun lispy--cl-process ()
  48. (unless lispy-use-sly
  49. (require 'slime-repl))
  50. (or (if lispy-use-sly
  51. (sly-current-connection)
  52. (slime-current-connection))
  53. (let (conn)
  54. (let ((wnd (current-window-configuration)))
  55. (if lispy-use-sly
  56. (sly)
  57. (slime))
  58. (while (not (if lispy-use-sly
  59. (and (setq conn (sly-current-connection))
  60. (sly-mrepl--find-buffer conn))
  61. (and
  62. (setq conn (slime-current-connection))
  63. (get-buffer-window (slime-output-buffer)))))
  64. (sit-for 0.2))
  65. (set-window-configuration wnd)
  66. conn))))
  67. (defun lispy--lisp-args (symbol)
  68. "Return a pretty string with arguments for SYMBOL."
  69. (let ((args
  70. (list
  71. (mapconcat
  72. #'prin1-to-string
  73. (read (lispy--eval-lisp
  74. (format (if lispy-use-sly
  75. "(slynk-backend:arglist #'%s)"
  76. "(swank-backend:arglist #'%s)")
  77. symbol)))
  78. " "))))
  79. (if (listp args)
  80. (format
  81. "(%s %s)"
  82. (propertize symbol 'face 'lispy-face-hint)
  83. (mapconcat
  84. #'identity
  85. (mapcar (lambda (x) (propertize (downcase x)
  86. 'face 'lispy-face-req-nosel))
  87. args)
  88. (concat "\n"
  89. (make-string (+ 2 (length symbol)) ?\ ))))
  90. (propertize args 'face 'lispy-face-hint))))
  91. (defun lispy--lisp-describe (symbol)
  92. "Return documentation for SYMBOL."
  93. (read
  94. (lispy--eval-lisp
  95. (substring-no-properties
  96. (format
  97. "(let ((x '%s))
  98. (or (if (boundp x)
  99. (documentation x 'variable)
  100. (documentation x 'function))
  101. \"undocumented\"))"
  102. symbol)))))
  103. (defun lispy-flatten--lisp ()
  104. (let* ((bnd (lispy--bounds-list))
  105. (str (lispy--string-dwim bnd))
  106. (expr (read str))
  107. (fexpr (read (lispy--eval-lisp
  108. (format "(function-lambda-expression #'%S)" (car expr))))))
  109. (if (not (eq (car-safe fexpr) 'SB-INT:NAMED-LAMBDA))
  110. (error "Could not find the body of %S" (car expr))
  111. (setq fexpr (downcase
  112. (prin1-to-string
  113. `(lambda ,(nth 2 fexpr) ,(cl-caddr (nth 3 fexpr))))))
  114. (goto-char (car bnd))
  115. (delete-region (car bnd) (cdr bnd))
  116. (let* ((e-args (cdr expr))
  117. (body (lispy--flatten-function fexpr e-args)))
  118. (lispy--insert body)))))
  119. (defun lispy-goto-symbol-lisp (symbol)
  120. ;; start SLY or SLIME if necessary
  121. (lispy--cl-process)
  122. (if lispy-use-sly
  123. (sly-edit-definition symbol)
  124. (slime-edit-definition symbol)))
  125. (provide 'le-lisp)
  126. ;;; le-lisp.el ends here