aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Távora2025-04-18 23:08:37 +0100
committerJoão Távora2025-04-20 23:20:33 +0100
commit53d732d775fb416f6a412c2a87f12beed682c96c (patch)
tree56074be7fe275b0da0c1a3f7e3e7f8038695e897
parented1311a62a4e02817e548b0873ab21114047c076 (diff)
downloademacs-53d732d775fb416f6a412c2a87f12beed682c96c.tar.gz
emacs-53d732d775fb416f6a412c2a87f12beed682c96c.zip
Flymake: dynamically resize and layout diagnostic listings
Since 'origin' and 'code' are new separate optional attributes of each diagnostic, it becomes important to not waste space in these listings when these are absent. When a specific column isn't used by any line, omit it. Also spare just enough horizontal space to hold the largest element in each column. * lisp/progmodes/flymake.el (flymake--tabulated-setup): New helper. (flymake-diagnostics-buffer-mode) (flymake-project-diagnostics-mode): Use flymake--setup-tabulated-listing. (flymake--fit-diagnostics-window): New helper. (flymake--tabulated-list-format-base): Rename from flymake--diagnostics-base-tabulated-list-format. (flymake--tabulated-setup-1): Rename and rework from flymake--tabulated-entries-1. (flymake--diagnostics-buffer-entries): Remove. (flymake-diagnostics-buffer-mode) (flymake-project-diagnostics-mode): Simplify. (flymake--project-diagnostics-entries): Remove.
-rw-r--r--lisp/progmodes/flymake.el210
1 files changed, 118 insertions, 92 deletions
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index f2f59f05131..2ea91ccb15c 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1948,8 +1948,9 @@ TYPE is usually keyword `:error', `:warning' or `:note'."
1948 (flymake--mode-line-counter-1 type)) 1948 (flymake--mode-line-counter-1 type))
1949 probe))) 1949 probe)))
1950 1950
1951;;; Per-buffer diagnostic listing 1951
1952 1952;;; Per-buffer diagnostic listings
1953;;;
1953(defvar-local flymake--diagnostics-buffer-source nil) 1954(defvar-local flymake--diagnostics-buffer-source nil)
1954 1955
1955(defvar flymake-diagnostics-buffer-mode-map 1956(defvar flymake-diagnostics-buffer-mode-map
@@ -2005,21 +2006,27 @@ POS can be a buffer position or a button"
2005 (pop-to-buffer 2006 (pop-to-buffer
2006 (flymake-show-diagnostic (if (button-type pos) (button-start pos) pos)))) 2007 (flymake-show-diagnostic (if (button-type pos) (button-start pos) pos))))
2007 2008
2008(defun flymake--tabulated-diagnostic-origin (diag) 2009(defvar flymake--tabulated-list-format-base
2009 (or (flymake-diagnostic-origin diag) 2010 `[("File" 15)
2010 (let* ((backend (flymake-diagnostic-backend diag)) 2011 ("Line" 5 ,(lambda (l1 l2)
2011 (bname (or (ignore-errors (symbol-name backend)) 2012 (< (plist-get (car l1) :line)
2012 "(anonymous function)"))) 2013 (plist-get (car l2) :line)))
2013 (propertize 2014 :right-align t)
2014 (replace-regexp-in-string "\\(.\\)[^-]+\\(-\\|$\\)" 2015 ("Col" 3 nil :right-align t)
2015 "\\1\\2" bname) 2016 ("Type" 8 ,(lambda (l1 l2)
2016 'help-echo (format "From `%s' backend" backend))))) 2017 (< (plist-get (car l1) :severity)
2017 2018 (plist-get (car l2) :severity))))
2018(defun flymake--tabulated-entries-1 (diags project-root) 2019 ("Origin" 8 t)
2019 "Helper for `flymake--diagnostics-buffer-entries'. 2020 ("Code" 8 t)
2020PROJECT-ROOT indicates that each entry should be preceded by the 2021 ("Message" 0 t)])
2021filename of the diagnostic relative to that directory." 2022
2023(defun flymake--tabulated-setup-1 (diags project-root)
2024 "Helper for `flymake--tabulated-setup'.
2025Sets `tabulated-list-format' and `tabulated-list-entries', dinamically
2026resizing columns and ommiting redudant columns."
2022 (cl-loop 2027 (cl-loop
2028 with fields = (copy-tree flymake--tabulated-list-format-base t)
2029 initially (cl-loop for y across fields do (setf (cadr y) nil))
2023 for diag in diags 2030 for diag in diags
2024 for locus = (flymake-diagnostic-buffer diag) 2031 for locus = (flymake-diagnostic-buffer diag)
2025 for file = (if (bufferp locus) 2032 for file = (if (bufferp locus)
@@ -2044,72 +2051,99 @@ filename of the diagnostic relative to that directory."
2044 (;; somehow dead annotated diagnostic, ignore/give up 2051 (;; somehow dead annotated diagnostic, ignore/give up
2045 t nil)) 2052 t nil))
2046 for type = (flymake-diagnostic-type diag) 2053 for type = (flymake-diagnostic-type diag)
2047 for origin = (flymake--tabulated-diagnostic-origin diag) 2054 for data-line = `[,(and project-root
2048 for data-vec = `[,(format "%s" line) 2055 `(,(file-name-nondirectory file)
2049 ,(format "%s" col) 2056 help-echo ,(file-relative-name file project-root)
2050 ,(propertize (format "%s" 2057 face nil
2051 (flymake--lookup-type-property 2058 mouse-face highlight
2052 type 'flymake-type-name type)) 2059 action flymake-goto-diagnostic
2053 'face (flymake--lookup-type-property 2060 mouse-action flymake-goto-diagnostic ))
2054 type 'mode-line-face 'flymake-error)) 2061 ,(format "%s" line)
2055 ,origin 2062 ,(format "%s" col)
2056 (,(flymake-diagnostic-text diag '(oneliner)) 2063 ,(propertize (format "%s"
2057 mouse-face highlight 2064 (flymake--lookup-type-property
2058 help-echo "mouse-2: visit this diagnostic" 2065 type 'flymake-type-name type))
2059 face nil 2066 'face (flymake--lookup-type-property
2060 action flymake-goto-diagnostic 2067 type 'mode-line-face 'flymake-error))
2061 mouse-action flymake-goto-diagnostic)] 2068 ,(flymake-diagnostic-origin diag)
2062 when (and line col) collect 2069 ,(flymake-diagnostic-code diag)
2063 (list (list :diagnostic diag 2070 (,(flymake-diagnostic-text diag '(oneliner))
2064 :line line 2071 mouse-face highlight
2065 :severity (flymake--lookup-type-property 2072 help-echo "mouse-2: visit this diagnostic"
2066 type 2073 face nil
2067 'severity (warning-numeric-level :error))) 2074 action flymake-goto-diagnostic
2068 (if project-root 2075 mouse-action flymake-goto-diagnostic)]
2069 (vconcat `[(,(file-name-nondirectory file) 2076 for meta = (and line col
2070 help-echo ,(file-relative-name file project-root) 2077 (list :diagnostic diag
2071 face nil 2078 :line line
2072 mouse-face highlight 2079 :severity (flymake--lookup-type-property
2073 action flymake-goto-diagnostic 2080 type
2074 mouse-action flymake-goto-diagnostic )] 2081 'severity (warning-numeric-level :error))))
2075 data-vec) 2082 when meta
2076 data-vec)))) 2083 do (cl-loop for x across data-line
2077 2084 for y across fields
2078(defun flymake--diagnostics-buffer-entries () 2085 for z across flymake--tabulated-list-format-base
2079 "Get tabulated list entries for current tabulated list buffer. 2086 for xlen = (cond ((stringp x) (length x))
2080Expects `flymake--diagnostics-buffer-entries' to be bound to a 2087 (t (length (car x))))
2081buffer." 2088 when (cl-plusp xlen)
2082 ;; Do nothing if 'flymake--diagnostics-buffer-source' has not yet 2089 do (setf (cadr y)
2083 ;; been set to a valid buffer. This could happen when this function 2090 (max xlen
2084 ;; is called too early. For example 'global-display-line-numbers-mode' 2091 (or (cadr y) (cadr z)))))
2085 ;; calls us from its mode hook, when the diagnostic buffer has just 2092 collect (list meta data-line) into data
2086 ;; been created by 'flymake-show-buffer-diagnostics', but is not yet 2093 finally
2087 ;; set up properly (Bug#40529). 2094 ;; `data' and `fields' now hold more or less suitable values for
2088 (when (bufferp flymake--diagnostics-buffer-source) 2095 ;; `tabulated-list-entries' and `tabulated-list-format' respectively,
2089 (with-current-buffer flymake--diagnostics-buffer-source 2096 ;; but we need to trim them, first removing the columns of data where
2090 (when flymake-mode 2097 ;; the corresponding field is known to be nil for every line, and
2091 (flymake--tabulated-entries-1 (flymake-diagnostics) nil))))) 2098 ;; then removing the field description itself.
2092 2099 (cl-loop
2093(defvar flymake--diagnostics-base-tabulated-list-format 2100 for entry in data
2094 `[("Line" 5 ,(lambda (l1 l2) 2101 do (setf (cadr entry) (cl-loop for x across (cadr entry)
2095 (< (plist-get (car l1) :line) 2102 for y across fields
2096 (plist-get (car l2) :line))) 2103 when (cadr y)
2097 :right-align t) 2104 vconcat (vector (or x "-")))))
2098 ("Col" 3 nil :right-align t) 2105 (setq tabulated-list-entries data
2099 ("Type" 8 ,(lambda (l1 l2) 2106 tabulated-list-format
2100 (< (plist-get (car l1) :severity) 2107 (cl-loop for y across fields
2101 (plist-get (car l2) :severity)))) 2108 when (cadr y) vconcat (vector y)))))
2102 ("Origin" 8 t) 2109
2103 ("Message" 0 t)]) 2110(defun flymake--tabulated-setup (use-project)
2111 "Helper for `flymake-diagnostics-buffer-mode'.
2112And also `flymake-project-diagnostics-mode'."
2113 (let ((saved-r-b-f revert-buffer-function)
2114 (refresh
2115 (lambda ()
2116 (cond
2117 (use-project
2118 (let ((p (project-current)))
2119 (flymake--tabulated-setup-1
2120 (flymake--project-diagnostics p)
2121 (project-root p))))
2122 (t
2123 ;; Do nothing if 'flymake--diagnostics-buffer-source' has
2124 ;; not yet been set to a valid buffer. This could happen
2125 ;; when this function is called too early. For example
2126 ;; 'global-display-line-numbers-mode' calls us from its
2127 ;; mode hook, when the diagnostic buffer has just been
2128 ;; created by 'flymake-show-buffer-diagnostics', but is not
2129 ;; yet set up properly (Bug#40529).
2130 (flymake--tabulated-setup-1
2131 (and (bufferp flymake--diagnostics-buffer-source)
2132 (with-current-buffer flymake--diagnostics-buffer-source
2133 (and flymake-mode
2134 (flymake-diagnostics))))
2135 nil)))
2136 (tabulated-list-init-header))))
2137 (setq revert-buffer-function
2138 (lambda (&rest args)
2139 (funcall refresh)
2140 (apply saved-r-b-f args)))))
2104 2141
2105(define-derived-mode flymake-diagnostics-buffer-mode tabulated-list-mode 2142(define-derived-mode flymake-diagnostics-buffer-mode tabulated-list-mode
2106 "Flymake diagnostics" 2143 "Flymake diagnostics"
2107 "A mode for listing Flymake diagnostics." 2144 "A mode for listing Flymake diagnostics."
2108 :interactive nil 2145 :interactive nil
2109 (setq tabulated-list-format flymake--diagnostics-base-tabulated-list-format) 2146 (flymake--tabulated-setup nil))
2110 (setq tabulated-list-entries
2111 'flymake--diagnostics-buffer-entries)
2112 (tabulated-list-init-header))
2113 2147
2114(defun flymake--diagnostics-buffer-name () 2148(defun flymake--diagnostics-buffer-name ()
2115 (format "*Flymake diagnostics for `%s'*" (current-buffer))) 2149 (format "*Flymake diagnostics for `%s'*" (current-buffer)))
@@ -2117,6 +2151,9 @@ buffer."
2117(define-obsolete-function-alias 'flymake-show-diagnostics-buffer 2151(define-obsolete-function-alias 'flymake-show-diagnostics-buffer
2118 'flymake-show-buffer-diagnostics "1.2.1") 2152 'flymake-show-buffer-diagnostics "1.2.1")
2119 2153
2154(defun flymake--fit-diagnostics-window (window)
2155 (fit-window-to-buffer window 15 8))
2156
2120(defun flymake-show-buffer-diagnostics (&optional diagnostic) 2157(defun flymake-show-buffer-diagnostics (&optional diagnostic)
2121 "Show a list of Flymake diagnostics for current buffer." 2158 "Show a list of Flymake diagnostics for current buffer."
2122 (interactive) 2159 (interactive)
@@ -2134,8 +2171,7 @@ buffer."
2134 (display-buffer (current-buffer) 2171 (display-buffer (current-buffer)
2135 `((display-buffer-reuse-window 2172 `((display-buffer-reuse-window
2136 display-buffer-below-selected) 2173 display-buffer-below-selected)
2137 (window-height . (lambda (window) 2174 (window-height . flymake--fit-diagnostics-window)))
2138 (fit-window-to-buffer window 10)))))
2139 (when (and diagnostic flymake-after-show-buffer-diagnostics-hook) 2175 (when (and diagnostic flymake-after-show-buffer-diagnostics-hook)
2140 (goto-char (point-min)) 2176 (goto-char (point-min))
2141 (catch 'done 2177 (catch 'done
@@ -2174,14 +2210,9 @@ some of this variable's contents the diagnostic listings.")
2174 2210
2175(define-derived-mode flymake-project-diagnostics-mode tabulated-list-mode 2211(define-derived-mode flymake-project-diagnostics-mode tabulated-list-mode
2176 "Flymake diagnostics" 2212 "Flymake diagnostics"
2177 "A mode for listing Flymake diagnostics." 2213 "A mode for listing Flymake diagnostics in a project."
2178 :interactive nil 2214 :interactive nil
2179 (setq tabulated-list-format 2215 (flymake--tabulated-setup t))
2180 (vconcat [("File" 25 t)]
2181 flymake--diagnostics-base-tabulated-list-format))
2182 (setq tabulated-list-entries
2183 'flymake--project-diagnostics-entries)
2184 (tabulated-list-init-header))
2185 2216
2186(cl-defun flymake--project-diagnostics (&optional (project (project-current))) 2217(cl-defun flymake--project-diagnostics (&optional (project (project-current)))
2187 "Get all known relevant diagnostics for PROJECT." 2218 "Get all known relevant diagnostics for PROJECT."
@@ -2226,11 +2257,6 @@ some of this variable's contents the diagnostic listings.")
2226 append diags)) 2257 append diags))
2227 (append buffer-annotated-diags relevant-foreign-diags list-only-diags))) 2258 (append buffer-annotated-diags relevant-foreign-diags list-only-diags)))
2228 2259
2229(defun flymake--project-diagnostics-entries ()
2230 (let ((p (project-current)))
2231 (flymake--tabulated-entries-1 (flymake--project-diagnostics p)
2232 (project-root p))))
2233
2234(defun flymake--project-diagnostics-buffer (root) 2260(defun flymake--project-diagnostics-buffer (root)
2235 (get-buffer-create (format "*Flymake diagnostics for `%s'*" root))) 2261 (get-buffer-create (format "*Flymake diagnostics for `%s'*" root)))
2236 2262
@@ -2247,7 +2273,7 @@ some of this variable's contents the diagnostic listings.")
2247 (display-buffer (current-buffer) 2273 (display-buffer (current-buffer)
2248 `((display-buffer-reuse-window 2274 `((display-buffer-reuse-window
2249 display-buffer-at-bottom) 2275 display-buffer-at-bottom)
2250 (window-height . fit-window-to-buffer)))))) 2276 (window-height . flymake--fit-diagnostics-window))))))
2251 2277
2252(defun flymake--update-diagnostics-listings (buffer) 2278(defun flymake--update-diagnostics-listings (buffer)
2253 "Update diagnostics listings somehow relevant to BUFFER." 2279 "Update diagnostics listings somehow relevant to BUFFER."