Skip to content

Commit 48f1d0f

Browse files
authored
Integration of lsp-mode diagnostics with dired (#2616)
Pretty much all of the code is stolen from @Alexander-Miller's `treemacs-icons-dired`
1 parent 8166a1f commit 48f1d0f

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

lsp-dired.el

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
;;; lsp-dired.el --- `lsp-mode' diagnostics integrated into `dired' -*- lexical-binding: t -*-
2+
3+
;; Copyright (C) 2021
4+
5+
;; Author: Alexander Miller <[email protected]>
6+
;; Author: Ivan Yonchovski <[email protected]>
7+
8+
;; This program is free software; you can redistribute it and/or modify
9+
;; it under the terms of the GNU General Public License as published by
10+
;; the Free Software Foundation, either version 3 of the License, or
11+
;; (at your option) any later version.
12+
13+
;; This program is distributed in the hope that it will be useful,
14+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
;; GNU General Public License for more details.
17+
18+
;; You should have received a copy of the GNU General Public License
19+
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
21+
;;; Commentary:
22+
;;; `lsp-mode' diagnostics integrated into `dired'
23+
24+
;;; Code:
25+
26+
(require 'dired)
27+
(require 'pcase)
28+
(require 'lsp-mode)
29+
30+
(defvar lsp-dired--ranger-adjust nil)
31+
(with-eval-after-load 'ranger (setf lsp-dired--ranger-adjust t))
32+
33+
(defvar-local lsp-dired-displayed nil
34+
"Flags whether icons have been added.")
35+
36+
(defvar-local lsp-dired--covered-subdirs nil
37+
"List of subdirs icons were already added for.")
38+
39+
(defun lsp-dired--display ()
40+
"Display the icons of files in a dired buffer."
41+
(when (and (display-graphic-p)
42+
(not lsp-dired-displayed)
43+
dired-subdir-alist)
44+
(setq-local lsp-dired-displayed t)
45+
(pcase-dolist (`(,path . ,pos) dired-subdir-alist)
46+
(lsp-dired--insert-for-subdir path pos))))
47+
48+
(defun lsp-dired--insert-for-subdir (path pos)
49+
"Display icons for subdir PATH at given POS."
50+
(let ((buf (current-buffer)))
51+
;; run the function after current to make sure that we are creating the
52+
;; overlays after `treemacs-icons-dired' has run.
53+
(run-with-idle-timer
54+
0.0 nil
55+
(lambda ()
56+
(unless (and (member path lsp-dired--covered-subdirs)
57+
(not (buffer-live-p buf)))
58+
(with-current-buffer buf
59+
(add-to-list 'lsp-dired--covered-subdirs path)
60+
(let (buffer-read-only)
61+
(save-excursion
62+
(goto-char pos)
63+
(forward-line (if lsp-dired--ranger-adjust 1 2))
64+
(cl-block :file
65+
(while (not (eobp))
66+
(if (dired-move-to-filename nil)
67+
(let* ((file (dired-get-filename nil t))
68+
(bol (progn
69+
(point-at-bol)
70+
(search-forward-regexp "^[[:space:]]*" (line-end-position) t)
71+
(point)))
72+
(face (lsp-dired--face-for-path file)))
73+
(when face
74+
(-doto (make-overlay bol (point-at-eol))
75+
(overlay-put 'evaporate t)
76+
(overlay-put 'face face))))
77+
(cl-return-from :file nil))
78+
(forward-line 1)))))))))))
79+
80+
(defface lsp-dired-path-face '((t :inherit font-lock-string-face))
81+
"Face used for breadcrumb paths on headerline."
82+
:group 'lsp-faces)
83+
84+
(defface lsp-dired-path-error-face
85+
'((t :underline (:style wave :color "Red1")))
86+
"Face used for breadcrumb paths on headerline when there is an error under that path"
87+
:group 'lsp-faces)
88+
89+
(defface lsp-dired-path-warning-face
90+
'((t :underline (:style wave :color "Yellow")))
91+
"Face used for breadcrumb paths on headerline when there is an warning under that path"
92+
:group 'lsp-faces)
93+
94+
(defface lsp-dired-path-info-face
95+
'((t :underline (:style wave :color "Green")))
96+
"Face used for breadcrumb paths on headerline when there is an info under that path"
97+
:group 'lsp-faces)
98+
99+
(defface lsp-dired-path-hint-face
100+
'((t :underline (:style wave :color "Green")))
101+
"Face used for breadcrumb paths on headerline when there is an hint under that path"
102+
:group 'lsp-faces)
103+
104+
(defun lsp-dired--face-for-path (dir)
105+
"Calculate the face for DIR."
106+
(when-let ((diags (lsp-diagnostics-stats-for (directory-file-name dir))))
107+
(cl-labels ((check-severity
108+
(severity)
109+
(not (zerop (aref diags severity)))))
110+
(cond
111+
((check-severity lsp/diagnostic-severity-error)
112+
'lsp-dired-path-error-face)
113+
((check-severity lsp/diagnostic-severity-warning)
114+
'lsp-dired-path-warning-face)
115+
((check-severity lsp/diagnostic-severity-information)
116+
'lsp-dired-path-info-face)
117+
((check-severity lsp/diagnostic-severity-hint)
118+
'lsp-dired-path-hint-face)))))
119+
120+
(defun lsp-dired--insert-subdir-advice (&rest args)
121+
"Advice to dired & dired+ insert-subdir commands.
122+
Will add icons for the subdir in the `car' of ARGS."
123+
(let* ((path (car args))
124+
(pos (cdr (assoc path dired-subdir-alist))))
125+
(when pos
126+
(lsp-dired--insert-for-subdir path pos))))
127+
128+
(defun lsp-dired--kill-subdir-advice (&rest _args)
129+
"Advice to dired kill-subdir commands.
130+
Will remove the killed subdir from `lsp-dired--covered-subdirs'."
131+
(setf lsp-dired--covered-subdirs (delete (dired-current-directory)
132+
lsp-dired--covered-subdirs)))
133+
134+
(defun lsp-dired--reset (&rest _args)
135+
"Reset metadata on revert."
136+
(setq-local lsp-dired--covered-subdirs nil)
137+
(setq-local lsp-dired-displayed nil))
138+
139+
;;;###autoload
140+
(define-minor-mode lsp-dired-mode
141+
"Display `lsp-mode' icons for each file in a dired buffer."
142+
:require 'lsp-dired
143+
:init-value nil
144+
:global t
145+
:group 'lsp-mode
146+
(cond
147+
(lsp-dired-mode
148+
(add-hook 'dired-after-readin-hook #'lsp-dired--display)
149+
(advice-add 'dired-kill-subdir :before #'lsp-dired--kill-subdir-advice)
150+
(advice-add 'dired-insert-subdir :after #'lsp-dired--insert-subdir-advice)
151+
(advice-add 'diredp-insert-subdirs :after #'lsp-dired--insert-subdir-advice)
152+
(advice-add 'dired-revert :before #'lsp-dired--reset)
153+
(dolist (buffer (buffer-list))
154+
(with-current-buffer buffer
155+
(when (derived-mode-p 'dired-mode)
156+
(lsp-dired--display)))))
157+
(t
158+
(advice-remove 'dired-kill-subdir #'lsp-dired--kill-subdir-advice)
159+
(advice-remove 'dired-insert-subdir #'lsp-dired--insert-subdir-advice)
160+
(advice-remove 'diredp-insert-subdirs #'lsp-dired--insert-subdir-advice)
161+
(advice-remove 'dired-revert #'lsp-dired--reset)
162+
(remove-hook 'dired-after-readin-hook #'lsp-dired--display)
163+
(dolist (buffer (buffer-list))
164+
(with-current-buffer buffer
165+
(when (derived-mode-p 'dired-mode)
166+
(dired-revert)))))))
167+
168+
(provide 'lsp-dired)
169+
170+
;;; lsp-dired.el ends here

0 commit comments

Comments
 (0)