Last active
May 5, 2024 21:11
-
-
Save kbauer/68db9deb88ae170a8f18a2b84de74fb6 to your computer and use it in GitHub Desktop.
Emacs-lisp command for compiling a javascript file into a bookmarklet, by stripping unnecessary characters and adding a wrapper.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; myjs-compile-bookmarklet.el --- strip javascript code as bookmarklet -*- lexical-binding: t; coding: utf-8; lisp-indent-offset: nil; -*- | |
;; Copyright (C) 2018 Klaus-Dieter Bauer | |
;; Author: Klaus-Dieter Bauer <[email protected]> | |
;; Keywords: javascript, bookmarklet | |
;; This program is free software; you can redistribute it and/or modify | |
;; it under the terms of the GNU General Public License as published by | |
;; the Free Software Foundation, either version 3 of the License, or | |
;; (at your option) any later version. | |
;; This program is distributed in the hope that it will be useful, | |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
;; GNU General Public License for more details. | |
;; You should have received a copy of the GNU General Public License | |
;; along with this program. If not, see <http://www.gnu.org/licenses/>. | |
;;; Commentary: | |
;; See docstrings. | |
;; | |
;; Published as https://gist.github.com/kbauer/68db9deb88ae170a8f18a2b84de74fb6 | |
;;; Code: | |
(defconst myjs-compile-bookmarklet-metachars | |
"(){}[];+-*/.,%>=<!\"'`|&" | |
"A string of operator-only characters. | |
Used for stripping unneeded whitespace between operators and identifiers.") | |
(defun myjs-compile-bookmarklet () | |
"Copy current buffer as bookmarklet. | |
In detail this means putting a copy of `buffer-string' | |
into `buffer-file-name'.txt and the (clipboard), where | |
- Comments and syntactically irrelevant whitespace are | |
stripped, to reduce character count and to reduce the code | |
to a single-line string. | |
- A wrapper is added, that contains the file name as a comment, | |
the `javascript:' prefix, required for executing javascript from | |
bookmarks, and a wrapper-function, that prevents the bookmarklet | |
from cluttering the namespace of the function. | |
==== KNOWN ISSUES ==== | |
- Some whitespace may be incorrectly judged as syntactically irrelevant, | |
e.g. whitespace in string-literals. Workaround: Avoid such strings, | |
its only a bookmarklet after all." | |
(interactive) | |
(when (buffer-file-name) | |
(save-buffer)) | |
(let ((raw-string (buffer-string)) | |
(file-name (buffer-file-name))) | |
(with-temp-buffer | |
(insert raw-string) | |
(goto-char (point-min)) | |
(save-excursion | |
(while (search-forward-regexp (rx "/*" (*? anything) "*/") nil t) | |
(replace-match ""))) | |
(save-excursion | |
(while (re-search-forward "//.*" nil t) | |
(replace-match " "))) | |
(save-excursion | |
(while (re-search-forward "[[:blank:]\n]+" nil t) | |
(unless (eq (save-excursion (forward-char -1) (face-at-point)) | |
'font-lock-string-face) | |
(replace-match " ")))) | |
;; Removal of whitespace separating punctuation outside strings. | |
(save-excursion | |
(while (search-forward-regexp " " nil t) | |
(let ((a (char-after (point))) | |
(b (char-before (- (point) 1))) | |
(meta (append myjs-compile-bookmarklet-metachars nil))) | |
(when (and (or (memq a meta) (memq b meta)) | |
(not (eq (save-excursion (forward-char -1) (face-at-point)) | |
'font-lock-string-face))) | |
(delete-char -1))))) | |
;; Add "private namespace" and "javascript:" wrappers. | |
(insert | |
"javascript:" | |
(if file-name | |
(concat "/* " (file-name-nondirectory file-name) " */") | |
"") | |
"(function(){") | |
(goto-char (point-max)) | |
(while (memq (char-before) '(?\ ?\n ?\t)) | |
(backward-delete-char 1)) | |
(insert "})();undefined;") | |
;; Export to .txt file. | |
(when file-name | |
(let ((txt-file-name (concat file-name ".txt")) | |
(contents (buffer-string))) | |
(with-temp-buffer | |
(when (file-exists-p txt-file-name) | |
(insert-file-contents txt-file-name)) | |
(if (string= contents (buffer-string)) | |
(message "%s: Unchanged contents, not updated." txt-file-name) | |
(erase-buffer) | |
(insert contents) | |
(write-file txt-file-name))) | |
(message "Exported bookmarklet to `%s'" txt-file-name))) | |
;; Copy to kill-ring | |
(message "Copied bookmarklet to kill-ring (%d characters)" (point-max)) | |
(kill-region (point-min) (point-max)) | |
;; Display result | |
(with-selected-window (display-buffer (get-buffer-create "*myjs:bookmarklet*")) | |
(erase-buffer) | |
(yank) | |
(insert "\n\n" | |
(format "Copied bookmarklet to kill-ring (%d characters)" (point-max))) | |
(unless (eq major-mode 'js-mode) | |
(js-mode))))) | |
nil) | |
(provide 'myjs-compile-bookmarklet) | |
;;; myjs-compile-bookmarklet.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment