Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
5.6 KiB

  1. ;;; flycheck-meghanada.el --- Flycheck support for meghanada -*- coding: utf-8; lexical-binding: t -*-
  2. ;; Copyright (C) 2017 Yutaka Matsubara
  3. ;; License: http://www.gnu.org/licenses/gpl.html
  4. ;; This program is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. ;;; Commentary:
  15. ;;
  16. ;; The `flycheck-meghanada' provides `flycheck-chcker' for java.
  17. ;;; Code:
  18. (eval-when-compile
  19. (require 'pcase))
  20. (require 'flycheck)
  21. (require 'meghanada)
  22. (require 'cl-lib)
  23. (defgroup flycheck-meghanada nil
  24. "Meghanada mode's flycheck checker."
  25. :group 'meghanada)
  26. (defcustom flycheck-meghanada-enable-live-check t
  27. "If true, check the buffer immediately after a new line or a short time."
  28. :group 'flycheck-meghanada
  29. :type 'boolean)
  30. (defcustom flycheck-meghanada-java-encoding 'utf-8
  31. "The default java compilation encoding."
  32. :group 'flycheck-meghanada
  33. :type 'symbol)
  34. (defun flycheck-meghanada--build-error (diagnostic checker buffer)
  35. (let* ((severity (intern (nth 2 diagnostic))))
  36. (when (memq severity '(NOTE MANDATORY_WARNING WARNING ERROR FATAL OTHER))
  37. (flycheck-error-new-at
  38. (nth 0 diagnostic)
  39. (nth 1 diagnostic)
  40. (pcase severity
  41. (`NOTE 'info)
  42. (`WARNING 'warning)
  43. (`MANDATORY_WARNING 'warning)
  44. ((or `ERROR `FATAL `OTHER) 'error))
  45. (nth 3 diagnostic)
  46. :checker checker
  47. :buffer buffer
  48. :filename (buffer-file-name buffer)))))
  49. (defun flycheck-meghanada--build-errors (buffer result callback checker)
  50. (mapc (lambda (r)
  51. (let ((file (nth 0 r))
  52. (diagnostics (nth 1 r)))
  53. (with-current-buffer (find-file-noselect file)
  54. (let* ((file-buf (current-buffer))
  55. (errors (mapcar (lambda (d)
  56. (flycheck-meghanada--build-error d checker file-buf))
  57. diagnostics)))
  58. (when (eq file-buf buffer)
  59. (funcall callback 'finished (delq nil errors)))))))
  60. result))
  61. (defun flycheck-meghanada--decode-diagnostics (diagnostics)
  62. (let (result result-errors file errors err msg)
  63. (setq result '())
  64. (dolist (buffer-errors diagnostics)
  65. (setq file (car buffer-errors))
  66. (setq errors (car (cdr buffer-errors)))
  67. (setq result-errors '())
  68. (dolist (err errors)
  69. (setq msg (decode-coding-string
  70. (encode-coding-string (car (last err)) flycheck-meghanada-java-encoding)
  71. 'utf-8))
  72. (cl-pushnew (append (cl-subseq err 0 -1) (list msg)) result-errors))
  73. (cl-pushnew (list file result-errors) result))
  74. result))
  75. (defun flycheck-meghanada--callback (result &rest args)
  76. (let* ((callback (nth 0 args))
  77. (checker (nth 1 args))
  78. (buffer (nth 2 args))
  79. (type (car result))
  80. (diagnostics (car (cdr result))))
  81. (pcase type
  82. (`fatal (funcall callback 'errored '("Meghanada diagnostics fatal error")))
  83. (`success (funcall callback 'finished nil))
  84. (`error (flycheck-meghanada--build-errors buffer (if (eq flycheck-meghanada-java-encoding 'utf-8) diagnostics (flycheck-meghanada--decode-diagnostics diagnostics)) callback checker))
  85. (_ (progn
  86. (message "WARN not match type")
  87. (funcall callback 'finished nil))))))
  88. (defun flycheck-meghanada--start (checker callback)
  89. (let ((buffer (current-buffer)))
  90. (meghanada-diagnostics-async
  91. (list #'flycheck-meghanada--callback callback checker buffer))))
  92. (defun flycheck-meghanada-live--start (checker callback)
  93. (let ((buffer (current-buffer)))
  94. (meghanada-diagnostic-string-async
  95. (list #'flycheck-meghanada--callback callback checker buffer))))
  96. (defun flycheck-meghanada-after-hook ()
  97. (let* ((errors flycheck-current-errors)
  98. (current (current-buffer))
  99. (new-error
  100. (cl-remove-if-not
  101. (lambda(e)
  102. (let ((err-buf (flycheck-error-buffer e)))
  103. (eq err-buf current))) errors)))
  104. (setq flycheck-current-errors new-error)))
  105. (flycheck-define-generic-checker 'meghanada
  106. "A syntax checker for java, using meghanada-mode."
  107. :start #'flycheck-meghanada--start
  108. :modes '(java-mode)
  109. :predicate (lambda ()
  110. (and (meghanada-alive-p)
  111. (flycheck-buffer-saved-p))))
  112. (flycheck-define-generic-checker 'meghanada-live
  113. "A syntax checker for java, using meghanada-mode."
  114. :start #'flycheck-meghanada-live--start
  115. :modes '(java-mode)
  116. :predicate (lambda ()
  117. (and (meghanada-alive-p)
  118. (not (flycheck-buffer-empty-p))))
  119. :verify (lambda (_)
  120. (list
  121. (flycheck-verification-result-new
  122. :label "Meghanada server"
  123. :message (if (meghanada-alive-p) "Running" "Not Running")
  124. :face (if (meghanada-alive-p) 'success '(bold error))))))
  125. ;;;###autoload
  126. (defun meghanada-flycheck-enable ()
  127. "Enable flycheck for meghanada-mode."
  128. (if flycheck-meghanada-enable-live-check
  129. (add-to-list 'flycheck-checkers 'meghanada-live)
  130. (add-to-list 'flycheck-checkers 'meghanada)))
  131. (provide 'flycheck-meghanada)
  132. ;;; flycheck-meghanada.el ends here