|
(require 'slime)
|
|
(require 'slime-repl)
|
|
(require 'cl-lib)
|
|
(eval-when-compile
|
|
(require 'cl)) ; lexical-let
|
|
|
|
(define-slime-contrib slime-clipboard
|
|
"This add a few commands to put objects into a clipboard and to
|
|
insert textual references to those objects.
|
|
|
|
The clipboard command prefix is C-c @.
|
|
|
|
C-c @ + adds an object to the clipboard
|
|
C-c @ @ inserts a reference to an object in the clipboard
|
|
C-c @ ? displays the clipboard
|
|
|
|
This package also also binds the + key in the inspector and
|
|
debugger to add the object at point to the clipboard."
|
|
(:authors "Helmut Eller <heller@common-lisp.net>")
|
|
(:license "GPL")
|
|
(:swank-dependencies swank-clipboard))
|
|
|
|
(define-derived-mode slime-clipboard-mode fundamental-mode
|
|
"Slime-Clipboard"
|
|
"SLIME Clipboad Mode.
|
|
|
|
\\{slime-clipboard-mode-map}")
|
|
|
|
(slime-define-keys slime-clipboard-mode-map
|
|
("g" 'slime-clipboard-redisplay)
|
|
((kbd "C-k") 'slime-clipboard-delete-entry)
|
|
("i" 'slime-clipboard-inspect))
|
|
|
|
(defvar slime-clipboard-map (make-sparse-keymap))
|
|
|
|
(slime-define-keys slime-clipboard-map
|
|
("?" 'slime-clipboard-display)
|
|
("+" 'slime-clipboard-add)
|
|
("@" 'slime-clipboard-ref))
|
|
|
|
(define-key slime-mode-map (kbd "C-c @") slime-clipboard-map)
|
|
(define-key slime-repl-mode-map (kbd "C-c @") slime-clipboard-map)
|
|
|
|
(slime-define-keys slime-inspector-mode-map
|
|
("+" 'slime-clipboard-add-from-inspector))
|
|
|
|
(slime-define-keys sldb-mode-map
|
|
("+" 'slime-clipboard-add-from-sldb))
|
|
|
|
(defun slime-clipboard-add (exp package)
|
|
"Add an object to the clipboard."
|
|
(interactive (list (slime-read-from-minibuffer
|
|
"Add to clipboard (evaluated): "
|
|
(slime-sexp-at-point))
|
|
(slime-current-package)))
|
|
(slime-clipboard-add-internal `(:string ,exp ,package)))
|
|
|
|
(defun slime-clipboard-add-internal (datum)
|
|
(slime-eval-async `(swank-clipboard:add ',datum)
|
|
(lambda (result) (message "%s" result))))
|
|
|
|
(defun slime-clipboard-display ()
|
|
"Display the content of the clipboard."
|
|
(interactive)
|
|
(slime-eval-async `(swank-clipboard:entries)
|
|
#'slime-clipboard-display-entries))
|
|
|
|
(defun slime-clipboard-display-entries (entries)
|
|
(slime-with-popup-buffer ((slime-buffer-name :clipboard)
|
|
:mode 'slime-clipboard-mode)
|
|
(slime-clipboard-insert-entries entries)))
|
|
|
|
(defun slime-clipboard-insert-entries (entries)
|
|
(let ((fstring "%2s %3s %s\n"))
|
|
(insert (format fstring "Nr" "Id" "Value")
|
|
(format fstring "--" "--" "-----" ))
|
|
(save-excursion
|
|
(cl-loop for i from 0 for (ref . value) in entries do
|
|
(slime-insert-propertized `(slime-clipboard-entry ,i
|
|
slime-clipboard-ref ,ref)
|
|
(format fstring i ref value))))))
|
|
|
|
(defun slime-clipboard-redisplay ()
|
|
"Update the clipboard buffer."
|
|
(interactive)
|
|
(lexical-let ((saved (point)))
|
|
(slime-eval-async
|
|
`(swank-clipboard:entries)
|
|
(lambda (entries)
|
|
(let ((inhibit-read-only t))
|
|
(erase-buffer)
|
|
(slime-clipboard-insert-entries entries)
|
|
(when (< saved (point-max))
|
|
(goto-char saved)))))))
|
|
|
|
(defun slime-clipboard-entry-at-point ()
|
|
(or (get-text-property (point) 'slime-clipboard-entry)
|
|
(error "No clipboard entry at point")))
|
|
|
|
(defun slime-clipboard-ref-at-point ()
|
|
(or (get-text-property (point) 'slime-clipboard-ref)
|
|
(error "No clipboard ref at point")))
|
|
|
|
(defun slime-clipboard-inspect (&optional entry)
|
|
"Inspect the current clipboard entry."
|
|
(interactive (list (slime-clipboard-ref-at-point)))
|
|
(slime-inspect (prin1-to-string `(swank-clipboard::clipboard-ref ,entry))))
|
|
|
|
(defun slime-clipboard-delete-entry (&optional entry)
|
|
"Delete the current entry from the clipboard."
|
|
(interactive (list (slime-clipboard-entry-at-point)))
|
|
(slime-eval-async `(swank-clipboard:delete-entry ,entry)
|
|
(lambda (result)
|
|
(slime-clipboard-redisplay)
|
|
(message "%s" result))))
|
|
|
|
(defun slime-clipboard-ref ()
|
|
"Ask for a clipboard entry number and insert a reference to it."
|
|
(interactive)
|
|
(slime-clipboard-read-entry-number #'slime-clipboard-insert-ref))
|
|
|
|
;; insert a reference to clipboard entry ENTRY at point. The text
|
|
;; receives a special 'display property to make it look nicer. We
|
|
;; remove this property in a modification when a user tries to modify
|
|
;; he real text.
|
|
(defun slime-clipboard-insert-ref (entry)
|
|
(cl-destructuring-bind (ref . string)
|
|
(slime-eval `(swank-clipboard:entry-to-ref ,entry))
|
|
(slime-insert-propertized
|
|
`(display ,(format "#@%d%s" ref string)
|
|
modification-hooks (slime-clipboard-ref-modified)
|
|
rear-nonsticky t)
|
|
(format "(swank-clipboard::clipboard-ref %d)" ref))))
|
|
|
|
(defun slime-clipboard-ref-modified (start end)
|
|
(when (get-text-property start 'display)
|
|
(let ((inhibit-modification-hooks t))
|
|
(save-excursion
|
|
(goto-char start)
|
|
(cl-destructuring-bind (dstart dend) (slime-property-bounds 'display)
|
|
(unless (and (= start dstart) (= end dend))
|
|
(remove-list-of-text-properties
|
|
dstart dend '(display modification-hooks))))))))
|
|
|
|
;; Read a entry number.
|
|
;; Written in CPS because the display the clipboard before reading.
|
|
(defun slime-clipboard-read-entry-number (k)
|
|
(slime-eval-async
|
|
`(swank-clipboard:entries)
|
|
(slime-rcurry
|
|
(lambda (entries window-config k)
|
|
(slime-clipboard-display-entries entries)
|
|
(let ((entry (unwind-protect
|
|
(read-from-minibuffer "Entry number: " nil nil t)
|
|
(set-window-configuration window-config))))
|
|
(funcall k entry)))
|
|
(current-window-configuration)
|
|
k)))
|
|
|
|
(defun slime-clipboard-add-from-inspector ()
|
|
(interactive)
|
|
(let ((part (or (get-text-property (point) 'slime-part-number)
|
|
(error "No part at point"))))
|
|
(slime-clipboard-add-internal `(:inspector ,part))))
|
|
|
|
(defun slime-clipboard-add-from-sldb ()
|
|
(interactive)
|
|
(slime-clipboard-add-internal
|
|
`(:sldb ,(sldb-frame-number-at-point)
|
|
,(sldb-var-number-at-point))))
|
|
|
|
(provide 'slime-clipboard)
|