aboutsummaryrefslogtreecommitdiffstats
path: root/sps-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'sps-mode.el')
-rw-r--r--sps-mode.el343
1 files changed, 0 insertions, 343 deletions
diff --git a/sps-mode.el b/sps-mode.el
deleted file mode 100644
index c5975c6..0000000
--- a/sps-mode.el
+++ /dev/null
@@ -1,343 +0,0 @@
-;;; sps-mode.el --- Live Parenscript interaction -*- lexical-binding: t -*-
-
-;; Copyright (C) 2013 John Mastro
-
-;; Author: John Mastro <john.b.mastro@gmail.com>
-;; Version: 0.0.1
-;; Keywords: languages, lisp, processes, tools
-;; Package-Requires: ((slime "2013-05-26") (skewer-mode "1.5.0")
-;; (s "1.6.1") (dash "1.0.3"))
-
-;;; Commentary:
-
-;; This is an Emacs minor mode and collection of commands for working with
-;; Parenscript code in SLIME and sending it to the browser via Skewer. The goal
-;; is to create an environment for hacking Parenscript which fits as naturally
-;; as possible into the Lisp style of interactive development.
-
-;; See https://github.com/johnmastro/sps-mode for additional information.
-
-;; Note that this is very young code and there are certain to be serious
-;; problems.
-
-;;; Code:
-
-(require 'dash)
-(require 's)
-
-;;;; Vars
-
-(defvar sps-mode-map (make-sparse-keymap)
- "Keymap for sps-mode.
-This keymap is initialized empty. You can optionally use
-`sps-add-keys-with-prefix' to add bindings for all commands on
-two-key sequences behind a prefix of your choice.")
-
-(defvar sps-expansion-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "e") 'sps-send-expanded-code)
- (define-key map (kbd "w") 'sps-kill-ring-save-dwim)
- (define-key map (kbd "s") 'write-file)
- (define-key map (kbd "q") 'quit-window)
- map)
- "Keymap for `sps-expansion-mode' buffers.")
-
-(defvar sps-scratch-mode-map (make-sparse-keymap)
- "Keymap for the *sps-scratch* buffer.")
-
-(defvar sps-expansion-major-mode 'javascript-mode
- "The major mode to enable in expansion buffers.
-Note that a serious bug seems to be triggered when using js2-mode
-in expansion buffers. Avoid it for the time being unless you know
-what you're doing."
- ;; It would be better to use js2-mode, especially since Skewer requires it
- ;; anyway (why make people load two different JavaScript modes)? But, I've
- ;; come across a bug somehow related to js2-mode and skewer - when an
- ;; expansion is loaded in a js2-mode buffer the code is unexpectedly
- ;; evaluated (even though we haven't called skewer-eval) and, worse, Emacs
- ;; occasionally freezes. Until I track this down I don't want to leave the
- ;; code laying around with js2-mode as the default in case anyone happens
- ;; across it and gives it a try.
- )
-
-;;;; Code expansion
-
-(defun sps-wrap-in-ps-form (string)
- "Return Parenscript STRING wrapped in a PS:PS form."
- (format "(ps:ps %s)" string))
-
-(defun sps-call-with-expansion (fn string)
- "Call FN on the result of expanding Parenscript STRING.
-
-Note that FN will be called asynchronously and its return value
-discarded; it must work through side effects alone.
-
-See also `sps-with-expansion'."
- (let ((string (sps-wrap-in-ps-form string)))
- (slime-eval-async `(swank:eval-and-grab-output ,string)
- #'(lambda (result)
- (funcall fn (read (cadr result))))
- (slime-current-package))))
-
-(defmacro sps-with-expansion (name-and-string &rest body)
- "Expand a Parenscript string and execute BODY.
-
-NAME-AND-STRING should be a two-item list, with the second item
-the string to be expanded and the first item the name to which to
-bind the result of the expansion. Note that BODY will be executed
-asynchronously and its return value discarded; it must work
-through side effects alone.
-
-See also `sps-call-with-expansion'."
- (let ((name (car name-and-string))
- (string (cadr name-and-string))
- (rv (make-symbol "rv")))
- `(slime-eval-async
- `(swank:eval-and-grab-output ,(sps-wrap-in-ps-form ,string))
- #'(lambda (,rv)
- (let ((,name (read (cadr ,rv))))
- ,@body))
- (slime-current-package))))
-
-(put 'sps-with-expansion 'lisp-indent-function 1)
-
-(defun sps-expand (string)
- "Display the JavaScript generated from Parenscript STRING.
-
-The resulting JavaScript is displayed in a temporary buffer. The
-buffer's major mode is determined by the variable
-`sps-expansion-major-mode' (`javascript-mode' by default).
-`sps-expansion-mode' is enabled as an additional minor mode."
- (sps-with-expansion (code string)
- (slime-with-popup-buffer ("*Parenscript generated JavaScript*")
- (setq buffer-read-only nil)
- (erase-buffer)
- (insert code)
- (funcall sps-expansion-major-mode)
- (sps-expansion-mode 1)
- (font-lock-fontify-buffer)
- (goto-char (point-min))
- (setq buffer-read-only t)
- (pop-to-buffer (current-buffer)))))
-
-(defun sps-compile-buffer-to-file ()
- "Compile the current buffer and write the result.
-Prompts for the destination. If a file already exists at the
-destination it's overwritten."
- (interactive)
- (when (and (buffer-modified-p)
- (y-or-n-p "Save buffer? "))
- (save-buffer))
- (let* ((this buffer-file-name)
- (dir (and this (file-name-directory this)))
- (initial (and this (concat (file-name-base this) ".js")))
- (destination (read-file-name "Destination: " dir nil nil initial nil))
- (string (buffer-substring-no-properties (point-min) (point-max))))
- (sps-with-expansion (code string)
- (with-temp-buffer
- (erase-buffer)
- (insert code)
- (write-region 1 (point-max) destination)))))
-
-(defun sps-expand-sexp ()
- "Display the expansion of the form at point."
- (interactive)
- (sps-expand (slime-sexp-at-point)))
-
-(defun sps-expand-last-expression ()
- "Display the expansion of the expression preceding point."
- (interactive)
- (sps-expand (slime-last-expression)))
-
-(defun sps-expand-defun ()
- "Display the expansion of the current toplevel form."
- (interactive)
- (sps-expand (slime-defun-at-point)))
-
-(defun sps-expand-region (beg end)
- "Display the expansion of the currently active region."
- (interactive "r")
- (sps-expand (buffer-substring-no-properties beg end)))
-
-(defun sps-expand-buffer ()
- "Display the expansion of the current buffer."
- (interactive)
- (sps-expand-region (point-min) (point-max)))
-
-(defun sps-expand-dwim ()
- "Display the expansion of the active region or toplevel form.
-If the region is active this is equivalent to invoking
-`sps-expand-region', otherwise it's equivalent to
-`sps-expand-defun'."
- (interactive)
- (if (region-active-p)
- (sps-expand-region (region-beginning) (region-end))
- (sps-expand-defun)))
-
-;;;; Code evaluation
-
-(defun sps-eval (string)
- "Compile Parenscript STRING and evaluate it in the browser.
-
-The code is first compiled to JavaScript in the CL image and then
-sent to the browser via `skewer-eval'."
- (sps-with-expansion (code string)
- (skewer-eval code #'skewer-post-minibuffer)))
-
-(defun sps-eval-sexp ()
- "Evaluate the expression at point as Parenscript."
- (interactive)
- (sps-eval (slime-sexp-at-point)))
-
-(defun sps-eval-last-expression ()
- "Evaluate the expression preceding point as Parenscript."
- (interactive)
- (sps-eval (slime-last-expression)))
-
-(defun sps-eval-defun ()
- "Evaluate the current toplevel form as Parenscript."
- (interactive)
- (sps-eval (slime-defun-at-point)))
-
-(defun sps-eval-region (beg end)
- "Evaluate the currently active region as Parenscript."
- (interactive "r")
- (sps-eval (buffer-substring-no-properties beg end)))
-
-(defun sps-eval-buffer ()
- "Evaluate the current buffer as Parenscript."
- (interactive)
- (sps-eval-region (point-min) (point-max)))
-
-(defun sps-eval-dwim ()
- "Evaluate the active region or toplevel form.
-If the region is active this is equivalent to invoking
-`sps-eval-region', otherwise it's equivalent to
-`sps-eval-defun'."
- (if (region-active-p)
- (sps-eval-region (region-beginning) (region-end))
- (sps-eval-defun)))
-
-;;;; Expansion buffer commands
-
-(defun sps-send-expanded-code ()
- "Send the expanded code to the browser.
-For use from `sps-expansion-mode' buffers."
- (interactive)
- (skewer-eval
- (buffer-substring-no-properties (point-min) (point-max))
- #'skewer-post-minibuffer))
-
-(defun sps-kill-ring-save-dwim ()
- "Save the current buffer's content to the kill ring.
-If the region is active, save it; otherwise save the entire
-buffer."
- (interactive)
- (if (region-active-p)
- (kill-ring-save (region-beginning) (region-end))
- (kill-ring-save (point-min) (point-max))))
-
-;;;; Keybindings
-
-(defun sps-prefix-keys (prefix keys)
- "Prepend PREFIX to KEYS and read with `read-kbd-macro'."
- (read-kbd-macro (concat prefix " " keys)))
-
-(defun sps-add-keys-with-prefix (p)
- "Add keybindings for `sps-mode' commands behind prefix P."
- (let ((map sps-mode-map))
- ;; Evaluation commands
- (define-key map (sps-prefix-keys p "e C-m") 'sps-eval-sexp)
- (define-key map (sps-prefix-keys p "ee") 'sps-eval-last-expression)
- (define-key map (sps-prefix-keys p "ed") 'sps-eval-defun)
- (define-key map (sps-prefix-keys p "er") 'sps-eval-region)
- (define-key map (sps-prefix-keys p "eb") 'sps-eval-buffer)
- (define-key map (sps-prefix-keys p "e SPC") 'sps-eval-dwim)
- ;; Expansion commands
- (define-key map (sps-prefix-keys p "x C-m") 'sps-expand-sexp)
- (define-key map (sps-prefix-keys p "xe") 'sps-expand-last-expression)
- (define-key map (sps-prefix-keys p "xd") 'sps-expand-defun)
- (define-key map (sps-prefix-keys p "xr") 'sps-expand-region)
- (define-key map (sps-prefix-keys p "xb") 'sps-expand-buffer)
- (define-key map (sps-prefix-keys p "x SPC") 'sps-expand-dwim)))
-
-;;;; Scratch buffer
-
-(defun sps-scratch-buffer ()
- "Return the scratch buffer, creating it if necessary."
- (let ((name "*sps-scratch*"))
- (or (get-buffer name)
- (with-current-buffer (get-buffer-create name)
- (lisp-mode)
- (slime-mode t)
- (sps-mode 1)
- (sps-scratch-mode 1)
- (current-buffer)))))
-
-(defun sps-switch-to-scratch-buffer ()
- "Jump to the *sps-scratch* buffer."
- (set-buffer (sps-scratch-buffer))
- (unless (eq (current-buffer) (window-buffer))
- (pop-to-buffer (current-buffer) t)))
-
-(defun sps-scratch ()
- "Jump to the *sps-scratch* buffer."
- (interactive)
- (sps-switch-to-scratch-buffer))
-
-;;;; A little extra SLIME integration
-
-(defun sps-mode-buffer-p (buffer)
- "Return t if `sps-mode' is active in BUFFER."
- (with-current-buffer buffer
- (bound-and-true-p sps-mode)))
-
-(defun sps-recently-visited-sps-buffer ()
- "Return the most recently visited `sps-mode' buffer.
-Only considers buffers that are not already visible."
- (or (-first #'(lambda (b) (and (sps-mode-buffer-p b)
- (null (get-buffer-window b 'visible))))
- (buffer-list))
- (error "Can't find unshown buffer in sps-mode")))
-
-(defun sps-add-slime-selector-methods ()
- "Add methods to `slime-selector' for `sps-mode' buffers.
-Allows access to the most recently visited buffer with sps-mode
-active via \"p\" and to the *sps-scratch* buffer via \"P\"."
- (interactive)
- (def-slime-selector-method ?p
- "most recently visited buffer using sps-mode."
- (sps-recently-visited-sps-buffer))
- (def-slime-selector-method ?P
- "*sps-scratch* buffer."
- (sps-scratch-buffer)))
-
-;;;; The minor modes
-
-;;;###autoload
-(define-minor-mode sps-mode
- "Minor mode for interactively evaluating Parenscript forms."
- :lighter " sps"
- :keymap sps-mode-map)
-
-;;;###autoload
-(define-minor-mode sps-scratch-mode
- "Mode for sps-mode scratch buffer."
- :lighter nil
- :keymap sps-scratch-mode-map)
-
-(define-minor-mode sps-expansion-mode
- "Minor mode for displaying the code generated by Parenscript."
- :lighter nil
- :keymap sps-expansion-mode-map)
-
-
-(provide 'sps-mode)
-
-;; Local Variables:
-;; lexical-binding: t
-;; indent-tabs-mode: nil
-;; coding: utf-8
-;; End:
-
-;;; sps-mode.el ends here