-
Notifications
You must be signed in to change notification settings - Fork 8
/
dime-note-tree.el
219 lines (179 loc) · 7.5 KB
/
dime-note-tree.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
;;; dime-note-tree.el --- Dylan interaction mode -*- lexical-binding: t -*-
;; Lineage: SLIME, Open Dylan
;; Copyright (C) 2011 Hannes Mehnert
;; Copyright (C) 2013 Erik Charlebois
;; Copyright (C) 2021 Lassi Kortela
;; SPDX-License-Identifier: GPL-2.0-or-later
;; URL: https://opendylan.org/
;; Package-Requires: ((emacs "25.1"))
;;; Commentary:
;; Dime add-on to browse compiler notes as a tree.
;;; Code:
(require 'cl-lib)
(require 'dime)
(define-dime-contrib dime-note-tree
"Display compiler messages in tree layout.
M-x dime-note-tree-show display the compiler notes in a tree
grouped by severity.
`dime-note-tree-maybe-show' can be used as
`dime-compilation-finished-hook'.
"
(:authors "Helmut Eller <[email protected]>")
(:license "GPL-2.0-or-later"))
(defun dime-note-tree-maybe-show (notes)
"Show the compiler NOTES if appropriate."
;; don't pop up a buffer if all notes are already annotated in the
;; buffer itself
(unless (cl-every #'dime-note-has-location-p notes)
(dime-note-tree-show notes)))
(defun dime-note-tree-show (notes)
"Show the compiler notes NOTES in tree view."
(interactive (list (dime-compiler-notes)))
(with-temp-message "Preparing compiler note tree..."
(dime-with-popup-buffer ((dime-buffer-name :notes)
:mode 'dime-note-tree-mode)
(when (null notes)
(insert "[no notes]"))
(dolist (tree (dime-note-tree--from-notes notes))
(dime-note-tree--insert tree "")
(insert "\n"))
(goto-char (point-min)))))
(defvar dime-note-tree-printer 'dime-note-tree-default-printer)
(defun dime-note-tree--for-note (note)
"Make a note tree for the given NOTE."
(make-dime-note-tree :item (dime-note.message note)
:plist (list 'note note)
:print-fn dime-note-tree-printer))
(defun dime-note-tree--for-severity (severity notes collapsed-p)
"Make a note tree for NOTES of the given SEVERITY.
COLLAPSED-P says whether the tree is initially collapsed."
(make-dime-note-tree :item (format "%s (%d)"
(dime-severity-label severity)
(length notes))
:kids (mapcar #'dime-note-tree--for-note notes)
:collapsed-p collapsed-p))
(defun dime-note-tree--from-notes (notes)
"Make a note tree from a list of NOTES."
(let* ((alist (dime-alistify notes #'dime-note.severity #'eq))
(collapsed-p (dime-length> alist 1)))
(cl-loop for (severity . notes) in alist
collect (dime-note-tree--for-severity severity notes
collapsed-p))))
(defvar dime-note-tree-mode-map (make-sparse-keymap)
"Keymap for Dime note tree mode.")
(define-derived-mode dime-note-tree-mode fundamental-mode
"Compiler-Notes"
"\\<dime-note-tree-mode-map>\
\\{dime-note-tree-mode-map}
\\{dime-popup-buffer-mode-map}
"
(dime-set-truncate-lines))
(dime-define-keys dime-note-tree-mode-map
((kbd "RET") 'dime-note-tree-default-action-or-show-details)
([return] 'dime-note-tree-default-action-or-show-details)
([mouse-2] 'dime-note-tree-mouse-default-action-or-show-details))
(defun dime-note-tree-mouse-default-action-or-show-details (event)
"Invoke the action pointed at by the mouse, or show details.
This command is meant to be bound to a mouse EVENT."
(interactive "e")
(cl-destructuring-bind (_mouse-2 (_w pos &rest ignore1) &rest ignore2) event
(save-excursion
(goto-char pos)
(let ((fn (get-text-property (point)
'dime-compiler-notes-default-action)))
(if fn (funcall fn) (dime-note-tree-show-details))))))
(defun dime-note-tree-default-action-or-show-details ()
"Invoke the action at point, or show details."
(interactive)
(let ((fn (get-text-property (point) 'dime-compiler-notes-default-action)))
(if fn (funcall fn) (dime-note-tree-show-details))))
(defun dime-note-tree-show-details ()
"Show details for the note tree at point."
(interactive)
(let* ((tree (dime-note-tree--at-point))
(note (plist-get (dime-note-tree--plist tree) 'note))
(inhibit-read-only t))
(cond ((not (dime-note-tree--leaf-p tree))
(dime-note-tree--toggle tree))
(t
(dime-show-source-location (dime-note.location note) t)))))
;;;;;; Tree Widget
(cl-defstruct (dime-note-tree (:conc-name dime-note-tree--))
item
(print-fn #'dime-note-tree-default-printer :type function)
(kids '() :type list)
(collapsed-p t :type boolean)
(prefix "" :type string)
(start-mark nil)
(end-mark nil)
(plist '() :type list))
(defun dime-note-tree--leaf-p (tree)
"Return t if the given note TREE is a leaf node, nil otherwise."
(not (dime-note-tree--kids tree)))
(defun dime-note-tree-default-printer (tree)
"Print note TREE using default representation."
(princ (dime-note-tree--item tree) (current-buffer)))
(defun dime-note-tree--decoration (tree)
"Return decorative prefix for note TREE as a string."
(cond ((dime-note-tree--leaf-p tree) "-- ")
((dime-note-tree--collapsed-p tree) "[+] ")
(t "-+ ")))
(defun dime-note-tree--insert-list (list prefix)
"Insert LIST of note trees using PREFIX for each."
(cl-loop for (elt . rest) on list
do (cond (rest
(insert prefix " |")
(dime-note-tree--insert elt (concat prefix " |"))
(insert "\n"))
(t
(insert prefix " `")
(dime-note-tree--insert elt (concat prefix " "))))))
(defun dime-note-tree--indent-item (start end prefix)
"Insert PREFIX at the beginning of each line except the first.
This is used for labels spanning multiple lines. START and END
are the region to modify."
(save-excursion
(goto-char end)
(beginning-of-line)
(while (< start (point))
(insert-before-markers prefix)
(forward-line -1))))
(defun dime-note-tree--insert (tree prefix)
"Insert TREE prefixed with PREFIX at point."
(dime--with-struct (dime-note-tree--
print-fn kids collapsed-p start-mark end-mark)
tree
(let ((line-start (line-beginning-position)))
(setf start-mark (point-marker))
(insert (dime-note-tree--decoration tree))
(funcall print-fn tree)
(dime-note-tree--indent-item start-mark (point) (concat prefix " "))
(add-text-properties line-start (point) (list 'dime-note-tree tree))
(set-marker-insertion-type start-mark t)
(when (and kids (not collapsed-p))
(terpri (current-buffer))
(dime-note-tree--insert-list kids prefix))
(setf (dime-note-tree--prefix tree) prefix)
(setf end-mark (point-marker)))))
(defun dime-note-tree--at-point ()
"Return the note tree at point, error if none."
(cond ((get-text-property (point) 'dime-note-tree))
(t (error "No tree at point"))))
(defun dime-note-tree--delete (tree)
"Delete the region for TREE."
(delete-region (dime-note-tree--start-mark tree)
(dime-note-tree--end-mark tree)))
(defun dime-note-tree--toggle (tree)
"Toggle the visibility of TREE's children."
(dime--with-struct (dime-note-tree--
collapsed-p start-mark end-mark prefix)
tree
(setf collapsed-p (not collapsed-p))
(dime-note-tree--delete tree)
(insert-before-markers " ") ; move parent's end-mark
(backward-char 1)
(dime-note-tree--insert tree prefix)
(delete-char 1)
(goto-char start-mark)))
(provide 'dime-note-tree)
;;; dime-note-tree.el ends here