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.

160 lines
6.8 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 'subr-x)
  19. (require 'seq)
  20. (require 'indium-render)
  21. (declare-function indium-debugger-get-current-scopes "indium-debugger" ())
  22. (declare-function indium-debugger-get-scope-properties "indium-debugger" (scope callback))
  23. (defun indium-debugger-litable-setup-buffer ()
  24. "Render locals in the current buffer."
  25. (let ((scope (car (indium-debugger-get-current-scopes))))
  26. (indium-debugger-get-scope-properties
  27. scope
  28. (lambda (properties _)
  29. ;; This is just cosmetic, don't break the session
  30. (ignore-errors
  31. (js2-mode-wait-for-parse
  32. (lambda ()
  33. (js2-visit-ast js2-mode-ast
  34. (indium-debugger-litable-make-visitor properties)))))))))
  35. (defun indium-debugger-litable-unset-buffer ()
  36. "Remove locals from the current buffer."
  37. (remove-overlays (point-min)
  38. (point-max)
  39. 'indium-litable t))
  40. (defun indium-debugger-litable-make-visitor (properties)
  41. "Return an AST visitor to add overlays for values in PROPERTIES."
  42. (lambda (node end-p)
  43. (unless end-p
  44. (cond ((js2-function-node-p node)
  45. (indium-debugger-litable-visit-function-node node properties)))
  46. (cond ((indium-debugger-litable-local-name-node-p node)
  47. (indium-debugger-litable-visit-name-node node properties))))
  48. t))
  49. (defun indium-debugger-litable-visit-function-node (node properties)
  50. "Visit the function NODE with PROPERTIES."
  51. (seq-do (lambda (param)
  52. (indium-debugger-litable-maybe-add-value-overlay param properties))
  53. (js2-function-node-params node)))
  54. (defun indium-debugger-litable-visit-name-node (node properties)
  55. "Visit a JS2 name NODE to add an overlay displaying PROPERTIES."
  56. (indium-debugger-litable-maybe-add-value-overlay node properties))
  57. (defun indium-debugger-litable-local-name-node-p (node)
  58. "Return non-nil if NODE represents a local variable."
  59. (let ((parent (js2-node-parent node)))
  60. (and parent (js2-name-node-p node)
  61. (or (js2-var-init-node-p parent)
  62. (js2-assign-node-p parent)))))
  63. (defun indium-debugger-litable-visit-var-init-node (node properties)
  64. "Visit variable initialization NODE with PROPERTIES."
  65. (seq-do (lambda (param)
  66. (indium-debugger-litable-maybe-add-value-overlay param properties))
  67. (js2-function-node-params node)))
  68. (defun indium-debugger-litable-maybe-add-value-overlay (node properties)
  69. "If NODE match PROPERTIES, add a value overlay."
  70. (if-let ((name (buffer-substring-no-properties (js2-node-abs-pos node)
  71. (js2-node-abs-end node)))
  72. (property (seq-find (lambda (property)
  73. (string= name
  74. (map-elt property 'name)))
  75. properties)))
  76. (indium-debugger-litable-add-value-overlay node property)))
  77. (defun indium-debugger-litable-add-exception-overlay (description)
  78. "Add an overlay with the DESCRIPTION of an exception where an error occurs."
  79. (let* ((inhibit-read-only t)
  80. (ov (make-overlay (point-at-bol) (point-at-eol)))
  81. (contents (indium-debugger-litable--overlay-string
  82. (format " %s" (car (split-string description "\n"))))))
  83. (overlay-put ov 'indium-litable t)
  84. (overlay-put ov 'indium-exception-description t)
  85. (font-lock-prepend-text-property 1
  86. (seq-length contents)
  87. 'face 'font-lock-warning-face
  88. contents)
  89. (overlay-put ov 'after-string contents)))
  90. (defun indium-debugger-litable-add-value-overlay (node property)
  91. "Add an overlay displaying the value of NODE for PROPERTY.
  92. Ignore if the object name of NODE is not in the current scope."
  93. (save-excursion
  94. (goto-char (js2-node-abs-pos node))
  95. (let ((inhibit-read-only t)
  96. (ov (indium-debugger-litable--get-overlay-at-pos))
  97. (contents (string-trim (indium-render-property-to-string property)))
  98. (name (map-elt property 'name)))
  99. (unless (seq-contains (overlay-get ov 'indium-properties) name)
  100. ;; The overlay is already used to display exception details, so do not
  101. ;; append anything to it.
  102. (unless (overlay-get ov 'indium-exception-description)
  103. (if-let ((existing-contents (overlay-get ov 'after-string)))
  104. (setq contents (concat existing-contents ", " contents))
  105. (setq contents (concat " " contents)))
  106. (setq contents (indium-debugger-litable--overlay-string contents))
  107. (font-lock-prepend-text-property 0
  108. (seq-length contents)
  109. 'face
  110. 'indium-litable-face
  111. contents)
  112. (overlay-put ov
  113. 'indium-properties
  114. (cons name (overlay-get ov 'indium-properties)))
  115. (overlay-put ov
  116. 'after-string
  117. contents))))))
  118. (defun indium-debugger-litable--overlay-string (string)
  119. "Return the STRING to be added to an overlay at the end of the line.
  120. If the display string overflows, trim it to avoid truncating the line."
  121. (save-excursion
  122. (goto-char (point-at-eol))
  123. (if (>= (+ (seq-length string) (current-column)) (window-width))
  124. (let ((width (- (window-width) (current-column) 1)))
  125. (truncate-string-to-width string width 0 nil "..."))
  126. string)))
  127. (defun indium-debugger-litable--get-overlay-at-pos ()
  128. "Return the overlay for litable at point.
  129. If no overlay exist, create one."
  130. (or (seq-find (lambda (ov)
  131. (overlay-get ov 'indium-litable))
  132. (overlays-in (point-at-bol) (point-at-eol)))
  133. (let ((ov (make-overlay (point-at-bol) (point-at-eol))))
  134. (overlay-put ov 'indium-litable t)
  135. ov)))
  136. (provide 'indium-debugger-litable)
  137. ;;; indium-debugger-litable.el ends here