emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 9a0b20d: Add proper Flymake support to cc-mode.el


From: João Távora
Subject: [Emacs-diffs] master 9a0b20d: Add proper Flymake support to cc-mode.el
Date: Sun, 3 Jun 2018 20:47:13 -0400 (EDT)

branch: master
commit 9a0b20d5b33e3e3282b597c3d0c836396071a547
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>

    Add proper Flymake support to cc-mode.el
    
    Except for the important detail that it doesn't make temporary files,
    the new flymake-cc backend doesn't yet behave much differently from
    the old flymake-proc-legacy-flymake, i.e. it still needs a special
    `check-syntax' Makefile target to provide the compiler and compilation
    flags.  However, the new infrastructure created should allow less
    intrusive cleverer flag guessers (yet to be written) to replace that
    mechanism.
    
    * lisp/progmodes/cc-mode.el (c-mode, c++-mode): Add to
    flymake-diagnostic-functions.
    
    * lisp/progmodes/flymake-cc.el: New file.
---
 lisp/progmodes/cc-mode.el    |   2 +
 lisp/progmodes/flymake-cc.el | 140 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+)

diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 49c9171..a1411ad 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -2039,6 +2039,7 @@ Key bindings:
   (c-common-init 'c-mode)
   (easy-menu-add c-c-menu)
   (cc-imenu-init cc-imenu-c-generic-expression)
+  (add-hook 'flymake-diagnostic-functions 'flymake-cc nil t)
   (c-run-mode-hooks 'c-mode-common-hook))
 
 (defconst c-or-c++-mode--regexp
@@ -2126,6 +2127,7 @@ Key bindings:
   (c-common-init 'c++-mode)
   (easy-menu-add c-c++-menu)
   (cc-imenu-init cc-imenu-c++-generic-expression)
+  (add-hook 'flymake-diagnostic-functions 'flymake-cc nil t)
   (c-run-mode-hooks 'c-mode-common-hook))
 
 
diff --git a/lisp/progmodes/flymake-cc.el b/lisp/progmodes/flymake-cc.el
new file mode 100644
index 0000000..ebcfd7d
--- /dev/null
+++ b/lisp/progmodes/flymake-cc.el
@@ -0,0 +1,140 @@
+;;; flymake-cc.el --- Flymake support for GNU tools for C/C++     -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2018  Free Software Foundation, Inc.
+
+;; Author: João Távora <address@hidden>
+;; Keywords: languages, c
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Flymake support for C/C++.
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defcustom flymake-cc-command 'flymake-cc-use-special-make-target
+  "Command used by the `flymake-cc' backend.
+A list of strings, or a symbol naming a function that produces one
+such list when called with no arguments in the buffer where the
+variable `flymake-mode' is active.
+
+The command should invoke a GNU-style compiler that checks the
+syntax of a (Obj)C(++) program passed to it via its standard
+input and prints the result on its standard output."
+  :type '(choice
+          (symbol :tag "Function")
+          ((repeat :) string))
+  :group 'flymake-cc)
+
+(defun flymake-cc--make-diagnostics (source)
+  "Parse GNU-compatible compilation messages in current buffer.
+Return a list of Flymake diagnostic objects for the source buffer
+SOURCE."
+  ;; TODO: if you can understand it, use `compilation-mode's regexps
+  ;; or even some of its machinery here.
+  ;;
+  ;;    (set (make-local-variable 'compilation-locs)
+  ;;         (make-hash-table :test 'equal :weakness 'value))
+  ;;    (compilation-parse-errors (point-min) (point-max)
+  ;;                              'gnu 'gcc-include)
+  ;;    (while (next-single-property-change 'compilation-message)
+  ;;       ...)
+  ;;
+  ;; For now, this works minimally well.
+  (cl-loop
+   while
+   (search-forward-regexp
+    "^\\(In file included from 
\\)?<stdin>:\\([0-9]+\\):\\([0-9]+\\):\n?\\(.*\\): \\(.*\\)$"
+    nil t)
+   for msg = (match-string 5)
+   for (beg . end) = (flymake-diag-region
+                      source
+                      (string-to-number (match-string 2))
+                      (string-to-number (match-string 3)))
+   for type = (if (match-string 1)
+                  :error
+                (assoc-default
+                 (match-string 4)
+                 '(("error" . :error)
+                   ("note" . :note)
+                   ("warning" . :warning))
+                 #'string-match))
+   collect (flymake-make-diagnostic source beg end type msg)))
+
+(defun flymake-cc-use-special-make-target ()
+  "Command for checking a file via a CHK_SOURCES Make target."
+  (unless (executable-find "make") (error "Make not found"))
+  `("make" "check-syntax" "CHK_SOURCES=-x c -"))
+
+(defvar-local flymake-cc--proc nil "Internal variable for `flymake-gcc'")
+
+;; forward declare this to shoosh compiler (instead of requiring
+;; flymake-proc)
+;;
+(defvar flymake-proc-allowed-file-name-masks)
+
+;;;###autoload
+(defun flymake-cc (report-fn &rest _args)
+  "Flymake backend for GNU-style C compilers.
+This backend uses `flymake-cc-command' (which see) to launch a
+process that is passed the current buffer's contents via stdin.
+REPORT-FN is Flymake's callback."
+  ;; HACK: XXX: Assuming this backend function is run before it in
+  ;; `flymake-diagnostic-functions', very hackingly convince the other
+  ;; backend `flymake-proc-legacy-backend', which is on by default, to
+  ;; disable itself.
+  ;;
+  (setq-local flymake-proc-allowed-file-name-masks nil)
+  (when (process-live-p flymake-cc--proc)
+    (kill-process flymake-cc--proc))
+  (let ((source (current-buffer)))
+    (save-restriction
+      (widen)
+      (setq
+       flymake-cc--proc
+       (make-process
+        :name "gcc-flymake"
+        :buffer (generate-new-buffer "*gcc-flymake*")
+        :command (if (symbolp flymake-cc-command)
+                     (funcall flymake-cc-command)
+                   flymake-cc-command)
+        :noquery t :connection-type 'pipe
+        :sentinel
+        (lambda (p _ev)
+          (when (eq 'exit (process-status p))
+            (unwind-protect
+                (when (with-current-buffer source (eq p flymake-cc--proc))
+                  (with-current-buffer (process-buffer p)
+                    (goto-char (point-min))
+                    (let ((diags
+                           (flymake-cc--make-diagnostics source)))
+                      (if (or diags (zerop (process-exit-status p)))
+                          (funcall report-fn diags)
+                        ;; non-zero exit with no diags is cause
+                        ;; for alarm
+                        (funcall report-fn
+                                 :panic :explanation
+                                 (buffer-substring
+                                  (point-min) (progn (goto-char (point-min))
+                                                     (line-end-position))))))))
+              ;; (display-buffer (process-buffer p)) ; uncomment to debug
+              (kill-buffer (process-buffer p)))))))
+      (process-send-region flymake-cc--proc (point-min) (point-max))
+      (process-send-eof flymake-cc--proc))))
+
+(provide 'flymake-cc)
+;;; flymake-cc.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]