branch: elpa/flamegraph
commit 98665b6ed24573c373925c94a6bb6f1076d2431c
Author: Dmitry Gutov <[email protected]>
Commit: Dmitry Gutov <[email protected]>

    Highlight children call sites (simple re search)
---
 flamegraph.el | 58 ++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 10 deletions(-)

diff --git a/flamegraph.el b/flamegraph.el
index cd62385e02..a6246d88f2 100644
--- a/flamegraph.el
+++ b/flamegraph.el
@@ -84,6 +84,9 @@ FILE:LINE location.  If nil, paths are resolved against the 
directory of
 the data file the graph was loaded from."
   :type '(choice (const :tag "Data file's directory" nil) directory))
 
+(defface flamegraph-call-site '((t :inherit highlight))
+  "Face for callee occurrences highlighted in a description buffer's source.")
+
 ;;; Layout: call tree -> flat list of frames
 
 (cl-defstruct (flamegraph-frame
@@ -523,14 +526,17 @@ necessarily its definition."
           n
           (buffer-substring (line-beginning-position) (line-end-position))))
 
-(defun flamegraph--source-snippet (path line &optional context)
+(defun flamegraph--source-snippet (path line &optional names context)
   "Return source context around LINE of PATH as a fontified string, or nil.
 The file is loaded in its major mode so the text is syntax-highlighted.
 Besides CONTEXT lines on each side of the sampled LINE (which is marked),
 the enclosing structural lines up to the definition are kept — each line
 that is less indented than the one below it — so the nesting that leads
-to the sampled line stays visible.  Skipped runs are elided with `⋯'.
-CONTEXT defaults to 4."
+to the sampled line stays visible.  NAMES is a list of callee names: lines
+within the enclosing defun where a name occurs as a whole symbol are also
+kept, and the occurrences highlighted with `flamegraph-call-site', so the
+call sites of a frame's children stay visible.  Skipped runs are elided
+with `⋯'.  CONTEXT defaults to 4."
   (setq context (or context 4))
   (when (and (file-readable-p path) (> line 0))
     (with-temp-buffer
@@ -542,12 +548,23 @@ CONTEXT defaults to 4."
         (when (<= line maxline)
           (let* ((lo (max 1 (- line context)))
                  (hi (min maxline (+ line context)))
-                 (def (save-excursion
-                        (goto-char (point-min))
-                        (forward-line (1- line))
-                        (let ((p (point)))
-                          (ignore-errors (beginning-of-defun))
-                          (if (< (point) p) (line-number-at-pos) 1))))
+                 (def-pos (save-excursion
+                            (goto-char (point-min))
+                            (forward-line (1- line))
+                            (let ((p (point)))
+                              (ignore-errors (beginning-of-defun))
+                              (if (< (point) p) (point) (point-min)))))
+                 (def (line-number-at-pos def-pos))
+                 (def-end (save-excursion
+                            (goto-char def-pos)
+                            (ignore-errors (end-of-defun))
+                            (if (> (point) def-pos) (point) (point-max))))
+                 (names (cl-remove-if-not
+                         (lambda (n)
+                           (and (stringp n)
+                                (string-match-p
+                                 "\\`[A-Za-z_][A-Za-z0-9_]*\\'" n)))
+                         names))
                  (keep nil))
             ;; The sampled line and its immediate context.
             (cl-loop for n from lo to hi do (push n keep))
@@ -567,6 +584,13 @@ CONTEXT defaults to 4."
                         (push n keep)
                         (setq min-ind ind)))))))
             (push def keep)
+            ;; Callee call sites anywhere in the enclosing defun.
+            (dolist (name names)
+              (save-excursion
+                (goto-char def-pos)
+                (let ((re (concat "\\_<" (regexp-quote name) "\\_>")))
+                  (while (re-search-forward re def-end t)
+                    (push (line-number-at-pos (match-beginning 0)) keep)))))
             (setq keep (sort (delete-dups keep) #'<))
             ;; Render kept lines in order, eliding the gaps with `⋯'.
             (let ((prev nil) (out nil))
@@ -578,6 +602,15 @@ CONTEXT defaults to 4."
                 (ignore-errors
                   (font-lock-ensure (line-beginning-position)
                                     (line-end-position)))
+                ;; Highlight callee occurrences on this line, additively
+                ;; over the font-lock faces.
+                (dolist (name names)
+                  (goto-char (line-beginning-position))
+                  (let ((re (concat "\\_<" (regexp-quote name) "\\_>"))
+                        (eol (line-end-position)))
+                    (while (re-search-forward re eol t)
+                      (add-face-text-property (match-beginning 0) (match-end 0)
+                                              'flamegraph-call-site))))
                 (push (flamegraph--snippet-line n (= n line)) out)
                 (setq prev n))
               (mapconcat #'identity (nreverse out) "\n"))))))))
@@ -620,7 +653,12 @@ frames, with Help-style back/forward navigation."
                        (message "Source file not found: %s" path)))
            'follow-link t
            'help-echo "mouse-1, RET: visit this line")
-          (when-let* ((snippet (flamegraph--source-snippet path (cdr loc))))
+          (when-let* ((snippet (flamegraph--source-snippet
+                                path (cdr loc)
+                                (mapcar (lambda (k)
+                                          (flamegraph--frame-display-name
+                                           (profiler-calltree-entry k)))
+                                        kids))))
             (insert "\n\n" snippet)))
         (insert (format "\n\nSamples  %s (%s of total)    self  %s (%s)\n"
                         (profiler-format-number count)

Reply via email to