70
70
(defvar slime-use-highlight-edits-mode nil
71
71
"When non-nil always enable slime-highlight-edits-mode in slime-mode")
73
(defvar slime-highlight-compiler-notes t
74
"When non-nil highlight buffers with compilation notes, warnings and errors.")
73
76
(defun* slime-setup (&key autodoc typeout-frame highlight-edits)
74
77
"Setup Emacs so that lisp-mode buffers always use SLIME."
75
78
(when (member 'lisp-mode slime-lisp-modes)
105
108
The default value is automatically computed from the location of the
106
109
Emacs Lisp package."))
112
(defun slime-changelog-date ()
113
"Return the datestring of the latest entry in the ChangeLog file.
114
Return nil if the ChangeLog file cannot be found."
115
(let ((changelog "/usr/share/doc/cl-swank/changelog"))
116
(if (file-exists-p changelog)
118
(insert-file-contents changelog nil 0 100)
119
(goto-char (point-min))
120
(symbol-name (read (current-buffer))))
123
(defvar slime-protocol-version nil)
124
(setq slime-protocol-version
125
(eval-when-compile (slime-changelog-date)))
109
128
;;;; Customize groups
258
277
:group 'slime-mode
261
(defcustom slime-complete-keywords-contextually t
262
"Use information from the arglist of the surrounding function call
263
to complete keywords."
280
(defcustom slime-fuzzy-completion-in-place nil
281
"When non-NIL the fuzzy symbol completion is done in place as
282
opposed to moving the point to the completion buffer."
264
283
:group 'slime-mode
286
(defcustom slime-fuzzy-completion-limit 300
287
"Only return and present this many symbols from swank."
291
(defcustom slime-fuzzy-completion-time-limit-in-msec 1500
292
"Limit the time spent (given in msec) in swank while gathering comletitions.
293
\(NOTE: currently it's rounded up the nearest second)"
267
297
(defcustom slime-space-information-p t
268
298
"Have the SPC key offer arglist information."
503
533
:group 'slime-repl)
505
(defcustom slime-repl-history-size 1000
535
(defcustom slime-repl-history-size 200
506
536
"*Maximum number of lines for persistent REPL history."
508
538
:group 'slime-repl)
542
;;;; slime-target-buffer-fuzzy-completions-mode
543
;;;; NOTE: this mode has to be able to override key mappings in slime-mode
545
(defun mimic-key-bindings (from-keymap to-keymap bindings-or-operation operation)
546
"Iterate on BINDINGS-OR-OPERATION. If an element is a symbol then
547
try to look it up (as an operation) in FROM-KEYMAP. Non symbols are taken
548
as default key bindings when none to be mimiced was found in FROM-KEYMAP.
549
Set the resulting list of keys in TO-KEYMAP to OPERATION."
550
(let ((mimic-keys nil)
552
(dolist (key-or-operation bindings-or-operation)
553
(if (symbolp key-or-operation)
554
(setf mimic-keys (append mimic-keys (where-is-internal key-or-operation from-keymap nil t)))
555
(push key-or-operation direct-keys)))
556
(dolist (key (or mimic-keys direct-keys))
557
(define-key to-keymap key operation))))
559
(defvar slime-target-buffer-fuzzy-completions-map
560
(let* ((map (make-sparse-keymap)))
561
(flet ((remap (keys to)
562
(mimic-key-bindings global-map map keys to)))
564
(remap (list 'keyboard-quit (kbd "C-g")) 'slime-fuzzy-abort)
566
(remap (list 'slime-fuzzy-indent-and-complete-symbol
567
'slime-indent-and-complete-symbol
569
'slime-fuzzy-select-or-update-completions)
570
(remap (list 'previous-line (kbd "<up>")) 'slime-fuzzy-prev)
571
(remap (list 'next-line (kbd "<down>")) 'slime-fuzzy-next)
572
(remap (list 'isearch-forward (kbd "C-s"))
575
(select-window (get-buffer-window (slime-get-fuzzy-buffer)))
576
(call-interactively 'isearch-forward)))
578
;; some unconditional direct bindings
579
(dolist (key (list (kbd "RET") (kbd "<SPC>") "(" ")" "[" "]"))
580
(define-key map key 'slime-fuzzy-select-and-process-event-in-target-buffer)))
583
"Keymap for slime-target-buffer-fuzzy-completions-mode. This will override the key
584
bindings in the target buffer temporarily during completion.")
586
(define-minor-mode slime-fuzzy-target-buffer-completions-mode
587
"This minor mode is intented to override key bindings during fuzzy
588
completions in the target buffer. Most of the bindings will do an implicit select
589
in the completion window and let the keypress be processed in the target buffer."
592
slime-target-buffer-fuzzy-completions-map)
594
(add-to-list 'minor-mode-alist
595
'(slime-fuzzy-target-buffer-completions-mode
596
" Fuzzy Target Buffer Completions"))
514
600
(define-minor-mode slime-mode
515
601
"\\<slime-mode-map>\
516
602
SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode).
948
1034
(easy-menu-add slime-sldb-easy-menu 'sldb-mode-map)))
1037
;;;; Emacs compatibility
1039
(or (fboundp 'add-local-hook)
1040
(defun add-local-hook (hook function &optional append)
1041
(make-local-hook hook)
1042
(add-hook hook function append t)))
1044
(or (fboundp 'remove-local-hook)
1045
(defun remove-local-hook (hook function)
1046
(if (local-variable-p hook (current-buffer))
1047
(remove-hook hook function t))))
951
1050
;;;; Setup initial `slime-mode' hooks
953
1052
(make-variable-buffer-local
966
1065
(add-hook 'pre-command-hook 'slime-pre-command-hook)))
968
1067
(defun slime-setup-command-hooks ()
969
"Setup a buffer-local `pre-command-h'ook' to call `slime-pre-command-hook'."
970
(make-local-hook 'pre-command-hook)
971
(make-local-hook 'post-command-hook)
972
;; alanr: need local t
973
(add-hook 'pre-command-hook 'slime-pre-command-hook nil t)
974
(add-hook 'post-command-hook 'slime-post-command-hook nil t)
1068
"Setup a buffer-local `pre-command-hook' to call `slime-pre-command-hook'."
1069
(add-local-hook 'pre-command-hook 'slime-pre-command-hook)
1070
(add-local-hook 'post-command-hook 'slime-post-command-hook)
975
1071
(when slime-repl-enable-presentations
976
(make-local-variable 'after-change-functions)
977
(add-hook 'after-change-functions 'slime-after-change-function nil t)))
1072
(add-local-hook 'after-change-functions 'slime-after-change-function)))
980
1075
;;;; Framework'ey bits
1257
1352
(defun slime-temp-buffer-quit ()
1258
"Kill the current buffer and restore the old window configuration.
1259
See `slime-temp-buffer-dismiss'."
1353
"Kill the current (temp) buffer without asking. To restore the
1354
window configuration without killing the buffer see
1355
`slime-dismiss-temp-buffer'."
1261
(let ((buf (current-buffer)))
1262
(slime-dismiss-temp-buffer)
1357
(let* ((buffer (current-buffer))
1358
(window (get-buffer-window buffer)))
1359
(kill-buffer buffer)
1361
(delete-window window))))
1266
1364
(defun slime-dismiss-temp-buffer ()
1615
1714
(concat slime-path slime-backend)))
1616
1715
(encoding (slime-coding-system-cl-name coding-system)))
1617
(format "%S\n%S\n\n"
1618
`(load ,loader :verbose t)
1619
`(swank:start-server ,port-filename :external-format ,encoding))))
1716
;; Return a single form to avoid problems with buffered input.
1719
(load ,loader :verbose t)
1720
(funcall (read-from-string "swank:start-server")
1722
:coding-system ,encoding)))))
1621
1724
(defun slime-swank-port-file ()
1622
1725
"Filename where the SWANK server writes its TCP port number."
1778
1881
;;;;; Coding system madness
1780
1883
(defvar slime-net-valid-coding-systems
1781
'((iso-latin-1-unix nil :iso-latin-1-unix)
1782
(iso-8859-1-unix nil :iso-latin-1-unix)
1783
(binary nil :iso-latin-1-unix)
1784
(utf-8-unix t :utf-8-unix)
1785
(emacs-mule-unix t :emacs-mule-unix)
1786
(euc-jp-unix t :euc-jp-unix))
1884
'((iso-latin-1-unix nil "iso-latin-1-unix")
1885
(iso-8859-1-unix nil "iso-latin-1-unix")
1886
(binary nil "iso-latin-1-unix")
1887
(utf-8-unix t "utf-8-unix")
1888
(emacs-mule-unix t "emacs-mule-unix")
1889
(euc-jp-unix t "euc-jp-unix"))
1787
1890
"A list of valid coding systems.
1788
1891
Each element is of the form: (NAME MULTIBYTEP CL-NAME)")
2162
2265
"Initialize CONNECTION with INFO received from Lisp."
2163
2266
(let ((slime-dispatching-connection connection))
2164
2267
(destructuring-bind (&key pid style lisp-implementation machine
2165
features package) info
2268
features package version &allow-other-keys) info
2269
(or (equal version slime-protocol-version)
2270
(yes-or-no-p "Protocol version mismatch. Continue anyway? ")
2271
(slime-net-close connection)
2166
2273
(setf (slime-pid) pid
2167
2274
(slime-communication-style) style
2168
2275
(slime-lisp-features) features)
2380
2487
(slime-find-buffer-package)))))
2382
(defvar slime-find-buffer-package-function nil
2383
"Function to use instead of `slime-find-buffer-package'.
2384
The result should be a string. The string will be READ at the Lisp
2489
(defvar slime-find-buffer-package-function 'slime-search-buffer-package
2490
"*Function to use for `slime-find-buffer-package'.
2491
The result should be the package-name (a string)
2492
or nil if nothing suitable can be found.")
2387
2494
(defun slime-find-buffer-package ()
2388
2495
"Figure out which Lisp package the current buffer is associated with."
2389
(if slime-find-buffer-package-function
2390
(funcall slime-find-buffer-package-function)
2496
(funcall slime-find-buffer-package-function))
2498
;; When modifing this code consider cases like:
2499
;; (in-package #.*foo*)
2500
;; (in-package #:cl)
2502
;; (in-package "CL")
2503
;; (in-package |CL|)
2504
;; (in-package #+ansi-cl :cl #-ansi-cl 'lisp)
2505
(defun slime-search-buffer-package ()
2506
(let ((case-fold-search t)
2507
(regexp (concat "^(\\(cl:\\|common-lisp:\\)?in-package\\>[ \n\t\r']*"
2508
"\\([^)]+\\)[ \n\t]*)")))
2391
2509
(save-excursion
2392
(when (let ((case-fold-search t)
2393
(regexp "^(\\(cl:\\|common-lisp:\\)?in-package\\>"))
2394
(or (re-search-backward regexp nil t)
2395
(re-search-forward regexp nil t)))
2396
(goto-char (match-end 0))
2397
(skip-chars-forward " \n\t\f\r#'")
2399
((looking-at "\\.\\*swig-module-name\\*") ; # was skipped
2400
(if (re-search-backward "(defparameter \\*swig-module-name\\* \\(:?\\sw*\\))"
2402
(match-string-no-properties 1)))
2404
(let ((pkg (ignore-errors (read (current-buffer)))))
2405
(if pkg (format "%S" pkg)))))))))
2510
(when (or (re-search-backward regexp nil t)
2511
(re-search-forward regexp nil t))
2512
(let ((string (match-string-no-properties 2)))
2513
(cond ((string-match "^\"" string) (ignore-errors (read string)))
2514
((string-match "^#?:" string) (substring string (match-end 0)))
2407
2517
;;; Synchronous requests are implemented in terms of asynchronous
2408
2518
;;; ones. We make an asynchronous request with a continuation function
2538
2648
(assert thread)
2539
2649
(sldb-exit thread level stepping))
2540
2650
((:emacs-interrupt thread)
2541
(cond ((slime-use-sigint-for-interrupt) (slime-send-sigint))
2542
(t (slime-send `(:emacs-interrupt ,thread)))))
2651
(slime-send `(:emacs-interrupt ,thread)))
2543
2652
((:read-string thread tag)
2544
2653
(assert thread)
2545
2654
(slime-repl-read-string thread tag))
2708
2817
(slime-repl-insert-prompt (cond (use-header-p `(:suppress-output))
2709
2818
(t `(:values (,(concat "; " banner))))))))
2711
(defun slime-changelog-date ()
2712
"Return the datestring of the latest entry in the ChangeLog file.
2713
Return nil if the ChangeLog file cannot be found."
2714
(let ((changelog "/usr/share/doc/cl-swank/changelog"))
2715
(if (file-exists-p changelog)
2717
(insert-file-contents changelog nil 0 100)
2718
(goto-char (point-min))
2719
(symbol-name (read (current-buffer))))
2722
2820
(defun slime-init-output-buffer (connection)
2723
2821
(with-current-buffer (slime-output-buffer t)
2724
2822
(setq slime-buffer-connection connection
2828
2926
(defstruct slime-presentation text id)
2928
(defvar slime-presentation-syntax-table
2929
(let ((table (copy-syntax-table lisp-mode-syntax-table)))
2930
;; We give < and > parenthesis syntax, so that #< ... > is treated
2931
;; as a balanced expression. This allows to use C-M-k, C-M-SPC,
2932
;; etc. to deal with a whole presentation. (For Lisp mode, this
2933
;; is not desirable, since we do not wish to get a mismatched
2934
;; paren highlighted everytime we type < or >.)
2935
(modify-syntax-entry ?< "(>" table)
2936
(modify-syntax-entry ?> ")<" table)
2938
"Syntax table for presentations.")
2830
2940
(defun slime-add-presentation-properties (start end id result-p)
2831
2941
"Make the text between START and END a presentation with ID.
2832
2942
RESULT-P decides whether a face for a return value or output text is used."
2879
2990
(defun slime-remove-presentation-properties (from to presentation)
2880
2991
(let ((inhibit-read-only t))
2881
2992
(remove-text-properties from to
2882
`(,presentation t rear-nonsticky t))
2993
`(,presentation t syntax-table t rear-nonsticky t))
2883
2994
(when (eq (get-text-property from 'slime-repl-presentation) presentation)
2884
2995
(remove-text-properties from (1+ from) `(slime-repl-presentation t)))
2885
2996
(when (eq (get-text-property (1- to) 'slime-repl-presentation) presentation)
2888
2999
(when (eq (overlay-get overlay 'slime-repl-presentation) presentation)
2889
3000
(delete-overlay overlay)))))
2891
(defun slime-insert-presentation (result output-id)
2892
(let ((start (point)))
2894
(slime-add-presentation-properties start (point) output-id t)))
3002
(defun slime-insert-presentation (string output-id)
3003
(cond ((not slime-repl-enable-presentations)
3006
(let ((start (point)))
3008
(slime-add-presentation-properties start (point) output-id t)))))
2896
3010
(defun slime-open-stream-to-lisp (port)
2897
3011
(let ((stream (open-network-stream "*lisp-output-stream*"
3067
3181
(set (make-local-variable 'scroll-conservatively) 20)
3068
3182
(set (make-local-variable 'scroll-margin) 0)
3069
3183
(slime-repl-safe-load-history)
3070
(make-local-hook 'kill-buffer-hook)
3071
(add-hook 'kill-buffer-hook 'slime-repl-safe-save-merged-history nil t)
3184
(add-local-hook 'kill-buffer-hook 'slime-repl-safe-save-merged-history)
3072
3185
(add-hook 'kill-emacs-hook 'slime-repl-save-all-histories)
3073
3186
(slime-setup-command-hooks)
3074
3187
(when slime-use-autodoc-mode
3075
3188
(slime-autodoc-mode 1))
3189
(when slime-repl-enable-presentations
3190
;; Respect the syntax text properties of presentations.
3191
(set (make-local-variable 'parse-sexp-lookup-properties) t))
3076
3192
(run-hooks 'slime-repl-mode-hook))
3078
3194
(defun slime-presentation-whole-p (presentation start end &optional object)
3490
3606
(when (and (plusp (length string))
3491
3607
(eq ?\n (aref string (1- (length string)))))
3492
3608
(setq string (substring string 0 -1)))
3493
(unless (equal string (car slime-repl-input-history))
3609
(unless (or (= (length string) 0)
3610
(equal string (car slime-repl-input-history)))
3494
3611
(push string slime-repl-input-history))
3495
3612
(setq slime-repl-input-history-position -1))
3825
3942
(defvar slime-repl-history-pattern nil
3826
3943
"The regexp most recently used for finding input history.")
3828
(defun slime-repl-history-replace (direction regexp &optional delete-at-end-p)
3945
;; initialized later when slime-repl-mode-map is available
3946
(defvar slime-repl-history-map (make-sparse-keymap)
3947
"Map active while in the minibuffer reading repl search regexp.")
3949
(defun* slime-repl-history-replace (direction &optional regexp delete-at-end-p)
3829
3950
"Replace the current input with the next line in DIRECTION matching REGEXP.
3830
3951
DIRECTION is 'forward' or 'backward' (in the history list).
3831
3952
If DELETE-AT-END-P is non-nil then remove the string if the end of the
3832
history is reached."
3833
(setq slime-repl-history-pattern regexp)
3834
(let ((pos (slime-repl-position-in-history direction regexp))
3835
(forward (eq direction 'forward)))
3953
history is reached. Returns t if there were any matches."
3955
(setq slime-repl-history-pattern regexp))
3956
(let* ((forward (eq direction 'forward))
3957
(history-length (length slime-repl-input-history))
3959
(slime-repl-position-in-history direction regexp)
3960
(if (>= slime-repl-input-history-position 0)
3961
(+ slime-repl-input-history-position
3967
(>= pos history-length)))
3837
3971
(slime-repl-replace-input (nth pos slime-repl-input-history))
3838
3972
(setq slime-repl-input-history-position pos)
3842
3976
(message "End of history"))
3843
3977
(t (message "Beginning of history")))
3844
3978
(setq slime-repl-input-history-position
3845
(if forward -1 (length slime-repl-input-history))))
3979
(if forward -1 history-length)))
3846
3980
((and delete-at-end-p slime-repl-wrap-history)
3847
3981
(slime-repl-replace-input "")
3848
3982
(setq slime-repl-input-history-position
3849
(if forward (length slime-repl-input-history) -1)))
3983
(if forward history-length -1)))
3851
(message "End of history; no matching item")))))
3985
(message "End of history; no matching item")
3986
(return-from slime-repl-history-replace nil))))
3853
3989
(defun slime-repl-position-in-history (direction regexp)
3854
3990
"Return the position of the history item matching regexp.
3857
3993
(let* ((step (ecase direction
3860
(history-pos0 slime-repl-input-history-position))
3996
(history-pos0 slime-repl-input-history-position)
3997
(history-length (length slime-repl-input-history)))
3861
3998
(loop for pos = (+ history-pos0 step) then (+ pos step)
3862
3999
while (and (<= 0 pos)
3863
(< pos (length slime-repl-input-history)))
4000
(< pos history-length))
3864
4001
do (let ((string (nth pos slime-repl-input-history)))
3865
4002
(when (and (string-match regexp string)
3866
4003
(not (string= string (slime-repl-current-input))))
3867
4004
(return pos))))))
4006
(defun slime-repl-previous-input ()
4008
(slime-repl-history-replace 'backward nil t))
4010
(defun slime-repl-next-input ()
4012
(slime-repl-history-replace 'forward nil t))
3869
4014
(defun slime-repl-matching-input-regexp ()
3870
4015
(if (memq last-command
3871
'(slime-repl-previous-input slime-repl-next-input))
4016
'(slime-repl-previous-input-starting-with-current-input slime-repl-next-input-starting-with-current-input))
3872
4017
slime-repl-history-pattern
3873
(concat "^" (regexp-quote (slime-buffer-substring-with-reified-output
3874
slime-repl-input-start-mark
3875
(if (> (point) slime-repl-input-start-mark)
3877
slime-repl-input-end-mark))))))
4018
(concat "^" (regexp-quote (slime-repl-current-input)))))
3879
(defun slime-repl-previous-input ()
4020
(defun slime-repl-previous-input-starting-with-current-input ()
3881
4022
(slime-repl-history-replace 'backward (slime-repl-matching-input-regexp) t))
3883
(defun slime-repl-next-input ()
4024
(defun slime-repl-next-input-starting-with-current-input ()
3885
4026
(slime-repl-history-replace 'forward (slime-repl-matching-input-regexp) t))
3887
(defun slime-repl-previous-matching-input (regexp)
3888
(interactive "sPrevious element matching (regexp): ")
3889
(slime-repl-history-replace 'backward regexp))
3891
(defun slime-repl-next-matching-input (regexp)
3892
(interactive "sNext element matching (regexp): ")
3893
(slime-repl-history-replace 'forward regexp))
4028
(defun slime-repl-continue-search-with-last-pattern ()
4030
(when slime-repl-history-pattern
4031
(throw 'continue slime-repl-history-pattern)))
4033
(defun slime-repl-previous-or-next-matching-input (regexp direction prompt)
4034
(let ((command this-command))
4036
(setf regexp (if (and slime-repl-history-pattern
4038
'(slime-repl-previous-matching-input slime-repl-next-matching-input)))
4039
slime-repl-history-pattern
4041
(slime-read-from-minibuffer
4042
prompt (slime-symbol-name-at-point) slime-repl-history-map)))))
4043
(when (and regexp (> (length regexp) 0))
4044
(when (slime-repl-history-replace direction regexp)
4045
(setf this-command command)))))
4047
(defun slime-repl-previous-matching-input ()
4049
(slime-repl-previous-or-next-matching-input
4050
nil 'backward "Previous element matching (regexp): "))
4052
(defun slime-repl-next-matching-input ()
4054
(slime-repl-previous-or-next-matching-input
4055
nil 'forward "Next element matching (regexp): "))
3895
4057
;;;;; Persistent History
4019
4181
("\C-a" 'slime-repl-bol)
4020
4182
([home] 'slime-repl-bol)
4021
4183
("\C-e" 'slime-repl-eol)
4022
("\M-p" 'slime-repl-previous-input)
4184
("\M-p" 'slime-repl-previous-input-starting-with-current-input)
4023
4185
((kbd "C-<up>") 'slime-repl-previous-input)
4024
("\M-n" 'slime-repl-next-input)
4186
("\M-n" 'slime-repl-next-input-starting-with-current-input)
4025
4187
((kbd "C-<down>") 'slime-repl-next-input)
4026
4188
("\M-r" 'slime-repl-previous-matching-input)
4027
4189
("\M-s" 'slime-repl-next-matching-input)
4047
4209
("\C-c\C-k" 'slime-compile-and-load-file)
4048
4210
("\C-c\C-z" 'slime-nop))
4212
;; set up slime-repl-history-map
4213
(flet ((remap (keys to)
4214
(mimic-key-bindings slime-repl-mode-map slime-repl-history-map keys to)))
4215
(remap (list 'slime-repl-previous-matching-input (kbd "M-r"))
4216
'slime-repl-continue-search-with-last-pattern)
4217
(remap (list 'slime-repl-next-matching-input (kbd "M-n"))
4218
'slime-repl-continue-search-with-last-pattern))
4050
4220
;;;;;; REPL Read Mode
4052
4222
(define-key slime-repl-mode-map
4112
4282
(defun slime-handle-repl-shortcut ()
4114
(if (= (point) slime-repl-input-start-mark)
4284
(if (> (point) slime-repl-input-start-mark)
4285
(insert (string slime-repl-shortcut-dispatch-char))
4115
4286
(let ((shortcut (slime-lookup-shortcut
4116
4287
(completing-read "Command: "
4117
4288
(slime-bogus-completion-alist
4118
4289
(slime-list-all-repl-shortcuts))
4120
4291
'slime-repl-shortcut-history))))
4121
(call-interactively (slime-repl-shortcut.handler shortcut)))
4122
(insert (string slime-repl-shortcut-dispatch-char))))
4292
(call-interactively (slime-repl-shortcut.handler shortcut)))))
4124
4294
(defun slime-list-all-repl-shortcuts ()
4125
4295
(loop for shortcut in slime-repl-shortcut-table
4424
4591
(slime-display-output-buffer))
4425
4592
(slime-eval-async
4426
4593
`(swank:compile-file-for-emacs
4427
,lisp-filename ,(if load t nil)
4428
,@(if (local-variable-p 'slime-coding (current-buffer))
4429
(list (slime-coding-system-cl-name slime-coding))))
4594
,lisp-filename ,(if load t nil))
4430
4595
(slime-compilation-finished-continuation))
4431
4596
(message "Compiling %s.." lisp-filename)))
4551
4716
(setf slime-compilation-just-finished t)
4552
4717
(multiple-value-bind (result secs) result
4553
4718
(slime-show-note-counts notes secs)
4554
(slime-highlight-notes notes)))
4719
(when slime-highlight-compiler-notes
4720
(slime-highlight-notes notes))))
4555
4721
(run-hook-with-args 'slime-compilation-finished-hook notes)))
4557
4723
(defun slime-compilation-finished-continuation ()
5562
5728
(when-let (name (slime-symbol-name-at-point))
5563
5729
(if (slime-global-variable-name-p name) name)))
5731
(defcustom slime-global-variable-name-regexp "^\\(.*:\\)?\\([*+]\\).+\\2$"
5732
"Regexp used to check if a symbol name is a global variable.
5734
Default value assumes +this+ or *that* naming conventions."
5565
5738
(defun slime-global-variable-name-p (name)
5566
5739
"Is NAME a global variable?
5567
5740
Globals are recognised purely by *this-naming-convention*."
5568
(string-match "^\\(.*::?\\)?[*+].*[*+]$" name))
5741
(and (< (length name) 80) ; avoid overflows in regexp matcher
5742
(string-match slime-global-variable-name-regexp name)))
5570
5744
(defun slime-get-cached-autodoc (symbol-name)
5571
5745
"Return the cached autodoc documentation for SYMBOL-NAME, or nil."
5984
6159
(defvar slime-read-expression-history '()
5985
6160
"History list of expressions read from the minibuffer.")
5987
(defun slime-read-from-minibuffer (prompt &optional initial-value)
6162
(defun slime-read-from-minibuffer (prompt &optional initial-value keymap)
5988
6163
"Read a string from the minibuffer, prompting with PROMPT.
5989
6164
If INITIAL-VALUE is non-nil, it is inserted into the minibuffer before
5990
6165
reading input. The result is a string (\"\" if no input was given)."
6026
6203
;; If no matching keyword was found, do regular symbol
6207
(string= (buffer-substring-no-properties (- beg 2) beg) "#\\"))
6208
;; Character name completion
6209
(return-from slime-contextual-completions
6210
(slime-completions-for-character token))))
6029
6211
;; Regular symbol completion
6030
(slime-completions (buffer-substring-no-properties beg end))))
6212
(slime-completions token)))
6032
6214
(defun slime-completions (prefix)
6033
6215
(slime-eval `(swank:completions ,prefix ',(slime-current-package))))
6070
6255
"The current completion object. If this is the same before and
6071
6256
after point moves in the completions buffer, the text is not
6072
6257
replaced in the target for efficiency.")
6258
(defvar slime-fuzzy-current-completion-overlay nil
6259
"The overlay representing the current completion in the completion
6260
buffer. This is used to hightlight the text.")
6074
6262
(define-derived-mode slime-fuzzy-completions-mode
6075
6263
fundamental-mode "Fuzzy Completions"
6082
6270
(defvar slime-fuzzy-completions-map
6083
6271
(let* ((map (make-sparse-keymap)))
6085
(define-key map "q" 'slime-fuzzy-abort)
6086
(define-key map "\r" 'slime-fuzzy-select)
6088
(define-key map "n" 'slime-fuzzy-next)
6089
(define-key map "\M-n" 'slime-fuzzy-next)
6091
(define-key map "p" 'slime-fuzzy-prev)
6092
(define-key map "\M-p" 'slime-fuzzy-prev)
6094
(define-key map "\d" 'scroll-down)
6095
(define-key map " " 'scroll-up)
6097
(define-key map [mouse-2] 'slime-fuzzy-select/mouse)
6272
(flet ((remap (keys to)
6273
(mimic-key-bindings global-map map keys to)))
6274
(remap (list 'keyboard-quit (kbd "C-g")) 'slime-fuzzy-abort)
6275
(define-key map "q" 'slime-fuzzy-abort)
6277
(remap (list 'previous-line (kbd "<up>")) 'slime-fuzzy-prev)
6278
(remap (list 'next-line (kbd "<down>")) 'slime-fuzzy-next)
6280
(define-key map "n" 'slime-fuzzy-next)
6281
(define-key map "\M-n" 'slime-fuzzy-next)
6283
(define-key map "p" 'slime-fuzzy-prev)
6284
(define-key map "\M-p" 'slime-fuzzy-prev)
6286
(define-key map "\d" 'scroll-down)
6288
(remap (list 'slime-fuzzy-indent-and-complete-symbol
6289
'slime-indent-and-complete-symbol
6291
'slime-fuzzy-select)
6293
(define-key map (kbd "<mouse-2>") 'slime-fuzzy-select/mouse))
6295
(define-key map (kbd "RET") 'slime-fuzzy-select)
6296
(define-key map (kbd "<SPC>") 'slime-fuzzy-select)
6100
"Keymap for slime-fuzzy-completions-mode.")
6299
"Keymap for slime-fuzzy-completions-mode when in the completion buffer.")
6102
6301
(defun slime-fuzzy-completions (prefix &optional default-package)
6103
6302
"Get the list of sorted completion objects from completing
6108
6307
(slime-eval `(swank:fuzzy-completions ,prefix
6109
6308
,(or default-package
6110
6309
(slime-find-buffer-package)
6111
(slime-current-package))))))
6310
(slime-current-package))
6311
:limit ,slime-fuzzy-completion-limit
6312
:time-limit-in-msec ,slime-fuzzy-completion-time-limit-in-msec))))
6113
6314
(defun slime-fuzzy-selected (prefix completion)
6114
6315
"Tell the connected Lisp that the user selected completion
6118
6319
(slime-eval `(swank:fuzzy-completion-selected ,no-properties
6119
6320
',completion))))
6322
(defun slime-fuzzy-indent-and-complete-symbol ()
6323
"Indent the current line and perform fuzzy symbol completion. First
6324
indent the line. If indenting doesn't move point, complete the
6325
symbol. If there's no symbol at the point, show the arglist for the
6326
most recently enclosed macro or function."
6328
(let ((pos (point)))
6329
(unless (get-text-property (line-beginning-position) 'slime-repl-prompt)
6331
(when (= pos (point))
6332
(cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t))
6333
(slime-fuzzy-complete-symbol))
6334
((memq (char-before) '(?\t ?\ ))
6335
(slime-echo-arglist))))))
6121
6337
(defun* slime-fuzzy-complete-symbol ()
6122
6338
"Fuzzily completes the abbreviation at point into a symbol."
6134
6350
(progn (slime-minibuffer-respecting-message
6135
6351
"Can't find completion for \"%s\"" prefix)
6137
(slime-complete-restore-window-configuration))
6138
6354
(goto-char end)
6139
6355
(cond ((= (length completion-set) 1)
6140
6356
(insert-and-inherit (caar completion-set))
6141
6357
(delete-region beg end)
6142
6358
(goto-char (+ beg (length (caar completion-set))))
6143
(slime-minibuffer-respecting-message "Sole completion"))
6359
(slime-minibuffer-respecting-message "Sole completion")
6146
6363
(slime-minibuffer-respecting-message "Complete but not unique")
6216
6433
`end'. This saves the window configuration before popping the
6217
6434
buffer so that it can possibly be restored when the user is
6219
(setq slime-fuzzy-target-buffer (current-buffer))
6220
(setq slime-fuzzy-start (move-marker (make-marker) start))
6221
(setq slime-fuzzy-end (move-marker (make-marker) end))
6222
(set-marker-insertion-type slime-fuzzy-end t)
6223
(setq slime-fuzzy-original-text (buffer-substring start end))
6224
(setq slime-fuzzy-text slime-fuzzy-original-text)
6225
(slime-fuzzy-save-window-configuration)
6436
(let ((new-completion-buffer (not slime-fuzzy-target-buffer)))
6437
(when new-completion-buffer
6438
(slime-fuzzy-save-window-configuration))
6439
(slime-fuzzy-enable-target-buffer-completions-mode)
6440
(setq slime-fuzzy-target-buffer (current-buffer))
6441
(setq slime-fuzzy-start (move-marker (make-marker) start))
6442
(setq slime-fuzzy-end (move-marker (make-marker) end))
6443
(set-marker-insertion-type slime-fuzzy-end t)
6444
(setq slime-fuzzy-original-text (buffer-substring start end))
6445
(setq slime-fuzzy-text slime-fuzzy-original-text)
6446
(slime-fuzzy-fill-completions-buffer completions)
6447
(pop-to-buffer (slime-get-fuzzy-buffer))
6448
(when new-completion-buffer
6449
(add-local-hook 'kill-buffer-hook 'slime-fuzzy-abort))
6450
(when slime-fuzzy-completion-in-place
6451
;; switch back to the original buffer
6452
(switch-to-buffer-other-window slime-fuzzy-target-buffer))))
6454
(defun slime-fuzzy-fill-completions-buffer (completions)
6455
"Erases and fills the completion buffer with the given completions."
6226
6456
(with-current-buffer (slime-get-fuzzy-buffer)
6227
6457
(setq buffer-read-only nil)
6242
6472
(setq buffer-read-only t))
6243
6473
(setq slime-fuzzy-current-completion
6244
6474
(caar completions))
6245
(slime-fuzzy-insert (caar completions))
6246
(goto-char slime-fuzzy-first)
6247
(pop-to-buffer (current-buffer))
6248
(add-hook (make-local-variable 'post-command-hook)
6249
'slime-fuzzy-post-command-hook)))
6476
(slime-fuzzy-next)))
6478
(defun slime-fuzzy-enable-target-buffer-completions-mode ()
6479
"Store the target buffer's local map, so that we can restore it."
6480
(unless slime-fuzzy-target-buffer-completions-mode
6481
; (slime-log-event "Enabling target buffer completions mode")
6482
(slime-fuzzy-target-buffer-completions-mode 1)))
6484
(defun slime-fuzzy-disable-target-buffer-completions-mode ()
6485
"Restores the target buffer's local map when completion is finished."
6486
(when slime-fuzzy-target-buffer-completions-mode
6487
; (slime-log-event "Disabling target buffer completions mode")
6488
(slime-fuzzy-target-buffer-completions-mode 0)))
6251
6490
(defun slime-fuzzy-insert-from-point ()
6252
6491
"Inserts the completion that is under point in the completions
6278
6517
"Moves point directly to the next completion in the completions
6282
(next-single-char-property-change (point) 'completion)))
6520
(with-current-buffer (slime-get-fuzzy-buffer)
6521
(slime-fuzzy-dehighlight-current-completion)
6522
(let ((point (next-single-char-property-change (point) 'completion)))
6523
(when (= point (point-max))
6524
(setf point (previous-single-char-property-change (point-max) 'completion nil slime-fuzzy-first)))
6525
(set-window-point (get-buffer-window (current-buffer)) point)
6527
(slime-fuzzy-highlight-current-completion)))
6284
6529
(defun slime-fuzzy-prev ()
6285
6530
"Moves point directly to the previous completion in the
6286
6531
completions buffer."
6288
(goto-char (previous-single-char-property-change
6290
nil slime-fuzzy-first)))
6533
(with-current-buffer (slime-get-fuzzy-buffer)
6534
(slime-fuzzy-dehighlight-current-completion)
6535
(let ((point (previous-single-char-property-change (point) 'completion nil slime-fuzzy-first)))
6536
(set-window-point (get-buffer-window (current-buffer)) point)
6538
(slime-fuzzy-highlight-current-completion)))
6540
(defun slime-fuzzy-dehighlight-current-completion ()
6541
"Restores the original face for the current completion."
6542
(when slime-fuzzy-current-completion-overlay
6543
(overlay-put slime-fuzzy-current-completion-overlay 'face 'nil)))
6545
(defun slime-fuzzy-highlight-current-completion ()
6546
"Highlights the current completion, so that the user can see it on the screen."
6547
(let ((pos (point)))
6548
(setq slime-fuzzy-current-completion-overlay (make-overlay (point) (search-forward " ") (current-buffer) t nil))
6549
(overlay-put slime-fuzzy-current-completion-overlay 'face 'secondary-selection)
6292
6552
(defun slime-fuzzy-abort ()
6293
6553
"Aborts the completion process, setting the completions slot in
6294
6554
the target buffer back to its original contents."
6296
6556
(when slime-fuzzy-target-buffer
6297
(slime-fuzzy-insert slime-fuzzy-original-text)
6298
6557
(slime-fuzzy-done)))
6300
6559
(defun slime-fuzzy-select ()
6312
6571
(slime-fuzzy-done))))))
6573
(defun slime-fuzzy-select-or-update-completions ()
6574
"If there were no changes since the last time fuzzy completion was started
6575
this function will select the current completion. Otherwise refreshes the completion
6576
list based on the changes made."
6578
; (slime-log-event "Selecting or updating completions")
6579
(if (string-equal slime-fuzzy-original-text
6580
(buffer-substring slime-fuzzy-start
6582
(slime-fuzzy-select)
6583
(slime-fuzzy-complete-symbol)))
6585
(defun slime-fuzzy-process-event-in-completions-buffer ()
6586
"Simply processes the event in the target buffer"
6588
(with-current-buffer (slime-get-fuzzy-buffer)
6589
(push last-input-event unread-command-events)))
6591
(defun slime-fuzzy-select-and-process-event-in-target-buffer ()
6592
"Selects the current completion, making sure that it is inserted
6593
into the target buffer and processes the event in the target buffer."
6595
; (slime-log-event "Selecting and processing event in target buffer")
6596
(when slime-fuzzy-target-buffer
6597
(let ((buff slime-fuzzy-target-buffer))
6598
(slime-fuzzy-select)
6599
(with-current-buffer buff
6600
(slime-fuzzy-disable-target-buffer-completions-mode)
6601
(push last-input-event unread-command-events)))))
6314
6603
(defun slime-fuzzy-select/mouse (event)
6315
6604
"Handle a mouse-2 click on a completion choice as if point were
6316
6605
on the completion choice and the slime-fuzzy-select command was
6328
6617
and attempts to restore the window configuration. If this fails,
6329
6618
it just burys the completions buffer and leaves the window
6330
6619
configuration alone."
6331
(set-buffer slime-fuzzy-target-buffer)
6332
(remove-hook 'post-command-hook
6333
'slime-fuzzy-post-command-hook)
6334
(if (slime-fuzzy-maybe-restore-window-configuration)
6335
(bury-buffer (slime-get-fuzzy-buffer))
6336
;; We couldn't restore the windows, so just bury the fuzzy
6337
;; completions buffer and let something else fill it in.
6338
(pop-to-buffer (slime-get-fuzzy-buffer))
6340
(pop-to-buffer slime-fuzzy-target-buffer)
6341
(goto-char slime-fuzzy-end)
6342
(setq slime-fuzzy-target-buffer nil))
6620
(when slime-fuzzy-target-buffer
6621
(set-buffer slime-fuzzy-target-buffer)
6622
(slime-fuzzy-disable-target-buffer-completions-mode)
6623
(if (slime-fuzzy-maybe-restore-window-configuration)
6624
(bury-buffer (slime-get-fuzzy-buffer))
6625
;; We couldn't restore the windows, so just bury the fuzzy
6626
;; completions buffer and let something else fill it in.
6627
(pop-to-buffer (slime-get-fuzzy-buffer))
6629
(pop-to-buffer slime-fuzzy-target-buffer)
6630
(goto-char slime-fuzzy-end)
6631
(setq slime-fuzzy-target-buffer nil)))
6344
6633
(defun slime-fuzzy-save-window-configuration ()
6345
6634
"Saves the current window configuration, and (if the
6522
6811
(save-match-data
6523
6812
(when (and (buffer-file-name)
6524
6813
(slime-background-activities-enabled-p))
6525
(let ((filename (slime-to-lisp-filename (buffer-file-name))))
6526
(slime-eval-async `(swank:buffer-first-change ,filename)))))))
6814
(let ((filename (slime-to-lisp-filename (buffer-file-name))))
6815
(slime-eval-async `(swank:buffer-first-change ,filename)))))))
6528
6817
(defun slime-setup-first-change-hook ()
6529
6818
(add-hook (make-local-variable 'first-change-hook)
6921
7210
"A helper function to determine the current context.
6922
7211
The pattern can have the form:
6923
7212
pattern ::= () ;matches always
6924
| (*) ;matches insde a list
7213
| (*) ;matches inside a list
6925
7214
| (<symbol> <pattern>) ;matches if the first element in
6926
; current the list is <symbol> and
7215
; the current list is <symbol> and
6927
7216
; if <pattern> matches.
6928
| ((<pattern>)) ;matches if are in a nested list."
7217
| ((<pattern>)) ;matches if we are in a nested list."
6929
7218
(save-excursion
6930
7219
(let ((path (reverse (slime-pattern-path pattern))))
6931
7220
(loop for p in path
6932
7221
always (ignore-errors
6934
7223
(symbol (slime-beginning-of-list)
6935
(looking-at (symbol-name p)))
7224
(eq (read (current-buffer)) p))
6936
7225
(number (backward-up-list p)
7888
8177
(defun sldb-activate (thread level)
7889
8178
(unless (let ((b (sldb-find-buffer thread)))
7890
8179
(and b (with-current-buffer b (equal sldb-level level))))
7891
(with-lexical-bindings (thread level)
7892
(slime-eval-async `(swank:debugger-info-for-emacs 0 10)
7894
(apply #'sldb-setup thread level result))))))
8180
(slime-rex (thread level)
8181
('(swank:debugger-info-for-emacs 0 10)
8184
(apply #'sldb-setup thread level result)))))
7896
8186
(defun sldb-exit (thread level &optional stepping)
7897
8187
(when-let (sldb (sldb-find-buffer thread))
8155
8445
(let ((start (or start (point)))
8156
8446
(end (or end (save-excursion (ignore-errors (forward-sexp)) (point)))))
8157
8447
(push (make-overlay start (1+ start)) sldb-overlays)
8158
(push (make-overlay (1- end) end) sldb-overlays)
8159
(dolist (overlay sldb-overlays)
8160
(overlay-put overlay 'face 'secondary-selection))))
8448
(push (make-overlay (1- end) end) sldb-overlays))
8449
(dolist (overlay sldb-overlays)
8450
(overlay-put overlay 'face 'secondary-selection)))
8163
8453
(defun sldb-toggle-details (&optional on)
9898
10189
debug-hook-max-depth depth)
9899
10190
(= debug-hook-max-depth depth))))))
10192
(def-slime-test unwind-to-previous-sldb-level (level2 level1)
10193
"Test recursive debugging and returning to lower SLDB levels."
10195
(slime-check-top-level)
10196
(lexical-let ((level2 level2)
10202
(with-current-buffer (sldb-get-default-buffer)
10203
(setq max-depth (max sldb-level max-depth))
10206
(cond ((= sldb-level level2)
10207
(setq state 'leave)
10208
(sldb-invoke-restart 0))
10210
(slime-eval-async `(cl:aref cl:nil ,sldb-level)))))
10212
(cond ((= sldb-level level1)
10216
(sldb-invoke-restart 0)))))))))
10217
(let ((sldb-hook (cons debug-hook sldb-hook)))
10218
(slime-eval-async `(cl:aref cl:nil 0))
10219
(slime-sync-to-top-level 15)
10220
(slime-check-top-level)
10221
(slime-check ("Maximum depth reached (%S) is %S." max-depth level2)
10222
(= max-depth level2))
10223
(slime-check ("Final state reached.")
10224
(eq state 'ok))))))
9901
10226
(def-slime-test loop-interrupt-quit
9903
10228
"Test interrupting a loop."
10125
10450
("(princ 10)" ";;;; (princ 10) ...
10128
("(princ \"����������������������������\")"
10129
";;;; (princ \"����������������������������\") ...
10130
����������������������������
10453
("(princ \"������������\")"
10454
";;;; (princ \"������������\") ...
10132
10457
(when (and (fboundp 'string-to-multibyte)
10133
10458
(with-current-buffer (process-buffer (slime-connection))