summaryrefslogtreecommitdiff
path: root/elpa/skewer-mode-20200304.1142
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/skewer-mode-20200304.1142')
-rw-r--r--elpa/skewer-mode-20200304.1142/cache-table.el66
-rw-r--r--elpa/skewer-mode-20200304.1142/cache-table.elcbin0 -> 6281 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/example.html9
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-bower.el217
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-bower.elcbin0 -> 7211 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-css.el134
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-css.elcbin0 -> 5346 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-everything.user.js54
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-html.el165
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-html.elcbin0 -> 7845 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-mode-autoloads.el160
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-mode-pkg.el12
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-mode.el620
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-mode.elcbin0 -> 29666 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-repl.el210
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-repl.elcbin0 -> 8507 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-setup.el21
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer-setup.elcbin0 -> 378 bytes
-rw-r--r--elpa/skewer-mode-20200304.1142/skewer.js436
19 files changed, 2104 insertions, 0 deletions
diff --git a/elpa/skewer-mode-20200304.1142/cache-table.el b/elpa/skewer-mode-20200304.1142/cache-table.el
new file mode 100644
index 0000000..c3b2448
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/cache-table.el
@@ -0,0 +1,66 @@
+;;; cache-table.el --- a hash table with expiring entries -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;; Author: Christopher Wellons <mosquitopsu@gmail.com>
+;; Version: 1.0
+
+;;; Commentary:
+
+;; See the docstring of `cache-table-create'. There is no
+;; `cache-table-put': use `setf' on `cache-table-get' instead.
+
+;;; Code:
+
+(require 'cl-lib)
+
+(cl-defstruct (cache-table (:constructor cache-table--create))
+ "A cache table with expiring entries."
+ expire-time table)
+
+(defun cache-table-create (expire-time &rest keyword-args)
+ "Create a new cache-table with entries automatically removed
+from the table after EXPIRE-TIME seconds. This function accepts
+the same keyword arguments as `make-hash-table'. Entries are not
+actually removed from the cache-table until an access is made to
+the cache-table.
+
+Use `cache-table-get' to get and put (via setf) entries."
+ (cache-table--create :expire-time expire-time
+ :table (apply #'make-hash-table keyword-args)))
+
+(defun cache-table-clear-expired (cache-table)
+ "Remove all expired entries from CACHE-TABLE."
+ (cl-loop with expire-time = (cache-table-expire-time cache-table)
+ with table = (cache-table-table cache-table)
+ with dead-time = (- (float-time) expire-time)
+ for key being the hash-keys of table using (hash-value entry)
+ for (time . value) = entry
+ when (< time dead-time) do (remhash key table)))
+
+(defun cache-table-get (key cache-table &optional default)
+ "Access the value for KEY in CACHE-TABLE if it has not yet
+expired. Behaves just like `gethash'."
+ (cache-table-clear-expired cache-table)
+ (cdr (gethash key (cache-table-table cache-table) (cons 0 default))))
+
+(gv-define-setter cache-table-get (value key cache-table)
+ "Put an entry in the hash table, like (setf (gethash key table) value)."
+ `(progn
+ (cache-table-clear-expired ,cache-table)
+ (puthash ,key (cons (float-time) ,value)
+ (cache-table-table ,cache-table))))
+
+(defun cache-table-map (f cache-table)
+ "Like `maphash', call F for all non-expired entries in CACHE-TABLE."
+ (cache-table-clear-expired cache-table)
+ (maphash (lambda (k v) (funcall f k (cdr v)))
+ (cache-table-table cache-table)))
+
+(defun cache-table-count (cache-table)
+ "Like `hash-table-count', count the number of non-expired entries."
+ (hash-table-count (cache-table-table cache-table)))
+
+(provide 'cache-table)
+
+;;; cache-table.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/cache-table.elc b/elpa/skewer-mode-20200304.1142/cache-table.elc
new file mode 100644
index 0000000..d83791e
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/cache-table.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/example.html b/elpa/skewer-mode-20200304.1142/example.html
new file mode 100644
index 0000000..a3e301a
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/example.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Skewer</title>
+ <script src="/skewer"></script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/elpa/skewer-mode-20200304.1142/skewer-bower.el b/elpa/skewer-mode-20200304.1142/skewer-bower.el
new file mode 100644
index 0000000..69bfbe6
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-bower.el
@@ -0,0 +1,217 @@
+;;; skewer-bower.el --- dynamic library loading -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;;; Commentary:
+
+;; This package loads libraries into the current page using the bower
+;; infrastructure. Note: bower is not actually used by this package
+;; and so does *not* need to be installed. Only git is required (see
+;; `skewer-bower-git-executable'). It will try to learn how to run git
+;; from Magit if available.
+
+;; The interactive command for loading libraries is
+;; `skewer-bower-load'. It will prompt for a library and a version,
+;; automatically fetching it from the bower infrastructure if needed.
+;; For example, I often find it handy to load some version of jQuery
+;; when poking around at a page that doesn't already have it loaded.
+
+;; Caveat: unfortunately the bower infrastructure is a mess; many
+;; packages are in some sort of broken state -- missing dependencies,
+;; missing metadata, broken metadata, or an invalid repository URL.
+;; Some of this is due to under-specification of the metadata by the
+;; bower project. Broken packages are unlikely to be loadable by
+;; skewer-bower.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'skewer-mode)
+(require 'simple-httpd)
+(require 'magit nil t) ; optional
+
+(defcustom skewer-bower-cache-dir (locate-user-emacs-file "skewer-cache")
+ "Location of library cache (git repositories)."
+ :type 'string
+ :group 'skewer)
+
+(defcustom skewer-bower-endpoint "https://bower.herokuapp.com"
+ "Endpoint for accessing package information."
+ :type 'string
+ :group 'skewer)
+
+(defcustom skewer-bower-json '("bower.json" "package.json" "component.json")
+ "Files to search for package metadata."
+ :type 'list
+ :group 'skewer)
+
+; Try to match Magit's configuration if available
+(defcustom skewer-bower-git-executable "git"
+ "Name of the git executable."
+ :type 'string
+ :group 'skewer)
+
+(defvar skewer-bower-packages nil
+ "Alist of all packages known to bower.")
+
+(defvar skewer-bower-refreshed nil
+ "List of packages that have been refreshed recently. This keeps
+them from hitting the network frequently.")
+
+;;;###autoload
+(defun skewer-bower-refresh ()
+ "Update the package listing and packages synchronously."
+ (interactive)
+ (cl-declare (special url-http-end-of-headers))
+ (setf skewer-bower-refreshed nil)
+ (with-current-buffer
+ (url-retrieve-synchronously (concat skewer-bower-endpoint "/packages"))
+ (setf (point) url-http-end-of-headers)
+ (setf skewer-bower-packages
+ (cl-sort
+ (cl-loop for package across (json-read)
+ collect (cons (cdr (assoc 'name package))
+ (cdr (assoc 'url package))))
+ #'string< :key #'car))))
+
+;; Git functions
+
+(defun skewer-bower-cache (package)
+ "Return the cache repository directory for PACKAGE."
+ (unless (file-exists-p skewer-bower-cache-dir)
+ (make-directory skewer-bower-cache-dir t))
+ (expand-file-name package skewer-bower-cache-dir))
+
+(defun skewer-bower-git (package &rest args)
+ "Run git for PACKAGE's repository with ARGS."
+ (with-temp-buffer
+ (when (zerop (apply #'call-process skewer-bower-git-executable nil t nil
+ (format "--git-dir=%s" (skewer-bower-cache package))
+ args))
+ (buffer-string))))
+
+(defun skewer-bower-git-clone (url package)
+ "Clone or fetch PACKAGE's repository from URL if needed."
+ (if (member package skewer-bower-refreshed)
+ t
+ (let* ((cache (skewer-bower-cache package))
+ (status
+ (if (file-exists-p cache)
+ (when (skewer-bower-git package "fetch")
+ (push package skewer-bower-refreshed))
+ (skewer-bower-git package "clone" "--bare" url cache))))
+ (not (null status)))))
+
+(defun skewer-bower-git-show (package version file)
+ "Grab FILE from PACKAGE at version VERSION."
+ (when (string-match-p "^\\./" file) ; avoid relative paths
+ (setf file (substring file 2)))
+ (skewer-bower-git package "show" (format "%s:%s" version file)))
+
+(defun skewer-bower-git-tag (package)
+ "List all the tags in PACKAGE's repository."
+ (split-string (skewer-bower-git package "tag")))
+
+;; Bower functions
+
+(defun skewer-bower-package-ensure (package)
+ "Ensure a package is installed in the cache and up to date.
+Emit an error if the package could not be ensured."
+ (when (null skewer-bower-packages) (skewer-bower-refresh))
+ (let ((url (cdr (assoc package skewer-bower-packages))))
+ (when (null url)
+ (error "Unknown package: %s" package))
+ (when (null (skewer-bower-git-clone url package))
+ (error "Failed to fetch: %s" url))
+ t))
+
+(defun skewer-bower-package-versions (package)
+ "List the available versions for a package. Always returns at
+least one version."
+ (skewer-bower-package-ensure package)
+ (or (sort (skewer-bower-git-tag package) #'string<)
+ (list "master")))
+
+(defun skewer-bower-get-config (package &optional version)
+ "Get the configuration alist for PACKAGE at VERSION. Return nil
+if no configuration could be found."
+ (skewer-bower-package-ensure package)
+ (unless version (setf version "master"))
+ (json-read-from-string
+ (cl-loop for file in skewer-bower-json
+ for config = (skewer-bower-git-show package version file)
+ when config return it
+ finally (return "null"))))
+
+;; Serving the library
+
+(defvar skewer-bower-history ()
+ "Library selection history for `completing-read'.")
+
+(defun skewer-bowser--path (package version main)
+ "Return the simple-httpd hosted path for PACKAGE."
+ (format "/skewer/bower/%s/%s/%s" package (or version "master") main))
+
+(defun skewer-bower-prompt-package ()
+ "Prompt for a package and version from the user."
+ (when (null skewer-bower-packages) (skewer-bower-refresh))
+ ;; ido-completing-read bug workaround:
+ (when (> (length skewer-bower-history) 32)
+ (setf skewer-bower-history (cl-subseq skewer-bower-history 0 16)))
+ (let* ((packages (mapcar #'car skewer-bower-packages))
+ (selection (nconc skewer-bower-history packages))
+ (package (completing-read "Library: " selection nil t nil
+ 'skewer-bower-history))
+ (versions (reverse (skewer-bower-package-versions package)))
+ (version (completing-read "Version: " versions
+ nil t nil nil (car versions))))
+ (list package version)))
+
+(defun skewer-bower--js-p (filename)
+ "Return non-nil if FILENAME looks like JavaScript."
+ (string-match "\\.js$" filename))
+
+(defun skewer-bower-guess-main (package version config)
+ "Attempt to determine the main entrypoints from a potentially
+incomplete or incorrect bower configuration. Returns nil if
+guessing failed."
+ (let ((check (apply-partially #'skewer-bower-git-show package version))
+ (main (cdr (assoc 'main config))))
+ (cond ((and (vectorp main) (cl-some check main))
+ (cl-coerce (cl-remove-if-not #'skewer-bower--js-p main) 'list))
+ ((and (stringp main) (funcall check main))
+ (list main))
+ ((funcall check (concat package ".js"))
+ (list (concat package ".js")))
+ ((funcall check package)
+ (list package)))))
+
+;;;###autoload
+(defun skewer-bower-load (package &optional version)
+ "Dynamically load a library from bower into the current page."
+ (interactive (skewer-bower-prompt-package))
+ (let* ((config (skewer-bower-get-config package version))
+ (deps (cdr (assoc 'dependencies config)))
+ (main (skewer-bower-guess-main package version config)))
+ (when (null main)
+ (error "Could not load %s (%s): no \"main\" entrypoint specified"
+ package version))
+ (cl-loop for (dep . version) in deps
+ do (skewer-bower-load (format "%s" dep) version))
+ (cl-loop for entrypoint in main
+ for path = (skewer-bowser--path package version entrypoint)
+ do (skewer-eval path nil :type "script"))))
+
+(defservlet skewer/bower "application/javascript; charset=utf-8" (path)
+ "Serve a script from the local bower repository cache."
+ (cl-destructuring-bind (_ _skewer _bower package version . parts)
+ (split-string path "/")
+ (let* ((file (mapconcat #'identity parts "/"))
+ (contents (skewer-bower-git-show package version file)))
+ (if contents
+ (insert contents)
+ (httpd-error t 404)))))
+
+(provide 'skewer-bower)
+
+;;; skewer-bower.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-bower.elc b/elpa/skewer-mode-20200304.1142/skewer-bower.elc
new file mode 100644
index 0000000..e85390c
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-bower.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer-css.el b/elpa/skewer-mode-20200304.1142/skewer-css.el
new file mode 100644
index 0000000..457c742
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-css.el
@@ -0,0 +1,134 @@
+;;; skewer-css.el --- skewer support for live-interaction CSS -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;;; Commentary:
+
+;; This minor mode provides functionality for CSS like plain Skewer
+;; does for JavaScript.
+
+;; * C-x C-e -- `skewer-css-eval-current-declaration'
+;; * C-M-x -- `skewer-css-eval-current-rule'
+;; * C-c C-k -- `skewer-css-eval-buffer'
+
+;; These functions assume there are no comments within a CSS rule,
+;; *especially* not within a declaration. In the former case, if you
+;; keep the comment free of CSS syntax it should be able to manage
+;; reasonably well. This may be fixed someday.
+
+;;; Code:
+
+(require 'css-mode)
+(require 'skewer-mode)
+
+(defun skewer-css-trim (string)
+ "Trim and compress whitespace in the string."
+ (let ((cleaned (replace-regexp-in-string "[\t\n ]+" " " string)))
+ (replace-regexp-in-string "^[\t\n ]+\\|[\t\n ]+$" "" cleaned)))
+
+;; Parsing
+
+(defun skewer-css-beginning-of-rule ()
+ "Move to the beginning of the current rule and return point."
+ (skewer-css-end-of-rule)
+ (re-search-backward "{")
+ (when (re-search-backward "[}/]" nil 'start)
+ (forward-char))
+ (re-search-forward "[^ \t\n]")
+ (backward-char)
+ (point))
+
+(defun skewer-css-end-of-rule ()
+ "Move to the end of the current rule and return point."
+ (if (eql (char-before) ?})
+ (point)
+ (re-search-forward "}")))
+
+(defun skewer-css-end-of-declaration ()
+ "Move to the end of the current declaration and return point."
+ (if (eql (char-before) ?\;)
+ (point)
+ (re-search-forward ";")))
+
+(defun skewer-css-beginning-of-declaration ()
+ "Move to the end of the current declaration and return point."
+ (skewer-css-end-of-declaration)
+ (re-search-backward ":")
+ (backward-sexp 1)
+ (point))
+
+(defun skewer-css-selectors ()
+ "Return the selectors for the current rule."
+ (save-excursion
+ (let ((start (skewer-css-beginning-of-rule))
+ (end (1- (re-search-forward "{"))))
+ (skewer-css-trim
+ (buffer-substring-no-properties start end)))))
+
+(defun skewer-css-declaration ()
+ "Return the current declaration as a pair of strings."
+ (save-excursion
+ (let ((start (skewer-css-beginning-of-declaration))
+ (end (skewer-css-end-of-declaration)))
+ (let* ((clip (buffer-substring-no-properties start end))
+ (pair (split-string clip ":")))
+ (mapcar #'skewer-css-trim pair)))))
+
+;; Evaluation
+
+(defun skewer-css (rule)
+ "Add RULE as a new stylesheet."
+ (skewer-eval rule nil :type "css"))
+
+(defun skewer-css-eval-current-declaration ()
+ "Evaluate the declaration at the point."
+ (interactive)
+ (save-excursion
+ (let ((selectors (skewer-css-selectors))
+ (rule (skewer-css-declaration))
+ (start (skewer-css-beginning-of-declaration))
+ (end (skewer-css-end-of-declaration)))
+ (skewer-flash-region start end)
+ (skewer-css (apply #'format "%s { %s: %s }" selectors rule)))))
+
+(defun skewer-css-eval-current-rule ()
+ "Evaluate the rule at the point."
+ (interactive)
+ (save-excursion
+ (let* ((start (skewer-css-beginning-of-rule))
+ (end (skewer-css-end-of-rule))
+ (rule (buffer-substring-no-properties start end)))
+ (skewer-flash-region start end)
+ (skewer-css (skewer-css-trim rule)))))
+
+(defun skewer-css-eval-buffer ()
+ "Send the entire current buffer as a new stylesheet."
+ (interactive)
+ (skewer-css (buffer-substring-no-properties (point-min) (point-max))))
+
+(defun skewer-css-clear-all ()
+ "Remove *all* Skewer-added styles from the document."
+ (interactive)
+ (skewer-eval nil nil :type "cssClearAll"))
+
+;; Minor mode definition
+
+(defvar skewer-css-mode-map
+ (let ((map (make-sparse-keymap)))
+ (prog1 map
+ (define-key map (kbd "C-x C-e") 'skewer-css-eval-current-declaration)
+ (define-key map (kbd "C-M-x") 'skewer-css-eval-current-rule)
+ (define-key map (kbd "C-c C-k") 'skewer-css-eval-buffer)
+ (define-key map (kbd "C-c C-c") 'skewer-css-clear-all)))
+ "Keymap for skewer-css-mode.")
+
+;;;###autoload
+(define-minor-mode skewer-css-mode
+ "Minor mode for interactively loading new CSS rules."
+ :lighter " skewer-css"
+ :keymap skewer-css-mode-map
+ :group 'skewer)
+
+(provide 'skewer-css)
+
+;;; skewer-css.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-css.elc b/elpa/skewer-mode-20200304.1142/skewer-css.elc
new file mode 100644
index 0000000..0026a9d
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-css.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer-everything.user.js b/elpa/skewer-mode-20200304.1142/skewer-everything.user.js
new file mode 100644
index 0000000..4d22273
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-everything.user.js
@@ -0,0 +1,54 @@
+// ==UserScript==
+// @name Skewer Everything
+// @description Add a toggle button to run Skewer on the current page
+// @lastupdated 2015-09-14
+// @version 1.3
+// @license Public Domain
+// @include /^https?:///
+// @grant none
+// @run-at document-start
+// ==/UserScript==
+
+window.skewerNativeXHR = XMLHttpRequest;
+window.skewerInject = inject;
+
+var host = 'http://localhost:8080';
+
+var toggle = document.createElement('div');
+toggle.onclick = inject;
+toggle.style.width = '0px';
+toggle.style.height = '0px';
+toggle.style.borderStyle = 'solid';
+toggle.style.borderWidth = '0 12px 12px 0';
+toggle.style.borderColor = 'transparent #F00 transparent transparent';
+toggle.style.position = 'fixed';
+toggle.style.right = 0;
+toggle.style.top = 0;
+toggle.style.zIndex = 214748364;
+
+var injected = false;
+
+function inject() {
+ if (!injected) {
+ var script = document.createElement('script');
+ script.src = host + '/skewer';
+ document.body.appendChild(script);
+ toggle.style.borderRightColor = '#0F0';
+ } else {
+ /* break skewer to disable it */
+ skewer.fn = null;
+ toggle.style.borderRightColor = '#F00';
+ }
+ injected = !injected;
+ localStorage._autoskewered = JSON.stringify(injected);
+}
+
+document.addEventListener('DOMContentLoaded', function() {
+ /* Don't use on iframes. */
+ if (window.top === window.self) {
+ document.body.appendChild(toggle);
+ if (JSON.parse(localStorage._autoskewered || 'false')) {
+ inject();
+ }
+ }
+});
diff --git a/elpa/skewer-mode-20200304.1142/skewer-html.el b/elpa/skewer-mode-20200304.1142/skewer-html.el
new file mode 100644
index 0000000..b21de16
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-html.el
@@ -0,0 +1,165 @@
+;;; skewer-html.el --- skewer support for live-interaction HTML -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;;; Commentary:
+
+;; This minor mode provides functionality for HTML like plain Skewer
+;; does for JavaScript. There's no clean way to replace the body and
+;; head elements of a live document, so "evaluating" these elements is
+;; not supported.
+
+;; * C-M-x -- `skewer-html-eval-tag'
+
+;; See also `skewer-html-fetch-selector-into-buffer' for grabbing the
+;; page as it current exists.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'sgml-mode)
+(require 'skewer-mode)
+
+;; Macros
+
+(defmacro skewer-html--with-html-mode (&rest body)
+ "Evaluate BODY as if in `html-mode', using a temp buffer if necessary."
+ (declare (indent 0))
+ (let ((orig-buffer (make-symbol "orig-buffer"))
+ (temp-buffer (make-symbol "temp-buffer"))
+ (orig-point (make-symbol "orig-point")))
+ `(let ((,temp-buffer (and (not (eq major-mode 'html-mode))
+ (generate-new-buffer " *skewer-html*")))
+ (,orig-buffer (current-buffer))
+ (,orig-point (point)))
+ (unwind-protect
+ (with-current-buffer (or ,temp-buffer ,orig-buffer)
+ (when ,temp-buffer
+ (insert-buffer-substring ,orig-buffer)
+ (setf (point) ,orig-point)
+ (html-mode))
+ ,@body)
+ (when ,temp-buffer
+ (kill-buffer ,temp-buffer))))))
+
+;; Selector computation
+
+(defun skewer-html--cleanup (tag)
+ "Cleanup TAG name from sgml-mode."
+ (skewer-html--with-html-mode
+ (replace-regexp-in-string "/$" "" (sgml-tag-name tag))))
+
+(defun skewer-html--tag-after-point ()
+ "Return the tag struct for the tag immediately following point."
+ (skewer-html--with-html-mode
+ (save-excursion
+ (forward-char 1)
+ (sgml-parse-tag-backward))))
+
+(defun skewer-html--get-context ()
+ "Like `sgml-get-context' but to the root, skipping close tags."
+ (skewer-html--with-html-mode
+ (save-excursion
+ (cl-loop for context = (sgml-get-context)
+ while context
+ nconc (nreverse context) into tags
+ finally return (cl-delete 'close tags :key #'sgml-tag-type)))))
+
+(cl-defun skewer-html-compute-tag-nth (&optional (point (point)))
+ "Compute the position of this tag within its parent."
+ (skewer-html--with-html-mode
+ (save-excursion
+ (setf (point) point)
+ (let ((context (skewer-html--get-context)))
+ (when context
+ (let ((tag-name (skewer-html--cleanup (car context)))
+ (target-depth (1- (length context))))
+ (cl-loop with n = 0
+ ;; If point doesn't move, we're at the root.
+ for point-start = (point)
+ do (sgml-skip-tag-backward 1)
+ until (= (point) point-start)
+ ;; If depth changed, we're done.
+ for current-depth = (length (skewer-html--get-context))
+ until (< current-depth target-depth)
+ ;; Examine the sibling tag.
+ for current-name = (save-excursion
+ (forward-char)
+ (sgml-parse-tag-name))
+ when (equal current-name tag-name)
+ do (cl-incf n)
+ finally return n)))))))
+
+(defun skewer-html-compute-tag-ancestry ()
+ "Compute the ancestry chain at point."
+ (skewer-html--with-html-mode
+ (nreverse
+ (cl-loop for tag in (skewer-html--get-context)
+ for nth = (skewer-html-compute-tag-nth (1+ (sgml-tag-start tag)))
+ for name = (skewer-html--cleanup tag)
+ unless (equal name "html")
+ collect (list name nth)))))
+
+(defun skewer-html-compute-selector ()
+ "Compute the selector for exactly the tag around point."
+ (let ((ancestry (skewer-html-compute-tag-ancestry)))
+ (mapconcat (lambda (tag)
+ (format "%s:nth-of-type(%d)" (cl-first tag) (cl-second tag)))
+ ancestry " > ")))
+
+;; Fetching
+
+(defun skewer-html-fetch-selector (selector)
+ "Fetch the innerHTML of a selector."
+ (let ((result (skewer-eval-synchronously selector :type "fetchselector")))
+ (if (skewer-success-p result)
+ (cdr (assoc 'value result))
+ "")))
+
+(defun skewer-html-fetch-selector-into-buffer (selector)
+ "Fetch the innerHTML of a selector and insert it into the active buffer."
+ (interactive "sSelector: ")
+ (insert (skewer-html-fetch-selector selector)))
+
+;; Evaluation
+
+(defun skewer-html-eval (string ancestry &optional append)
+ "Load HTML into a selector, optionally appending."
+ (let ((ancestry* (cl-coerce ancestry 'vector))) ; for JSON
+ (skewer-eval string nil :type "html" :extra `((ancestry . ,ancestry*)
+ (append . ,append)))))
+
+(defun skewer-html-eval-tag ()
+ "Load HTML from the immediately surrounding tag."
+ (interactive)
+ (let ((ancestry (skewer-html-compute-tag-ancestry)))
+ (save-excursion
+ ;; Move to beginning of opening tag
+ (let* ((beg (skewer-html--with-html-mode
+ (sgml-skip-tag-forward 1) (point)))
+ (end (skewer-html--with-html-mode
+ (sgml-skip-tag-backward 1) (point)))
+ (region (buffer-substring-no-properties beg end)))
+ (skewer-flash-region beg end)
+ (if (= (length ancestry) 1)
+ (error "Error: cannot eval body and head tags.")
+ (skewer-html-eval region ancestry nil))))))
+
+;; Minor mode definition
+
+(defvar skewer-html-mode-map
+ (let ((map (make-sparse-keymap)))
+ (prog1 map
+ (define-key map (kbd "C-M-x") 'skewer-html-eval-tag)))
+ "Keymap for skewer-html-mode")
+
+;;;###autoload
+(define-minor-mode skewer-html-mode
+ "Minor mode for interactively loading new HTML."
+ :lighter " skewer-html"
+ :keymap skewer-html-mode-map
+ :group 'skewer)
+
+(provide 'skewer-html)
+
+;;; skewer-html.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-html.elc b/elpa/skewer-mode-20200304.1142/skewer-html.elc
new file mode 100644
index 0000000..017178f
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-html.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer-mode-autoloads.el b/elpa/skewer-mode-20200304.1142/skewer-mode-autoloads.el
new file mode 100644
index 0000000..f09afb8
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-mode-autoloads.el
@@ -0,0 +1,160 @@
+;;; skewer-mode-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+
+;;;### (autoloads nil "cache-table" "cache-table.el" (0 0 0 0))
+;;; Generated autoloads from cache-table.el
+
+(register-definition-prefixes "cache-table" '("cache-table-"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-bower" "skewer-bower.el" (0 0 0 0))
+;;; Generated autoloads from skewer-bower.el
+
+(autoload 'skewer-bower-refresh "skewer-bower" "\
+Update the package listing and packages synchronously." t nil)
+
+(autoload 'skewer-bower-load "skewer-bower" "\
+Dynamically load a library from bower into the current page.
+
+\(fn PACKAGE &optional VERSION)" t nil)
+
+(register-definition-prefixes "skewer-bower" '("skewer"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-css" "skewer-css.el" (0 0 0 0))
+;;; Generated autoloads from skewer-css.el
+
+(autoload 'skewer-css-mode "skewer-css" "\
+Minor mode for interactively loading new CSS rules.
+
+This is a minor mode. If called interactively, toggle the
+`skewer-css mode' mode. If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `skewer-css-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+\(fn &optional ARG)" t nil)
+
+(register-definition-prefixes "skewer-css" '("skewer-css"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-html" "skewer-html.el" (0 0 0 0))
+;;; Generated autoloads from skewer-html.el
+
+(autoload 'skewer-html-mode "skewer-html" "\
+Minor mode for interactively loading new HTML.
+
+This is a minor mode. If called interactively, toggle the
+`skewer-html mode' mode. If the prefix argument is positive,
+enable the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `skewer-html-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+\(fn &optional ARG)" t nil)
+
+(register-definition-prefixes "skewer-html" '("skewer-html-"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-mode" "skewer-mode.el" (0 0 0 0))
+;;; Generated autoloads from skewer-mode.el
+
+(autoload 'list-skewer-clients "skewer-mode" "\
+List the attached browsers in a buffer." t nil)
+
+(autoload 'skewer-mode "skewer-mode" "\
+Minor mode for interacting with a browser.
+
+This is a minor mode. If called interactively, toggle the
+`skewer mode' mode. If the prefix argument is positive, enable
+the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `skewer-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'run-skewer "skewer-mode" "\
+Attach a browser to Emacs for a skewer JavaScript REPL. Uses
+`browse-url' to launch a browser.
+
+With a prefix arugment (C-u), it will ask the filename of the
+root document. With two prefix arguments (C-u C-u), it will use
+the contents of the current buffer as the root document.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'skewer-run-phantomjs "skewer-mode" "\
+Connect an inferior PhantomJS process to Skewer, returning the process." t nil)
+
+(register-definition-prefixes "skewer-mode" '("httpd/skewer/" "phantomjs-program-name" "skewer"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-repl" "skewer-repl.el" (0 0 0 0))
+;;; Generated autoloads from skewer-repl.el
+
+(autoload 'skewer-repl--response-hook "skewer-repl" "\
+Catches all browser messages logging some to the REPL.
+
+\(fn RESPONSE)" nil nil)
+
+(autoload 'skewer-repl "skewer-repl" "\
+Start a JavaScript REPL to be evaluated in the visiting browser." t nil)
+
+(eval-after-load 'skewer-mode '(progn (add-hook 'skewer-response-hook #'skewer-repl--response-hook) (add-hook 'skewer-repl-mode-hook #'skewer-repl-mode-compilation-shell-hook) (define-key skewer-mode-map (kbd "C-c C-z") #'skewer-repl)))
+
+(register-definition-prefixes "skewer-repl" '("company-skewer-repl" "skewer-"))
+
+;;;***
+
+;;;### (autoloads nil "skewer-setup" "skewer-setup.el" (0 0 0 0))
+;;; Generated autoloads from skewer-setup.el
+
+(autoload 'skewer-setup "skewer-setup" "\
+Fully integrate Skewer into js2-mode, css-mode, and html-mode buffers." nil nil)
+
+;;;***
+
+;;;### (autoloads nil nil ("skewer-mode-pkg.el") (0 0 0 0))
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; skewer-mode-autoloads.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-mode-pkg.el b/elpa/skewer-mode-20200304.1142/skewer-mode-pkg.el
new file mode 100644
index 0000000..ff0e79a
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-mode-pkg.el
@@ -0,0 +1,12 @@
+(define-package "skewer-mode" "20200304.1142" "live browser JavaScript, CSS, and HTML interaction"
+ '((simple-httpd "1.4.0")
+ (js2-mode "20090723")
+ (emacs "24"))
+ :commit "e5bed351939c92a1f788f78398583c2f83f1bb3c" :authors
+ '(("Christopher Wellons" . "wellons@nullprogram.com"))
+ :maintainer
+ '("Christopher Wellons" . "wellons@nullprogram.com")
+ :url "https://github.com/skeeto/skewer-mode")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
diff --git a/elpa/skewer-mode-20200304.1142/skewer-mode.el b/elpa/skewer-mode-20200304.1142/skewer-mode.el
new file mode 100644
index 0000000..a439a9c
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-mode.el
@@ -0,0 +1,620 @@
+;;; skewer-mode.el --- live browser JavaScript, CSS, and HTML interaction -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;; Author: Christopher Wellons <wellons@nullprogram.com>
+;; URL: https://github.com/skeeto/skewer-mode
+
+;;; Commentary:
+
+;; Quick start (without package.el):
+
+;; 1. Put this directory in your `load-path'
+;; 2. Load skewer-mode.el
+;; 3. M-x `run-skewer' to attach a browser to Emacs
+;; 4. From a `js2-mode' buffer with `skewer-mode' minor mode enabled,
+;; send forms to the browser to evaluate
+
+;; The function `skewer-setup' can be used to configure all of mode
+;; hooks (previously this was the default). This can also be done
+;; manually like so,
+
+;; (add-hook 'js2-mode-hook 'skewer-mode)
+;; (add-hook 'css-mode-hook 'skewer-css-mode)
+;; (add-hook 'html-mode-hook 'skewer-html-mode)
+
+;; The keybindings for evaluating expressions in the browser are just
+;; like the Lisp modes. These are provided by the minor mode
+;; `skewer-mode'.
+
+;; * C-x C-e -- `skewer-eval-last-expression'
+;; * C-M-x -- `skewer-eval-defun'
+;; * C-c C-k -- `skewer-load-buffer'
+
+;; The result of the expression is echoed in the minibuffer.
+
+;; Additionally, `css-mode' and `html-mode' get a similar set of
+;; bindings for modifying the CSS rules and updating HTML on the
+;; current page.
+
+;; Note: `run-skewer' uses `browse-url' to launch the browser. This
+;; may require further setup depending on your operating system and
+;; personal preferences.
+
+;; Multiple browsers and browser tabs can be attached to Emacs at
+;; once. JavaScript forms are sent to all attached clients
+;; simultaneously, and each will echo back the result
+;; individually. Use `list-skewer-clients' to see a list of all
+;; currently attached clients.
+
+;; Sometimes Skewer's long polls from the browser will timeout after a
+;; number of hours of inactivity. If you find the browser disconnected
+;; from Emacs for any reason, use the browser's console to call
+;; skewer() to reconnect. This avoids a page reload, which would lose
+;; any fragile browser state you might care about.
+
+;; To skewer your own document rather than the provided blank page,
+
+;; 1. Load the dependencies
+;; 2. Load skewer-mode.el
+;; 3. Start the HTTP server (`httpd-start')
+;; 4. Include "http://localhost:8080/skewer" as a script
+;; (see `example.html' and check your `httpd-port')
+;; 5. Visit the document from your browser
+
+;; Skewer fully supports CORS, so the document need not be hosted by
+;; Emacs itself. A Greasemonkey userscript and a bookmarklet are
+;; provided for injecting Skewer into any arbitrary page you're
+;; visiting without needing to modify the page on the host.
+
+;; With skewer-repl.el loaded, a REPL into the browser can be created
+;; with M-x `skewer-repl', or C-c C-z. This should work like a console
+;; within the browser. Messages can be logged to this REPL with
+;; skewer.log() (just like console.log()).
+
+;; Extending Skewer:
+
+;; Skewer is flexible and open to extension. The REPL and the CSS and
+;; HTML minor modes are a partial examples of this. You can extend
+;; skewer.js with your own request handlers and talk to them from
+;; Emacs using `skewer-eval' (or `skewer-eval-synchronously') with
+;; your own custom :type. The :type string chooses the dispatch
+;; function under the skewer.fn object. To inject your own JavaScript
+;; into skewer.js, use `skewer-js-hook'.
+
+;; You can also catch messages sent from the browser not in response
+;; to an explicit request. Use `skewer-response-hook' to see all
+;; incoming objects.
+
+;;; History:
+
+;; Version 1.8.0: features
+;; * Work around XMLHttpRequest tampering in userscript
+;; * Add Makefile "run" target for testing
+;; Version 1.7.0: features and fixes
+;; * Support for other major modes (including web-mode) in skewer-html-mode
+;; * Opportunistic support for company-mode completions
+;; * Always serve content as UTF-8
+;; * Improve skewer-everything.js portability
+;; Version 1.6.2: fixes
+;; * skewer.log() takes multiple arguments
+;; * comint and encoding fixes
+;; Version 1.6.1: fixes
+;; * Add `skewer-css-clear-all'
+;; * Better IE8 compatibility
+;; * User interface tweaks
+;; Version 1.6.0: fixes
+;; * Bring up to speed with Emacs 24.3
+;; * Switch to cl-lib from cl
+;; Version 1.5.3: features
+;; * Add `skewer-run-phantomjs'
+;; Version 1.5.2: small cleanup
+;; * Add `skewer-apply' and `skewer-funall'
+;; * Improved safeStringify
+;; Version 1.5.1: features
+;; * No more automatic hook setup (see `skewer-setup')
+;; * Support for HTML interaction
+;; * Support for loading Bower packages
+;; * Drop jQuery dependency
+;; * Many small improvements
+;; Version 1.4: features
+;; * Full CSS interaction
+;; * Greasemonkey userscript for injection
+;; * Full, working CORS support
+;; * Better browser presence detection
+;; Version 1.3: features and fixes
+;; * Full offline support
+;; * No more callback registering
+;; * Fix 64-bit support
+;; * Two new hooks for improved extension support
+;; * More uniform keybindings with other interactive modes
+;; Version 1.2: features
+;; * Add a skewer-eval-print-last-expression
+;; * Display evaluation time when it's long
+;; * Flash the region on eval
+;; * Improve JS stringification
+;; Version 1.1: features and fixes
+;; * Added `list-skewer-clients'
+;; * Reduce the number of HTTP requests needed
+;; * Fix stringification issues
+;; Version 1.0: initial release
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'json)
+(require 'url-util)
+(require 'simple-httpd)
+(require 'js2-mode)
+(require 'cache-table)
+
+(defgroup skewer nil
+ "Live browser JavaScript interaction."
+ :group 'languages)
+
+(defvar skewer-mode-map
+ (let ((map (make-sparse-keymap)))
+ (prog1 map
+ (define-key map (kbd "C-x C-e") 'skewer-eval-last-expression)
+ (define-key map (kbd "C-M-x") 'skewer-eval-defun)
+ (define-key map (kbd "C-c C-k") 'skewer-load-buffer)))
+ "Keymap for skewer-mode.")
+
+(defvar skewer-data-root (file-name-directory load-file-name)
+ "Location of data files needed by impatient-mode.")
+
+(defvar skewer-js-hook ()
+ "Hook to run when skewer.js is being served to the browser.
+
+When hook functions are called, the current buffer is the buffer
+to be served to the client (a defservlet), with skewer.js script
+already inserted. This is the chance for other packages to insert
+their own JavaScript to extend skewer in the browser, such as
+adding a new type handler.")
+
+(defvar skewer-response-hook ()
+ "Hook to run when a response arrives from the browser. Used for
+catching messages from the browser with no associated
+callback. The response object is passed to the hook function.")
+
+(defvar skewer-timeout 3600
+ "Maximum time to wait on the browser to respond, in seconds.")
+
+(defvar skewer-clients ()
+ "Browsers awaiting JavaScript snippets.")
+
+(defvar skewer-callbacks (cache-table-create skewer-timeout :test 'equal)
+ "Maps evaluation IDs to local callbacks.")
+
+(defvar skewer-queue ()
+ "Queued messages for the browser.")
+
+(defvar skewer--last-timestamp 0
+ "Timestamp of the last browser response. Use
+`skewer-last-seen-seconds' to access this.")
+
+(cl-defstruct skewer-client
+ "A client connection awaiting a response."
+ proc agent)
+
+(defun skewer-process-queue ()
+ "Send all queued messages to clients."
+ (when (and skewer-queue skewer-clients)
+ (let ((message (pop skewer-queue))
+ (sent nil))
+ (while skewer-clients
+ (ignore-errors
+ (progn
+ (let ((proc (skewer-client-proc (pop skewer-clients))))
+ (with-temp-buffer
+ (insert (json-encode message))
+ (httpd-send-header proc "text/plain" 200
+ :Cache-Control "no-cache"
+ :Access-Control-Allow-Origin "*")))
+ (setq skewer--last-timestamp (float-time))
+ (setq sent t))))
+ (if (not sent) (push message skewer-queue)))
+ (skewer-process-queue)))
+
+(defun skewer-clients-tabulate ()
+ "Prepare client list for tabulated-list-mode."
+ (cl-loop for client in skewer-clients collect
+ (let ((proc (skewer-client-proc client))
+ (agent (skewer-client-agent client)))
+ (cl-destructuring-bind (host port) (process-contact proc)
+ `(,client [,host ,(format "%d" port) ,agent])))))
+
+(define-derived-mode skewer-clients-mode tabulated-list-mode "skewer-clients"
+ "Mode for listing browsers attached to Emacs for skewer-mode."
+ (setq tabulated-list-format [("Host" 12 t)
+ ("Port" 5 t)
+ ("User Agent" 0 t)])
+ (setq tabulated-list-entries #'skewer-clients-tabulate)
+ (tabulated-list-init-header))
+
+(define-key skewer-clients-mode-map (kbd "g")
+ (lambda ()
+ (interactive)
+ (skewer-ping)
+ (revert-buffer)))
+
+(defun skewer-update-list-buffer ()
+ "Revert the client list, due to an update."
+ (save-window-excursion
+ (let ((list-buffer (get-buffer "*skewer-clients*")))
+ (when list-buffer
+ (with-current-buffer list-buffer
+ (revert-buffer))))))
+
+;;;###autoload
+(defun list-skewer-clients ()
+ "List the attached browsers in a buffer."
+ (interactive)
+ (pop-to-buffer (get-buffer-create "*skewer-clients*"))
+ (skewer-clients-mode)
+ (tabulated-list-print))
+
+(defun skewer-queue-client (proc req)
+ "Add a client to the queue, given the HTTP header."
+ (let ((agent (cl-second (assoc "User-Agent" req))))
+ (push (make-skewer-client :proc proc :agent agent) skewer-clients))
+ (skewer-update-list-buffer)
+ (skewer-process-queue))
+
+;; Servlets
+
+(defservlet skewer "text/javascript; charset=UTF-8" ()
+ (insert-file-contents (expand-file-name "skewer.js" skewer-data-root))
+ (goto-char (point-max))
+ (run-hooks 'skewer-js-hook))
+
+(defun httpd/skewer/get (proc _path _query req &rest _args)
+ (skewer-queue-client proc req))
+
+(defun httpd/skewer/post (proc _path _query req &rest _args)
+ (let* ((result (json-read-from-string (cadr (assoc "Content" req))))
+ (id (cdr (assoc 'id result)))
+ (callback (cache-table-get id skewer-callbacks)))
+ (setq skewer--last-timestamp (float-time))
+ (when callback
+ (funcall callback result))
+ (if id
+ (skewer-queue-client proc req)
+ (with-temp-buffer
+ (httpd-send-header proc "text/plain" 200
+ :Access-Control-Allow-Origin "*")))
+ (dolist (hook skewer-response-hook)
+ (funcall hook result))))
+
+(defvar skewer-demo-source
+ (expand-file-name "example.html" skewer-data-root)
+ "Source file name or buffer for `httpd/skewer/demo' servlet.")
+
+(defservlet skewer/demo "text/html; charset=UTF-8" ()
+ (cl-etypecase skewer-demo-source
+ (buffer (insert-buffer-substring skewer-demo-source))
+ (string (insert-file-contents skewer-demo-source))))
+
+;; Minibuffer display
+
+(defun skewer-success-p (result)
+ "Return T if result was a success."
+ (equal "success" (cdr (assoc 'status result))))
+
+(define-derived-mode skewer-error-mode special-mode "skewer-error"
+ :group 'skewer
+ "Mode for displaying JavaScript errors returned by skewer-mode."
+ (setq truncate-lines t))
+
+(defface skewer-error-face
+ '((((class color) (background light))
+ :foreground "red" :underline t)
+ (((class color) (background dark))
+ :foreground "red" :underline t))
+ "Face for JavaScript errors."
+ :group 'skewer)
+
+(defun skewer--error (string)
+ "Return STRING propertized as an error message."
+ (propertize (or string "<unknown>") 'font-lock-face 'skewer-error-face))
+
+(defun skewer-post-minibuffer (result)
+ "Report results in the minibuffer or the error buffer."
+ (if (skewer-success-p result)
+ (let ((value (cdr (assoc 'value result)))
+ (time (cdr (assoc 'time result))))
+ (if (and time (> time 1.0))
+ (message "%s (%.3f seconds)" value time)
+ (message "%s" value)))
+ (with-current-buffer (pop-to-buffer (get-buffer-create "*skewer-error*"))
+ (let ((inhibit-read-only t)
+ (error (cdr (assoc 'error result))))
+ (erase-buffer)
+ (skewer-error-mode)
+ (insert (skewer--error (cdr (assoc 'name error))) ": ")
+ (insert (or (cdr (assoc 'message error)) "") "\n\n")
+ (insert (or (cdr (assoc 'stack error)) "") "\n\n")
+ (insert (format "Expression: %s\n\n"
+ (if (cdr (assoc 'strict result)) "(strict)" ""))
+ (cdr (assoc 'eval error)))
+ (goto-char (point-min))))))
+
+;; Evaluation functions
+
+(cl-defun skewer-eval (string &optional callback
+ &key verbose strict (type "eval") extra)
+ "Evaluate STRING in the waiting browsers, giving the result to CALLBACK.
+
+:VERBOSE -- if T, the return will try to be JSON encoded
+:STRICT -- if T, expression is evaluated with 'use strict'
+:TYPE -- chooses the JavaScript handler (default: eval)
+:EXTRA -- additional alist keys to append to the request object"
+ (let* ((id (format "%x" (random most-positive-fixnum)))
+ (request `((type . ,type)
+ (eval . ,string)
+ (id . ,id)
+ (verbose . ,verbose)
+ (strict . ,strict)
+ ,@extra)))
+ (prog1 request
+ (setf (cache-table-get id skewer-callbacks) callback)
+ (setq skewer-queue (append skewer-queue (list request)))
+ (skewer-process-queue))))
+
+(defun skewer-eval-synchronously (string &rest args)
+ "Just like `skewer-eval' but synchronously, so don't provide a
+callback. Use with caution."
+ (let ((result nil))
+ (apply #'skewer-eval string (lambda (v) (setq result v)) args)
+ (cl-loop until result
+ do (accept-process-output nil 0.01)
+ finally (return result))))
+
+(defun skewer-apply (function args)
+ "Synchronously apply FUNCTION in the browser with the supplied
+arguments, returning the result. All ARGS must be printable by
+`json-encode'. For example,
+
+ (skewer-apply \"Math.atan2\" '(1 -2)) ; => 2.677945044588987
+
+Uncaught exceptions propagate to Emacs as an error."
+ (let ((specials '(("undefined" . nil)
+ ("NaN" . 0.0e+NaN)
+ ("Infinity" . 1.0e+INF)
+ ("-Infinity" . -1.0e+INF))))
+ (let* ((expr (concat function "(" (mapconcat #'json-encode args ", ") ")"))
+ (result (skewer-eval-synchronously expr :verbose t))
+ (value (cdr (assoc 'value result))))
+ (if (skewer-success-p result)
+ (if (assoc value specials)
+ (cdr (assoc value specials))
+ (condition-case _
+ (json-read-from-string value)
+ (json-readtable-error value)))
+ (signal 'javascript
+ (list (cdr (assoc 'message (cdr (assoc'error result))))))))))
+
+(defun skewer-funcall (function &rest args)
+ "Synchronously call FUNCTION with the supplied ARGS. All ARGS
+must be printable by `json-read-from-string. For example,
+
+ (skewer-funcall \"Math.sin\" 0.5) ; => 0.479425538604203
+
+Uncaught exceptions propagate to Emacs as an error."
+ (skewer-apply function args))
+
+(defun skewer--save-point (f &rest args)
+ "Return a function that calls F with point at the current point."
+ (let ((saved-point (point)))
+ (lambda (&rest more)
+ (save-excursion
+ (goto-char saved-point)
+ (apply f (append args more))))))
+
+(defun skewer-ping ()
+ "Ping the browser to test that it's still alive."
+ (unless (null skewer-clients) ; don't queue pings
+ (skewer-eval (prin1-to-string (float-time)) nil :type "ping")))
+
+(defun skewer-last-seen-seconds ()
+ "Return the number of seconds since the browser was last seen."
+ (skewer-ping) ; make sure it's still alive next request
+ (- (float-time) skewer--last-timestamp))
+
+(defun skewer-mode-strict-p ()
+ "Return T if buffer contents indicates strict mode."
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (js2-forward-sws)
+ (forward-char 1)
+ (let* ((stricts '("\"use strict\"" "'use strict'"))
+ (node (js2-node-at-point))
+ (code (buffer-substring-no-properties (js2-node-abs-pos node)
+ (js2-node-abs-end node))))
+ (and (member code stricts) t)))))
+
+(defun skewer-flash-region (start end &optional timeout)
+ "Temporarily highlight region from START to END."
+ (let ((overlay (make-overlay start end)))
+ (overlay-put overlay 'face 'secondary-selection)
+ (run-with-timer (or timeout 0.2) nil 'delete-overlay overlay)))
+
+(defun skewer-get-last-expression ()
+ "Return the JavaScript expression before the point as a
+list: (string start end)."
+ (save-excursion
+ (js2-backward-sws)
+ (backward-char)
+ (let ((node (js2-node-at-point nil t)))
+ (when (eq js2-FUNCTION (js2-node-type (js2-node-parent node)))
+ (setq node (js2-node-parent node)))
+ (when (js2-ast-root-p node)
+ (error "no expression found"))
+ (let ((start (js2-node-abs-pos node))
+ (end (js2-node-abs-end node)))
+ (list (buffer-substring-no-properties start end) start end)))))
+
+(defun skewer-eval-last-expression (&optional prefix)
+ "Evaluate the JavaScript expression before the point in the
+waiting browser. If invoked with a prefix argument, insert the
+result into the current buffer."
+ (interactive "P")
+ (if prefix
+ (skewer-eval-print-last-expression)
+ (if js2-mode-buffer-dirty-p
+ (js2-mode-wait-for-parse
+ (skewer--save-point #'skewer-eval-last-expression))
+ (cl-destructuring-bind (string start end) (skewer-get-last-expression)
+ (skewer-flash-region start end)
+ (skewer-eval string #'skewer-post-minibuffer)))))
+
+(defun skewer-get-defun ()
+ "Return the toplevel JavaScript expression around the point as
+a list: (string start end)."
+ (save-excursion
+ (js2-backward-sws)
+ (backward-char)
+ (let ((node (js2-node-at-point nil t)))
+ (when (js2-ast-root-p node)
+ (error "no expression found"))
+ (while (and (js2-node-parent node)
+ (not (js2-ast-root-p (js2-node-parent node))))
+ (setf node (js2-node-parent node)))
+ (let ((start (js2-node-abs-pos node))
+ (end (js2-node-abs-end node)))
+ (list (buffer-substring-no-properties start end) start end)))))
+
+(defun skewer-eval-defun ()
+ "Evaluate the JavaScript expression before the point in the
+waiting browser."
+ (interactive)
+ (if js2-mode-buffer-dirty-p
+ (js2-mode-wait-for-parse (skewer--save-point #'skewer-eval-defun))
+ (cl-destructuring-bind (string start end) (skewer-get-defun)
+ (skewer-flash-region start end)
+ (skewer-eval string #'skewer-post-minibuffer))))
+
+;; Print last expression
+
+(defvar skewer-eval-print-map (cache-table-create skewer-timeout :test 'equal)
+ "A mapping of evaluation IDs to insertion points.")
+
+(defun skewer-post-print (result)
+ "Insert the result after its source expression."
+ (if (not (skewer-success-p result))
+ (skewer-post-minibuffer result)
+ (let* ((id (cdr (assoc 'id result)))
+ (pos (cache-table-get id skewer-eval-print-map)))
+ (when pos
+ (with-current-buffer (car pos)
+ (goto-char (cdr pos))
+ (insert (cdr (assoc 'value result)) "\n"))))))
+
+(defun skewer-eval-print-last-expression ()
+ "Evaluate the JavaScript expression before the point in the
+waiting browser and insert the result in the buffer at point."
+ (interactive)
+ (if js2-mode-buffer-dirty-p
+ (js2-mode-wait-for-parse
+ (skewer--save-point #'skewer-eval-print-last-expression))
+ (cl-destructuring-bind (string start end) (skewer-get-defun)
+ (skewer-flash-region start end)
+ (insert "\n")
+ (let* ((request (skewer-eval string #'skewer-post-print :verbose t))
+ (id (cdr (assoc 'id request)))
+ (pos (cons (current-buffer) (point))))
+ (setf (cache-table-get id skewer-eval-print-map) pos)))))
+
+;; Script loading
+
+(defvar skewer-hosted-scripts (cache-table-create skewer-timeout)
+ "Map of hosted scripts to IDs.")
+
+(defun skewer-host-script (string)
+ "Host script STRING from the script servlet, returning the script ID."
+ (let ((id (random most-positive-fixnum)))
+ (prog1 id
+ (setf (cache-table-get id skewer-hosted-scripts) string))))
+
+(defun skewer-load-buffer ()
+ "Load the entire current buffer into the browser. A snapshot of
+the buffer is hosted so that browsers visiting late won't see an
+inconsistent buffer."
+ (interactive)
+ (let ((id (skewer-host-script (buffer-string)))
+ (buffer-name (buffer-name)))
+ (skewer-eval (format "/skewer/script/%d/%s"
+ id (url-hexify-string buffer-name))
+ (lambda (_) (message "%s loaded" buffer-name))
+ :type "script")))
+
+(defservlet skewer/script "text/javascript; charset=UTF-8" (path)
+ (let ((id (string-to-number (nth 3 (split-string path "/")))))
+ (insert (cache-table-get id skewer-hosted-scripts ""))))
+
+;; Define the minor mode
+
+;;;###autoload
+(define-minor-mode skewer-mode
+ "Minor mode for interacting with a browser."
+ :lighter " skewer"
+ :keymap skewer-mode-map
+ :group 'skewer)
+
+;;;###autoload
+(defun run-skewer (&optional arg)
+ "Attach a browser to Emacs for a skewer JavaScript REPL. Uses
+`browse-url' to launch a browser.
+
+With a prefix arugment (C-u), it will ask the filename of the
+root document. With two prefix arguments (C-u C-u), it will use
+the contents of the current buffer as the root document."
+ (interactive "p")
+ (cl-case arg
+ (4 (setf skewer-demo-source (read-file-name "Skewer filename: ")))
+ (16 (setf skewer-demo-source (current-buffer))))
+ (httpd-start)
+ (browse-url (format "http://127.0.0.1:%d/skewer/demo" httpd-port)))
+
+;; PhantomJS
+
+(defvar phantomjs-program-name "/usr/bin/phantomjs"
+ "Path to the phantomjs executable.")
+
+(defvar skewer-phantomjs-processes ()
+ "List of phantomjs processes connected to Skewer.")
+
+(defun skewer-phantomjs-sentinel (proc event)
+ "Cleanup after phantomjs exits."
+ (when (cl-some (lambda (s) (string-match-p s event))
+ '("finished" "abnormal" "killed"))
+ (delete-file (process-get proc 'tempfile))))
+
+;;;###autoload
+(defun skewer-run-phantomjs ()
+ "Connect an inferior PhantomJS process to Skewer, returning the process."
+ (interactive)
+ (httpd-start)
+ (let ((script (make-temp-file "phantomjs-"))
+ (url (format "http://0:%d/skewer/demo" httpd-port)))
+ (with-temp-buffer
+ (insert (format "require('webpage').create().open('%s')" url))
+ (write-region nil nil script nil 0)
+ (let ((proc (start-process "phantomjs" nil
+ phantomjs-program-name script)))
+ (prog1 proc
+ (push proc skewer-phantomjs-processes)
+ (process-put proc 'tempfile script)
+ (set-process-sentinel proc 'skewer-phantomjs-sentinel))))))
+
+(defun skewer-phantomjs-kill ()
+ "Kill all inferior phantomjs processes connected to Skewer."
+ (interactive)
+ (mapc #'delete-process skewer-phantomjs-processes)
+ (setf skewer-phantomjs-processes nil))
+
+(provide 'skewer-mode)
+
+;;; skewer-mode.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-mode.elc b/elpa/skewer-mode-20200304.1142/skewer-mode.elc
new file mode 100644
index 0000000..61c8fda
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-mode.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer-repl.el b/elpa/skewer-mode-20200304.1142/skewer-repl.el
new file mode 100644
index 0000000..6a55d13
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-repl.el
@@ -0,0 +1,210 @@
+;;; skewer-repl.el --- create a REPL in a visiting browser -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;;; Commentary:
+
+;; This is largely based on of IELM's code. Run `skewer-repl' to
+;; switch to the REPL buffer and evaluate code. Use
+;; `skewer-repl-toggle-strict-mode' to turn strict mode on and off.
+
+;; If `compilation-search-path' is set up properly, along with
+;; `skewer-path-strip-level', asynchronous errors will provide
+;; clickable error messages that will take you to the source file of
+;; the error. This is done using `compilation-shell-minor-mode'.
+
+;;; Code:
+
+(require 'comint)
+(require 'compile)
+(require 'skewer-mode)
+
+(defcustom skewer-repl-strict-p nil
+ "When non-NIL, all REPL evaluations are done in strict mode."
+ :type 'boolean
+ :group 'skewer)
+
+(defcustom skewer-repl-prompt "js> "
+ "Prompt string for JavaScript REPL."
+ :type 'string
+ :group 'skewer)
+
+(defvar skewer-repl-welcome
+ (propertize "*** Welcome to Skewer ***\n"
+ 'font-lock-face 'font-lock-comment-face)
+ "Header line to show at the top of the REPL buffer. Hack
+notice: this allows log messages to appear before anything is
+evaluated because it provides insertable space at the top of the
+buffer.")
+
+(defun skewer-repl-process ()
+ "Return the process for the skewer REPL."
+ (get-buffer-process (current-buffer)))
+
+(defface skewer-repl-log-face
+ '((((class color) (background light))
+ :foreground "#77F")
+ (((class color) (background dark))
+ :foreground "#77F"))
+ "Face for skewer.log() messages."
+ :group 'skewer)
+
+(define-derived-mode skewer-repl-mode comint-mode "js-REPL"
+ "Provide a REPL into the visiting browser."
+ :group 'skewer
+ :syntax-table emacs-lisp-mode-syntax-table
+ (setq comint-prompt-regexp (concat "^" (regexp-quote skewer-repl-prompt))
+ comint-input-sender 'skewer-input-sender
+ comint-process-echoes nil)
+ ;; Make opportunistic use of company-mode, but don't require it.
+ ;; This means company-backends may be undeclared, so don't emit a
+ ;; warning about it.
+ (with-no-warnings
+ (setq-local company-backends '(company-skewer-repl)))
+ (unless (comint-check-proc (current-buffer))
+ (insert skewer-repl-welcome)
+ (start-process "skewer-repl" (current-buffer) nil)
+ (set-process-query-on-exit-flag (skewer-repl-process) nil)
+ (goto-char (point-max))
+ (set (make-local-variable 'comint-inhibit-carriage-motion) t)
+ (comint-output-filter (skewer-repl-process) skewer-repl-prompt)
+ (set-process-filter (skewer-repl-process) 'comint-output-filter)))
+
+(defun skewer-repl-toggle-strict-mode ()
+ "Toggle strict mode for expressions evaluated by the REPL."
+ (interactive)
+ (setq skewer-repl-strict-p (not skewer-repl-strict-p))
+ (message "REPL strict mode %s"
+ (if skewer-repl-strict-p "enabled" "disabled")))
+
+(defun skewer-input-sender (_ input)
+ "REPL comint handler."
+ (skewer-eval input 'skewer-post-repl
+ :verbose t :strict skewer-repl-strict-p))
+
+(defun skewer-post-repl (result)
+ "Callback for reporting results in the REPL."
+ (let ((buffer (get-buffer "*skewer-repl*"))
+ (output (cdr (assoc 'value result))))
+ (when buffer
+ (with-current-buffer buffer
+ (comint-output-filter (skewer-repl-process)
+ (concat output "\n" skewer-repl-prompt))))))
+
+(defvar skewer-repl-types
+ '(("log" . skewer-repl-log-face)
+ ("error" . skewer-error-face))
+ "Faces to use for different types of log messages.")
+
+(defun skewer-log-filename (log)
+ "Create a log string for the source file in LOG if present."
+ (let ((name (cdr (assoc 'filename log)))
+ (line (cdr (assoc 'line log)))
+ (column (cdr (assoc 'column log))))
+ (when name
+ (concat (format "\n at %s:%s" name line)
+ (if column (format ":%s" column))))))
+
+(defun skewer-post-log (log)
+ "Callback for logging messages to the REPL."
+ (let* ((buffer (get-buffer "*skewer-repl*"))
+ (face (cdr (assoc (cdr (assoc 'type log)) skewer-repl-types)))
+ (value (or (cdr (assoc 'value log)) "<unspecified error>"))
+ (output (propertize value 'font-lock-face face)))
+ (when buffer
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-max))
+ (forward-line 0)
+ (if (bobp)
+ (insert (concat output (skewer-log-filename log) "\n"))
+ (backward-char)
+ (insert (concat "\n" output (skewer-log-filename log)))))))))
+
+(defcustom skewer-path-strip-level 1
+ "Number of folders which will be stripped from url when discovering paths.
+Use this to limit path matching to files in your filesystem. You
+may want to add some folders to `compilation-search-path', so
+matched files can be found."
+ :type 'number
+ :group 'skewer)
+
+(defun skewer-repl-mode-compilation-shell-hook ()
+ "Setup compilation shell minor mode for highlighting files"
+ (let ((error-re (format "^[ ]*at https?://[^/]+/\\(?:[^/]+/\\)\\{%d\\}\\([^:?#]+\\)\\(?:[?#][^:]*\\)?:\\([[:digit:]]+\\)\\(?::\\([[:digit:]]+\\)\\)?$" skewer-path-strip-level)))
+ (setq-local compilation-error-regexp-alist `((,error-re 1 2 3 2))))
+ (compilation-shell-minor-mode 1))
+
+;;;###autoload
+(defun skewer-repl--response-hook (response)
+ "Catches all browser messages logging some to the REPL."
+ (let ((type (cdr (assoc 'type response))))
+ (when (member type '("log" "error"))
+ (skewer-post-log response))))
+
+;;;###autoload
+(defun skewer-repl ()
+ "Start a JavaScript REPL to be evaluated in the visiting browser."
+ (interactive)
+ (when (not (get-buffer "*skewer-repl*"))
+ (with-current-buffer (get-buffer-create "*skewer-repl*")
+ (skewer-repl-mode)))
+ (pop-to-buffer (get-buffer "*skewer-repl*")))
+
+(defun company-skewer-repl (command &optional arg &rest _args)
+ "Skewerl REPL backend for company-mode.
+See `company-backends' for more info about COMMAND and ARG."
+ (interactive (list 'interactive))
+ (cl-case command
+ (interactive
+ (with-no-warnings ;; opportunistic use of company-mode
+ (company-begin-backend 'company-skewer-repl)))
+ (prefix (skewer-repl-company-prefix))
+ (ignore-case t)
+ (sorted t)
+ (candidates (cons :async
+ (lambda (callback)
+ (skewer-repl-get-completions arg callback))))))
+
+(defun skewer-repl-get-completions (arg callback)
+ "Get the completion list matching the prefix ARG.
+Evaluate CALLBACK with the completion candidates."
+ (let* ((expression (skewer-repl--get-completion-expression arg))
+ (pattern (if expression
+ (substring arg (1+ (length expression)))
+ arg)))
+ (skewer-eval (or expression "window")
+ (lambda (result)
+ (cl-loop with value = (cdr (assoc 'value result))
+ for key being the elements of value
+ when expression
+ collect (concat expression "." key) into results
+ else
+ collect key into results
+ finally (funcall callback results)))
+ :type "completions"
+ :extra `((regexp . ,pattern)))))
+
+(defun skewer-repl--get-completion-expression (arg)
+ "Get completion expression from ARG."
+ (let ((components (split-string arg "\\.")))
+ (when (> (length components) 1)
+ (mapconcat #'identity (cl-subseq components 0 -1) "."))))
+
+(defun skewer-repl-company-prefix ()
+ "Prefix for company."
+ (and (eq major-mode 'skewer-repl-mode)
+ (or (with-no-warnings ;; opportunistic use of company-mode
+ (company-grab-symbol-cons "\\." 1))
+ 'stop)))
+
+;;;###autoload
+(eval-after-load 'skewer-mode
+ '(progn
+ (add-hook 'skewer-response-hook #'skewer-repl--response-hook)
+ (add-hook 'skewer-repl-mode-hook #'skewer-repl-mode-compilation-shell-hook)
+ (define-key skewer-mode-map (kbd "C-c C-z") #'skewer-repl)))
+
+(provide 'skewer-repl)
+
+;;; skewer-repl.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-repl.elc b/elpa/skewer-mode-20200304.1142/skewer-repl.elc
new file mode 100644
index 0000000..0f0560b
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-repl.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer-setup.el b/elpa/skewer-mode-20200304.1142/skewer-setup.el
new file mode 100644
index 0000000..77aea1b
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-setup.el
@@ -0,0 +1,21 @@
+;;; skewer-setup.el --- automatic setup for the Skewer minor modes -*- lexical-binding: t; -*-
+
+;; This is free and unencumbered software released into the public domain.
+
+;;; Commentary:
+
+;; This exists as a separate file so that Skewer need not be fully
+;; loaded just to use this setup function.
+
+;;; Code:
+
+;;;###autoload
+(defun skewer-setup ()
+ "Fully integrate Skewer into js2-mode, css-mode, and html-mode buffers."
+ (add-hook 'js2-mode-hook 'skewer-mode)
+ (add-hook 'css-mode-hook 'skewer-css-mode)
+ (add-hook 'html-mode-hook 'skewer-html-mode))
+
+(provide 'skewer-setup)
+
+;;; skewer-setup.el ends here
diff --git a/elpa/skewer-mode-20200304.1142/skewer-setup.elc b/elpa/skewer-mode-20200304.1142/skewer-setup.elc
new file mode 100644
index 0000000..10c79d0
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer-setup.elc
Binary files differ
diff --git a/elpa/skewer-mode-20200304.1142/skewer.js b/elpa/skewer-mode-20200304.1142/skewer.js
new file mode 100644
index 0000000..eb741c7
--- /dev/null
+++ b/elpa/skewer-mode-20200304.1142/skewer.js
@@ -0,0 +1,436 @@
+/**
+ * @fileOverview Live browser interaction with Emacs
+ * @version 1.4
+ */
+
+/**
+ * Connects to Emacs and waits for a request. After handling the
+ * request it sends back the results and queues itself for another
+ * request.
+ * @namespace Holds all of Skewer's functionality.
+ */
+function skewer() {
+ function callback(request) {
+ var result = skewer.fn[request.type](request);
+ if (result) {
+ result = skewer.extend({
+ id: request.id,
+ type: request.type,
+ status: 'success',
+ value: ''
+ }, result);
+ skewer.postJSON(skewer.host + "/skewer/post", result, callback);
+ } else {
+ skewer.getJSON(skewer.host + "/skewer/get", callback);
+ }
+ };
+ skewer.getJSON(skewer.host + "/skewer/get", callback);
+}
+
+/**
+ * Get a JSON-encoded object from a server.
+ * @param {String} url The location of the remote server
+ * @param {Function} [callback] The callback to receive a response object
+ */
+skewer.getJSON = function(url, callback) {
+ var XHR = window.skewerNativeXHR || XMLHttpRequest;
+ var xhr = new XHR();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ callback(JSON.parse(xhr.responseText));
+ }
+ };
+ xhr.open('GET', url, true);
+ xhr.send();
+};
+
+/**
+ * Send a JSON-encoded object to a server.
+ * @param {String} url The location of the remote server
+ * @param {Object} object The object to transmit to the server
+ * @param {Function} [callback] The callback to receive a response object
+ */
+skewer.postJSON = function(url, object, callback) {
+ var XHR = window.skewerNativeXHR || XMLHttpRequest;
+ var xhr = new XHR();
+ xhr.onreadystatechange = function() {
+ if (callback && xhr.readyState === 4 && xhr.status === 200) {
+ callback(JSON.parse(xhr.responseText));
+ }
+ };
+ xhr.open('POST', url, true);
+ xhr.setRequestHeader("Content-Type", "text/plain"); // CORS
+ xhr.send(JSON.stringify(object));
+};
+
+/**
+ * Add the properties other objects to a target object (jQuery.extend).
+ * @param {Object} target The object to receive new properties
+ * @param {...Object} objects Source objects for properties
+ * @returns The target object
+ */
+skewer.extend = function(target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var object = arguments[i];
+ for (var key in object) {
+ if (object.hasOwnProperty(key)) {
+ target[key] = object[key];
+ }
+ }
+ }
+ return target;
+};
+
+/**
+ * Globally evaluate an expression and return the result. This
+ * <i>only</i> works when the implementation's indirect eval performs
+ * a global eval. If not, there's no alternative, since a return value
+ * is essential.
+ *
+ * @see http://perfectionkills.com/global-eval-what-are-the-options/
+ *
+ * @param expression A string containing an expression to evaluate
+ * @returns The result of the evaluation
+ */
+skewer.globalEval = (function() {
+ var eval0 = (function(original, Object) {
+ try {
+ return [eval][0]('Object') === original;
+ } catch (e) {
+ return false;
+ }
+ }(Object, false));
+ if (eval0) {
+ return function(expression) {
+ return [eval][0](expression);
+ };
+ } else {
+ return function(expression) { // Safari
+ return eval.call(window, expression);
+ };
+ }
+}());
+
+/**
+ * Same as Date.now(), supplied for pre-ES5 JS (<=IE8).
+ * @returns {number} The epoch time in milliseconds
+ */
+skewer.now = function() {
+ return new Date().valueOf();
+};
+
+/**
+ * Handlers accept a request object from Emacs and return either a
+ * logical false (no response) or an object to return to Emacs.
+ * @namespace Request handlers.
+ */
+skewer.fn = {};
+
+/**
+ * Handles an code evaluation request from Emacs.
+ * @param request The request object sent by Emacs
+ * @returns The result object to be returned to Emacs
+ */
+skewer.fn.eval = function(request) {
+ var result = {
+ strict: request.strict
+ };
+ var start = skewer.now();
+ try {
+ var prefix = request.strict ? '"use strict";\n' : "";
+ var value = skewer.globalEval(prefix + request.eval);
+ result.value = skewer.safeStringify(value, request.verbose);
+ } catch (error) {
+ result = skewer.errorResult(error, result, request);
+ }
+ result.time = (skewer.now() - start) / 1000;
+ return result;
+};
+
+/**
+ * Load a hosted script named by the request.
+ * @param request The request object sent by Emacs
+ * @returns The result object to be returned to Emacs
+ */
+skewer.fn.script = function(request) {
+ var script = document.createElement('script');
+ script.src = skewer.host + request.eval;
+ document.body.appendChild(script);
+ return {value: JSON.stringify(request.eval)};
+};
+
+/**
+ * A keep-alive and connecton testing handler.
+ * @param request The request object sent by Emacs
+ * @returns The result object to be returned to Emacs
+ */
+skewer.fn.ping = function(request) {
+ return {
+ type: 'pong',
+ date: skewer.now() / 1000,
+ value: request.eval
+ };
+};
+
+/**
+ * Establish a new stylesheet with the provided value.
+ */
+skewer.fn.css = function(request) {
+ var style = document.createElement('style');
+ style.type = 'text/css';
+ style.className = 'skewer';
+ if (style.styleSheet) { // < IE9
+ style.styleSheet.cssText = request.eval;
+ } else {
+ style.appendChild(document.createTextNode(request.eval));
+ }
+ document.body.appendChild(style);
+ return {};
+};
+
+/**
+ * Remove all of Skewer's style tags from the document.
+ */
+skewer.fn.cssClearAll = function(request) {
+ var styles = document.body.querySelectorAll('style.skewer');
+ for (var i = 0; i < styles.length; i++) {
+ styles[i].parentNode.removeChild(styles[i]);
+ }
+ return {};
+};
+
+/**
+ * HTML evaluator, appends or replaces a selection with given HTML.
+ */
+skewer.fn.html = function(request) {
+ function buildSelector(ancestry) {
+ return ancestry.map(function(tag) {
+ return tag[0] + ':nth-of-type(' + tag[1] + ')';
+ }).join(' > ');
+ }
+ function query(ancestry) {
+ return document.querySelector(buildSelector(ancestry));
+ }
+ function htmlToNode(html) {
+ var wrapper = document.createElement('div');
+ wrapper.innerHTML = html;
+ return wrapper.firstChild;
+ }
+
+ var target = query(request.ancestry);
+
+ if (target == null) {
+ /* Determine missing part of the ancestry. */
+ var path = request.ancestry.slice(0); // copy
+ var missing = [];
+ while (query(path) == null) {
+ missing.push(path.pop());
+ }
+
+ /* Build up the missing elements. */
+ target = query(path);
+ while (missing.length > 0) {
+ var tag = missing.pop(),
+ name = tag[0],
+ nth = tag[1];
+ var empty = null;
+ var count = target.querySelectorAll(name).length;
+ for (; count < nth; count++) {
+ empty = document.createElement(tag[0]);
+ target.appendChild(empty);
+ }
+ target = empty;
+ }
+ }
+
+ target.parentNode.replaceChild(htmlToNode(request.eval), target);
+ return {};
+};
+
+/**
+ * Fetch the HTML contents of selector.
+ */
+skewer.fn.fetchselector = function(request) {
+ var element = document.querySelector(request.eval);
+ return { value: element.innerHTML };
+};
+
+/**
+ * Return a list of completions for an object.
+ */
+skewer.fn.completions = function(request) {
+ var object = skewer.globalEval(request.eval);
+ var keys = new Set();
+ var regex = new RegExp(request.regexp);
+ for (var key in object) {
+ if (regex.test(key)) {
+ keys.add(key);
+ }
+ }
+ var props = object != null ? Object.getOwnPropertyNames(object) : [];
+ for (var i = 0; i < props.length; i++) {
+ if (regex.test(props[i])) {
+ keys.add(props[i]);
+ }
+ }
+ return { value: Array.from(keys).sort() };
+};
+
+/**
+ * Host of the skewer script (CORS support).
+ * @type string
+ */
+(function() {
+ var script = document.querySelector('script[src$="/skewer"]');
+ if (script) {
+ skewer.host = script.src.match(/\w+:\/\/[^/]+/)[0];
+ } else {
+ skewer.host = ''; // default to the current host
+ }
+}());
+
+/**
+ * Stringify a potentially circular object without throwing an exception.
+ * @param object The object to be printed.
+ * @param {boolean} verbose Enable more verbose output.
+ * @returns {string} The printed object.
+ */
+skewer.safeStringify = function (object, verbose) {
+ "use strict";
+ var circular = "#<Circular>";
+ var seen = [];
+
+ var stringify = function(obj) {
+ if (obj === true) {
+ return "true";
+ } else if (obj === false) {
+ return "false";
+ } else if (obj === undefined) {
+ return "undefined";
+ } else if (obj === null) {
+ return "null";
+ } else if (typeof obj === "number") {
+ return obj.toString();
+ } else if (obj instanceof Array) {
+ if (seen.indexOf(obj) >= 0) {
+ return circular;
+ } else {
+ seen.push(obj);
+ return "[" + obj.map(function(e) {
+ return stringify(e);
+ }).join(", ") + "]";
+ }
+ } else if (typeof obj === "string") {
+ return JSON.stringify(obj);
+ } else if (window.Node != null && obj instanceof Node) {
+ return obj.toString(); // DOM elements can't stringify
+ } else if (typeof obj === "function") {
+ if (verbose)
+ return obj.toString();
+ else
+ return "Function";
+ } else if (Object.prototype.toString.call(obj) === '[object Date]') {
+ if (verbose)
+ return JSON.stringify(obj);
+ else
+ return obj.toString();
+ } else {
+ if (verbose) {
+ if (seen.indexOf(obj) >= 0)
+ return circular;
+ else
+ seen.push(obj);
+ var pairs = [];
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ var pair = JSON.stringify(key) + ":";
+ pair += stringify(obj[key]);
+ pairs.push(pair);
+ }
+ }
+ return "{" + pairs.join(',') + "}";
+ } else {
+ try {
+ return obj.toString();
+ } catch (error) {
+ return ({}).toString();
+ }
+ }
+ }
+ };
+
+ try {
+ return stringify(object);
+ } catch (error) {
+ return skewer.safeStringify(object, false);
+ }
+};
+
+/**
+ * Log an object to the Skewer REPL in Emacs (console.log).
+ * @param message The object to be logged.
+ */
+skewer.log = function() {
+ "use strict";
+ for (var i = 0; i < arguments.length; i++) {
+ var log = {
+ type: "log",
+ value: skewer.safeStringify(arguments[i], true)
+ };
+ skewer.postJSON(skewer.host + "/skewer/post", log);
+ }
+};
+
+/**
+ * Report an error event to the REPL.
+ * @param event An error event object.
+ */
+skewer.error = function(event) {
+ "use strict";
+ var log = {
+ type: "error",
+ value: event.message,
+ filename: event.filename,
+ line: event.lineno,
+ column: event.column
+ };
+ skewer.postJSON(skewer.host + "/skewer/post", log);
+};
+
+/**
+ * Prepare a result when an error occurs evaluating Javascript code.
+ * @param error The error object given by catch.
+ * @param result The resutl object to return to Emacs.
+ * @param request The request object from Emacs.
+ * @return The result object to send back to Emacs.
+ */
+skewer.errorResult = function(error, result, request) {
+ "use strict";
+ return skewer.extend({}, result, {
+ value: error.toString(),
+ status: 'error',
+ error: {
+ name: error.name,
+ stack: error.stack,
+ type: error.type,
+ message: error.message,
+ eval: request.eval
+ }
+ });
+};
+
+if (window.addEventListener) {
+ window.addEventListener('error', skewer.error);
+ if (document.readyState === 'complete') {
+ skewer();
+ } else {
+ window.addEventListener('load', skewer);
+ }
+} else { // < IE9
+ window.attachEvent('onerror', skewer.error);
+ if (document.readyState === 'complete') {
+ skewer();
+ } else {
+ window.attachEvent('onload', skewer);
+ }
+}