From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: joaotavora@gmail.com (=?utf-8?B?Sm/Do28gVMOhdm9yYQ==?=) Newsgroups: gmane.emacs.devel Subject: Re: Flymake refactored Date: Fri, 06 Oct 2017 00:01:56 +0100 Message-ID: <87bmll19nf.fsf@gmail.com> References: <87h8vmj3tr.fsf@lolita> <1507138648.1972.0@smtp.gmail.com> <874lre2von.fsf@gmail.com> <87mv566yjx.fsf@udel.edu> <87shex276r.fsf@gmail.com> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1507244566 17780 195.159.176.226 (5 Oct 2017 23:02:46 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Thu, 5 Oct 2017 23:02:46 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.60 (gnu/linux) Cc: John Wiegley , emacs-devel@gnu.org, Mark Oteiza , Simen =?utf-8?Q?Heggest=C3=B8yl?= , dgutov@yandex.ru, Steve Purcell , sdl.web@gmail.com To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Oct 06 01:02:41 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e0FA3-0003V1-Jn for ged-emacs-devel@m.gmane.org; Fri, 06 Oct 2017 01:02:35 +0200 Original-Received: from localhost ([::1]:42294 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e0FAA-0007rG-Qc for ged-emacs-devel@m.gmane.org; Thu, 05 Oct 2017 19:02:42 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:51102) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e0F9Y-0007rB-Oy for emacs-devel@gnu.org; Thu, 05 Oct 2017 19:02:05 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e0F9V-000674-Le for emacs-devel@gnu.org; Thu, 05 Oct 2017 19:02:04 -0400 Original-Received: from mail-wm0-x232.google.com ([2a00:1450:400c:c09::232]:53199) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1e0F9V-000668-Db for emacs-devel@gnu.org; Thu, 05 Oct 2017 19:02:01 -0400 Original-Received: by mail-wm0-x232.google.com with SMTP id k4so4862221wmc.1 for ; Thu, 05 Oct 2017 16:02:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-transfer-encoding; bh=37rzLRRU/yIfGpjXNsd+bquJC/hO+OLqteS+PpVFqSs=; b=J18W6a8mnsrcFIZ6748CF4J8tKoG9YZCGVHyvUm/8cKmrUCqyCgxFBC/mwrtR7V1NH SX0En35C/4p/73WsDSoPXa0YPwSZYzaohscy3Jz9PBfbNwlx7kyNZJT/AOkGqiA+dyCy SLdTvIPIxcYXKe2P3qNuR44YmqNEgIVkzU8If9qf0ebcGvT+EDnk0dZSOwRIQii0sND/ Hq3P4RQsVptzBXAd1ZqZqHLjm2gTOm1Sw9K4ln0/GXfJUYOwJjue13yj+Znm7AfLvCEr 5lIkg6Ttkged2gIGzLPFHRDY10rnHLr/6SEZrZcJURMVdLaJ4fRJHPgMPaYwJgsXQc3E Olaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version:content-transfer-encoding; bh=37rzLRRU/yIfGpjXNsd+bquJC/hO+OLqteS+PpVFqSs=; b=n95hbj5NWS59vy/M/UCqIzrLSd5HY2ctNgc73aYbRBed5ivdDqSc4uYX3DqHponW2k mz4via9wbMKtTKS8E2suo8aw+Qg5k6X0qat3CeH7WiaUzu7JNY3uoo5HkctMYG8XIWAi w98AB/eV4T0CmrNYRRuZwPtnRxcVFHhhynqe7jkesCmUihxbuxkQsgDTPFuLW0i5yZMJ TRxN1K78ul9oyoQs8LTpOIq/7M5av18DDb0KWyjCUrgEtiCCbsItezqOj1iU5tKo8eHy +3DVWbWm2dFiTTQXxSjRpnMZd+Q/axL5I5OYRCoLQbDHWc/zmSpE5ujt2trBUvQyvprs +H+A== X-Gm-Message-State: AMCzsaUOqQjznNOuoU1BHbofaMHUym2XwxWQln/M4RLwcOfwoHHVu2Da vGycNUOgCaCf65HC15wgK0A= X-Google-Smtp-Source: AOwi7QBMbn6rytLn5Ms6nr5ecwa1PTsP2zPsm6d4jqhvf6zHyPORiYSN7HDoTWf1jr/JxzwIOcoHBA== X-Received: by 10.28.232.75 with SMTP id f72mr76583wmh.90.1507244520027; Thu, 05 Oct 2017 16:02:00 -0700 (PDT) Original-Received: from lolita.yourcompany.com (188.139.62.94.rev.vodafone.pt. [94.62.139.188]) by smtp.gmail.com with ESMTPSA id v2sm465441wmf.40.2017.10.05.16.01.58 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 05 Oct 2017 16:01:59 -0700 (PDT) In-Reply-To: (=?utf-8?Q?=22Jo=C3=A3o_T=C3=A1vora=22's?= message of "Thu, 5 Oct 2017 15:45:38 +0100") X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::232 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:219153 Archived-At: Jo=C3=A3o T=C3=A1vora writes: > We should come up with a canonic way to launch flymake processes > and then either hide that behind an abstraction or document it. Attached is a possible such function: it's just like make-process, but does all those boring checks and has some good defaults. I didn't give it much testing, but it seems to work and backends become easier to read. Of course, some macrology can probably get us further, but I wouldn't want to straitjacket backend writers. Here's what the Ruby backend looks like after using the diff below my sig. Notice how no separate variable is needed. (defun ruby-flymake (report-fn &rest _args) (unless (executable-find (car ruby-flymake-command)) (error "Cannot find a suitable ru= by")) (let ((source (current-buffer))) (save-restriction (widen) (let ((proc (flymake-easy-make-process :name "ruby-flymake" :command '("ruby" "-w" "-c") :sentinel (lambda (proc _event) (with-current-buffer (process-buffer proc) (goto-char (point-min)) (cl-loop while (search-forward-regexp "^\\(?:.*.rb\\|-\\):\\([0-9]+\\): \\(.*\\)$" n= il t) for msg =3D (match-string 2) for (beg . end) =3D (flymake-diag-region source (string-to-number (match-string 1)= )) for type =3D (if (string-match "^warning" msg) :warni= ng :error) collect (flymake-make-diagnostic source beg end type = msg) into diags finally (funcall report-fn diags))))))) (process-send-region proc (point-min) (point-max)) (process-send-eof proc))))) Jo=C3=A3o diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index e747f1a12d..5277e48bc6 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -617,6 +617,82 @@ flymake-make-report-fn (with-current-buffer buffer (apply #'flymake--handle-report backend token args)))))) =20 +(defvar-local flymake-easy-make-process--processes + nil) + +;;;###autoload +(defun flymake-easy-make-process (&rest args) + "Like `make-process', but suitable for writing Flymake backends. +Use this function when writing Flymake backends based on invoking +external processes as it preserves the semantics explained + +ARGS is a plist of keyword-value pairs. The same keywords are +accepted as in `make-process', but with slightly different +semantics: + +* `:name' is mandatory and `:backend' is a synonym for it. Can + be a string or a symbol and must be constant for the backend, + i.e. you mustn't generate a different name every time. + +* `:buffer' defaults to a temporary buffer, which is always + killed after the process exits. + +* `:noquery' defaults to t. + +* `:connection-type' defaults to 'pipe' + +* `:filter', if provided, is only executed if the process is the + most recent process created with `flymake-easy-make-process' + for a given buffer and `:name'. If these conditions aren't met, + the process is killed immediately. + +* `:sentinel', if provided, is only executed if the process has + exited cleanly and is the most recent process created with + `flymake-easy-make-process' for a given buffer and `:name'." + (let* ((backend (or (plist-get args :name) + (plist-get args :backend) + (error "`:name' or `:backend' are mandatory"))) + (backend (if (symbolp backend) (symbol-name backend) backend)) + (existing (gethash backend + (or flymake-easy-make-process--processes + (setq flymake-easy-make-process--processes + (make-hash-table :test #'equal)))))) + (if (process-live-p existing) (kill-process existing)) + (setq existing + (make-process + :name backend + :command (plist-get args :command) + :buffer (if (plist-member args :buffer) + (plist-get args :buffer) + (generate-new-buffer + (concat " *flymake-easy-make-process-" + backend + "*"))) + :coding (plist-get args :coding) + :noquery (if (plist-member args :noquery) + (plist-get args :noquery) + t) + :connection-type (if (plist-member args :connection-type) + (plist-get args :connection-type) + 'pipe) + :filter (lambda (proc string) + (when (eq proc existing) + (if (plist-member args :filter) + (funcall (plist-get args :filter) + proc string) + (internal-default-process-filter proc + string)))) + :sentinel (lambda (proc event) + (unwind-protect + (when (and (plist-member args :sentinel) + (eq proc existing) + (eq 'exit (process-status proc))) + (funcall (plist-get args :sentinel) + proc event)) + (let ((buf (process-buffer proc))) + (when buf (kill-buffer buf))))))) + (puthash backend existing flymake-easy-make-process--processes))) + (defun flymake--collect (fn) (let (retval) (maphash (lambda (backend state)