A JavaScript development environment for Emacs https://indium.readthedocs.io
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

174 lines
7.3 KiB

  1. ;;; indium-debugger-litable.el --- Display local values in debugger buffers -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2017-2018 Nicolas Petton
  3. ;; Author: Nicolas Petton <nicolas@petton.fr>
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;;
  16. ;;; Code:
  17. (require 'js2-mode)
  18. (require 'js2-refactor)
  19. (require 'subr-x)
  20. (require 'seq)
  21. (require 'indium-render)
  22. (declare-function indium-debugger-get-current-scopes "indium-debugger.el" ())
  23. (declare-function indium-debugger-get-scopes-properties "indium-debugger.el" (scope callback))
  24. (declare-function indium-debugger-get-buffer-create "indium-debugger.el" ())
  25. (defun indium-debugger-litable-setup-buffer ()
  26. "Render locals in the current buffer."
  27. (indium-debugger-get-scopes-properties
  28. (indium-debugger-get-current-scopes)
  29. (lambda (properties _)
  30. ;; This is just cosmetic, don't break the session
  31. (ignore-errors
  32. (with-current-buffer (indium-debugger-get-buffer-create)
  33. (js2-mode-wait-for-parse
  34. (lambda ()
  35. (with-current-buffer (indium-debugger-get-buffer-create)
  36. (js2-visit-ast (indium-debugger-litable--scope-node)
  37. (indium-debugger-litable-make-visitor properties))))))))))
  38. (defun indium-debugger-litable--scope-node ()
  39. "Return the scope node from point."
  40. (or (js2r--closest #'js2-function-node-p)
  41. js2-mode-ast))
  42. (defun indium-debugger-litable-unset-buffer ()
  43. "Remove locals from the current buffer."
  44. (remove-overlays (point-min)
  45. (point-max)
  46. 'indium-litable t))
  47. (defun indium-debugger-litable-make-visitor (properties)
  48. "Return an AST visitor to add overlays for values in PROPERTIES."
  49. (lambda (node end-p)
  50. (unless end-p
  51. (cond ((js2-function-node-p node)
  52. (indium-debugger-litable-visit-function-node node properties)))
  53. (cond ((indium-debugger-litable-local-name-node-p node)
  54. (indium-debugger-litable-visit-name-node node properties))))
  55. t))
  56. (defun indium-debugger-litable-visit-function-node (node properties)
  57. "Visit the function NODE with PROPERTIES."
  58. (seq-do (lambda (param)
  59. (indium-debugger-litable-maybe-add-value-overlay param properties))
  60. (js2-function-node-params node)))
  61. (defun indium-debugger-litable-visit-name-node (node properties)
  62. "Visit a JS2 name NODE to add an overlay displaying PROPERTIES."
  63. (indium-debugger-litable-maybe-add-value-overlay node properties))
  64. (defun indium-debugger-litable-local-name-node-p (node)
  65. "Return non-nil if NODE represents a local variable."
  66. (let ((parent (js2-node-parent node)))
  67. (and parent (js2-name-node-p node)
  68. (or (js2-var-init-node-p parent)
  69. (js2-object-prop-node-p parent)
  70. (js2-assign-node-p parent)))))
  71. (defun indium-debugger-litable-visit-var-init-node (node properties)
  72. "Visit variable initialization NODE with PROPERTIES."
  73. (seq-do (lambda (param)
  74. (indium-debugger-litable-maybe-add-value-overlay param properties))
  75. (js2-function-node-params node)))
  76. (defun indium-debugger-litable-maybe-add-value-overlay (node properties)
  77. "If NODE match PROPERTIES, add a value overlay."
  78. (if-let ((name (buffer-substring-no-properties (js2-node-abs-pos node)
  79. (js2-node-abs-end node)))
  80. (property (seq-find (lambda (property)
  81. (string= name
  82. (indium-property-name property)))
  83. properties)))
  84. (indium-debugger-litable-add-value-overlay node property)))
  85. (defun indium-debugger-litable-add-exception-overlay (description)
  86. "Add an overlay with the DESCRIPTION of an exception where an error occurs."
  87. (let* ((inhibit-read-only t)
  88. (ov (make-overlay (point-at-bol) (point-at-eol)))
  89. (contents (indium-debugger-litable--overlay-string
  90. (format " %s" (car (split-string description "\n"))))))
  91. (overlay-put ov 'indium-litable t)
  92. (overlay-put ov 'indium-exception-description t)
  93. (font-lock-prepend-text-property 1
  94. (seq-length contents)
  95. 'face 'font-lock-warning-face
  96. contents)
  97. (overlay-put ov 'after-string contents)))
  98. (defun indium-debugger-litable-add-value-overlay (node property)
  99. "Add an overlay displaying the value of NODE for PROPERTY.
  100. Ignore if the object name of NODE is not in the current scope."
  101. (save-excursion
  102. (goto-char (js2-node-abs-pos node))
  103. (let ((inhibit-read-only t)
  104. (ov (indium-debugger-litable--get-overlay-at-pos))
  105. (contents (string-trim (indium-render-property-to-string property)))
  106. (name (indium-property-name property)))
  107. (unless (seq-contains (overlay-get ov 'indium-properties) name)
  108. ;; The overlay is already used to display exception details, so do not
  109. ;; append anything to it.
  110. (unless (overlay-get ov 'indium-exception-description)
  111. (if-let ((existing-contents (overlay-get ov 'after-string)))
  112. (setq contents (concat existing-contents ", " contents))
  113. (setq contents (concat " " contents)))
  114. (setq contents (indium-debugger-litable--overlay-string contents))
  115. (font-lock-prepend-text-property 0
  116. (seq-length contents)
  117. 'face
  118. 'indium-litable-face
  119. contents)
  120. (overlay-put ov
  121. 'indium-properties
  122. (cons name (overlay-get ov 'indium-properties)))
  123. (overlay-put ov
  124. 'after-string
  125. contents))))))
  126. (defun indium-debugger-litable--overlay-string (string)
  127. "Return the STRING to be added to an overlay at the end of the line.
  128. If the display string overflows, trim it to avoid truncating the line."
  129. (save-excursion
  130. (goto-char (point-at-eol))
  131. (if (>= (+ (seq-length string) (current-column)) (window-width))
  132. (let* ((line-number-width (if (fboundp 'line-number-display-width)
  133. (line-number-display-width 'columns)
  134. 0))
  135. (width (- (window-width) (current-column) line-number-width 1)))
  136. (truncate-string-to-width string width 0 nil "..."))
  137. string)))
  138. (defun indium-debugger-litable--get-overlay-at-pos ()
  139. "Return the overlay for litable at point.
  140. If no overlay exist, create one."
  141. (or (seq-find (lambda (ov)
  142. (overlay-get ov 'indium-litable))
  143. (overlays-in (point-at-bol) (point-at-eol)))
  144. (let ((ov (make-overlay (point-at-bol) (point-at-eol))))
  145. (overlay-put ov 'indium-litable t)
  146. ov)))
  147. (provide 'indium-debugger-litable)
  148. ;;; indium-debugger-litable.el ends here