Browse Source

Make indium-connection a cl-struct

* Refactor all map-* calls to get/set properties of a connection.
* Extract functions to access the current connection.
workspaces
Nicolas Petton 3 years ago
parent
commit
5b96938f34
Signed by: nico GPG Key ID: 233587A47C207910
19 changed files with 283 additions and 164 deletions
  1. +12
    -25
      indium-backend.el
  2. +7
    -6
      indium-breakpoint.el
  3. +3
    -1
      indium-chrome.el
  4. +6
    -9
      indium-debugger-frames.el
  5. +22
    -28
      indium-debugger.el
  6. +1
    -1
      indium-inspector.el
  7. +7
    -7
      indium-interaction.el
  8. +8
    -8
      indium-repl.el
  9. +2
    -1
      indium-scratch.el
  10. +4
    -6
      indium-script.el
  11. +74
    -0
      indium-structs.el
  12. +44
    -35
      indium-webkit.el
  13. +4
    -3
      indium-workspace.el
  14. +1
    -1
      test/test-helper.el
  15. +7
    -7
      test/unit/indium-backend-test.el
  16. +9
    -9
      test/unit/indium-debugger-test.el
  17. +44
    -0
      test/unit/indium-structs-test.el
  18. +17
    -10
      test/unit/indium-webkit-test.el
  19. +11
    -7
      test/unit/indium-workspace-test.el

+ 12
- 25
indium-backend.el View File

