emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 39d9b96: Remove MozRepl stuff from js.el


From: Lars Ingebrigtsen
Subject: master 39d9b96: Remove MozRepl stuff from js.el
Date: Mon, 4 Oct 2021 05:57:01 -0400 (EDT)

branch: master
commit 39d9b96a606d1c605c329a6c7d1dab6afbd3b824
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Remove MozRepl stuff from js.el
    
    * lisp/progmodes/js.el: Remove all the mozrepl stuff from js.el
    (bug#40771).
---
 etc/NEWS             |    5 +
 lisp/progmodes/js.el | 1138 +-------------------------------------------------
 2 files changed, 15 insertions(+), 1128 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index f7e52f6..7deff1f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -82,6 +82,11 @@ Emacs buffers, like indentation and the like.  The new ert 
function
 
 * Incompatible Lisp Changes in Emacs 29.1
 
+---
+** MozRepl has been removed from js.el.
+MozRepl was removed from Firefox in 2017, so this code doesn't work
+with recent versions of Firefox.
+
 
 * Lisp Changes in Emacs 29.1
 
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 845ca86..f6603f8 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -33,7 +33,7 @@
 ;; The main features of this JavaScript mode are syntactic
 ;; highlighting (enabled with `font-lock-mode' or
 ;; `global-font-lock-mode'), automatic indentation and filling of
-;; comments, C preprocessor fontification, and MozRepl integration.
+;; comments, and C preprocessor fontification.
 ;;
 ;; General Remarks:
 ;;
@@ -51,7 +51,6 @@
   (require 'cc-fonts))
 (require 'newcomment)
 (require 'imenu)
-(require 'moz nil t)
 (require 'json)
 (require 'prog-mode)
 
@@ -59,12 +58,9 @@
   (require 'cl-lib)
   (require 'ido))
 
-(defvar inferior-moz-buffer)
-(defvar moz-repl-name)
 (defvar ido-cur-list)
 (defvar electric-layout-rules)
 (declare-function ido-mode "ido" (&optional arg))
-(declare-function inferior-moz-process "ext:mozrepl" ())
 
 ;;; Constants
 
@@ -485,25 +481,22 @@ seldom use, either globally or on a per-buffer basis."
                              (list 'const x))
                            js--available-frameworks)))
 
-(defcustom js-js-switch-tabs
-  (and (memq system-type '(darwin)) t)
+(defvar js-js-switch-tabs (and (memq system-type '(darwin)) t)
   "Whether `js-mode' should display tabs while selecting them.
 This is useful only if the windowing system has a good mechanism
-for preventing Firefox from stealing the keyboard focus."
-  :type 'boolean)
+for preventing Firefox from stealing the keyboard focus.")
+(make-obsolete-variable 'js-js-switch-tabs "MozRepl no longer exists" "28.1")
 
-(defcustom js-js-tmpdir
-  (locate-user-emacs-file "js/js")
+(defvar js-js-tmpdir (locate-user-emacs-file "js/js")
   "Temporary directory used by `js-mode' to communicate with Mozilla.
-This directory must be readable and writable by both Mozilla and Emacs."
-  :type 'directory
-  :version "28.1")
+This directory must be readable and writable by both Mozilla and Emacs.")
+(make-obsolete-variable 'js-js-tmpdir "MozRepl no longer exists" "28.1")
 
-(defcustom js-js-timeout 5
+(defvar js-js-timeout 5
   "Reply timeout for executing commands in Mozilla via `js-mode'.
 The value is given in seconds.  Increase this value if you are
-getting timeout messages."
-  :type 'integer)
+getting timeout messages.")
+(make-obsolete-variable 'js-js-timeout "MozRepl no longer exists" "28.1")
 
 (defcustom js-indent-first-init nil
   "Non-nil means specially indent the first variable declaration's initializer.
@@ -671,18 +664,7 @@ This variable is like `sgml-attribute-offset'."
 
 (defvar js-mode-map
   (let ((keymap (make-sparse-keymap)))
-    (define-key keymap [(control ?c) (meta ?:)] #'js-eval)
-    (define-key keymap [(control ?c) (control ?j)] #'js-set-js-context)
-    (define-key keymap [(control meta ?x)] #'js-eval-defun)
     (define-key keymap [(meta ?.)] #'js-find-symbol)
-    (easy-menu-define nil keymap "JavaScript Menu"
-      '("JavaScript"
-        ["Select New Mozilla Context..." js-set-js-context
-         (fboundp #'inferior-moz-process)]
-        ["Evaluate Expression in Mozilla Context..." js-eval
-         (fboundp #'inferior-moz-process)]
-        ["Send Current Function to Mozilla..." js-eval-defun
-         (fboundp #'inferior-moz-process)]))
     keymap)
   "Keymap for `js-mode'.")
 
@@ -3336,1106 +3318,6 @@ current buffer.  Pushes a mark onto the tag ring just 
like
     (push-mark)
     (goto-char marker)))
 
-;;; MozRepl integration
-
-(define-error 'js-moz-bad-rpc "Mozilla RPC Error") ;; '(timeout error))
-(define-error 'js-js-error "JavaScript Error") ;; '(js-error error))
-
-(defun js--wait-for-matching-output
-  (process regexp timeout &optional start)
-  "Wait TIMEOUT seconds for PROCESS to output a match for REGEXP.
-On timeout, return nil.  On success, return t with match data
-set.  If START is non-nil, look for output starting from START.
-Otherwise, use the current value of `process-mark'."
-  (with-current-buffer (process-buffer process)
-    (cl-loop with start-pos = (or start
-                                  (marker-position (process-mark process)))
-            with end-time = (time-add nil timeout)
-            for time-left = (float-time (time-subtract end-time nil))
-             do (goto-char (point-max))
-             if (looking-back regexp start-pos) return t
-             while (> time-left 0)
-             do (accept-process-output process time-left nil t)
-             do (goto-char (process-mark process))
-             finally do (signal
-                         'js-moz-bad-rpc
-                         (list (format "Timed out waiting for output matching 
%S" regexp))))))
-
-(cl-defstruct js--js-handle
-  ;; Integer, mirrors the value we see in JS
-  (id nil :read-only t)
-
-  ;; Process to which this thing belongs
-  (process nil :read-only t))
-
-(defun js--js-handle-expired-p (x)
-  (not (eq (js--js-handle-process x)
-           (inferior-moz-process))))
-
-(defvar js--js-references nil
-  "Maps Elisp JavaScript proxy objects to their JavaScript IDs.")
-
-(defvar js--js-process nil
-  "The most recent MozRepl process object.")
-
-(defvar js--js-gc-idle-timer nil
-  "Idle timer for cleaning up JS object references.")
-
-(defvar js--js-last-gcs-done nil)
-
-(defconst js--moz-interactor
-  (replace-regexp-in-string
-   "[ \n]+" " "
-   ; */" Make Emacs happy
-"(function(repl) {
-  repl.defineInteractor('js', {
-    onStart: function onStart(repl) {
-      if(!repl._jsObjects) {
-        repl._jsObjects = {};
-        repl._jsLastID = 0;
-        repl._jsGC = this._jsGC;
-      }
-      this._input = '';
-    },
-
-    _jsGC: function _jsGC(ids_in_use) {
-      var objects = this._jsObjects;
-      var keys = [];
-      var num_freed = 0;
-
-      for(var pn in objects) {
-        keys.push(Number(pn));
-      }
-
-      keys.sort(function(x, y) x - y);
-      ids_in_use.sort(function(x, y) x - y);
-      var i = 0;
-      var j = 0;
-
-      while(i < ids_in_use.length && j < keys.length) {
-        var id = ids_in_use[i++];
-        while(j < keys.length && keys[j] !== id) {
-          var k_id = keys[j++];
-          delete objects[k_id];
-          ++num_freed;
-        }
-        ++j;
-      }
-
-      while(j < keys.length) {
-        var k_id = keys[j++];
-        delete objects[k_id];
-        ++num_freed;
-      }
-
-      return num_freed;
-    },
-
-    _mkArray: function _mkArray() {
-      var result = [];
-      for(var i = 0; i < arguments.length; ++i) {
-        result.push(arguments[i]);
-      }
-      return result;
-    },
-
-    _parsePropDescriptor: function _parsePropDescriptor(parts) {
-      if(typeof parts === 'string') {
-        parts = [ parts ];
-      }
-
-      var obj = parts[0];
-      var start = 1;
-
-      if(typeof obj === 'string') {
-        obj = window;
-        start = 0;
-      } else if(parts.length < 2) {
-        throw new Error('expected at least 2 arguments');
-      }
-
-      for(var i = start; i < parts.length - 1; ++i) {
-        obj = obj[parts[i]];
-      }
-
-      return [obj, parts[parts.length - 1]];
-    },
-
-    _getProp: function _getProp(/*...*/) {
-      if(arguments.length === 0) {
-        throw new Error('no arguments supplied to getprop');
-      }
-
-      if(arguments.length === 1 &&
-         (typeof arguments[0]) !== 'string')
-      {
-        return arguments[0];
-      }
-
-      var [obj, propname] = this._parsePropDescriptor(arguments);
-      return obj[propname];
-    },
-
-    _putProp: function _putProp(properties, value) {
-      var [obj, propname] = this._parsePropDescriptor(properties);
-      obj[propname] = value;
-    },
-
-    _delProp: function _delProp(propname) {
-      var [obj, propname] = this._parsePropDescriptor(arguments);
-      delete obj[propname];
-    },
-
-    _typeOf: function _typeOf(thing) {
-      return typeof thing;
-    },
-
-    _callNew: function(constructor) {
-      if(typeof constructor === 'string')
-      {
-        constructor = window[constructor];
-      } else if(constructor.length === 1 &&
-                typeof constructor[0] !== 'string')
-      {
-        constructor = constructor[0];
-      } else {
-        var [obj,propname] = this._parsePropDescriptor(constructor);
-        constructor = obj[propname];
-      }
-
-      /* Hacky, but should be robust */
-      var s = 'new constructor(';
-      for(var i = 1; i < arguments.length; ++i) {
-        if(i != 1) {
-          s += ',';
-        }
-
-        s += 'arguments[' + i + ']';
-      }
-
-      s += ')';
-      return eval(s);
-    },
-
-    _callEval: function(thisobj, js) {
-      return eval.call(thisobj, js);
-    },
-
-    getPrompt: function getPrompt(repl) {
-      return 'EVAL>'
-    },
-
-    _lookupObject: function _lookupObject(repl, id) {
-      if(typeof id === 'string') {
-        switch(id) {
-        case 'global':
-          return window;
-        case 'nil':
-          return null;
-        case 't':
-          return true;
-        case 'false':
-          return false;
-        case 'undefined':
-          return undefined;
-        case 'repl':
-          return repl;
-        case 'interactor':
-          return this;
-        case 'NaN':
-          return NaN;
-        case 'Infinity':
-          return Infinity;
-        case '-Infinity':
-          return -Infinity;
-        default:
-          throw new Error('No object with special id:' + id);
-        }
-      }
-
-      var ret = repl._jsObjects[id];
-      if(ret === undefined) {
-        throw new Error('No object with id:' + id + '(' + typeof id + ')');
-      }
-      return ret;
-    },
-
-    _findOrAllocateObject: function _findOrAllocateObject(repl, value) {
-      if(typeof value !== 'object'  && typeof value !== 'function') {
-        throw new Error('_findOrAllocateObject called on non-object('
-                        + typeof(value) + '): '
-                        + value)
-      }
-
-      for(var id in repl._jsObjects) {
-        id = Number(id);
-        var obj = repl._jsObjects[id];
-        if(obj === value) {
-          return id;
-        }
-      }
-
-      var id = ++repl._jsLastID;
-      repl._jsObjects[id] = value;
-      return id;
-    },
-
-    _fixupList: function _fixupList(repl, list) {
-      for(var i = 0; i < list.length; ++i) {
-        if(list[i] instanceof Array) {
-          this._fixupList(repl, list[i]);
-        } else if(typeof list[i] === 'object') {
-          var obj = list[i];
-          if(obj.funcall) {
-            var parts = obj.funcall;
-            this._fixupList(repl, parts);
-            var [thisobj, func] = this._parseFunc(parts[0]);
-            list[i] = func.apply(thisobj, parts.slice(1));
-          } else if(obj.objid) {
-            list[i] = this._lookupObject(repl, obj.objid);
-          } else {
-            throw new Error('Unknown object type: ' + obj.toSource());
-          }
-        }
-      }
-    },
-
-    _parseFunc: function(func) {
-      var thisobj = null;
-
-      if(typeof func === 'string') {
-        func = window[func];
-      } else if(func instanceof Array) {
-        if(func.length === 1 && typeof func[0] !== 'string') {
-          func = func[0];
-        } else {
-          [thisobj, func] = this._parsePropDescriptor(func);
-          func = thisobj[func];
-        }
-      }
-
-      return [thisobj,func];
-    },
-
-    _encodeReturn: function(value, array_as_mv) {
-      var ret;
-
-      if(value === null) {
-        ret = ['special', 'null'];
-      } else if(value === true) {
-        ret = ['special', 'true'];
-      } else if(value === false) {
-        ret = ['special', 'false'];
-      } else if(value === undefined) {
-        ret = ['special', 'undefined'];
-      } else if(typeof value === 'number') {
-        if(isNaN(value)) {
-          ret = ['special', 'NaN'];
-        } else if(value === Infinity) {
-          ret = ['special', 'Infinity'];
-        } else if(value === -Infinity) {
-          ret = ['special', '-Infinity'];
-        } else {
-          ret = ['atom', value];
-        }
-      } else if(typeof value === 'string') {
-        ret = ['atom', value];
-      } else if(array_as_mv && value instanceof Array) {
-        ret = ['array', value.map(this._encodeReturn, this)];
-      } else {
-        ret = ['objid', this._findOrAllocateObject(repl, value)];
-      }
-
-      return ret;
-    },
-
-    _handleInputLine: function _handleInputLine(repl, line) {
-      var ret;
-      var array_as_mv = false;
-
-      try {
-        if(line[0] === '*') {
-          array_as_mv = true;
-          line = line.substring(1);
-        }
-        var parts = eval(line);
-        this._fixupList(repl, parts);
-        var [thisobj, func] = this._parseFunc(parts[0]);
-        ret = this._encodeReturn(
-          func.apply(thisobj, parts.slice(1)),
-          array_as_mv);
-      } catch(x) {
-        ret = ['error', x.toString() ];
-      }
-
-      var JSON = 
Components.classes['@mozilla.org/dom/json;1'].createInstance(Components.interfaces.nsIJSON);
-      repl.print(JSON.encode(ret));
-      repl._prompt();
-    },
-
-    handleInput: function handleInput(repl, chunk) {
-      this._input += chunk;
-      var match, line;
-      while(match = this._input.match(/.*\\n/)) {
-        line = match[0];
-
-        if(line === 'EXIT\\n') {
-          repl.popInteractor();
-          repl._prompt();
-          return;
-        }
-
-        this._input = this._input.substring(line.length);
-        this._handleInputLine(repl, line);
-      }
-    }
-  });
-})
-")
-
-  "String to set MozRepl up into a simple-minded evaluation mode.")
-
-(defun js--js-encode-value (x)
-  "Marshall the given value for JS.
-Strings and numbers are JSON-encoded.  Lists (including nil) are
-made into JavaScript array literals and their contents encoded
-with `js--js-encode-value'."
-  (cond ((or (stringp x) (numberp x)) (json-encode x))
-        ((symbolp x) (format "{objid:%S}" (symbol-name x)))
-        ((js--js-handle-p x)
-
-         (when (js--js-handle-expired-p x)
-           (error "Stale JS handle"))
-
-         (format "{objid:%s}" (js--js-handle-id x)))
-
-        ((sequencep x)
-         (if (eq (car-safe x) 'js--funcall)
-             (format "{funcall:[%s]}"
-                     (mapconcat #'js--js-encode-value (cdr x) ","))
-           (concat
-            "[" (mapconcat #'js--js-encode-value x ",") "]")))
-        (t
-         (error "Unrecognized item: %S" x))))
-
-(defconst js--js-prompt-regexp "\\(repl[0-9]*\\)> $")
-(defconst js--js-repl-prompt-regexp "^EVAL>$")
-(defvar js--js-repl-depth 0)
-
-(defun js--js-wait-for-eval-prompt ()
-  (js--wait-for-matching-output
-   (inferior-moz-process)
-   js--js-repl-prompt-regexp js-js-timeout
-
-   ;; start matching against the beginning of the line in
-   ;; order to catch a prompt that's only partially arrived
-   (save-excursion (forward-line 0) (point))))
-
-;; Presumably "inferior-moz-process" loads comint.
-(declare-function comint-send-string "comint" (process string))
-(declare-function comint-send-input "comint"
-                  (&optional no-newline artificial))
-
-(defun js--js-enter-repl ()
-  (inferior-moz-process) ; called for side-effect
-  (with-current-buffer inferior-moz-buffer
-    (goto-char (point-max))
-
-    ;; Do some initialization the first time we see a process
-    (unless (eq (inferior-moz-process) js--js-process)
-      (setq js--js-process (inferior-moz-process))
-      (setq js--js-references (make-hash-table :test 'eq :weakness t))
-      (setq js--js-repl-depth 0)
-
-      ;; Send interactor definition
-      (comint-send-string js--js-process js--moz-interactor)
-      (comint-send-string js--js-process
-                          (concat "(" moz-repl-name ")\n"))
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-prompt-regexp
-       js-js-timeout))
-
-    ;; Sanity check
-    (when (looking-back js--js-prompt-regexp
-                        (save-excursion (forward-line 0) (point)))
-      (setq js--js-repl-depth 0))
-
-    (if (> js--js-repl-depth 0)
-        ;; If js--js-repl-depth > 0, we *should* be seeing an
-        ;; EVAL> prompt. If we don't, give Mozilla a chance to catch
-        ;; up with us.
-        (js--js-wait-for-eval-prompt)
-
-      ;; Otherwise, tell Mozilla to enter the interactor mode
-      (insert (match-string-no-properties 1)
-              ".pushInteractor('js')")
-      (comint-send-input nil t)
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-repl-prompt-regexp
-       js-js-timeout))
-
-    (cl-incf js--js-repl-depth)))
-
-(defun js--js-leave-repl ()
-  (cl-assert (> js--js-repl-depth 0))
-  (when (= 0 (cl-decf js--js-repl-depth))
-    (with-current-buffer inferior-moz-buffer
-      (goto-char (point-max))
-      (js--js-wait-for-eval-prompt)
-      (insert "EXIT")
-      (comint-send-input nil t)
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-prompt-regexp
-       js-js-timeout))))
-
-(defsubst js--js-not (value)
-  (memq value '(nil null false undefined)))
-
-(defsubst js--js-true (value)
-  (not (js--js-not value)))
-
-(eval-and-compile
-  (defun js--optimize-arglist (arglist)
-    "Convert immediate js< and js! references to deferred ones."
-    (cl-loop for item in arglist
-             if (eq (car-safe item) 'js<)
-             collect (append (list 'list ''js--funcall
-                                   '(list 'interactor "_getProp"))
-                             (js--optimize-arglist (cdr item)))
-             else if (eq (car-safe item) 'js>)
-             collect (append (list 'list ''js--funcall
-                                   '(list 'interactor "_putProp"))
-
-                             (if (atom (cadr item))
-                                 (list (cadr item))
-                               (list
-                                (append
-                                 (list 'list ''js--funcall
-                                       '(list 'interactor "_mkArray"))
-                                 (js--optimize-arglist (cadr item)))))
-                             (js--optimize-arglist (cddr item)))
-             else if (eq (car-safe item) 'js!)
-             collect (pcase-let ((`(,_ ,function . ,body) item))
-                       (append (list 'list ''js--funcall
-                                     (if (consp function)
-                                         (cons 'list
-                                               (js--optimize-arglist function))
-                                       function))
-                               (js--optimize-arglist body)))
-             else
-             collect item)))
-
-(defmacro js--js-get-service (class-name interface-name)
-    `(js! ("Components" "classes" ,class-name "getService")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro js--js-create-instance (class-name interface-name)
-  `(js! ("Components" "classes" ,class-name "createInstance")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro js--js-qi (object interface-name)
-  `(js! (,object "QueryInterface")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro with-js (&rest forms)
-  "Run FORMS with the Mozilla repl set up for js commands.
-Inside the lexical scope of `with-js', `js?', `js!',
-`js-new', `js-eval', `js-list', `js<', `js>', `js-get-service',
-`js-create-instance', and `js-qi' are defined."
-  (declare (indent 0) (debug t))
-  `(progn
-     (js--js-enter-repl)
-     (unwind-protect
-         (cl-macrolet ((js? (&rest body) `(js--js-true ,@body))
-                       (js! (function &rest body)
-                            `(js--js-funcall
-                              ,(if (consp function)
-                                   (cons 'list
-                                         (js--optimize-arglist function))
-                                 function)
-                              ,@(js--optimize-arglist body)))
-
-                       (js-new (function &rest body)
-                               `(js--js-new
-                                 ,(if (consp function)
-                                      (cons 'list
-                                            (js--optimize-arglist function))
-                                    function)
-                                 ,@body))
-
-                       (js-eval (thisobj js)
-                                `(js--js-eval
-                                  ,@(js--optimize-arglist
-                                     (list thisobj js))))
-
-                       (js-list (&rest args)
-                                `(js--js-list
-                                  ,@(js--optimize-arglist args)))
-
-                       (js-get-service (&rest args)
-                                       `(js--js-get-service
-                                         ,@(js--optimize-arglist args)))
-
-                       (js-create-instance (&rest args)
-                                           `(js--js-create-instance
-                                             ,@(js--optimize-arglist args)))
-
-                       (js-qi (&rest args)
-                              `(js--js-qi
-                                ,@(js--optimize-arglist args)))
-
-                       (js< (&rest body) `(js--js-get
-                                           ,@(js--optimize-arglist body)))
-                       (js> (props value)
-                            `(js--js-funcall
-                              '(interactor "_putProp")
-                              ,(if (consp props)
-                                   (cons 'list
-                                         (js--optimize-arglist props))
-                                 props)
-                              ,@(js--optimize-arglist (list value))
-                              ))
-                       (js-handle? (arg) `(js--js-handle-p ,arg)))
-           ,@forms)
-       (js--js-leave-repl))))
-
-(defvar js--js-array-as-list nil
-  "Whether to listify any Array returned by a Mozilla function.
-If nil, the whole Array is treated as a JS symbol.")
-
-(defun js--js-decode-retval (result)
-  (pcase (intern (cl-first result))
-    ('atom (cl-second result))
-    ('special (intern (cl-second result)))
-    ('array
-     (mapcar #'js--js-decode-retval (cl-second result)))
-    ('objid
-     (or (gethash (cl-second result)
-                  js--js-references)
-         (puthash (cl-second result)
-                  (make-js--js-handle
-                   :id (cl-second result)
-                   :process (inferior-moz-process))
-                  js--js-references)))
-
-    ('error (signal 'js-js-error (list (cl-second result))))
-    (x (error "Unmatched case in js--js-decode-retval: %S" x))))
-
-(defvar comint-last-input-end)
-
-(defun js--js-funcall (function &rest arguments)
-  "Call the Mozilla function FUNCTION with arguments ARGUMENTS.
-If function is a string, look it up as a property on the global
-object and use the global object for `this'.
-If FUNCTION is a list with one element, use that element as the
-function with the global object for `this', except that if that
-single element is a string, look it up on the global object.
-If FUNCTION is a list with more than one argument, use the list
-up to the last value as a property descriptor and the last
-argument as a function."
-
-  (with-js
-   (let ((argstr (js--js-encode-value
-                  (cons function arguments))))
-
-     (with-current-buffer inferior-moz-buffer
-       ;; Actual funcall
-       (when js--js-array-as-list
-         (insert "*"))
-       (insert argstr)
-       (comint-send-input nil t)
-       (js--wait-for-matching-output
-        (inferior-moz-process) "EVAL>"
-        js-js-timeout)
-       (goto-char comint-last-input-end)
-
-       ;; Read the result
-       (let* ((json-array-type 'list)
-              (result (prog1 (json-read)
-                        (goto-char (point-max)))))
-         (js--js-decode-retval result))))))
-
-(defun js--js-new (constructor &rest arguments)
-  "Call CONSTRUCTOR as a constructor, with arguments ARGUMENTS.
-CONSTRUCTOR is a JS handle, a string, or a list of these things."
-  (apply #'js--js-funcall
-         '(interactor "_callNew")
-         constructor arguments))
-
-(defun js--js-eval (thisobj js)
-  (js--js-funcall '(interactor "_callEval") thisobj js))
-
-(defun js--js-list (&rest arguments)
-  "Return a Lisp array resulting from evaluating each of ARGUMENTS."
-  (let ((js--js-array-as-list t))
-    (apply #'js--js-funcall '(interactor "_mkArray")
-           arguments)))
-
-(defun js--js-get (&rest props)
-  (apply #'js--js-funcall '(interactor "_getProp") props))
-
-(defun js--js-put (props value)
-  (js--js-funcall '(interactor "_putProp") props value))
-
-(defun js-gc (&optional force)
-  "Tell the repl about any objects we don't reference anymore.
-With argument, run even if no intervening GC has happened."
-  (interactive)
-
-  (when force
-    (setq js--js-last-gcs-done nil))
-
-  (let ((this-gcs-done gcs-done) keys num)
-    (when (and js--js-references
-               (boundp 'inferior-moz-buffer)
-               (buffer-live-p inferior-moz-buffer)
-
-               ;; Don't bother running unless we've had an intervening
-               ;; garbage collection; without a gc, nothing is deleted
-               ;; from the weak hash table, so it's pointless telling
-               ;; MozRepl about that references we still hold
-               (not (eq js--js-last-gcs-done this-gcs-done))
-
-               ;; Are we looking at a normal prompt? Make sure not to
-               ;; interrupt the user if he's doing something
-               (with-current-buffer inferior-moz-buffer
-                 (save-excursion
-                   (goto-char (point-max))
-                   (looking-back js--js-prompt-regexp
-                                 (save-excursion (forward-line 0) (point))))))
-
-      (setq keys (cl-loop for x being the hash-keys
-                          of js--js-references
-                          collect x))
-      (setq num (js--js-funcall '(repl "_jsGC") (or keys [])))
-
-      (setq js--js-last-gcs-done this-gcs-done)
-      (when (called-interactively-p 'interactive)
-        (message "Cleaned %s entries" num))
-
-      num)))
-
-(run-with-idle-timer 30 t #'js-gc)
-
-(defun js-eval (js)
-  "Evaluate the JavaScript in JS and return JSON-decoded result."
-  (interactive "MJavaScript to evaluate: ")
-  (with-js
-   (let* ((content-window (js--js-content-window
-                           (js--get-js-context)))
-          (result (js-eval content-window js)))
-     (when (called-interactively-p 'interactive)
-       (message "%s" (js! "String" result)))
-     result)))
-
-(defun js--get-tabs ()
-  "Enumerate all JavaScript contexts available.
-Each context is a list:
-   (TITLE URL BROWSER TAB TABBROWSER) for content documents
-   (TITLE URL WINDOW) for windows
-
-All tabs of a given window are grouped together.  The most recent
-window is first.  Within each window, the tabs are returned
-left-to-right."
-  (with-js
-   (let (windows)
-
-     (cl-loop with window-mediator = (js! ("Components" "classes"
-                                           
"@mozilla.org/appshell/window-mediator;1"
-                                           "getService")
-                                          (js< "Components" "interfaces"
-                                               "nsIWindowMediator"))
-              with enumerator = (js! (window-mediator "getEnumerator") nil)
-
-              while (js? (js! (enumerator "hasMoreElements")))
-              for window = (js! (enumerator "getNext"))
-              for window-info = (js-list window
-                                         (js< window "document" "title")
-                                         (js! (window "location" "toString"))
-                                         (js< window "closed")
-                                         (js< window "windowState"))
-
-              unless (or (js? (cl-fourth window-info))
-                         (eq (cl-fifth window-info) 2))
-              do (push window-info windows))
-
-     (cl-loop for (window title location) in windows
-              collect (list title location window)
-
-              for gbrowser = (js< window "gBrowser")
-              if (js-handle? gbrowser)
-              nconc (cl-loop
-                     for x below (js< gbrowser "browsers" "length")
-                     collect (js-list (js< gbrowser
-                                           "browsers"
-                                           x
-                                           "contentDocument"
-                                           "title")
-
-                                      (js! (gbrowser
-                                            "browsers"
-                                            x
-                                            "contentWindow"
-                                            "location"
-                                            "toString"))
-                                      (js< gbrowser
-                                           "browsers"
-                                           x)
-
-                                      (js! (gbrowser
-                                            "tabContainer"
-                                            "childNodes"
-                                            "item")
-                                           x)
-
-                                      gbrowser))))))
-
-(defvar js-read-tab-history nil)
-
-(declare-function ido-chop "ido" (items elem))
-
-(defun js--read-tab (prompt)
-  "Read a Mozilla tab with prompt PROMPT.
-Return a cons of (TYPE . OBJECT).  TYPE is either `window' or
-`tab', and OBJECT is a JavaScript handle to a ChromeWindow or a
-browser, respectively."
-
-  ;; Prime IDO
-  (unless ido-mode
-    (ido-mode 1)
-    (ido-mode -1))
-
-  (with-js
-   (let ((tabs (js--get-tabs)) selected-tab-cname
-         selected-tab prev-hitab)
-
-     ;; Disambiguate names
-     (setq tabs
-           (cl-loop with tab-names = (make-hash-table :test 'equal)
-                    for tab in tabs
-                    for cname = (format "%s (%s)"
-                                        (cl-second tab) (cl-first tab))
-                    for num = (cl-incf (gethash cname tab-names -1))
-                    if (> num 0)
-                    do (setq cname (format "%s <%d>" cname num))
-                    collect (cons cname tab)))
-
-     (cl-labels
-         ((find-tab-by-cname
-           (cname)
-           (cl-loop for tab in tabs
-                    if (equal (car tab) cname)
-                    return (cdr tab)))
-
-          (mogrify-highlighting
-           (hitab unhitab)
-
-           ;; Hack to reduce the number of
-           ;; round-trips to mozilla
-           (let (cmds)
-             (cond
-              ;; Highlighting tab
-              ((cl-fourth hitab)
-               (push '(js! ((cl-fourth hitab) "setAttribute")
-                       "style"
-                       "color: red; font-weight: bold")
-                     cmds)
-
-               ;; Highlight window proper
-               (push '(js! ((cl-third hitab)
-                            "setAttribute")
-                       "style"
-                       "border: 8px solid red")
-                     cmds)
-
-               ;; Select tab, when appropriate
-               (when js-js-switch-tabs
-                 (push
-                  '(js> ((cl-fifth hitab) "selectedTab") (cl-fourth hitab))
-                  cmds)))
-
-              ;; Highlighting whole window
-              ((cl-third hitab)
-               (push '(js! ((cl-third hitab) "document"
-                            "documentElement" "setAttribute")
-                       "style"
-                       (concat "-moz-appearance: none;"
-                               "border: 8px solid red;"))
-                     cmds)))
-
-             (cond
-              ;; Unhighlighting tab
-              ((cl-fourth unhitab)
-               (push '(js! ((cl-fourth unhitab) "setAttribute") "style" "")
-                     cmds)
-               (push '(js! ((cl-third unhitab) "setAttribute") "style" "")
-                     cmds))
-
-              ;; Unhighlighting window
-              ((cl-third unhitab)
-               (push '(js! ((cl-third unhitab) "document"
-                            "documentElement" "setAttribute")
-                       "style" "")
-                     cmds)))
-
-             (eval `(with-js
-                        (js-list ,@(nreverse cmds)))
-                   t)))
-
-          (command-hook
-           ()
-           (let* ((tab (find-tab-by-cname (car ido-matches))))
-             (mogrify-highlighting tab prev-hitab)
-             (setq prev-hitab tab)))
-
-          (setup-hook
-           ()
-           ;; Fiddle with the match list a bit: if our first match
-           ;; is a tabbrowser window, rotate the match list until
-           ;; the active tab comes up
-           (let ((matched-tab (find-tab-by-cname (car ido-matches))))
-             (when (and matched-tab
-                        (null (cl-fourth matched-tab))
-                        (equal "navigator:browser"
-                               (js! ((cl-third matched-tab)
-                                     "document"
-                                     "documentElement"
-                                     "getAttribute")
-                                    "windowtype")))
-
-               (cl-loop with tab-to-match = (js< (cl-third matched-tab)
-                                                 "gBrowser"
-                                                 "selectedTab")
-
-                        for match in ido-matches
-                        for candidate-tab = (find-tab-by-cname match)
-                        if (eq (cl-fourth candidate-tab) tab-to-match)
-                        do (setq ido-cur-list
-                                 (ido-chop ido-cur-list match))
-                        and return t)))
-
-           (add-hook 'post-command-hook #'command-hook t t)))
-
-
-       (unwind-protect
-           ;; FIXME: Don't impose IDO on the user.
-           (setq selected-tab-cname
-                 (let ((ido-minibuffer-setup-hook
-                        (cons #'setup-hook ido-minibuffer-setup-hook)))
-                   (ido-completing-read
-                    prompt
-                    (mapcar #'car tabs)
-                    nil t nil
-                    'js-read-tab-history)))
-
-         (when prev-hitab
-           (mogrify-highlighting nil prev-hitab)
-           (setq prev-hitab nil)))
-
-       (add-to-history 'js-read-tab-history selected-tab-cname)
-
-       (setq selected-tab (cl-loop for tab in tabs
-                                   if (equal (car tab) selected-tab-cname)
-                                   return (cdr tab)))
-
-       (cons (if (cl-fourth selected-tab) 'browser 'window)
-             (cl-third selected-tab))))))
-
-(defun js--guess-eval-defun-info (pstate)
-  "Helper function for `js-eval-defun'.
-Return a list (NAME . CLASSPARTS), where CLASSPARTS is a list of
-strings making up the class name and NAME is the name of the
-function part."
-  (cond ((and (= (length pstate) 3)
-              (eq (js--pitem-type (cl-first pstate)) 'function)
-              (= (length (js--pitem-name (cl-first pstate))) 1)
-              (consp (js--pitem-type (cl-second pstate))))
-
-         (append (js--pitem-name (cl-second pstate))
-                 (list (cl-first (js--pitem-name (cl-first pstate))))))
-
-        ((and (= (length pstate) 2)
-              (eq (js--pitem-type (cl-first pstate)) 'function))
-
-         (append
-          (butlast (js--pitem-name (cl-first pstate)))
-          (list (car (last (js--pitem-name (cl-first pstate)))))))
-
-        (t (error "Function not a toplevel defun or class member"))))
-
-(defvar js--js-context nil
-  "The current JavaScript context.
-This is a cons like the one returned from `js--read-tab'.
-Change with `js-set-js-context'.")
-
-(defconst js--js-inserter
-  "(function(func_info,func) {
-    func_info.unshift('window');
-    var obj = window;
-    for(var i = 1; i < func_info.length - 1; ++i) {
-      var next = obj[func_info[i]];
-      if(typeof next !== 'object' && typeof next !== 'function') {
-        next = obj.prototype && obj.prototype[func_info[i]];
-        if(typeof next !== 'object' && typeof next !== 'function') {
-          alert('Could not find ' + func_info.slice(0, i+1).join('.') +
-                ' or ' + func_info.slice(0, i+1).join('.') + '.prototype');
-          return;
-        }
-
-        func_info.splice(i+1, 0, 'prototype');
-        ++i;
-      }
-    }
-
-    obj[func_info[i]] = func;
-    alert('Successfully updated '+func_info.join('.'));
-  })")
-
-(defun js-set-js-context (context)
-  "Set the JavaScript context to CONTEXT.
-When called interactively, prompt for CONTEXT."
-  (interactive (list (js--read-tab "JavaScript Context: ")))
-  (setq js--js-context context))
-
-(defun js--get-js-context ()
-  "Return a valid JavaScript context.
-If one hasn't been set, or if it's stale, prompt for a new one."
-  (with-js
-   (when (or (null js--js-context)
-             (js--js-handle-expired-p (cdr js--js-context))
-             (pcase (car js--js-context)
-               ('window (js? (js< (cdr js--js-context) "closed")))
-               ('browser (not (js? (js< (cdr js--js-context)
-                                        "contentDocument"))))
-               (x (error "Unmatched case in js--get-js-context: %S" x))))
-     (setq js--js-context (js--read-tab "JavaScript Context: ")))
-   js--js-context))
-
-(defun js--js-content-window (context)
-  (with-js
-   (pcase (car context)
-     ('window (cdr context))
-     ('browser (js< (cdr context)
-                    "contentWindow" "wrappedJSObject"))
-     (x (error "Unmatched case in js--js-content-window: %S" x)))))
-
-(defun js--make-nsilocalfile (path)
-  (with-js
-   (let ((file (js-create-instance "@mozilla.org/file/local;1"
-                                   "nsILocalFile")))
-     (js! (file "initWithPath") path)
-     file)))
-
-(defun js--js-add-resource-alias (alias path)
-  (with-js
-   (let* ((io-service (js-get-service "@mozilla.org/network/io-service;1"
-                                                "nsIIOService"))
-          (res-prot (js! (io-service "getProtocolHandler") "resource"))
-          (res-prot (js-qi res-prot "nsIResProtocolHandler"))
-          (path-file (js--make-nsilocalfile path))
-          (path-uri (js! (io-service "newFileURI") path-file)))
-     (js! (res-prot "setSubstitution") alias path-uri))))
-
-(cl-defun js-eval-defun ()
-  "Update a Mozilla tab using the JavaScript defun at point."
-  (interactive)
-
-  ;; This function works by generating a temporary file that contains
-  ;; the function we'd like to insert. We then use the elisp-js bridge
-  ;; to command mozilla to load this file by inserting a script tag
-  ;; into the document we set. This way, debuggers and such will have
-  ;; a way to find the source of the just-inserted function.
-  ;;
-  ;; We delete the temporary file if there's an error, but otherwise
-  ;; we add an unload event listener on the Mozilla side to delete the
-  ;; file.
-
-  (save-excursion
-    (let (begin end pstate defun-info temp-name defun-body)
-      (js-end-of-defun)
-      (setq end (point))
-      (js--ensure-cache)
-      (js-beginning-of-defun)
-      (re-search-forward "\\_<function\\_>")
-      (setq begin (match-beginning 0))
-      (setq pstate (js--forward-pstate))
-
-      (when (or (null pstate)
-                (> (point) end))
-        (error "Could not locate function definition"))
-
-      (setq defun-info (js--guess-eval-defun-info pstate))
-
-      (let ((overlay (make-overlay begin end)))
-        (overlay-put overlay 'face 'highlight)
-        (unwind-protect
-            (unless (y-or-n-p (format "Send %s to Mozilla? "
-                                      (mapconcat #'identity defun-info ".")))
-              (message "") ; question message lingers until next command
-              (cl-return-from js-eval-defun))
-          (delete-overlay overlay)))
-
-      (setq defun-body (buffer-substring-no-properties begin end))
-
-      (make-directory js-js-tmpdir t)
-
-      ;; (Re)register a Mozilla resource URL to point to the
-      ;; temporary directory
-      (js--js-add-resource-alias "js" js-js-tmpdir)
-
-      (setq temp-name (make-temp-file (concat js-js-tmpdir
-                                             "/js-")
-                                      nil ".js"))
-      (unwind-protect
-          (with-js
-            (with-temp-buffer
-              (insert js--js-inserter)
-              (insert "(")
-              (let ((standard-output (current-buffer)))
-                (json--print-list defun-info))
-              (insert ",\n")
-              (insert defun-body)
-              (insert "\n)")
-              (write-region (point-min) (point-max) temp-name
-                            nil 1))
-
-            ;; Give Mozilla responsibility for deleting this file
-            (let* ((content-window (js--js-content-window
-                                    (js--get-js-context)))
-                   (content-document (js< content-window "document"))
-                   (head (if (js? (js< content-document "body"))
-                             ;; Regular content
-                             (js< (js! (content-document 
"getElementsByTagName")
-                                       "head")
-                                  0)
-                           ;; Chrome
-                           (js< content-document "documentElement")))
-                   (elem (js! (content-document "createElementNS")
-                              "http://www.w3.org/1999/xhtml"; "script")))
-
-              (js! (elem "setAttribute") "type" "text/javascript")
-              (js! (elem "setAttribute") "src"
-                   (format "resource://js/%s"
-                           (file-name-nondirectory temp-name)))
-
-              (js! (head "appendChild") elem)
-
-              (js! (content-window "addEventListener") "unload"
-                   (js! ((js-new
-                          "Function" "file"
-                          "return function() { file.remove(false) }"))
-                        (js--make-nsilocalfile temp-name))
-                   'false)
-              (setq temp-name nil)
-
-
-
-              ))
-
-        ;; temp-name is set to nil on success
-        (when temp-name
-          (delete-file temp-name))))))
-
 ;;; Syntax extensions
 
 (defvar js-syntactic-mode-name t



reply via email to

[Prev in Thread] Current Thread [Next in Thread]