PageRenderTime 35ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/elisp/erlang-compile-server.el

https://github.com/altrg/distel
Emacs Lisp | 627 lines | 471 code | 112 blank | 44 comment | 25 complexity | 88db0e9164001fdf27fdd0477c98c57a MD5 | raw file
  1. ;;;-------------------------------------------------------------
  2. ;;; File : erlang-compile-server.el
  3. ;;; Author : Sebastian Weddmark Olsson
  4. ;;; github.com/sebastiw
  5. ;;; Purpose : Used with distel to mark compilation/xref/dialyzer
  6. ;;; & eunit errors and warnings while writing, in the
  7. ;;; current buffer.
  8. ;;;
  9. ;;; Created : June 2012 as an internship at Klarna AB
  10. ;;; Comment : Please let me know if you find any bugs or you
  11. ;;; want some feature or something
  12. ;;;------------------------------------------------------------
  13. (require 'distel)
  14. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  15. ;; Defvars and initialization ;;
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17. ;; Customization
  18. (defvar erl-ecs-backends '(compiler xref dialyzer eunit)
  19. "These backends will be activated.")
  20. (defcustom erl-ecs-enable-eunit t
  21. "If non-nil also checks the eunit tests in the module-file."
  22. :type '(boolean)
  23. :group 'erl-ecs)
  24. (defcustom erl-ecs-enable-xref t
  25. "If non-nil also checks for exported functions that isn't used externally through xref."
  26. :type '(boolean)
  27. :group 'erl-ecs)
  28. (defcustom erl-ecs-enable-dialyzer t
  29. "If non-nil also checks Dialyzer for type warnings."
  30. :type '(boolean)
  31. :group 'erl-ecs)
  32. (defcustom erl-ecs-check-on-save t
  33. "Checks errors and warnings on save."
  34. :type '(boolean)
  35. :group 'erl-ecs)
  36. (defcustom erl-ecs-compile-if-ok nil
  37. "Compiles the module if it doesn't have any errors or warnings."
  38. :type '(boolean)
  39. :group 'erl-ecs)
  40. (defcustom erl-ecs-verbose nil
  41. "Writes output to *Messages* buffer."
  42. :type '(boolean)
  43. :group 'erl-ecs)
  44. (defcustom erl-ecs-cut-at-mouseover 100
  45. "The distance between the newlines for the message when hovering over at an error."
  46. :type '(number)
  47. :group 'erl-ecs)
  48. (defcustom erl-ecs-cut-at-distance 200
  49. "When inserting a newline, this is the distance between the insertions."
  50. :type '(number)
  51. :group 'erl-ecs)
  52. (defcustom erl-ecs-check-on-interval nil
  53. "Checks errors and warnings on given intervals."
  54. :type '(boolean)
  55. :group 'erl-ecs)
  56. (defcustom erl-ecs-interval 120
  57. "Seconds between checks if `erl-ecs-check-on-interval' is set."
  58. :type '(integer)
  59. :group 'erl-ecs)
  60. (defvar erl-ecs-timer '()
  61. "Holds the timer as soon as it is started.")
  62. (defvar erl-ecs-compile-options '()
  63. "A list of compile options that should be run when testing and compiling.
  64. For more info, check out the variable `erlang-compile-extra-opts'.")
  65. (defvar erl-ecs-compile-includes '()
  66. "A list of compile include paths that should be run when testing and compiling.")
  67. ;;; Error lists
  68. (defvar erl-ecs-error-list '())
  69. (defvar erl-ecs-eunit-list '())
  70. (defvar erl-ecs-xref-list '())
  71. (defvar erl-ecs-dialyzer-list '())
  72. (defvar erl-ecs-user-specified-errors '()
  73. "Must be a list of tuples with lineno, type and an error tuple.
  74. Erlang example: [{35, warning, {err_type, \"There is a cat in the ceiling.\"}}],
  75. Elisp : (list (tuple 35 'warning (tuple err_type \"There is a cat in the ceiling.\"))).")
  76. (defvar erl-ecs-lineno-list '()
  77. "Short list, specifies which linenumber the errors appear on and what type of error.")
  78. (defvar erl-ecs-before-eval-hooks '())
  79. (defvar erl-ecs-after-eval-hooks '())
  80. ;; Faces for highlighting
  81. (defface erl-ecs-error-line
  82. '((((class color) (background dark)) (:background "Firebrick"))
  83. (((class color) (background light)) (:background "LightPink1"))
  84. (t (:bold t)))
  85. "Face used for marking error lines."
  86. :group 'erl-ecs)
  87. (defface erl-ecs-warning-line
  88. '((((class color) (background dark)) (:background "dark blue"))
  89. (((class color) (background light)) (:background "light blue"))
  90. (t (:bold t)))
  91. "Face used for marking warning lines."
  92. :group 'erl-ecs)
  93. (defface erl-ecs-lesser-line
  94. '((((class color) (background dark)) (:background "dark olive green"))
  95. (((class color) (background light)) (:background "pale green"))
  96. (t (:bold t)))
  97. "Face used for marking lesser warning lines."
  98. :group 'erl-ecs)
  99. (defface erl-ecs-user-specified-line
  100. '((((class color) (background dark)) (:background "orange red"))
  101. (((class color) (background light)) (:background "yellow"))
  102. (t (:bold t)))
  103. "Face used for marking lesser warning lines."
  104. :group 'erl-ecs)
  105. (defvar erl-node-isup nil
  106. "To track if the node is up or not.")
  107. ;; Check that module is loaded else load it
  108. (add-hook 'erl-nodeup-hook 'erl-ecs-check-backend)
  109. (add-hook 'erl-nodedown-hook 'erl-ecs-nodedown)
  110. (defun erl-ecs-check-backend (node _fsm)
  111. "Reloads 'erlang_compile_server' module to `node'."
  112. (setq erl-node-isup t)
  113. (unless distel-inhibit-backend-check
  114. (progn (erl-ecs-message "ECS: reloading 'erlang_compile_server' onto %s" node)
  115. (erl-spawn
  116. (erl-send `[rex ,node]
  117. `[,erl-self [call
  118. code load_file (erlang_compile_server)
  119. ,(erl-group-leader)]])
  120. (erl-receive (node)
  121. ((['rex ['error _]]
  122. (&erl-load-backend node))
  123. (_ t)))))))
  124. (defun erl-ecs-nodedown (node)
  125. "Track if the node goes down."
  126. (setq erl-node-isup))
  127. (defun erl-ecs-setup ()
  128. (add-hook 'erlang-mode-hook 'erl-ecs-mode-hook)
  129. ;; for now, just set the enables on each backend
  130. (unless (member 'xref erl-ecs-backends) (setq erl-ecs-enable-xref nil))
  131. (unless (member 'eunit erl-ecs-backends) (setq erl-ecs-enable-eunit nil))
  132. (unless (member 'dialyzer erl-ecs-backends) (setq erl-ecs-enable-dialyzer nil))
  133. (erl-ecs-message "ECS loaded.")
  134. (when erl-ecs-check-on-interval (erl-ecs-start-interval)))
  135. (defun erl-ecs-mode-hook ()
  136. (erl-ecs-mode t)
  137. (add-hook 'after-save-hook 'erl-ecs-on-save t t))
  138. (defun erl-ecs-on-save ()
  139. "Check for warnings on save."
  140. (when erl-ecs-check-on-save (erl-ecs-evaluate)))
  141. (define-minor-mode erl-ecs-mode
  142. "Extends distel with error evaluation.
  143. Add the following lines to your .emacs file (after distel is initialized):
  144. \(require 'erlang-compile-server)
  145. And then set one or more of the following variables (defaults):
  146. `erl-ecs-backends' (compiler xref dialyzer eunit)
  147. `erl-ecs-check-on-save' (t) - check on save
  148. `erl-ecs-compile-if-ok' (nil) - if no compile fails, compile
  149. `erl-ecs-verbose' (nil) - prints alot of messages
  150. `erl-ecs-check-on-interval' (nil) (not supported yet)
  151. `erl-ecs-interval' (120) (not supported yet)
  152. `erl-ecs-compile-options' (nil) - to specify what extra compile options to be runned
  153. `erl-ecs-compile-includes' (nil) - to specify what compile include paths to be used
  154. `erl-ecs-user-specified-errors' (nil) - specify own errors, must be a list of tuples of lineno, type,and error tuple
  155. For custom colors define the faces:
  156. `erl-ecs-error-line', `erl-ecs-warning-line', `erl-ecs-lesser-line' and `erl-ecs-user-specified-line'
  157. Bindings:
  158. \\[erl-ecs-evaluate] - check for errors/warnings/testfails etc
  159. \\[erl-ecs-next-error] - goto next error
  160. \\[erl-ecs-prev-error] - goto previous error"
  161. :lighter " ECS"
  162. :keymap '(("\C-c\C-dq" undefined))
  163. (if erl-ecs-mode
  164. (progn (setq erl-ecs-temp-output erl-popup-on-output
  165. erl-popup-on-output)
  166. (ad-activate-regexp "erl-ecs-.*"))
  167. (setq erl-popup-on-output erl-ecs-temp-output)
  168. (ad-deactivate-regexp "erl-ecs-.*")))
  169. (defadvice next-line (after erl-ecs-next-line)
  170. "Moves point to the next line using `next-line' and then prints the error if there is one."
  171. (when erl-ecs-mode (erl-ecs-show-error-on-line)))
  172. (defadvice previous-line (after erl-ecs-previous-line)
  173. "Moves point to previous line and prints error if there is one."
  174. (when erl-ecs-mode (erl-ecs-show-error-on-line)))
  175. (defadvice forward-paragraph (after erl-ecs-next-paragraph)
  176. "Next paragraph, then check and print if there is errors."
  177. (when erl-ecs-mode (erl-ecs-show-error-on-line)))
  178. (defadvice backward-paragraph (after erl-ecs-previous-paragraph)
  179. "Previous paragraph, check if there is errors."
  180. (when erl-ecs-mode (erl-ecs-show-error-on-line)))
  181. (defconst erl-ecs-key-binding
  182. '(("\C-c\C-dq" erl-ecs-evaluate)
  183. ("\C-c\C-n" erl-ecs-next-error)
  184. ("\C-c\C-p" erl-ecs-prev-error))
  185. "Erlang compile server key binding")
  186. ;; rebinds the keys
  187. (dolist (k erl-ecs-key-binding) (define-key erl-ecs-mode-map (car k) (cadr k)))
  188. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  189. ;; Main ;;
  190. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  191. (defvar erl-ecs-temp-output nil
  192. "Take care of the original value of the variable `erl-popup-on-output'. This is to keep eunit from popup and leave unwanted output.")
  193. (defvar erl-ecs-have-already-run-once nil
  194. "If the evaluation function have already been run one time, and you are still not connected, it should stop evaluate.")
  195. (defconst erl-ecs-xref-string "Xref")
  196. (defconst erl-ecs-dialyzer-string "Dialyzer")
  197. (defconst erl-ecs-eunit-string "Eunit")
  198. (defconst erl-ecs-default-string "Erlang")
  199. (defconst erl-ecs-user-specified-string "User specified")
  200. (defun erl-ecs-evaluate ()
  201. "Checks for errors in current buffer. If this function have been executed and the node wasn't up, you need to connect with distels ping command \\[erl-ping]."
  202. (interactive)
  203. (when (and
  204. erl-ecs-mode
  205. (or (not erl-ecs-have-already-run-once) erl-node-isup))
  206. (setq erl-ecs-current-buffer (current-buffer)
  207. erl-ecs-have-already-run-once t)
  208. (erl-ecs-message "ECS: Evaluating...")
  209. (setq erl-ecs-lineno-list '())
  210. (run-hooks 'erl-ecs-before-eval-hooks)
  211. ;; seems to only work when recompiled full _plt
  212. (if erl-ecs-enable-dialyzer (erl-ecs-check-dialyzer)
  213. (erl-ecs-remove-overlays erl-ecs-dialyzer-string))
  214. (erl-ecs-check-compile)
  215. ;; seems to only work when recompiled file
  216. (if erl-ecs-enable-xref (erl-ecs-check-xref)
  217. (erl-ecs-remove-overlays erl-ecs-xref-string))
  218. (if erl-ecs-enable-eunit (erl-ecs-check-eunit)
  219. (erl-ecs-remove-overlays erl-ecs-eunit-string))
  220. (if erl-ecs-user-specified-errors
  221. (erl-ecs-print-errors 'user-specified-error erl-ecs-user-specified-errors erl-ecs-user-specified-string 'erl-ecs-user-specified-line)
  222. (erl-ecs-remove-overlays erl-ecs-user-specified-string))
  223. (run-hooks 'erl-ecs-after-eval-hooks)))
  224. (defun erl-ecs-check-compile (&optional compile-options)
  225. "Checks for compilation errors and warnings.
  226. Optional parameter `compile-options' should be a list of compile options.
  227. Extra compile options could also be specified by setting the `erl-ecs-compile-options'-variable."
  228. (erl-ecs-message "ECS: Checking erlang faults.")
  229. (let ((node (erl-target-node))
  230. (path (buffer-file-name))
  231. (incstring (erl-ecs-get-includes))
  232. (options (or compile-options erl-ecs-compile-options)))
  233. (erl-ecs-remove-overlays erl-ecs-default-string)
  234. (if (buffer-modified-p)
  235. (let ((bfr-str (buffer-string)))
  236. (erl-spawn
  237. (erl-send-rpc node 'erlang_compile_server 'get_warnings_from_string (list bfr-str incstring options))
  238. (erl-ecs-receive-compile)))
  239. (erl-spawn
  240. (erl-send-rpc node 'erlang_compile_server 'get_warnings (list path incstring options))
  241. (erl-ecs-receive-compile)))))
  242. (defun erl-ecs-receive-compile ()
  243. (erl-receive ()
  244. ;; no errors
  245. ((['rex ['ok]]
  246. (erl-ecs-message "ECS erlang: No faults.")
  247. (setq erl-ecs-error-list '())
  248. (erl-ecs-delete-items 'compile erl-ecs-lineno-list)
  249. (erl-ecs-if-no-compile-faults))
  250. ;; errors
  251. (['rex ['e errors]]
  252. (erl-ecs-message "ECS erlang: faults found.")
  253. (setq erl-ecs-error-list errors)
  254. (erl-ecs-print-errors 'compile erl-ecs-error-list))
  255. (else
  256. (erl-ecs-message "ECS erlang unexpected end: %s" else)))))
  257. (defun erl-ecs-if-no-compile-faults ()
  258. "Compile if compile-if-ok is set."
  259. (let ((incstring (erl-ecs-get-includes))
  260. (inclist '())
  261. tempopts)
  262. (set-buffer erl-ecs-current-buffer)
  263. (when (and (not (buffer-modified-p))
  264. erl-ecs-compile-if-ok)
  265. (dolist (i incstring inclist) (setq inclist (cons (cons 'i i) inclist)))
  266. (progn (erl-ecs-message "ECS: Compiling.")
  267. (setq tempopts erlang-compile-extra-opts)
  268. (setq erlang-compile-extra-opts inclist)
  269. (erlang-compile)
  270. (setq erlang-compile-extra-opts tempopts)))))
  271. (defun erl-ecs-check-dialyzer ()
  272. "Checks type and function warnings."
  273. (erl-ecs-message "ECS: Checking Dialyzer.")
  274. (let ((path (buffer-file-name))
  275. (node (erl-target-node)))
  276. (erl-ecs-remove-overlays erl-ecs-dialyzer-string)
  277. (erl-spawn
  278. (erl-send-rpc node 'erlang_compile_server 'check_dialyzer (list path))
  279. (erl-receive ()
  280. ;; no dialyzer warnings
  281. ((['rex ['ok]]
  282. (erl-ecs-message "ECS Dialyzer: No warnings.")
  283. (setq erl-ecs-dialyzer-list '())
  284. (erl-ecs-delete-items 'dialyzer erl-ecs-lineno-list))
  285. ;; dialyzer warnings
  286. (['rex ['w warnings]]
  287. (erl-ecs-message "ECS Dialyzer err at %s." warnings)
  288. (setq erl-ecs-dialyzer-list warnings)
  289. (erl-ecs-print-errors 'dialyzer erl-ecs-dialyzer-list erl-ecs-dialyzer-string))
  290. (else))))))
  291. (defun erl-ecs-check-xref ()
  292. "Checks for exported function that is not used outside the module."
  293. (erl-ecs-message "ECS: Checking XREF.")
  294. (let ((node (erl-target-node))
  295. (path (buffer-file-name))
  296. (expline (erl-ecs-find-exportline)))
  297. (erl-ecs-remove-overlays erl-ecs-xref-string)
  298. (erl-spawn
  299. (erl-send-rpc node 'erlang_compile_server 'xref (list path))
  300. (erl-receive (expline)
  301. ;; no xref warnings
  302. ((['rex ['ok]]
  303. (erl-ecs-message "ECS XREF: No warnings.")
  304. (setq erl-ecs-xref-list '())
  305. (erl-ecs-delete-items 'xref erl-ecs-lineno-list))
  306. ;; xref warnings
  307. (['rex ['w warnings]]
  308. (let ((a (list (tuple expline 'warning (tuple 'exported_unused_function warnings)))))
  309. (erl-ecs-message "ECS XREF err at %s." a)
  310. (setq erl-ecs-xref-list a)
  311. (erl-ecs-print-errors 'xref erl-ecs-xref-list erl-ecs-xref-string)))
  312. (else))))))
  313. (defun erl-ecs-check-eunit ()
  314. "Checks eunit tests."
  315. (erl-ecs-message "ECS: Checking EUNIT.")
  316. ;; reset eunit errors
  317. (setq erl-ecs-eunit-list '())
  318. (erl-ecs-delete-items 'eunit erl-ecs-lineno-list)
  319. (erl-ecs-remove-overlays erl-ecs-eunit-string)
  320. (let ((node (erl-target-node))
  321. (path (buffer-name)))
  322. (erl-spawn
  323. (erl-send-rpc node 'erlang_compile_server 'check_eunit (list path erl-self))
  324. (erl-ecs-eunit-receive))))
  325. (defun erl-ecs-eunit-receive ()
  326. (erl-receive ()
  327. ((['ok which]
  328. (erl-ecs-message "ECS EUNIT ok at %s." which)
  329. (erl-ecs-eunit-receive))
  330. (['e error]
  331. (erl-ecs-message "ECS EUNIT err at %s." error)
  332. (add-to-list 'erl-ecs-eunit-list error)
  333. (erl-ecs-eunit-receive))
  334. (['klar]))
  335. (erl-ecs-print-errors 'eunit erl-ecs-eunit-list erl-ecs-eunit-string)))
  336. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  337. ;; Helpers ;;
  338. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  339. (defun erl-ecs-start-interval ()
  340. "Defines a timer that runs (erl-ecs-evaluate) every `erl-ecs-interval' second."
  341. (interactive)
  342. (erl-ecs-stop-interval)
  343. (setq erl-ecs-timer (run-at-time (format "%s sec" erl-ecs-interval) erl-ecs-interval 'erl-ecs-evaluate)))
  344. (defun erl-ecs-stop-interval ()
  345. "Stops the timer."
  346. (interactive)
  347. (when erl-ecs-timer (cancel-timer erl-ecs-timer))
  348. (setq erl-ecs-timer))
  349. (defun erl-ecs-get-includes ()
  350. "Find the includefiles for an erlang module."
  351. (save-excursion
  352. (set-buffer erl-ecs-current-buffer)
  353. (let ((inc-regexp (concat "^-include\\(_lib\\)?(\"\\([^\)]*\\)"))
  354. (include-list erl-ecs-compile-includes)
  355. (pt (point-min)))
  356. (while (string-match inc-regexp (buffer-string) pt)
  357. (add-to-list 'include-list (file-name-directory (substring (match-string 2) 1)))
  358. (setq pt (match-end 0)))
  359. include-list)))
  360. (defun erl-ecs-find-exportline ()
  361. "Find out which line the exports are made."
  362. (save-excursion
  363. (set-buffer erl-ecs-current-buffer)
  364. (goto-char (or (string-match "^-export\\|^-compile" (buffer-string))
  365. (point-min)))
  366. (line-number-at-pos (forward-char))))
  367. (defun erl-ecs-remove-overlays (which)
  368. "Removes all overlays with the name `WHICH'"
  369. (interactive)
  370. (set-buffer erl-ecs-current-buffer)
  371. (dolist (ol (overlays-in (point-min) (point-max)))
  372. (when (and (overlayp ol)
  373. (eql (overlay-get ol 'erl-ecs-type) which))
  374. (delete-overlay ol))))
  375. (defun erl-ecs-goto-beg-of-line (line-no)
  376. "Return the beginning of the line without whitespaces."
  377. (save-excursion
  378. (goto-line line-no)
  379. (goto-char (line-beginning-position))
  380. (while (looking-at "[ \t]")
  381. (forward-char))
  382. (point)))
  383. (defun erl-ecs-goto-end-of-line (line-no)
  384. "Return the end of the line without whitespaces"
  385. (save-excursion
  386. (goto-line line-no)
  387. (goto-char (line-end-position))
  388. (while (and (looking-at "[ \t\r\n]") (> (point) 1))
  389. (backward-char))
  390. (+ 1 (point))))
  391. (defun erl-ecs-print-errors (tag errors &optional lesser lesser-face)
  392. "Makes the overlays."
  393. (set-buffer erl-ecs-current-buffer)
  394. (let ((err-list '()))
  395. (dolist (x errors err-list)
  396. (setq err-list (cons (vector (tuple-elt x 1) tag) err-list))
  397. (erl-ecs-display-overlay
  398. (erl-ecs-goto-beg-of-line (tuple-elt x 1)) ; beginning
  399. (erl-ecs-goto-end-of-line (tuple-elt x 1)) ; end
  400. (if (not lesser) ; face
  401. (if (string= (tuple-elt x 2) "error")
  402. 'erl-ecs-error-line
  403. 'erl-ecs-warning-line)
  404. (if lesser-face lesser-face 'erl-ecs-lesser-line))
  405. (format "%s %s @line %s: %s "
  406. (if lesser lesser erl-ecs-default-string)
  407. (tuple-elt x 2)
  408. (tuple-elt x 1)
  409. (tuple-elt x 3)) ; help-echo
  410. lesser) ;; lesser-type
  411. err-list)
  412. (setq erl-ecs-lineno-list (append erl-ecs-lineno-list err-list))))
  413. (defun erl-ecs-display-overlay (beg end face tooltip-text &optional lesser)
  414. "Display the overlays."
  415. (let ((ov (make-overlay beg end nil t t)))
  416. (overlay-put ov 'erl-ecs t)
  417. (overlay-put ov 'face face)
  418. (overlay-put ov 'help-echo (erl-ecs-add-newline tooltip-text erl-ecs-cut-at-mouseover))
  419. (overlay-put ov 'erl-ecs-type (if lesser lesser
  420. erl-ecs-default-string))
  421. (overlay-put ov 'priority (if lesser 90 100))
  422. ov))
  423. (defun erl-ecs-add-newline (string distance)
  424. "Adds a newline at every `distance' chars in `string'."
  425. (if (> (length string) distance)
  426. (concat (substring string 0 distance)
  427. "\n" (erl-ecs-add-newline (substring string distance) distance))
  428. string))
  429. (defun erl-ecs-goto-error (&optional prev pos)
  430. "Leave point at the next error and print the message. If `prev' is set goto the previous error. If `pos' is set, goto that line."
  431. (let* ((delta (line-number-at-pos (if prev (point-min) (point-max))))
  432. (pt (line-number-at-pos pos))
  433. (min-max delta)
  434. (comparison delta))
  435. (dolist (it erl-ecs-lineno-list delta)
  436. ;; set the first/last err
  437. (when (or (and prev
  438. (> (elt it 0) min-max))
  439. (and (not prev)
  440. (< (elt it 0) min-max)))
  441. (setq min-max (elt it 0)))
  442. ;; set the next/prev error
  443. (when (or (and (not prev)
  444. (> (elt it 0) pt)
  445. (< (elt it 0) delta))
  446. (and prev
  447. (< (elt it 0) pt)
  448. (> (elt it 0) delta)))
  449. (setq delta (elt it 0))))
  450. (if (= delta comparison) min-max delta)))
  451. (defun erl-ecs-next-error ()
  452. "Moves point to the next error and prints the error."
  453. (interactive)
  454. (let* ((max (line-number-at-pos (point-max)))
  455. (next-err-line (erl-ecs-goto-error)))
  456. (when erl-ecs-lineno-list
  457. (goto-char
  458. (erl-ecs-goto-beg-of-line
  459. next-err-line)))
  460. (erl-ecs-show-error-on-line)))
  461. (defun erl-ecs-prev-error ()
  462. "Moves point to the previous error and prints the error."
  463. (interactive)
  464. (let* ((min (line-number-at-pos (point-min)))
  465. (prev-err-line (erl-ecs-goto-error t)))
  466. (when erl-ecs-lineno-list
  467. (goto-char
  468. (erl-ecs-goto-beg-of-line
  469. prev-err-line)))
  470. (erl-ecs-show-error-on-line)))
  471. (defun erl-ecs-show-error-on-line (&optional line)
  472. "Prints the errors for a certain line. If `line' is nil use the current line."
  473. (interactive)
  474. (let (str)
  475. (dolist (ov (overlays-at (point)) str)
  476. (let ((help-echo (overlay-get ov 'help-echo)))
  477. (when (overlay-get ov 'erl-ecs-type)
  478. (setq str (concat
  479. (replace-regexp-in-string "\n" ""
  480. (substring help-echo 0
  481. (when (> (length help-echo) erl-ecs-cut-at-distance)
  482. erl-ecs-cut-at-distance)))
  483. (when (> (length help-echo) erl-ecs-cut-at-distance) "...")
  484. (when str (concat "\n" str)))))))
  485. (when str (message str))))
  486. (defun erl-ecs-message (msg &rest r)
  487. "Prints message if `erl-ecs-verbose' is non-nil."
  488. (when erl-ecs-verbose (message msg r)))
  489. (defun erl-ecs-delete-items (tag erl-ecs-list)
  490. "Deletes all items that has a value matching `TAG' from a list"
  491. (let ((new-list '()))
  492. (dolist (it erl-ecs-list new-list)
  493. (unless (equal tag (elt it 1)) (setq new-list (cons it new-list))))
  494. (setq erl-ecs-lineno-list new-list)))
  495. (defun erl-ecs-check-backends ()
  496. "See which backends should be used."
  497. (interactive)
  498. (unless (member 'xref erl-ecs-backends)
  499. (erl-ecs-message "xref not set")
  500. (setq erl-ecs-enable-xref nil))
  501. (unless (member 'eunit erl-ecs-backends)
  502. (erl-ecs-message "eunit not set")
  503. (setq erl-ecs-enable-eunit nil))
  504. (unless (member 'dialyzer erl-ecs-backends)
  505. (erl-ecs-message "dialyzer not set")
  506. (setq erl-ecs-enable-dialyzer nil)))
  507. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  508. ;; TODO ;;
  509. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  510. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  511. ;; Last ;;
  512. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  513. (add-hook 'erl-ecs-before-eval-hooks 'erl-ecs-check-backends)
  514. (erl-ecs-setup)
  515. (provide 'erlang-compile-server)