(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 ") (: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)