@ -23,12 +23,15 @@
;; Generic backend implementation.
;; Backends should define a new backend symbol using `indium-register-backend'.
;; Once a connection to a JavaScript runtime is established by the backend, it
;; should set `indium-current-connection'.
;;; Code:
(require 'map)
(require 'seq)
(require 'indium-debugger-litable)
(eval-and-compile (require 'indium-structs))
(declare 'indium-debugger-unset-current-buffer)
@ -47,19 +50,8 @@
:group 'indium-backend
:type 'hook)
(defvar indium-current-connection nil
"Current connection to the browser tab.
A connection should be an alist with the following required keys:
`backend' and `url'. Other backend-specific keys might be used
by backends.")
(defvar indium-backends nil "List of registered backends.")
(defun indium-backend ()
"Return the backend for the current connection."
(map-elt indium-current-connection 'backend))
(defun indium-register-backend (backend)
"Register a new BACKEND.
BACKEND should be a symbol."
@ -69,12 +61,12 @@ BACKEND should be a symbol."
"Close the current connection and kill its REPL buffer if any.
When called interactively, prompt for a confirmation first."
(interactive)
(unless indium-current-connection
(unless-indium-connected
(user-error "No active connection to close"))
(when (or (not (called-interactively-p 'interactive))
(y-or-n-p (format "Do you really want to close the connection to %s ? "
(map-elt indium-current-connection 'url))))
(indium-backend-close-connection (indium-backend))
(indium-current-connection-url))))
(indium-backend-close-connection (indium-current-connection-backend))
(indium-backend-cleanup-buffers)
(setq indium-current-connection nil)))
@ -82,9 +74,9 @@ When called interactively, prompt for a confirmation first."
"Try to re-establish a connection.
The new connection is based on the current (usually closed) one."
(interactive)
(unless indium-current-connection
(unless-indium-connected
(user-error "No Indium connection to reconnect to"))
(indium-backend-reconnect (indium-backend)))
(indium-backend-reconnect (indium-current-connection-backend)))
(declare-function indium-repl-get-buffer "indium-repl.el")
(declare-function indium-debugger-unset-current-buffer "indium-debugger.el")
@ -99,8 +91,6 @@ The new connection is based on the current (usually closed) one."
(when-let ((buf (indium-repl-get-buffer)))
(kill-buffer buf)))
;;; indium-connection methods
(cl-defgeneric indium-backend-active-connection-p (_backend)
"Return non-nil if the current connection is active."
t)
@ -150,7 +140,7 @@ performed.")
"Remove all breakpoints from BUFFER."
(with-current-buffer buffer
(seq-do (lambda (brk)
(indium-backend-remove-breakpoint (indium-backend)
(indium-backend-remove-breakpoint (indium-current-connection-backend)
(map-elt brk 'id)))
(indium-backend-get-breakpoints-in-file buffer-file-name))))
@ -160,23 +150,20 @@ performed.")
Breakpoints are registered locally in the current connection so
that if a buffer later visits FILE with `indium-interaction-mode'
turned on, the breakpoint can be added back to the buffer."
(when (and indium-current-connection
(null (map-elt indium-current-connection 'breakpoints)))
(map-put indium-current-connection 'breakpoints (make-hash-table)))
(let ((breakpoint `((line . ,line)
(file . ,file)
(condition . ,condition))))
(map-put (map-elt indium-current-connection 'breakpoints) id breakpoint)))
(map-put (indium-current-connection-breakpoints) id breakpoint)))
(defun indium-backend-unregister-breakpoint (id)
"Remove the breakpoint with ID from the current connection."
(map-delete (map-elt indium-current-connection 'breakpoints) id))
(map-delete (indium-current-connection-breakpoints) id))
(defun indium-backend-get-breakpoints ()
"Return all breakpoints in the current connection.
A breakpoint is an alist with the keys `id', `file', `line' and
`condition'."
(let ((breakpoints (map-elt indium-current-connection 'breakpoints)))
(let ((breakpoints (indium-current-connection-breakpoints)))
(map-keys-apply (lambda (key)
`((id . ,key)
(file . ,(map-nested-elt breakpoints `(,key file)))


+ 7
- 6
indium-breakpoint.el View File

@ -30,7 +30,8 @@
(require 'indium-backend)
(require 'indium-faces)
(require 'indium-script)
(eval-and-compile
(require 'indium-script))
(defun indium-breakpoint-add (location &optional condition)
"Add a breakpoint at LOCATION.
@ -38,8 +39,8 @@
When CONDITION is non-nil, the breakpoint will be hit when
CONDITION is true."
(let ((ov (indium-breakpoint--put-icon condition)))
(when indium-current-connection
(indium-backend-add-breakpoint (indium-backend)
(when-indium-connected
(indium-backend-add-breakpoint (indium-current-connection-backend)
location
(lambda (id)
(indium-breakpoint-added id ov))
@ -63,8 +64,8 @@ CONDITION is true."
(defun indium-breakpoint-remove ()
"Remove the breakpoint from the current line."
(if-let ((id (indium-breakpoint-id-at-point)))
(when indium-current-connection
(indium-backend-remove-breakpoint (indium-backend) id)))
(when-indium-connected
(indium-backend-remove-breakpoint (indium-current-connection-backend) id)))
(indium-breakpoint--remove-icon))
(defun indium-breakpoint-remove-all ()
@ -96,7 +97,7 @@ This function does no unset breakpoints,"
(defun indium-breakpoint-update-breakpoints ()
"Update all breakpoints for the current buffer in the backend."
(when indium-current-connection
(when-indium-connected
(indium-backend-remove-all-breakpoints-from-buffer (current-buffer))
(indium-breakpoint-restore-breakpoints)))


+ 3
- 1
indium-chrome.el View File

@ -36,6 +36,8 @@
(require 'indium-webkit)
(require 'indium-workspace)
(eval-and-compile (require 'indium-structs))
(defgroup indium-chrome nil
"Chrome interaction."
:prefix "indium-chrome-"
@ -96,7 +98,7 @@ Try a maximum of NUM-TRIES."
(interactive)
(when (or (null indium-current-connection)
(yes-or-no-p "This requires closing the current connection. Are you sure? "))
(when indium-current-connection
(when-indium-connected
(indium-quit))
(let ((host (read-from-minibuffer "Host: " "127.0.0.1"))
(port (read-from-minibuffer "Port: " (number-to-string indium-chrome-port))))


+ 6
- 9
indium-debugger-frames.el View File

@ -25,32 +25,29 @@
(require 'indium-render)
(require 'indium-script)
(require 'indium-structs)
(declare 'indium-debugger-frames)
(declare 'indium-debugger-current-frame)
(declare 'indium-debugger-select-frame)
(declare-function indium-debugger-select-frame "indium-debugger.el")
(defun indium-debugger-stack-frames ()
"List the stack frames in a separate buffer and switch to it."
(interactive)
(let ((buf (indium-debugger-frames-get-buffer-create))
(frames (indium-debugger-frames))
(current-frame (indium-debugger-current-frame))
(inhibit-read-only t))
(with-current-buffer buf
(indium-debugger-frames-list frames current-frame))
(indium-debugger-frames-list (indium-current-connection-frames)
(indium-current-connection-current-frame)))
(pop-to-buffer buf)))
(defun indium-debugger-frames-maybe-refresh ()
"When a buffer listing the stack frames is open, refresh it."
(interactive)
(let ((buf (indium-debugger-frames-get-buffer))
(frames (indium-debugger-frames))
(current-frame (indium-debugger-current-frame))
(inhibit-read-only t))
(when buf
(with-current-buffer buf
(indium-debugger-frames-list frames current-frame)))))
(indium-debugger-frames-list (indium-current-connection-frames)
(indium-current-connection-current-frame))))))
(defun indium-debugger-frames-list (frames &optional current-frame)
"Render the list of stack frames FRAMES.


+ 22
- 28
indium-debugger.el View File

@ -29,6 +29,7 @@
(require 'easymenu)
(require 'indium-structs)
(require 'indium-inspector)
(require 'indium-repl)
(require 'indium-interaction)
@ -130,7 +131,7 @@ Unset the debugging context and turn off indium-debugger-mode."
(indium-debugger-unset-current-buffer)
(indium-debugger-litable-unset-buffer)))
(let ((locals-buffer (indium-debugger-locals-get-buffer))
(frames-buffer (indium-debugger-frames-get-buffer)))
(frames-buffer (indium-debugger-frames-get-buffer)))
(when locals-buffer (kill-buffer locals-buffer))
(when frames-buffer (kill-buffer frames-buffer))))
@ -147,16 +148,17 @@ Unset the debugging context and turn off indium-debugger-mode."
(defun indium-debugger--jump-to-frame (direction)
"Jump to the next frame in DIRECTION.
DIRECTION is `forward' or `backward' (in the frame list)."
(let* ((current-position (seq-position (indium-debugger-frames) (indium-debugger-current-frame)))
(let* ((current-position (seq-position (indium-current-connection-frames)
(indium-current-connection-current-frame)))
(step (pcase direction
(`forward -1)
(`backward 1)))
(position (+ current-position step)))
(when (>= position (seq-length (indium-debugger-frames)))
(when (>= position (seq-length (indium-current-connection-frames)))
(user-error "End of frames"))
(when (< position 0)
(user-error "Beginning of frames"))
(indium-debugger-select-frame (seq-elt (indium-debugger-frames) position))))
(indium-debugger-select-frame (seq-elt (indium-current-connection-frames) position))))
(defun indium-debugger-select-frame (frame)
"Make FRAME the current debugged stack frame.
@ -173,7 +175,7 @@ remote source for that frame."
(if buffer-file-name
(indium-debugger-setup-buffer-with-file)
(indium-backend-get-script-source
(indium-backend)
(indium-current-connection-backend)
frame
(lambda (source)
(indium-debugger-setup-buffer-with-source
@ -196,7 +198,7 @@ remote source for that frame."
(defun indium-debugger--goto-current-frame ()
"Move the point to the current stack frame position in the current buffer."
(let* ((frame (indium-debugger-current-frame))
(let* ((frame (indium-current-connection-current-frame))
(location (indium-script-get-frame-original-location frame)))
(goto-char (point-min))
(forward-line (indium-location-line location))
@ -269,33 +271,33 @@ remote source for that frame."
(defun indium-debugger-top-frame ()
"Return the top frame of the current debugging context."
(car (indium-debugger-frames)))
(car (indium-current-connection-frames)))
(defun indium-debugger-step-into ()
"Request a step into."
(interactive)
(indium-backend-step-into (indium-backend)))
(indium-backend-step-into (indium-current-connection-backend)))
(defun indium-debugger-step-over ()
"Request a step over."
(interactive)
(indium-backend-step-over (indium-backend)))
(indium-backend-step-over (indium-current-connection-backend)))
(defun indium-debugger-step-out ()
"Request a step out."
(interactive)
(indium-backend-step-out (indium-backend)))
(indium-backend-step-out (indium-current-connection-backend)))
(defun indium-debugger-resume ()
"Request the runtime to resume the execution."
(interactive)
(indium-backend-resume (indium-backend)))
(indium-backend-resume (indium-current-connection-backend)))
(defun indium-debugger-here ()
"Request the runtime to resume the execution until the point.
When the position of the point is reached, pause the execution."
(interactive)
(indium-backend-continue-to-location (indium-backend)
(indium-backend-continue-to-location (indium-current-connection-backend)
(make-indium-location
:line (1- (line-number-at-pos))
:file buffer-file-name)))
@ -304,7 +306,7 @@ When the position of the point is reached, pause the execution."
"Prompt for EXPRESSION to be evaluated.
Evaluation happens in the context of the current call frame."
(interactive "sEvaluate on frame: ")
(indium-backend-evaluate (indium-backend)
(indium-backend-evaluate (indium-current-connection-backend)
expression
(lambda (value _error)
(message "%s" (indium-render-value-to-string value)))))
@ -313,29 +315,21 @@ Evaluation happens in the context of the current call frame."
(defun indium-debugger-set-frames (frames)
"Set the debugger FRAMES."
(map-put indium-current-connection 'frames frames)
(setf (indium-current-connection-frames) frames)
(indium-debugger-set-current-frame (car frames)))
(defun indium-debugger-set-current-frame (frame)
"Set FRAME as the current frame."
(map-put indium-current-connection 'current-frame frame))
(setf (indium-current-connection-current-frame) frame))
(defun indium-debugger-unset-frames ()
"Remove debugging information from the current connection."
(setq indium-current-connection (map-delete indium-current-connection 'frames))
(setq indium-current-connection (map-delete indium-current-connection 'current-frame)))
(defun indium-debugger-current-frame ()
"Return the current debugged stack frame."
(map-elt indium-current-connection 'current-frame))
(defun indium-debugger-frames ()
"Return all frames in the current stack."
(map-elt indium-current-connection 'frames))
(setf (indium-current-connection-frames) nil)
(setf (indium-current-connection-current-frame) nil))
(defun indium-debugger-get-current-scopes ()
"Return the scope of the current stack frame."
(indium-frame-scope-chain (indium-debugger-current-frame)))
(indium-frame-scope-chain (indium-current-connection-current-frame)))
;; TODO: move to backends?
(defun indium-debugger-get-scopes-properties (scopes callback)
@ -352,7 +346,7 @@ CALLBACK is evaluated with the result."
"Request the properties of SCOPE and evaluate CALLBACK.
CALLBACK is evaluated with two arguments, the properties and SCOPE."
(indium-backend-get-properties
(indium-backend)
(indium-current-connection-backend)
(map-nested-elt scope '(object objectid))
(lambda (properties)
(funcall callback properties scope))))
@ -361,7 +355,7 @@ CALLBACK is evaluated with two arguments, the properties and SCOPE."
"Create a debugger buffer for the current connection and return it.
If a buffer already exists, just return it."
(let* ((location (indium-script-get-frame-original-location (indium-debugger-current-frame)))
(let* ((location (indium-script-get-frame-original-location (indium-current-connection-current-frame)))
(buf (if-let ((file (indium-location-file location)))
(find-file file)
(get-buffer-create (indium-debugger--buffer-name-no-file)))))


+ 1
- 1
indium-inspector.el View File

@ -39,7 +39,7 @@
"Open an inspector on the remote object REFERENCE."
(let ((objectid (map-elt reference 'objectid)))
(if objectid
(indium-backend-get-properties (indium-backend)
(indium-backend-get-properties (indium-current-connection-backend)
objectid
(lambda (properties)
(indium-inspector--inspect-properties properties reference)))


+ 7
- 7
indium-interaction.el View File

@ -58,7 +58,7 @@ When CALLBACK is non-nil, evaluate CALLBACK with the result.
When called interactively, prompt the user for the string to be
evaluated."
(interactive "sEvaluate JavaScript: ")
(indium-backend-evaluate (indium-backend) string callback))
(indium-backend-evaluate (indium-current-connection-backend) string callback))
(defun indium-eval-buffer ()
"Evaluate the accessible portion of current buffer."
@ -100,7 +100,7 @@ If PRINT is non-nil, print the output into the current buffer."
"Reload the page."
(interactive)
(indium-interaction--ensure-connection)
(indium-backend-evaluate (indium-backend) "window.location.reload()"))
(indium-backend-evaluate (indium-current-connection-backend) "window.location.reload()"))
(defun indium-inspect-last-node ()
"Evaluate and inspect the node before point."
@ -153,13 +153,13 @@ If PRINT is non-nil, print the output into the current buffer."
Breakpoints are not removed, but the runtime won't pause when
hitting a breakpoint."
(interactive)
(indium-backend-deactivate-breakpoints (indium-backend))
(indium-backend-deactivate-breakpoints (indium-current-connection-backend))
(message "Breakpoints deactivated"))
(defun indium-activate-breakpoints ()
"Activate all breakpoints in all buffers."
(interactive)
(indium-backend-activate-breakpoints (indium-backend))
(indium-backend-activate-breakpoints (indium-current-connection-backend))
(message "Breakpoints activated"))
(defun indium-list-breakpoints ()
@ -219,7 +219,7 @@ hitting a breakpoint."
(defun indium-interaction--ensure-connection ()
"Signal an error if there is no indium connection."
(unless indium-current-connection
(unless-indium-connected
(user-error "No Indium connection")))
(defvar indium-interaction-mode-map
@ -269,7 +269,7 @@ hitting a breakpoint."
(defun indium-interaction-mode-on ()
"Function to be evaluated when `indium-interaction-mode' is turned on."
(when indium-current-connection
(when-indium-connected
(indium-breakpoint-add-breakpoints-to-buffer)))
(defun indium-interaction-mode-off ()
@ -287,7 +287,7 @@ hitting a breakpoint."
"Update the script source of the backend based on the current buffer."
(interactive)
(when-let ((url (indium-workspace-make-url buffer-file-name)))
(indium-backend-set-script-source (indium-backend)
(indium-backend-set-script-source (indium-current-connection-backend)
url
(buffer-string)
(lambda ()


+ 8
- 8
indium-repl.el View File

@ -111,8 +111,8 @@ Doing this will also close all inspectors and debugger buffers
connected to the process.
")
(map-elt indium-current-connection 'backend)
(map-elt indium-current-connection 'url)))
(indium-current-connection-backend)
(indium-current-connection-url)))
(defun indium-repl-setup-markers ()
@ -163,10 +163,10 @@ connected to the process.
(defun indium-repl-inspect ()
"Inspect the result of the evaluation of the input at point."
(interactive)
(indium-backend-evaluate (indium-backend)
(indium-repl--input-content)
(lambda (result _error)
(indium-inspector-inspect result))))
(indium-backend-evaluate (indium-current-connection-backend)
(indium-repl--input-content)
(lambda (result _error)
(indium-inspector-inspect result))))
(defun indium-repl--input-content ()
"Return the content of the current input."
@ -181,7 +181,7 @@ connected to the process.
(defun indium-repl-evaluate (string)
"Evaluate STRING in the browser tab and emit the output."
(push string indium-repl-history)
(indium-backend-evaluate (indium-backend) string #'indium-repl-emit-value)
(indium-backend-evaluate (indium-current-connection-backend) string #'indium-repl-emit-value)
;; move the output markers so that output is put after the current prompt
(save-excursion
(goto-char (point-max))
@ -366,7 +366,7 @@ Evaluate CALLBACK with the completion candidates."
(max bol prev-delimiter)
bol))
(point))))
(indium-backend-get-completions (indium-backend) expression arg callback)))
(indium-backend-get-completions (indium-current-connection-backend) expression arg callback)))
(defun indium-repl--complete-or-indent ()
"Complete or indent at point."


+ 2
- 1
indium-scratch.el View File

@ -26,6 +26,7 @@
(require 'indium-interaction)
(require 'indium-repl)
(eval-and-compile (require 'indium-structs))
(defun indium-scratch ()
"Pop to the scratch buffer.
@ -39,7 +40,7 @@ one first."
If no buffer exists, create one.
If there is no current connection, throw an error."
(unless indium-current-connection
(unless-indium-connected
(user-error "No current connection"))
(let* ((bufname (indium-scratch-buffer-name))
(buf (get-buffer bufname)))


+ 4
- 6
indium-script.el View File

@ -48,9 +48,7 @@
(defun indium-script-add-script-parsed (id url &optional sourcemap-url)
"Add a parsed script from the runtime with ID at URL.
If SOURCEMAP-URL is non-nil, add it to the parsed script."
(unless (map-elt indium-current-connection 'scripts)
(map-put indium-current-connection 'scripts '()))
(map-put (map-elt indium-current-connection 'scripts)
(map-put (indium-current-connection-scripts)
(intern id)
(make-indium-script :id id
:url url
@ -59,7 +57,7 @@ If SOURCEMAP-URL is non-nil, add it to the parsed script."
(defun indium-script-find-by-id (id)
"Return the parsed script with id ID in the current connection.
If not such script was parsed, return nil."
(map-elt (map-elt indium-current-connection 'scripts) (intern id)))
(map-elt (indium-current-connection-scripts) (intern id)))
(defun indium-script-get-file (script)
"Lookup the local file associated with SCRIPT.
@ -73,7 +71,7 @@ Return nil if no script can be found."
(map-apply (lambda (_id script)
(when (string= url (indium-script-url script))
script))
(map-elt indium-current-connection 'scripts))))
(indium-current-connection-scripts))))
(defun indium-script-find-from-file (file)
"Lookup a script from a local FILE.
@ -88,7 +86,7 @@ Return nil if no script can be found."
(defun indium-script-all-scripts-with-sourcemap ()
"Return all parsed scripts that contain a sourcemap."
(seq-filter #'indium-script-has-sourcemap-p
(map-values (map-elt indium-current-connection 'scripts))))
(map-values (indium-current-connection-scripts))))
(defun indium-script-sourcemap-file (script)
"Return the local sourcemap file associated with SCRIPT.


+ 74
- 0
indium-structs.el View File

@ -40,6 +40,80 @@
(declare-function indium-script-get-file "indium-script.el")
(declare-function indium-script-find-by-id "indium-script.el")
(defmacro when-indium-connected (&rest body)
"Evaluate BODY if there is a current Indium connection."
(declare (indent 0))
`(when indium-current-connection
,@body))
(defmacro unless-indium-connected (&rest body)
"Evalute BODY unless there is a current Indium connection."
(declare (indent 0))
`(unless indium-current-connection
,@body))
(defvar indium-current-connection nil
"Current connection to the browser tab.")
(cl-defstruct indium-connection
(backend nil :type symbol :read-only t)
(url nil :type string :read-only t)
(callbacks (make-hash-table) :type hash-table)
(scripts (make-hash-table) :type hash-table)
(breakpoints (make-hash-table) :type hash-table)
(frames nil :type list)
(current-frame nil :type indium-frame)
;; extra properties that can be added by the backend
(props (make-hash-table) :type hash-table))
(defun indium-current-connection-backend ()
"Return the backend of the current connection if any."
(when-indium-connected
(indium-connection-backend indium-current-connection)))
(defun indium-current-connection-url ()
"Return the url of the current connection if any."
(when-indium-connected
(indium-connection-url indium-current-connection)))
(defun indium-current-connection-callbacks ()
"Return the callbacks of the current connection if any."
(when-indium-connected
(indium-connection-callbacks indium-current-connection)))
(defun indium-current-connection-scripts ()
"Return the scripts of the current connection if any."
(when-indium-connected
(indium-connection-scripts indium-current-connection)))
(defun indium-current-connection-breakpoints ()
"Return the breakpoints of the current connection if any."
(when-indium-connected
(indium-connection-breakpoints indium-current-connection)))
(defun indium-current-connection-props ()
"Return the props of the current connection if any."
(when-indium-connected
(indium-connection-props indium-current-connection)))
(defun indium-current-connection-frames ()
"Return the frames of the current connection if any."
(when-indium-connected
(indium-connection-frames indium-current-connection)))
(cl-defmethod (setf indium-current-connection-frames) (frames)
(when-indium-connected
(setf (indium-connection-frames indium-current-connection) frames)))
(defun indium-current-connection-current-frame ()
"Return the current frame of the current connection if any."
(when-indium-connected
(indium-connection-current-frame indium-current-connection)))
(cl-defmethod (setf indium-current-connection-current-frame) (frame)
(when-indium-connected
(setf (indium-connection-current-frame indium-current-connection) frame)))
(cl-defstruct indium-script
(id nil :type string :read-only t)
(url nil :type string :read-only t)


+ 44
- 35
indium-webkit.el View File

@ -36,10 +36,10 @@
(require 'seq)
(require 'indium-backend)
(require 'indium-structs)
(require 'indium-repl)
(require 'indium-debugger)
(require 'indium-workspace)
(require 'indium-structs)
(require 'indium-script)
(defvar indium-webkit-cache-disabled nil
@ -49,29 +49,40 @@
(indium-register-backend 'webkit)
(defun indium-connection-ws (connection)
"Return the websocket associated to CONNECTION."
(map-elt (indium-connection-props connection) 'ws))
(cl-defmethod (setf indium-connection-ws) (ws (connection indium-connection))
(map-put (indium-connection-props connection) 'ws ws))
(defun indium-connection-nodejs-p (connection)
"Return non-nil if CONNECTION is for Nodejs."
(and connection
(map-elt (indium-connection-props connection) 'nodejs)))
(cl-defmethod indium-backend-active-connection-p ((_backend (eql webkit)))
"Return non-nil if the current connection is active."
(and indium-current-connection
(websocket-openp (map-elt indium-current-connection 'ws))))
(when-indium-connected
(websocket-openp (indium-connection-ws indium-current-connection))))
(cl-defmethod indium-backend-close-connection ((_backend (eql webkit)))
"Close the websocket associated with the current connection."
(websocket-close (map-elt indium-current-connection 'ws)))
(websocket-close (indium-connection-ws indium-current-connection)))
(cl-defmethod indium-backend-reconnect ((_backend (eql webkit)))
(let* ((url (map-elt indium-current-connection 'url))
(websocket-url (websocket-url (map-elt indium-current-connection 'ws))))
(indium-webkit--open-ws-connection url
websocket-url
;; close all buffers related to the closed
;; connection the first
#'indium-quit)))
(indium-webkit--open-ws-connection
(indium-current-connection-url)
(websocket-url (indium-connection-ws indium-current-connection))
;; close all buffers related to the closed
;; connection the first
#'indium-quit))
(cl-defmethod indium-backend-evaluate ((_backend (eql webkit)) string &optional callback)
"Evaluate STRING then call CALLBACK.
CALLBACK is called with two arguments, the value returned by the
evaluation and non-nil if the evaluation threw an error."
(let* ((current-frame (map-elt indium-current-connection 'current-frame))
(let* ((current-frame (indium-current-connection-current-frame))
(callFrameId (and current-frame (indium-frame-id current-frame))))
(indium-webkit--send-request
`((method . ,(if callFrameId
@ -289,25 +300,21 @@ connection."
(defun indium-webkit--make-connection (ws url &optional nodejs)
"Return a new connection for WS and URL.
If NODEJS is non-nil, add a `nodejs' flag to the connection."
(let ((connection (make-hash-table)))
(map-put connection 'ws ws)
(map-put connection 'url url)
(map-put connection 'backend 'webkit)
(map-put connection 'callbacks (make-hash-table))
If NODEJS is non-nil, add a `nodejs' extra property to the
connection."
(let ((conn (make-indium-connection
:backend 'webkit
:url url)))
(setf (indium-connection-ws conn) ws)
(when nodejs
(map-put connection 'nodejs t))
connection))
(defun indium-webkit--callbacks ()
"Return the callbacks associated with the current connection."
(map-elt indium-current-connection 'callbacks))
(map-put (indium-connection-props conn) 'nodejs t))
conn))
(defun indium-webkit--handle-ws-open (ws url nodejs workspace)
"Setup indium for a new connection for the websocket WS.
URL points to the browser tab.
If NODEJS is non-nil, set a flag in the connection.
If NODEJS is non-nil, set an extra property in the connection.
If WORKSPACE is non-nil, make it the workspace used for the connection."
(setq indium-current-connection (indium-webkit--make-connection ws url nodejs))
(indium-webkit--enable-tools)
@ -322,7 +329,8 @@ If WORKSPACE is non-nil, make it the workspace used for the connection."
(error (map-elt message 'error))
(method (map-elt message 'method))
(request-id (map-elt message 'id))
(callback (map-elt (indium-webkit--callbacks) request-id)))
(callback (map-elt (indium-current-connection-callbacks)
request-id)))
(cond
(error (message (map-elt error 'message)))
(request-id (when callback
@ -368,13 +376,13 @@ MESSAGE explains why the connection has been closed."
(exception (equal (map-nested-elt message '(params reason)) "exception"))
(reason (if exception "Exception occured" "Breakpoint hit"))
(description (map-nested-elt message '(params data description))))
(unless (map-elt indium-current-connection 'nodejs)
(unless (indium-connection-nodejs-p indium-current-connection)
(indium-webkit-set-overlay-message "Paused in Emacs debugger"))
(indium-debugger-paused (indium-webkit--frames frames) reason description)))
(defun indium-webkit--handle-debugger-resumed (_message)
"Handle a runtime execution resumed event."
(unless (map-elt indium-current-connection 'nodejs)
(unless (indium-connection-nodejs-p indium-current-connection)
(indium-webkit-remove-overlay-message))
(indium-debugger-resumed))
@ -401,12 +409,13 @@ Evaluate CALLBACK with the response.
If the current connection is closed, display a message."
(if (indium-webkit--connected-p)
(let ((id (indium-webkit--next-request-id))
(callbacks (indium-webkit--callbacks)))
(when callback
(map-put callbacks id callback))
(websocket-send-text (map-elt indium-current-connection 'ws)
(json-encode (cons `(id . ,id) request))))
(let ((id (indium-webkit--next-request-id)))
(when callback
(map-put (indium-current-connection-callbacks)
id
callback))
(websocket-send-text (indium-connection-ws indium-current-connection)
(json-encode (cons `(id . ,id) request))))
(message "Socket connection closed")))
(defun indium-webkit--read-ws-message (frame)
@ -419,7 +428,7 @@ If the current connection is closed, display a message."
There is currently no support for the DOM inspector and network
inspectors."
(indium-webkit--enable-runtime)
(unless (map-elt indium-current-connection 'nodejs)
(unless (indium-connection-nodejs-p indium-current-connection)
(indium-webkit--enable-page)
(indium-webkit--enable-network)
(indium-webkit--enable-log))


+ 4
- 3
indium-workspace.el View File

@ -61,6 +61,7 @@
(require 'map)
(require 'subr-x)
(require 'indium-structs)
(require 'indium-backend)
(declare-function indium-repl-get-buffer "indium-repl.el")
@ -138,7 +139,7 @@ If no file is found, return nil."
(defun indium-workspace--make-url-using-file-path (file)
"When using nodejs, the path of FILE should be used directly."
(when (map-elt indium-current-connection 'nodejs)
(when (indium-connection-nodejs-p indium-current-connection)
file))
(defun indium-workspace--make-url-using-file-protocol (file)
@ -151,14 +152,14 @@ If the current connection doesn't use the file protocol, return nil."
"Return the url associated with the local FILE.
The url is built using `indium-workspace-root'."
(if-let ((root (indium-workspace-root)))
(let* ((url (indium-workspace--url-basepath (map-elt indium-current-connection 'url)))
(let* ((url (indium-workspace--url-basepath (indium-current-connection-url)))
(path (file-relative-name file root)))
(setf (url-filename url) (indium-workspace--absolute-path path))
(url-recreate-url url))))
(defun indium-workspace--file-protocol-p ()
"Return non-nil if the current connection use the file protocol."
(let ((url (url-generic-parse-url (map-elt indium-current-connection 'url))))
(let ((url (url-generic-parse-url (indium-current-connection-url))))
(string= (url-type url) "file")))
(defun indium-workspace--absolute-path (path)


+ 1
- 1
test/test-helper.el View File

@ -82,7 +82,7 @@ a temporary file, which is removed afterwards."
(defmacro with-fake-indium-connection (&rest body)
"Evaluate BODY with an indium connection with a fake backend."
(declare (indent 0))
`(with-indium-connection '((backend . fake))
`(with-indium-connection (make-indium-connection :backend 'fake)
,@body))
(defmacro with-nodejs-connection (&rest body)


+ 7
- 7
test/unit/indium-backend-test.el View File

@ -32,12 +32,12 @@
(expect (indium-backend-active-connection-p 'fake) :to-be-truthy)))
(it "should not be active unless a websocket is open"
(with-indium-connection '((backend . webkit))
(with-indium-connection (make-indium-connection :backend 'webkit)
(expect (indium-backend-active-connection-p 'webkit) :to-be nil))))
(describe "Backend breakpoints"
(it "can register breakpoints"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond")
(expect (indium-backend-get-breakpoints) :to-equal
'(((id . a)
@ -46,7 +46,7 @@
(condition . "cond"))))))
(it "can get breakpoints in a file"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond1")
(indium-backend-register-breakpoint 'b 25 "foo.js" "cond2")
(indium-backend-register-breakpoint 'c 3 "bar.js" "cond3")
@ -61,7 +61,7 @@
(condition . "cond2"))))))
(it "can get breakpoints in a file with line"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond1")
(indium-backend-register-breakpoint 'b 25 "foo.js" "cond2")
(indium-backend-register-breakpoint 'c 3 "bar.js" "cond3")
@ -72,7 +72,7 @@
(condition . "cond2"))))))
(it "can get breakpoint from ID"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond")
(expect (indium-backend-get-breakpoint 'a) :to-equal
'((id . a)
@ -81,12 +81,12 @@
(condition . "cond")))))
(it "get nil when no breakpoint found for ID"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond")
(expect (indium-backend-get-breakpoint 'b) :to-equal nil)))
(it "can unregister breakpoints"
(with-indium-connection '((backend . fake))
(with-indium-connection (make-indium-connection :backend 'fake)
(indium-backend-register-breakpoint 'a 12 "foo.js" "cond")
(indium-backend-unregister-breakpoint 'a)
(expect (indium-backend-get-breakpoints) :to-be nil))))


+ 9
- 9
test/unit/indium-debugger-test.el View File

@ -30,8 +30,8 @@
(let ((frames '(first second))
(current-frame 'first))
(indium-debugger-set-frames frames)
(expect (indium-debugger-frames) :to-be frames)
(expect (indium-debugger-current-frame) :to-be current-frame))))
(expect (indium-current-connection-frames) :to-be frames)
(expect (indium-current-connection-current-frame) :to-be current-frame))))
(it "can set the current frame"
;; We're not interested in buffer setups
@ -39,14 +39,14 @@
(with-fake-indium-connection
(indium-debugger-set-current-frame 'current)
(expect (indium-debugger-current-frame) :to-be 'current)))
(expect (indium-current-connection-current-frame) :to-be 'current)))
(it "can unset the debugging frames"
(with-fake-indium-connection
(indium-debugger-set-frames '(first second))
(indium-debugger-unset-frames)
(expect (indium-debugger-frames) :to-be nil)
(expect (indium-debugger-current-frame) :to-be nil))))
(expect (indium-current-connection-frames) :to-be nil)
(expect (indium-current-connection-current-frame) :to-be nil))))
(describe "Jumping to the next/previous frame"
(before-each
@ -117,24 +117,24 @@
(it "should call the backend when stepping into"
(spy-on 'indium-backend-step-into)
(spy-on 'indium-backend :and-return-value 'backend)
(spy-on 'indium-current-connection-backend :and-return-value 'backend)
(indium-debugger-step-into)
(expect #'indium-backend-step-into :to-have-been-called-with 'backend))
(it "should call the backend when stepping over"
(spy-on 'indium-backend-step-over)
(spy-on 'indium-backend :and-return-value 'backend)
(spy-on 'indium-current-connection-backend :and-return-value 'backend)
(indium-debugger-step-over)
(expect #'indium-backend-step-over :to-have-been-called-with 'backend))
(it "should call the backend when stepping out"
(spy-on 'indium-backend-step-out)
(spy-on 'indium-backend :and-return-value 'backend)
(spy-on 'indium-current-connection-backend :and-return-value 'backend)
(indium-debugger-step-out)
(expect #'indium-backend-step-out :to-have-been-called-with 'backend))
(it "should call the backend when resuming execution"
(spy-on 'indium-backend-resume)
(spy-on 'indium-backend :and-return-value 'backend)
(spy-on 'indium-current-connection-backend :and-return-value 'backend)
(indium-debugger-resume)
(expect #'indium-backend-resume :to-have-been-called-with 'backend)))


+ 44
- 0
test/unit/indium-structs-test.el View File

@ -0,0 +1,44 @@
;;; indium-structs-test.el --- Unit tests for indium-structs.el -*- lexical-binding: t; -*-
;; Copyright (C) 2017 Nicolas Petton
;; Author: Nicolas Petton <nicolas@petton.fr>
;; Keywords: test
;; 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:
;;
;;; Code:
(require 'buttercup)
(require 'indium-structs)
(describe "Setting current connection slots"
(it "should be able to set the frames"
(with-indium-connection (make-indium-connection)
(setf (indium-current-connection-frames) 'foo)
(expect (indium-current-connection-frames)
:to-be 'foo)))
(it "should be able to set the current frame"
(with-indium-connection (make-indium-connection)
(setf (indium-current-connection-current-frame) 'foo)
(expect (indium-current-connection-current-frame)
:to-be 'foo))))
(provide 'indium-structs-test)
;;; indium-structs-test.el ends here

+ 17
- 10
test/unit/indium-webkit-test.el View File

@ -35,6 +35,13 @@
(expect (indium-webkit--next-request-id) :to-be 3)
(expect (indium-webkit--next-request-id) :to-be 4))))
(describe "Webkit connection websocket"
(it "should be able to set a websocket"
(let ((conn (make-indium-connection)))
(setf (indium-connection-ws conn) 'foo)
(expect (indium-connection-ws conn)
:to-be 'foo))))
(describe "Webkit connection handling"
(it "should be active if the websocket is open"
(spy-on 'websocket-openp :and-return-value t)
@ -42,13 +49,13 @@
(expect (indium-backend-active-connection-p 'webkit) :to-be-truthy)))
(it "should be inactive if the websocket is closed"
(let ((indium-current-connection '((backend . webkit))))
(let ((indium-current-connection (make-indium-connection :backend 'webkit)))
(expect (indium-backend-active-connection-p 'webkit) :to-be nil)))
(it "should close the socket when closing the connection"
(spy-on 'websocket-close)
(with-indium-connection '((backend . webkit)
(ws . ws))
(with-indium-connection (make-indium-connection :backend 'webkit)
(map-put (indium-current-connection-props) 'ws 'ws)
(indium-backend-close-connection 'webkit)
(expect #'websocket-close :to-have-been-called-with 'ws))))
@ -70,9 +77,9 @@
(spy-on 'websocket-send-text)
(spy-on 'indium-backend-active-connection-p :and-return-value t)
(spy-on 'indium-webkit--next-request-id :and-return-value 'id)
(with-indium-connection '((backend . webkit)
(ws . ws))
(indium-webkit--send-request '((message ."message")))
(with-indium-connection (make-indium-connection :backend 'webkit)
(map-put (indium-current-connection-props) 'ws 'ws)
(indium-webkit--send-request '((message . "message")))
(expect #'websocket-send-text :to-have-been-called-with
'ws (json-encode '((id . id) (message . "message"))))))
@ -80,10 +87,9 @@
(spy-on 'websocket-send-text)
(spy-on 'indium-backend-active-connection-p :and-return-value t)
(spy-on 'indium-webkit--next-request-id :and-return-value 'id)
(with-indium-connection `((backend . webkit)
(callbacks . ,(make-hash-table)))
(with-indium-connection (make-indium-connection :backend 'webkit)
(indium-webkit--send-request '((message . "message")) 'callback)
(expect (map-elt (indium-webkit--callbacks) 'id) :to-equal 'callback))))
(expect (map-elt (indium-current-connection-callbacks) 'id) :to-equal 'callback))))
(describe "Making completion expressions"
(it "should return \"this\" if there is no property to complete"
@ -110,7 +116,8 @@
(it "calls Debugger.evaluateOnCallFrame when there is stack frame"
(spy-on 'indium-webkit--send-request)
(with-indium-connection `((current-frame . ,(make-indium-frame :id 1)))
(with-indium-connection (make-indium-connection
:current-frame (make-indium-frame :id 1))
(indium-backend-evaluate 'webkit "foo")
(expect #'indium-webkit--send-request :to-have-been-called-with
'((method . "Debugger.evaluateOnCallFrame")


+ 11
- 7
test/unit/indium-workspace-test.el View File

@ -21,6 +21,8 @@
;;; Code:
(require 'map)
(require 'buttercup)
(require 'assess)
(require 'indium-workspace)
@ -127,30 +129,32 @@
(describe "Making workspace urls from file names"
(it "cannot make a url when no workspace is set"
(with-indium-connection '((url . "http://localhost:9229"))
(with-indium-connection (make-indium-connection :url "http://localhost:9229")
(expect (indium-workspace-make-url "js/app.js")
:to-be nil)))
(it "can make workspace urls"
(with-indium-connection '((url . "http://localhost:9229"))
(with-indium-connection (make-indium-connection :url "http://localhost:9229")
(assess-with-filesystem indium-workspace--test-fs
(expect (indium-workspace-make-url "js/app.js")
:to-equal "http://localhost:9229/js/app.js"))))
(it "should strip query strings from computing urls"
(with-indium-connection '((url . "http://localhost:9229?foo=bar"))
(with-indium-connection (make-indium-connection :url "http://localhost:9229?foo=bar")
(assess-with-filesystem indium-workspace--test-fs
(expect (indium-workspace-make-url "js/app.js")
:to-equal "http://localhost:9229/js/app.js"))))
(it "should strip paths based on the .indium marker when computing urls"
(with-indium-connection '((url . "http://localhost:9229/foo/bar"))
(with-indium-connection (make-indium-connection :url "http://localhost:9229/foo/bar")
(assess-with-filesystem indium-workspace--test-fs
(expect (indium-workspace-make-url "js/app.js")
:to-equal "http://localhost:9229/js/app.js"))))
(it "should use the file path if the connection uses nodejs when computing urls"
(with-indium-connection '((nodejs . t))
(with-indium-connection (make-indium-connection)
(map-put (indium-current-connection-props)
'nodejs t)
(assess-with-filesystem indium-workspace--test-fs
(let ((file (expand-file-name "js/app.js")))
(expect (indium-workspace-make-url file)
@ -159,7 +163,7 @@
(describe "File protocol"
(it "can lookup files using the file:// protocol"
(assess-with-filesystem indium-workspace--test-fs
(with-indium-connection '((url . "file:///foo/bar/index.html"))
(with-indium-connection (make-indium-connection :url "file:///foo/bar/index.html")
(let* ((file (expand-file-name "js/app.js"))
(url (format "file://%s" file)))
(expect (indium-workspace-lookup-file url)
@ -167,7 +171,7 @@
(it "can make a url when using the file protocol"
(assess-with-filesystem indium-workspace--test-fs
(with-indium-connection '((url . "file:///foo/bar/index.html"))
(with-indium-connection (make-indium-connection :url "file:///foo/bar/index.html")
(let* ((file (expand-file-name "js/app.js")))
(expect (indium-workspace-make-url file)
:to-equal (format "file://%s" file)))))))


Loading…
Cancel
Save