guile-scheme.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. ;;; guile-scheme.el --- Guile Scheme editing mode
  2. ;; Copyright (C) 2001, 2006 Free Software Foundation, Inc.
  3. ;; GNU Emacs is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation; either version 2, or (at your option)
  6. ;; any later version.
  7. ;; GNU Emacs is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with GNU Emacs; see the file COPYING. If not, write to the
  13. ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. ;; Boston, MA 02110-1301, USA.
  15. ;;; Commentary:
  16. ;; Put the following lines in your ~/.emacs:
  17. ;;
  18. ;; (require 'guile-scheme)
  19. ;; (setq initial-major-mode 'scheme-interaction-mode)
  20. ;;; Code:
  21. (require 'guile)
  22. (require 'scheme)
  23. (defgroup guile-scheme nil
  24. "Editing Guile-Scheme code"
  25. :group 'lisp)
  26. (defvar guile-scheme-syntax-keywords
  27. '((begin 0) (if 1) (cond 0) (case 1) (do 2)
  28. quote syntax lambda and or else delay receive use-modules
  29. (match 1) (match-lambda 0) (match-lambda* 0)
  30. (let scheme-let-indent) (let* 1) (letrec 1) (and-let* 1)
  31. (let-syntax 1) (letrec-syntax 1) (syntax-rules 1) (syntax-case 2)))
  32. (defvar guile-scheme-special-procedures
  33. '((catch 1) (lazy-catch 1) (stack-catch 1)
  34. map for-each (dynamic-wind 3)))
  35. ;; set indent functions
  36. (dolist (x (append guile-scheme-syntax-keywords
  37. guile-scheme-special-procedures))
  38. (when (consp x)
  39. (put (car x) 'scheme-indent-function (cadr x))))
  40. (defconst guile-scheme-font-lock-keywords
  41. (eval-when-compile
  42. (list
  43. (list (concat "(\\(define\\*?\\("
  44. ;; Function names.
  45. "\\(\\|-public\\|-method\\|-generic\\)\\|"
  46. ;; Macro names, as variable names.
  47. "\\(-syntax\\|-macro\\)\\|"
  48. ;; Others
  49. "-\\sw+\\)\\)\\>"
  50. ;; Any whitespace and declared object.
  51. "\\s *(?\\(\\sw+\\)?")
  52. '(1 font-lock-keyword-face)
  53. '(5 (cond ((match-beginning 3) font-lock-function-name-face)
  54. ((match-beginning 4) font-lock-variable-name-face)
  55. (t font-lock-type-face)) nil t))
  56. (list (concat
  57. "(" (regexp-opt
  58. (mapcar (lambda (e)
  59. (prin1-to-string (if (consp e) (car e) e)))
  60. (append guile-scheme-syntax-keywords
  61. guile-scheme-special-procedures)) 'words))
  62. '(1 font-lock-keyword-face))
  63. '("<\\sw+>" . font-lock-type-face)
  64. '("\\<:\\sw+\\>" . font-lock-builtin-face)
  65. ))
  66. "Expressions to highlight in Guile Scheme mode.")
  67. ;;;
  68. ;;; Guile Scheme mode
  69. ;;;
  70. (defvar guile-scheme-mode-map nil
  71. "Keymap for Guile Scheme mode.
  72. All commands in `lisp-mode-shared-map' are inherited by this map.")
  73. (unless guile-scheme-mode-map
  74. (let ((map (make-sparse-keymap "Guile-Scheme")))
  75. (setq guile-scheme-mode-map map)
  76. (cond ((boundp 'lisp-mode-shared-map)
  77. (set-keymap-parent map lisp-mode-shared-map))
  78. ((boundp 'shared-lisp-mode-map)
  79. (set-keymap-parent map shared-lisp-mode-map)))
  80. (define-key map [menu-bar] (make-sparse-keymap))
  81. (define-key map [menu-bar guile-scheme] (cons "Guile-Scheme" map))
  82. (define-key map [uncomment-region]
  83. '("Uncomment Out Region" . (lambda (beg end)
  84. (interactive "r")
  85. (comment-region beg end '(4)))))
  86. (define-key map [comment-region] '("Comment Out Region" . comment-region))
  87. (define-key map [indent-region] '("Indent Region" . indent-region))
  88. (define-key map [indent-line] '("Indent Line" . lisp-indent-line))
  89. (define-key map "\e\C-i" 'guile-scheme-complete-symbol)
  90. (define-key map "\e\C-x" 'guile-scheme-eval-define)
  91. (define-key map "\C-x\C-e" 'guile-scheme-eval-last-sexp)
  92. (define-key map "\C-c\C-b" 'guile-scheme-eval-buffer)
  93. (define-key map "\C-c\C-r" 'guile-scheme-eval-region)
  94. (define-key map "\C-c:" 'guile-scheme-eval-expression)
  95. (define-key map "\C-c\C-a" 'guile-scheme-apropos)
  96. (define-key map "\C-c\C-d" 'guile-scheme-describe)
  97. (define-key map "\C-c\C-k" 'guile-scheme-kill-process)
  98. (put 'comment-region 'menu-enable 'mark-active)
  99. (put 'uncomment-region 'menu-enable 'mark-active)
  100. (put 'indent-region 'menu-enable 'mark-active)))
  101. (defcustom guile-scheme-mode-hook nil
  102. "Normal hook run when entering `guile-scheme-mode'."
  103. :type 'hook
  104. :group 'guile-scheme)
  105. ;;;###autoload
  106. (defun guile-scheme-mode ()
  107. "Major mode for editing Guile Scheme code.
  108. Editing commands are similar to those of `scheme-mode'.
  109. \\{scheme-mode-map}
  110. Entry to this mode calls the value of `scheme-mode-hook'
  111. if that value is non-nil."
  112. (interactive)
  113. (kill-all-local-variables)
  114. (setq mode-name "Guile Scheme")
  115. (setq major-mode 'guile-scheme-mode)
  116. (use-local-map guile-scheme-mode-map)
  117. (scheme-mode-variables)
  118. (setq mode-line-process
  119. '(:eval (if (processp guile-scheme-adapter)
  120. (format " [%s]" guile-scheme-command)
  121. "")))
  122. (setq font-lock-defaults
  123. '((guile-scheme-font-lock-keywords)
  124. nil t (("+-*/.<>=!?$%_&~^:@" . "w")) beginning-of-defun
  125. (font-lock-mark-block-function . mark-defun)))
  126. (run-hooks 'guile-scheme-mode-hook))
  127. ;;;
  128. ;;; Scheme interaction mode
  129. ;;;
  130. (defvar scheme-interaction-mode-map ()
  131. "Keymap for Scheme Interaction mode.
  132. All commands in `guile-scheme-mode-map' are inherited by this map.")
  133. (unless scheme-interaction-mode-map
  134. (let ((map (make-sparse-keymap)))
  135. (setq scheme-interaction-mode-map map)
  136. (set-keymap-parent map guile-scheme-mode-map)
  137. (define-key map "\C-j" 'guile-scheme-eval-print-last-sexp)
  138. ))
  139. (defvar scheme-interaction-mode-hook nil
  140. "Normal hook run when entering `scheme-interaction-mode'.")
  141. (defun scheme-interaction-mode ()
  142. "Major mode for evaluating Scheme expressions with Guile.
  143. \\{scheme-interaction-mode-map}"
  144. (interactive)
  145. (guile-scheme-mode)
  146. (use-local-map scheme-interaction-mode-map)
  147. (setq major-mode 'scheme-interaction-mode)
  148. (setq mode-name "Scheme Interaction")
  149. (run-hooks 'scheme-interaction-mode-hook))
  150. ;;;
  151. ;;; Guile Scheme adapter
  152. ;;;
  153. (defvar guile-scheme-command "guile")
  154. (defvar guile-scheme-adapter nil)
  155. (defvar guile-scheme-module nil)
  156. (defun guile-scheme-adapter ()
  157. (if (and (processp guile-scheme-adapter)
  158. (eq (process-status guile-scheme-adapter) 'run))
  159. guile-scheme-adapter
  160. (setq guile-scheme-module nil)
  161. (setq guile-scheme-adapter
  162. (guile:make-adapter guile-scheme-command 'emacs-scheme-channel))))
  163. (defun guile-scheme-set-module ()
  164. "Set the current module based on buffer contents.
  165. If there is a (define-module ...) form, evaluate it.
  166. Otherwise, choose module (guile-user)."
  167. (save-excursion
  168. (let ((module (if (re-search-backward "^(define-module " nil t)
  169. (let ((start (match-beginning 0)))
  170. (goto-char start)
  171. (forward-sexp)
  172. (buffer-substring-no-properties start (point)))
  173. "(define-module (emacs-user))")))
  174. (unless (string= guile-scheme-module module)
  175. (prog1 (guile:eval module (guile-scheme-adapter))
  176. (setq guile-scheme-module module))))))
  177. (defun guile-scheme-eval-string (string)
  178. (guile-scheme-set-module)
  179. (guile:eval string (guile-scheme-adapter)))
  180. (defun guile-scheme-display-result (value flag)
  181. (if (string= value "#<unspecified>")
  182. (setq value "done"))
  183. (if flag
  184. (insert value)
  185. (message "%s" value)))
  186. ;;;
  187. ;;; Interactive commands
  188. ;;;
  189. (defun guile-scheme-eval-expression (string)
  190. "Evaluate the expression in STRING and show value in echo area."
  191. (interactive "SGuile Scheme Eval: ")
  192. (guile-scheme-display-result (guile-scheme-eval-string string) nil))
  193. (defun guile-scheme-eval-region (start end)
  194. "Evaluate the region as Guile Scheme code."
  195. (interactive "r")
  196. (guile-scheme-eval-expression (buffer-substring-no-properties start end)))
  197. (defun guile-scheme-eval-buffer ()
  198. "Evaluate the current buffer as Guile Scheme code."
  199. (interactive)
  200. (guile-scheme-eval-expression (buffer-string)))
  201. (defun guile-scheme-eval-last-sexp (arg)
  202. "Evaluate sexp before point; show value in echo area.
  203. With argument, print output into current buffer."
  204. (interactive "P")
  205. (guile-scheme-display-result
  206. (guile-scheme-eval-string
  207. (buffer-substring-no-properties
  208. (point) (save-excursion (backward-sexp) (point)))) arg))
  209. (defun guile-scheme-eval-print-last-sexp ()
  210. "Evaluate sexp before point; print value into current buffer."
  211. (interactive)
  212. (let ((start (point)))
  213. (guile-scheme-eval-last-sexp t)
  214. (insert "\n")
  215. (save-excursion (goto-char start) (insert "\n"))))
  216. (defun guile-scheme-eval-define ()
  217. (interactive)
  218. (guile-scheme-eval-region (save-excursion (end-of-defun) (point))
  219. (save-excursion (beginning-of-defun) (point))))
  220. (defun guile-scheme-load-file (file)
  221. "Load a Guile Scheme file."
  222. (interactive "fGuile Scheme load file: ")
  223. (guile-scheme-eval-string (format "(load %s)" (expand-file-name file)))
  224. (message "done"))
  225. (guile-import guile-emacs-complete-alist)
  226. (defun guile-scheme-complete-symbol ()
  227. (interactive)
  228. (let* ((end (point))
  229. (start (save-excursion (skip-syntax-backward "w_") (point)))
  230. (pattern (buffer-substring-no-properties start end))
  231. (alist (guile-emacs-complete-alist pattern)))
  232. (goto-char end)
  233. (let ((completion (try-completion pattern alist)))
  234. (cond ((eq completion t))
  235. ((not completion)
  236. (message "Can't find completion for \"%s\"" pattern)
  237. (ding))
  238. ((not (string= pattern completion))
  239. (delete-region start end)
  240. (insert completion))
  241. (t
  242. (message "Making completion list...")
  243. (with-output-to-temp-buffer "*Completions*"
  244. (display-completion-list alist))
  245. (message "Making completion list...done"))))))
  246. (guile-import guile-emacs-apropos)
  247. (defun guile-scheme-apropos (regexp)
  248. (interactive "sGuile Scheme apropos (regexp): ")
  249. (guile-scheme-set-module)
  250. (with-output-to-temp-buffer "*Help*"
  251. (princ (guile-emacs-apropos regexp))))
  252. (guile-import guile-emacs-describe)
  253. (defun guile-scheme-describe (symbol)
  254. (interactive (list (guile-scheme-input-symbol "Describe Guile variable")))
  255. (guile-scheme-set-module)
  256. (with-output-to-temp-buffer "*Help*"
  257. (princ (guile-emacs-describe symbol))))
  258. (defun guile-scheme-kill-process ()
  259. (interactive)
  260. (if guile-scheme-adapter
  261. (guile-process-kill guile-scheme-adapter))
  262. (setq guile-scheme-adapter nil))
  263. ;;;
  264. ;;; Internal functions
  265. ;;;
  266. (guile-import apropos-internal guile-apropos-internal)
  267. (defvar guile-scheme-complete-table (make-vector 151 nil))
  268. (defun guile-scheme-input-symbol (prompt)
  269. (mapc (lambda (sym)
  270. (if (symbolp sym)
  271. (intern (symbol-name sym) guile-scheme-complete-table)))
  272. (guile-apropos-internal ""))
  273. (let* ((str (thing-at-point 'symbol))
  274. (default (if (intern-soft str guile-scheme-complete-table)
  275. (concat " (default " str ")")
  276. "")))
  277. (intern (completing-read (concat prompt default ": ")
  278. guile-scheme-complete-table nil t nil nil str))))
  279. ;;;
  280. ;;; Turn on guile-scheme-mode for .scm files by default.
  281. ;;;
  282. (setq auto-mode-alist
  283. (cons '("\\.scm\\'" . guile-scheme-mode) auto-mode-alist))
  284. (provide 'guile-scheme)
  285. ;;; guile-scheme.el ends here