diff options
| author | João Távora | 2017-09-27 02:31:58 +0100 |
|---|---|---|
| committer | João Távora | 2017-10-03 14:18:54 +0100 |
| commit | e0df7b9699539a6831dd7d72d6845d2995fb619e (patch) | |
| tree | f94fa89ece1463c79b0e015fa95f4d2fc12b9b9b | |
| parent | 73601787b45d08cdd5026ea36ff680bd49076950 (diff) | |
| download | emacs-e0df7b9699539a6831dd7d72d6845d2995fb619e.tar.gz emacs-e0df7b9699539a6831dd7d72d6845d2995fb619e.zip | |
Fancy Flymake mode-line construct displays status
Imitates compilation-mode's mode-line a bit, and uses its faces.
* lisp/progmodes/flymake.el
(flymake-error, flymake-warning, flymake-note): Add
mode-line-face to these flymake error types.
(flymake-note): Notes don't need a noisy fringe bitmap.
(flymake-lighter): Delete.
(flymake--update-lighter): Delete.
(flymake--mode-line-format): New function and variable.
(flymake--diagnostics-table): New buffer-local variable.
(flymake--handle-report): Don't update "lighters". Affect
flymake--diagnostics-table.
(flymake--run-backend): Init flymake--diagnostics-table for backend.
(flymake-mode): Use flymake--mode-line-format.
(flymake-mode): Don't update lighter.
(flymake--highlight-line): Be more careful when overriding a
nil default overlay property.
| -rw-r--r-- | lisp/progmodes/flymake.el | 134 |
1 files changed, 112 insertions, 22 deletions
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index f136e14ec19..03b319f8715 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el | |||
| @@ -35,7 +35,8 @@ | |||
| 35 | (require 'cl-lib) | 35 | (require 'cl-lib) |
| 36 | (require 'thingatpt) ; end-of-thing | 36 | (require 'thingatpt) ; end-of-thing |
| 37 | (require 'warnings) ; warning-numeric-level, display-warning | 37 | (require 'warnings) ; warning-numeric-level, display-warning |
| 38 | (eval-when-compile (require 'subr-x)) ; when-let*, if-let* | 38 | (require 'compile) ; for some faces |
| 39 | (eval-when-compile (require 'subr-x)) ; when-let*, if-let*, hash-table-keys | ||
| 39 | 40 | ||
| 40 | (defgroup flymake nil | 41 | (defgroup flymake nil |
| 41 | "Universal on-the-fly syntax checker." | 42 | "Universal on-the-fly syntax checker." |
| @@ -362,20 +363,23 @@ the diagnostics of each type. The recognized properties are: | |||
| 362 | (put 'flymake-error 'face 'flymake-error) | 363 | (put 'flymake-error 'face 'flymake-error) |
| 363 | (put 'flymake-error 'bitmap flymake-error-bitmap) | 364 | (put 'flymake-error 'bitmap flymake-error-bitmap) |
| 364 | (put 'flymake-error 'severity (warning-numeric-level :error)) | 365 | (put 'flymake-error 'severity (warning-numeric-level :error)) |
| 366 | (put 'flymake-error 'mode-line-face 'compilation-error) | ||
| 365 | 367 | ||
| 366 | (put 'flymake-warning 'face 'flymake-warning) | 368 | (put 'flymake-warning 'face 'flymake-warning) |
| 367 | (put 'flymake-warning 'bitmap flymake-warning-bitmap) | 369 | (put 'flymake-warning 'bitmap flymake-warning-bitmap) |
| 368 | (put 'flymake-warning 'severity (warning-numeric-level :warning)) | 370 | (put 'flymake-warning 'severity (warning-numeric-level :warning)) |
| 371 | (put 'flymake-warning 'mode-line-face 'compilation-warning) | ||
| 369 | 372 | ||
| 370 | (put 'flymake-note 'face 'flymake-note) | 373 | (put 'flymake-note 'face 'flymake-note) |
| 371 | (put 'flymake-note 'bitmap flymake-warning-bitmap) | 374 | (put 'flymake-note 'bitmap nil) |
| 372 | (put 'flymake-note 'severity (warning-numeric-level :debug)) | 375 | (put 'flymake-note 'severity (warning-numeric-level :debug)) |
| 376 | (put 'flymake-note 'mode-line-face 'compilation-info) | ||
| 373 | 377 | ||
| 374 | (defun flymake--lookup-type-property (type prop &optional default) | 378 | (defun flymake--lookup-type-property (type prop &optional default) |
| 375 | "Look up PROP for TYPE in `flymake-diagnostic-types-alist'. | 379 | "Look up PROP for TYPE in `flymake-diagnostic-types-alist'. |
| 376 | If TYPE doesn't declare PROP in either | 380 | If TYPE doesn't declare PROP in either |
| 377 | `flymake-diagnostic-types-alist' or its associated | 381 | `flymake-diagnostic-types-alist' or in the symbol of its |
| 378 | `flymake-category', return DEFAULT." | 382 | associated `flymake-category' return DEFAULT." |
| 379 | (let ((alist-probe (assoc type flymake-diagnostic-types-alist))) | 383 | (let ((alist-probe (assoc type flymake-diagnostic-types-alist))) |
| 380 | (cond (alist-probe | 384 | (cond (alist-probe |
| 381 | (let* ((alist (cdr alist-probe)) | 385 | (let* ((alist (cdr alist-probe)) |
| @@ -496,16 +500,6 @@ If TYPE doesn't declare PROP in either | |||
| 496 | ;; | 500 | ;; |
| 497 | (when choice (goto-char (overlay-start choice))))) | 501 | (when choice (goto-char (overlay-start choice))))) |
| 498 | 502 | ||
| 499 | ;; flymake minor mode declarations | ||
| 500 | (defvar-local flymake-lighter nil) | ||
| 501 | |||
| 502 | (defun flymake--update-lighter (info &optional extended) | ||
| 503 | "Update Flymake’s \"lighter\" with INFO and EXTENDED." | ||
| 504 | (setq flymake-lighter (format " Flymake(%s%s)" | ||
| 505 | info | ||
| 506 | (if extended | ||
| 507 | (format ",%s" extended) | ||
| 508 | "")))) | ||
| 509 | 503 | ||
| 510 | ;; Nothing in flymake uses this at all any more, so this is just for | 504 | ;; Nothing in flymake uses this at all any more, so this is just for |
| 511 | ;; third-party compatibility. | 505 | ;; third-party compatibility. |
| @@ -520,6 +514,9 @@ that has been invoked but hasn't reported any final status yet.") | |||
| 520 | "List of currently disabled flymake backends. | 514 | "List of currently disabled flymake backends. |
| 521 | A backend is disabled if it reported `:panic'.") | 515 | A backend is disabled if it reported `:panic'.") |
| 522 | 516 | ||
| 517 | (defvar-local flymake--diagnostics-table nil | ||
| 518 | "Hash table of all diagnostics indexed by backend.") | ||
| 519 | |||
| 523 | (defun flymake-is-running () | 520 | (defun flymake-is-running () |
| 524 | "Tell if flymake has running backends in this buffer" | 521 | "Tell if flymake has running backends in this buffer" |
| 525 | flymake--running-backends) | 522 | flymake--running-backends) |
| @@ -547,6 +544,7 @@ A backend is disabled if it reported `:panic'.") | |||
| 547 | (eq backend | 544 | (eq backend |
| 548 | (flymake--diag-backend | 545 | (flymake--diag-backend |
| 549 | (overlay-get ov 'flymake--diagnostic))))) | 546 | (overlay-get ov 'flymake--diagnostic))))) |
| 547 | (puthash backend diagnostics flymake--diagnostics-table) | ||
| 550 | (mapc (lambda (diag) | 548 | (mapc (lambda (diag) |
| 551 | (flymake--highlight-line diag) | 549 | (flymake--highlight-line diag) |
| 552 | (setf (flymake--diag-backend diag) backend)) | 550 | (setf (flymake--diag-backend diag) backend)) |
| @@ -557,11 +555,7 @@ A backend is disabled if it reported `:panic'.") | |||
| 557 | (when flymake-check-start-time | 555 | (when flymake-check-start-time |
| 558 | (flymake-log 2 "%d error(s), %d other(s) in %.2f second(s)" | 556 | (flymake-log 2 "%d error(s), %d other(s) in %.2f second(s)" |
| 559 | err-count warn-count | 557 | err-count warn-count |
| 560 | (- (float-time) flymake-check-start-time))) | 558 | (- (float-time) flymake-check-start-time))))))) |
| 561 | (if (null diagnostics) | ||
| 562 | (flymake--update-lighter "[ok]") | ||
| 563 | (flymake--update-lighter | ||
| 564 | (format "%d/%d" err-count warn-count))))))) | ||
| 565 | (t | 559 | (t |
| 566 | (flymake--disable-backend "?" | 560 | (flymake--disable-backend "?" |
| 567 | :strange | 561 | :strange |
| @@ -584,6 +578,7 @@ sources." | |||
| 584 | (defun flymake--run-backend (backend) | 578 | (defun flymake--run-backend (backend) |
| 585 | "Run the backend BACKEND." | 579 | "Run the backend BACKEND." |
| 586 | (push backend flymake--running-backends) | 580 | (push backend flymake--running-backends) |
| 581 | (remhash backend flymake--diagnostics-table) | ||
| 587 | ;; FIXME: Should use `condition-case-unless-debug' | 582 | ;; FIXME: Should use `condition-case-unless-debug' |
| 588 | ;; here, but that won't let me catch errors during | 583 | ;; here, but that won't let me catch errors during |
| 589 | ;; testing where `debug-on-error' is always t | 584 | ;; testing where `debug-on-error' is always t |
| @@ -621,7 +616,7 @@ non-nil." | |||
| 621 | 616 | ||
| 622 | ;;;###autoload | 617 | ;;;###autoload |
| 623 | (define-minor-mode flymake-mode nil | 618 | (define-minor-mode flymake-mode nil |
| 624 | :group 'flymake :lighter flymake-lighter | 619 | :group 'flymake :lighter flymake--mode-line-format |
| 625 | (setq flymake--running-backends nil | 620 | (setq flymake--running-backends nil |
| 626 | flymake--disabled-backends nil) | 621 | flymake--disabled-backends nil) |
| 627 | (cond | 622 | (cond |
| @@ -635,10 +630,9 @@ non-nil." | |||
| 635 | (add-hook 'after-save-hook 'flymake-after-save-hook nil t) | 630 | (add-hook 'after-save-hook 'flymake-after-save-hook nil t) |
| 636 | (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) | 631 | (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) |
| 637 | 632 | ||
| 638 | (flymake--update-lighter "*" "*") | ||
| 639 | |||
| 640 | (setq flymake-timer | 633 | (setq flymake-timer |
| 641 | (run-at-time nil 1 'flymake-on-timer-event (current-buffer))) | 634 | (run-at-time nil 1 'flymake-on-timer-event (current-buffer))) |
| 635 | (setq flymake--diagnostics-table (make-hash-table)) | ||
| 642 | 636 | ||
| 643 | (when flymake-start-syntax-check-on-find-file | 637 | (when flymake-start-syntax-check-on-find-file |
| 644 | (flymake--start-syntax-check))))) | 638 | (flymake--start-syntax-check))))) |
| @@ -757,6 +751,102 @@ diagnostics of type `:error' and `:warning'." | |||
| 757 | t)) | 751 | t)) |
| 758 | (flymake-goto-next-error (- (or n 1)) filter interactive)) | 752 | (flymake-goto-next-error (- (or n 1)) filter interactive)) |
| 759 | 753 | ||
| 754 | |||
| 755 | ;;; Mode-line fanciness | ||
| 756 | ;;; | ||
| 757 | (defvar flymake--mode-line-format `(:eval (flymake--mode-line-format))) | ||
| 758 | |||
| 759 | (put 'flymake--mode-line-format 'risky-local-variable t) | ||
| 760 | |||
| 761 | (defun flymake--mode-line-format () | ||
| 762 | "Produce a pretty minor mode indicator." | ||
| 763 | (let ((running flymake--running-backends) | ||
| 764 | (reported (hash-table-keys flymake--diagnostics-table))) | ||
| 765 | `((:propertize " Flymake" | ||
| 766 | mouse-face mode-line-highlight | ||
| 767 | ,@(when (not reported) | ||
| 768 | `(face compilation-mode-line-fail)) | ||
| 769 | help-echo | ||
| 770 | ,(concat (format "%s registered backends\n" | ||
| 771 | (length flymake-diagnostic-functions)) | ||
| 772 | (format "%s running\n" | ||
| 773 | (length running)) | ||
| 774 | (format "%s disabled\n" | ||
| 775 | (length flymake--disabled-backends)) | ||
| 776 | "mouse-1: go to log buffer ") | ||
| 777 | keymap | ||
| 778 | ,(let ((map (make-sparse-keymap))) | ||
| 779 | (define-key map [mode-line mouse-1] | ||
| 780 | (lambda (_event) | ||
| 781 | (interactive "e") | ||
| 782 | (switch-to-buffer "*Flymake log*"))) | ||
| 783 | map)) | ||
| 784 | ,@(when running | ||
| 785 | `(":" (:propertize "Run" | ||
| 786 | face compilation-mode-line-run | ||
| 787 | help-echo | ||
| 788 | ,(format "%s running backends" | ||
| 789 | (length running))))) | ||
| 790 | ,@(when reported | ||
| 791 | (let ((by-type (make-hash-table))) | ||
| 792 | (maphash (lambda (_backend diags) | ||
| 793 | (mapc (lambda (diag) | ||
| 794 | (push diag | ||
| 795 | (gethash (flymake--diag-type diag) | ||
| 796 | by-type))) | ||
| 797 | diags)) | ||
| 798 | flymake--diagnostics-table) | ||
| 799 | (cl-loop | ||
| 800 | for (type . severity) | ||
| 801 | in (cl-sort (mapcar (lambda (type) | ||
| 802 | (cons type (flymake--lookup-type-property | ||
| 803 | type | ||
| 804 | 'severity | ||
| 805 | (warning-numeric-level :error)))) | ||
| 806 | (cl-union (hash-table-keys by-type) | ||
| 807 | '(:error :warning))) | ||
| 808 | #'> | ||
| 809 | :key #'cdr) | ||
| 810 | for diags = (gethash type by-type) | ||
| 811 | for face = (flymake--lookup-type-property type | ||
| 812 | 'mode-line-face | ||
| 813 | 'compilation-error) | ||
| 814 | when (or diags | ||
| 815 | (>= severity (warning-numeric-level :warning))) | ||
| 816 | collect `(:propertize | ||
| 817 | ,(format "%d" (length diags)) | ||
| 818 | face ,face | ||
| 819 | mouse-face mode-line-highlight | ||
| 820 | keymap | ||
| 821 | ,(let ((map (make-sparse-keymap)) | ||
| 822 | (type type)) | ||
| 823 | (define-key map [mode-line mouse-4] | ||
| 824 | (lambda (_event) | ||
| 825 | (interactive "e") | ||
| 826 | (flymake-goto-prev-error 1 (list type) t))) | ||
| 827 | (define-key map [mode-line mouse-5] | ||
| 828 | (lambda (_event) | ||
| 829 | (interactive "e") | ||
| 830 | (flymake-goto-next-error 1 (list type) t))) | ||
| 831 | map) | ||
| 832 | help-echo | ||
| 833 | ,(concat (format "%s diagnostics of type %s\n" | ||
| 834 | (propertize (format "%d" | ||
| 835 | (length diags)) | ||
| 836 | 'face face) | ||
| 837 | (propertize (format "%s" type) | ||
| 838 | 'face face)) | ||
| 839 | "mouse-4/mouse-5: previous/next of this type\n")) | ||
| 840 | into forms | ||
| 841 | finally return | ||
| 842 | `((:propertize "[") | ||
| 843 | ,@(cl-loop for (a . rest) on forms by #'cdr | ||
| 844 | collect a when rest collect | ||
| 845 | '(:propertize " ")) | ||
| 846 | (:propertize "]")))))))) | ||
| 847 | |||
| 848 | |||
| 849 | |||
| 760 | 850 | ||
| 761 | (provide 'flymake) | 851 | (provide 'flymake) |
| 762 | 852 | ||