[elpa] elpa-admin c362980: Don't use `date` to parse date from git; it's unportable.

2021-09-28 Thread Mattias Engdegrd
branch: elpa-admin
commit c36298077e35d8d43f149711b92df69775740572
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't use `date` to parse date from git; it's unportable.

BSD date doesn't work like GNU date. Do it in Lisp instead.

* elpa-admin.el (elpaa--git-date-to-timestamp): New function.
(elpaa--get-devel-version): Call it.
---
 elpa-admin.el | 40 +++-
 1 file changed, 35 insertions(+), 5 deletions(-)

diff --git a/elpa-admin.el b/elpa-admin.el
index ac72f2f..0cdff76 100644
--- a/elpa-admin.el
+++ b/elpa-admin.el
@@ -624,11 +624,42 @@ Return non-nil if a new tarball was created."
  dir
  'new)))
 
+(defun elpaa--git-date-to-timestamp (gitdate)
+  "Convert date from git (ISO 6401) to a timestamp."
+  (unless (string-match (rx bos
+(group-n 1 (+ digit)) "-"
+(group-n 2 (+ digit)) "-"
+(group-n 3 (+ digit)) "T"
+(group-n 4 (+ digit)) ":"
+(group-n 5 (+ digit)) ":"
+(group-n 6 (+ digit))
+(? "+"
+   (group-n 7 (+ digit)) ":"
+   (group-n 8 (+ digit
+gitdate)
+(error "unknown date format: %S" gitdate))
+  (let* ((field
+  (lambda (group)
+(and (match-beginning group)
+ (string-to-number (match-string group gitdate)
+ (y (funcall field 1))
+ (mo (funcall field 2))
+ (d (funcall field 3))
+ (h (funcall field 4))
+ (mi (funcall field 5))
+ (s (funcall field 6))
+ (zh (funcall field 7))
+ (zm (funcall field 8))
+ (zs (if zh
+ (* 60 (+ (* zh 60) zm))
+   0)))
+(encode-time (list s mi h d mo y nil nil zs
+
 (defun elpaa--get-devel-version (dir pkg-spec)
   "Compute the date-based pseudo-version used for devel builds."
   (let* ((ftn (file-truename  ;; Follow symlinks!
   (expand-file-name (elpaa--main-file pkg-spec) dir)))
-(default-directory (file-name-directory ftn))
+ (default-directory (file-name-directory ftn))
  (gitdate
   (with-temp-buffer
(if (plist-get (cdr pkg-spec) :core)
@@ -643,10 +674,9 @@ Return non-nil if a new tarball was created."
   ;; Convert Git's date into something that looks like a version 
number.
   ;; While we're at it, convert Git's date into its UTC equivalent,
   ;; to try and make sure time-versions are monotone.
-  (let ((process-environment (cons "TZ=UTC" process-environment)))
-(with-temp-buffer
-  (elpaa--call t "date" "-d" gitdate "+%Y%m%d.%H%M%S")
-  (buffer-string)
+  (format-time-string "%Y%m%d.%H%M%S"
+  (elpaa--git-date-to-timestamp gitdate)
+  0)))
 ;; Get rid of leading zeros since ELPA's version numbers don't allow them.
 (replace-regexp-in-string "\\(\\`\\|[^0-9]\\)0+\\([0-9]\\)" "\\1\\2"
   ;; Remove trailing newline or anything untoward.



[elpa] main 81d1bc3: * elpa-packages ("relint", "xr"): Auto.sync.

2021-04-06 Thread Mattias Engdegrd
branch: main
commit 81d1bc3e3ca0fcc5a614530d7fe9b3f086586d44
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

* elpa-packages ("relint", "xr"): Auto.sync.
---
 elpa-packages | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/elpa-packages b/elpa-packages
index c4a7bdf..51ac4f7 100644
--- a/elpa-packages
+++ b/elpa-packages
@@ -302,7 +302,8 @@
  ("realgud-trepan-ni"   :url "https://github.com/realgud/realgud-ni;)
  ("rec-mode"   :url 
"https://git.savannah.gnu.org/git/recutils/rec-mode.git;)
  ("register-list"  :url nil)
- ("relint" :url "https://github.com/mattiase/relint;)
+ ("relint" :url "https://github.com/mattiase/relint;
+  :auto-sync t)
  ("repology"   :url nil)
  ("rich-minority"  :url "https://github.com/Malabarba/rich-minority;)
  ("rnc-mode"   :url nil)
@@ -385,7 +386,8 @@
  ("xclip"  :url nil)
  ("xelb"   :url "https://github.com/ch11ng/xelb.git;)
  ("xpm":url nil)
- ("xr" :url "https://github.com/mattiase/xr;)
+ ("xr" :url "https://github.com/mattiase/xr;
+  :auto-sync t)
  ("xref"   :core "lisp/progmodes/xref.el")
  ("yasnippet"  :url "https://github.com/capitaomorte/yasnippet.git;)
  ("yasnippet-classic-snippets" :url nil)



[elpa] externals/xr 647dbaa 1/2: Don't complain about (? (+ X))

2021-02-17 Thread Mattias Engdegrd
branch: externals/xr
commit 647dbaad55d661d89270c4c4c07820953ff61681
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't complain about (? (+ X))

An optional repetition where the repetition is one-or-more isn't
ambiguous, and was just seen in the wild.
Previously, we only suppressed the warning if there was a group around
the repetition.
---
 xr-test.el |  2 ++
 xr.el  | 88 ++
 2 files changed, 44 insertions(+), 46 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 90e5be2..2d5d885 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -388,6 +388,8 @@
'((2  . "Repetition of option")
  (14 . "Repetition of repetition")
  (25 . "Repetition of repetition"
+(should (equal (xr-lint "\\(?:a+\\)?")
+   nil))
 (should (equal (xr-lint "\\(a*\\)*\\(b+\\)*\\(c*\\)?\\(d+\\)?")
'((6 .  "Repetition of repetition")
  (13 . "Repetition of repetition")
diff --git a/xr.el b/xr.el
index f3ffdb8..6b080e1 100644
--- a/xr.el
+++ b/xr.el
@@ -546,53 +546,49 @@ like (* (* X) ... (* X))."
   (let ((operator (match-string 0))
 (operand (car sequence)))
 (when warnings
-  (cond
-   ((and (consp operand)
- (or
-  ;; (* (* X)), for any repetitions *
-  (memq (car operand)
-'(opt zero-or-more one-or-more +? *? ??))
-  ;; (* (group (* X))), for any repetitions *
-  (and
-   (eq (car operand) 'group)
-   (null (cddr operand))
-   (let ((inner (cadr operand)))
- (and (consp inner)
-  (memq (car inner)
-'(opt zero-or-more one-or-more
-  +? *? ??))
-  ;; Except (? (group (+ X))), since that may
-  ;; be legitimate.
-  (not (and (equal operator "?")
-(memq (car inner)
-  '(one-or-more +?)
-(let ((outer-opt (member operator '("?" "??")))
-  (inner-opt (or (memq (car operand) '(opt ??))
- (and (eq (car operand) 'group)
-  (memq (caadr operand)
-'(opt ??))
-  (xr--report warnings (match-beginning 0)
-  (if outer-opt
+  ;; Check both (OP (OP X)) and (OP (group (OP X))).
+  (let ((inner-op
+ (and (consp operand)
+  (if (eq (car operand) 'group)
+  (and (null (cddr operand))
+   (let ((inner (cadr operand)))
+ (and (consp inner)
+  (car inner
+(car operand)
+(cond
+ ((and
+   ;; (OP1 (OP2 X)), for any repetitions OP1, OP2
+   (memq inner-op '(opt zero-or-more one-or-more *? +? ??))
+   ;; Except (? (+ X)) which may be legitimate.
+   (not (and (equal operator "?")
+ (consp operand)
+ (memq inner-op '(one-or-more +?)
+  (let ((outer-opt (member operator '("?" "??")))
+(inner-opt (memq inner-op '(opt ??
+(xr--report warnings (match-beginning 0)
+(if outer-opt
+(if inner-opt
+"Optional option"
+  "Optional repetition")
   (if inner-opt
-  "Optional option"
-"Optional repetition")
-(if inner-opt
-"Repetition of option"
-  "Repetition of repetition")
-   ((memq operand xr--zero-width-assertions)
-(xr--report warnings (match-beginning 0)
-(if (member operator '("?" "??"))
-"Optional zero-width assertion"
-  "Repetition of 

[elpa] externals/xr updated (2a82e8d -> 2889b88)

2021-02-17 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  2a82e8d   Increment version to 1.20
   new  647dbaa   Don't complain about (? (+ X))
   new  2889b88   Increment version to 1.21


Summary of changes:
 xr-test.el |  2 ++
 xr.el  | 92 ++
 2 files changed, 47 insertions(+), 47 deletions(-)



[elpa] externals/xr 2889b88 2/2: Increment version to 1.21

2021-02-17 Thread Mattias Engdegrd
branch: externals/xr
commit 2889b88cab47109f8ddadf1d2c67cac6a46c9420
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.21
---
 xr.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 6b080e1..d43a795 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.20
+;; Version: 1.21
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,8 @@
 
 ;;; News:
 
+;; Version 1.21:
+;; - Suppress false complaint about (? (+ X))
 ;; Version 1.20:
 ;; - Fix duplication removal in character alternatives, like [aaa]
 ;; - All diagnostics are now described in the README file



[elpa] elpa-admin 922d625: * GNUmakefile (EMACS): Split out EMACSBIN for convenience

2020-12-22 Thread Mattias Engdegrd
branch: elpa-admin
commit 922d625d447c87952734d174476ccc50374085ed
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

* GNUmakefile (EMACS): Split out EMACSBIN for convenience
---
 GNUmakefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/GNUmakefile b/GNUmakefile
index c5d5a12..9dda824 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,7 +1,8 @@
 # Makefile for GNU Emacs Lisp Package Archive.
 #
 
-EMACS=emacs --batch
+EMACSBIN=emacs
+EMACS=$(EMACSBIN) --batch
 RM=rm -f
 
 PKG_DESCS_MK=.pkg-descs.mk



[elpa] externals/relint 26639c5 16/16: Require xr 1.20

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 26639c58045189b4807c99f9097132f86cd54163
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Require xr 1.20

Not strictly necessary but will ensure that users get the updated version.
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 4cb5219..3c17a57 100644
--- a/relint.el
+++ b/relint.el
@@ -4,7 +4,7 @@
 
 ;; Author: Mattias Engdegård 
 ;; Version: 1.19
-;; Package-Requires: ((xr "1.19") (emacs "26.1"))
+;; Package-Requires: ((xr "1.20") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
 



[elpa] externals/relint 5720e12 07/16: Scan regexp arguments to functions in s.el

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 5720e122321715ff36c890b8612094559d4fb783
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Scan regexp arguments to functions in s.el

The following functions all take a regexp as first argument:

 s-matches?, s-matches-p, s-match-strings-all, s-matched-positions-all,
 s-match, s-slice-at, s-count-matches, s-count-matches-all,
 s-split, s-split-up-to
---
 relint.el | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 7f46b46..08f61aa 100644
--- a/relint.el
+++ b/relint.el
@@ -1862,7 +1862,11 @@ directly."
'search-forward-regexp 'search-backward-regexp
'kill-matching-buffers
'keep-lines 'flush-lines 'how-many
-   'delete-matching-lines 'delete-non-matching-lines 
'count-matches)
+   'delete-matching-lines 'delete-non-matching-lines 'count-matches
+   ;; From s.el
+   's-matches? 's-matches-p 's-match-strings-all
+   's-matched-positions-all 's-match 's-slice-at
+   's-count-matches 's-count-matches-all 's-split 's-split-up-to)
   ,re-arg . ,_)
 (unless (and (symbolp re-arg)
  (memq re-arg relint--checked-variables))



[elpa] externals/relint d0fa8a8 10/16: Fix false positives in regexp provenance checks

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit d0fa8a8d13263c09962d5c8e9f5da644a1f78843
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix false positives in regexp provenance checks

Detect more common functions which harmlessly absorb regexps without
returning them.
---
 relint.el   | 30 +++---
 test/6.elisp|  6 +-
 test/6.expected | 33 +
 3 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/relint.el b/relint.el
index 7a45323..81859ac 100644
--- a/relint.el
+++ b/relint.el
@@ -1284,12 +1284,36 @@ EXPANDED is a list of expanded functions, to prevent 
recursion."
((atom expr) nil)
((memq (car expr) relint--regexp-returning-functions)
 (list (car expr)))
-   ((memq (car expr) '(looking-at re-search-forward re-search-backward
-   string-match string-match-p looking-back looking-at-p))
+   ((memq (car expr)
+  ;; These forms never produce regexps at all, but are listed here
+  ;; to prevent false positives since their bodies often do.
+  '(while
+looking-at re-search-forward re-search-backward
+string-match string-match-p looking-back looking-at-p
+replace-regexp
+query-replace-regexp
+posix-looking-at posix-search-backward
+posix-search-forward
+posix-string-match
+search-forward-regexp search-backward-regexp
+kill-matching-buffers
+keep-lines flush-lines how-many
+delete-matching-lines delete-non-matching-lines
+count-matches
+s-matches? s-matches-p s-matched-positions-all
+s-count-matches s-count-matches-all))
 nil)
((null (cdr (last expr)))
 (let* ((head (car expr))
-   (args (if (memq head '(if when unless while))
+   (args
+(if (memq head
+  ;; These forms may generate regexps but the provenance
+  ;; of their first argument is irrelevant.
+  ;; This list, too, could be expanded vastly.
+  '(if when unless
+replace-regexp-in-string
+s-match-strings-all s-match s-slice-at
+s-split s-split-up-to))
  (cddr expr)
(cdr expr)))
(alias (assq head relint--alias-defs)))
diff --git a/test/6.elisp b/test/6.elisp
index cbbdf4b..2180df6 100644
--- a/test/6.elisp
+++ b/test/6.elisp
@@ -17,7 +17,11 @@
(format "[%s]" (regexp-quote x))
(format "[%s]" (myrefun y))
(format "[%s]" (rx ?a "b" nonl))
-   (format "[%s]" (rx-to-string z
+   (format "[%s]" (rx-to-string z))
+   (format "[%s]" (f (string-match (regexp-quote x) a))) ; ok
+   (format "[%s]" (f (replace-regexp-in-string (regexp-quote x) a b))) ; ok
+   (format "[%s]" (f (replace-regexp-in-string a b (regexp-quote x ; bad
+   ))
 
 ;; Test skip-chars
 (defun test-skip-chars (x y z)
diff --git a/test/6.expected b/test/6.expected
index 0e8728e..e8851d5 100644
--- a/test/6.expected
+++ b/test/6.expected
@@ -8,27 +8,28 @@
 6.elisp:18:19: Value from `regexp-opt' cannot be spliced into `[...]'
 6.elisp:19:19: Value from `rx' cannot be spliced into `[...]'
 6.elisp:20:19: Value from `rx-to-string' cannot be spliced into `[...]'
-6.elisp:24:24: In call to skip-chars-forward: Suspect skip set framed in 
`[...]' (pos 0)
+6.elisp:23:19: Value from `regexp-quote' cannot be spliced into `[...]'
+6.elisp:28:24: In call to skip-chars-forward: Suspect skip set framed in 
`[...]' (pos 0)
   "[a-z]"
^
-6.elisp:25:26: In call to skip-chars-backward: Duplicated character `a' (pos 1)
+6.elisp:29:26: In call to skip-chars-backward: Duplicated character `a' (pos 1)
   "aa"
.^
-6.elisp:26:23: `some-re' cannot be used for arguments to `skip-chars-forward'
-6.elisp:27:24: `regexp-quote' cannot be used for arguments to 
`skip-chars-backward'
-6.elisp:28:23: `regexp-opt' cannot be used for arguments to 
`skip-chars-forward'
-6.elisp:29:24: `rx' cannot be used for arguments to `skip-chars-backward'
-6.elisp:30:23: `rx-to-string' cannot be used for arguments to 
`skip-chars-forward'
-6.elisp:34:27: In call to skip-syntax-forward: Invalid char `s' in syntax 
string (pos 1)
+6.elisp:30:23: `some-re' cannot be used for arguments to `skip-chars-forward'
+6.elisp:31:24: `regexp-quote' cannot be used for arguments to 
`skip-chars-backward'
+6.elisp:32:23: `regexp-opt' cannot be used for arguments to 
`skip-chars-forward'
+6.elisp:33:24: `rx' cannot be used for arguments to `skip-chars-backward'
+6.elisp:34:23: `rx-to-string' cannot be used for arguments to 
`skip-chars-forward'
+6.elisp:38:27: In call to skip-syntax-forward: Invalid char `s' in syntax 
string (pos 1)
   "\\s-"
..^
-6.elisp:35:27: In call to skip-syntax-backward: Duplicated syntax code ` ' 
(pos 1)
+6.elisp:39:27: In call to skip-syntax-backward: 

[elpa] externals/relint 7690e3a 08/16: Scan font-lock-defaults correctly

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 7690e3af91ec8f9649cc5685404ffe61497b1643
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Scan font-lock-defaults correctly

Previously, font-lock-defaults was treated as font-lock-keywords which
is incorrect; the forms are different. Now assignments to variables
whose name contain 'font-lock-keywords' are scanned as such.
---
 relint.el   | 30 ++
 test/9.elisp| 22 +-
 test/9.expected | 18 --
 3 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index 08f61aa..7a45323 100644
--- a/relint.el
+++ b/relint.el
@@ -1154,6 +1154,22 @@ source."
 (if literal (cons 1 elem-path) elem-path
form path))
 
+(defun relint--check-font-lock-defaults (form name pos path)
+  "Check a value for `font-lock-defaults'."
+  (let ((val (relint--eval-or-nil form)))
+(when (consp val)
+ (cond
+  ((symbolp (car val))
+   (unless (memq (car val) relint--checked-variables)
+ (relint--check-font-lock-keywords (car val) name pos path)))
+  ((consp (car val))
+   (let ((keywords (car val)))
+ (while keywords
+   (when (and (symbolp (car keywords))
+  (not (memq (car keywords) relint--checked-variables)))
+ (relint--check-font-lock-keywords (car keywords) name pos path))
+   (setq keywords (cdr keywords)
+
 (defun relint--check-font-lock-keywords (form name pos path)
   "Check a font-lock-keywords list.  A regexp can be found in an element,
 or in the car of an element."
@@ -1761,8 +1777,11 @@ directly."
(cond
 ((memq name relint--known-regexp-variables)
  (relint--check-re expr name pos (cons i path)))
-((memq name '(font-lock-defaults font-lock-keywords))
+((and (symbolp name) (string-match-p (rx "font-lock-keywords")
+ (symbol-name name)))
  (relint--check-font-lock-keywords expr name pos (cons i path)))
+((eq name 'font-lock-defaults)
+ (relint--check-font-lock-defaults expr name pos (cons i path)))
 ((eq name 'imenu-generic-expression)
  (relint--check-imenu-generic-expression
   expr name pos (cons i path)))
@@ -1969,8 +1988,8 @@ directly."
   (symbol-name name)))
   (relint--check-list re-arg name pos (cons 2 path) nil)
   (push name relint--checked-variables))
- ((string-match-p (rx "font-lock-keywords")
-  (symbol-name name))
+ ((and (symbolp name) (string-match-p (rx "font-lock-keywords")
+  (symbol-name name)))
   (relint--check-font-lock-keywords re-arg name pos (cons 2 path))
   (push name relint--checked-variables))
  ((eq name 'compilation-error-regexp-alist-alist)
@@ -2040,7 +2059,10 @@ directly."
(`(set (make-local-variable ',name) ,expr)
 (cond ((memq name relint--known-regexp-variables)
(relint--check-re expr name pos (cons 2 path)))
-  ((memq name '(font-lock-defaults font-lock-keywords))
+  ((eq name 'font-lock-defaults)
+   (relint--check-font-lock-defaults expr name pos (cons 2 path)))
+  ((and (symbolp name) (string-match-p (rx "font-lock-keywords")
+   (symbol-name name)))
(relint--check-font-lock-keywords expr name pos (cons 2 path)))
   ((eq name 'imenu-generic-expression)
(relint--check-imenu-generic-expression
diff --git a/test/9.elisp b/test/9.elisp
index 4a37174..ef6ae86 100644
--- a/test/9.elisp
+++ b/test/9.elisp
@@ -19,12 +19,24 @@
(comment-end-skip "[ll]"))
   (asdf
 
-(defun test-9-fl ()
-  (setq-local font-lock-defaults '(("[mm]" . tag)))
-  (setq font-lock-defaults '(("[nn]" . tag)))
-  (set (make-local-variable 'font-lock-defaults) '(("[oo]" . tag
-
 (defun test-9-ge ()
   (setq-local imenu-generic-expression
   '((nil "oh" 0)
 ("*more*" "+a+" 0
+
+(defun test-9-fl-kw ()
+  (setq-local font-lock-keywords '(("[mm]" . tag)))
+  (setq font-lock-keywords '(("[nn]" . tag)))
+  (set (make-local-variable 'font-lock-keywords) '(("[oo]" . tag
+
+(defconst my-fl-keyw-1
+  '(("[pp]" . alpha)))
+
+(defconst my-font-lock-keywords-2
+  '(("[qq]" . beta)))
+
+(defun test-9-fl-def ()
+  (setq font-lock-defaults
+'((my-fl-keyw-1
+   my-font-lock-keywords-2)
+  moo mooo)))
diff --git a/test/9.expected b/test/9.expected
index 7bab898..b960f81 100644
--- a/test/9.expected
+++ b/test/9.expected
@@ -34,15 +34,21 @@
 9.elisp:19:33: In comment-end-skip: Duplicated `l' inside character 
alternative (pos 2)
   

[elpa] externals/relint updated (0c35e02 -> 26639c5)

2020-11-30 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  0c35e02   Increment version to 1.18
   new  a1ea26c   Check regexp arguments to more functions
   new  b572fcd   Run automatic tests on Emacs 27.1
   new  14a5135   Minor README correction
   new  8ee9f79   Avoid descending into .git/ when looking for .el files
   new  9173a91   Add progress indicator for interactive relint-directory
   new  1c66438   Add string-search and string-replace to the list of pure 
functions
   new  5720e12   Scan regexp arguments to functions in s.el
   new  7690e3a   Scan font-lock-defaults correctly
   new  4b78e14   Add table of contents to README, and some advice
   new  d0fa8a8   Fix false positives in regexp provenance checks
   new  29e5427   Recognise a few more `featurep` arguments
   new  c8fd922   Minor looking-at optimisation
   new  f0241bc   Increment version to 1.19
   new  5572c57   Emacs 26 compatibility: `directory-files-recursively`
   new  c792bde   Perform Emacs version check at compile time
   new  26639c5   Require xr 1.20


Summary of changes:
 .github/workflows/test.yml |   1 +
 README |  15 +-
 relint.el  | 118 -
 test/2.elisp   |   9 +++-
 test/2.expected|  55 +
 test/6.elisp   |   6 ++-
 test/6.expected|  33 +++--
 test/9.elisp   |  22 +++--
 test/9.expected|  18 ---
 9 files changed, 205 insertions(+), 72 deletions(-)



[elpa] externals/relint 14a5135 03/16: Minor README correction

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 14a5135efb3582eec85efcf017ab9a1d9bd40b2d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Minor README correction
---
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README b/README
index 98e8a1d..0f042ad 100644
--- a/README
+++ b/README
@@ -187,7 +187,7 @@ skip-syntax-backward.
 
   - Literal '-' not first or last
 
-It is good style to put literal hyphens last in character
+It is good style to put a literal hyphen last in character
 alternatives and skip sets, to clearly indicate that it was not
 intended as part of a range.
 



[elpa] externals/relint 1c66438 06/16: Add string-search and string-replace to the list of pure functions

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 1c664381d81286bacda026d1aabf8a64c344d514
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add string-search and string-replace to the list of pure functions

These were added in (the yet unreleased) Emacs 28.
---
 relint.el | 1 +
 1 file changed, 1 insertion(+)

diff --git a/relint.el b/relint.el
index 8fc2de3..7f46b46 100644
--- a/relint.el
+++ b/relint.el
@@ -444,6 +444,7 @@ or (NAME val VAL), for values.")
 string-join string-trim-left string-trim-right string-trim
 string-prefix-p string-suffix-p
 string-blank-p string-remove-prefix string-remove-suffix
+string-search string-replace
 vector aref elt vconcat
 char-to-string string-to-char
 number-to-string string-to-number int-to-string



[elpa] externals/relint 8ee9f79 04/16: Avoid descending into .git/ when looking for .el files

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 8ee9f79d4b8cd5b27df1bb6342f4962db1d0930e
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Avoid descending into .git/ when looking for .el files

This saves quite some time when scanning directories containing lots
of git trees.
---
 relint.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 3b40d12..ee670b7 100644
--- a/relint.el
+++ b/relint.el
@@ -2328,7 +2328,9 @@ TARGET is the file or directory to use for a repeated 
run."
 
 (defun relint--tree-files (dir)
   (directory-files-recursively
-   dir (rx bos (not (any ".")) (* anything) ".el" eos)))
+   dir (rx bos (not (any ".")) (* anything) ".el" eos) nil
+   ;; Save time by not pointlessly descending into huge .git directories.
+   (lambda (s) (not (string-suffix-p "/.git" s)
 
 (defun relint--scan-buffer (buffer)
   "Scan BUFFER; return (COMPLAINTS . SUPPRESSED) where



[elpa] externals/relint c792bde 15/16: Perform Emacs version check at compile time

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit c792bde7e84c5d13727e287a195898262c8f7b11
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Perform Emacs version check at compile time
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 10f5d74..4cb5219 100644
--- a/relint.el
+++ b/relint.el
@@ -2392,7 +2392,7 @@ TARGET is the file or directory to use for a repeated 
run."
 
 (defun relint--tree-files (dir)
   (let ((re (rx bos (not (any ".")) (* anything) ".el" eos)))
-(if (>= emacs-major-version 27)
+(if (eval-when-compile (>= emacs-major-version 27))
 (directory-files-recursively
  dir re nil
  ;; Save time by not pointlessly descending into huge .git directories.



[elpa] externals/relint b572fcd 02/16: Run automatic tests on Emacs 27.1

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit b572fcd34d73a91364b62b8eaa7b40be24ca9d1c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Run automatic tests on Emacs 27.1
---
 .github/workflows/test.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 3e23562..d8fdbce 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,6 +15,7 @@ jobs:
   matrix:
 emacs_version:
   - "26.3"
+  - "27.1"
   - snapshot
 steps:
   - name: Set up Emacs



[elpa] externals/relint 5572c57 14/16: Emacs 26 compatibility: `directory-files-recursively`

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 5572c5770ceba5b3aff3864a49985cadd32e71d4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Emacs 26 compatibility: `directory-files-recursively`

The PREDICATE argument to `directory-files-recursively` was added in
Emacs 27.1; use it conditionally.
---
 relint.el | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/relint.el b/relint.el
index 81d46be..10f5d74 100644
--- a/relint.el
+++ b/relint.el
@@ -2391,10 +2391,13 @@ TARGET is the file or directory to use for a repeated 
run."
 (cons total-errors total-suppressed)))
 
 (defun relint--tree-files (dir)
-  (directory-files-recursively
-   dir (rx bos (not (any ".")) (* anything) ".el" eos) nil
-   ;; Save time by not pointlessly descending into huge .git directories.
-   (lambda (s) (not (string-suffix-p "/.git" s)
+  (let ((re (rx bos (not (any ".")) (* anything) ".el" eos)))
+(if (>= emacs-major-version 27)
+(directory-files-recursively
+ dir re nil
+ ;; Save time by not pointlessly descending into huge .git directories.
+ (lambda (s) (not (string-suffix-p "/.git" s
+  (directory-files-recursively dir re
 
 (defun relint--scan-buffer (buffer)
   "Scan BUFFER; return (COMPLAINTS . SUPPRESSED) where



[elpa] externals/relint 4b78e14 09/16: Add table of contents to README, and some advice

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 4b78e144230cd44b072bcb44ba911d0d01e4b21b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add table of contents to README, and some advice
---
 README | 13 +
 1 file changed, 13 insertions(+)

diff --git a/README b/README
index 0f042ad..5a987a2 100644
--- a/README
+++ b/README
@@ -6,6 +6,16 @@ syntax and bad practice. It also checks the regexp-like 
arguments to
 skip-chars-forward, skip-chars-backward, skip-syntax-forward and
 skip-syntax-backward.
 
+* Contents
+
+   - Usage
+   - Installation
+   - What the diagnostics mean
+   - Suppressing diagnostics
+   - How it works
+   - Bugs
+
+
 * Usage
 
   - Check a single file:
@@ -49,6 +59,9 @@ skip-syntax-backward.
 
 * What the diagnostics mean
 
+  Tip: if a regexp string is difficult to understand, consider
+  decoding it using 'xr', as in (xr-lint "gibberish").
+
   - Unescaped literal 'X'
 
 A special character is taken literally because it occurs in a



[elpa] externals/relint 9173a91 05/16: Add progress indicator for interactive relint-directory

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 9173a91599b1f3cbc39bf3c406789101d6e5fbed
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add progress indicator for interactive relint-directory

The count is updated every 50 files which seems about right.
---
 relint.el | 19 ---
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/relint.el b/relint.el
index ee670b7..8fc2de3 100644
--- a/relint.el
+++ b/relint.el
@@ -2305,8 +2305,15 @@ STRING-START is the start of the string literal (first 
double quote)."
 TARGET is the file or directory to use for a repeated run."
   (relint--prepare-error-buffer target base-dir error-buffer nil)
   (let ((total-errors 0)
-(total-suppressed 0))
+(total-suppressed 0)
+(nfiles (length files))
+(count 0))
 (dolist (file files)
+  (when (and (not noninteractive)
+ (zerop (% count 50)))
+(message "Scanned %d/%d file%s..."
+ count nfiles (if (= nfiles 1) "" "s")))
+  (setq count (1+ count))
   (with-temp-buffer
 (emacs-lisp-mode)
 (insert-file-contents file)
@@ -2368,12 +2375,10 @@ and SUPPRESSED is the number of suppressed diagnostics."
   "Scan all *.el files in DIR for regexp-related errors."
   (interactive "DRelint directory: ")
   (message "Finding .el files in %s..." dir)
-  (let* ((files (relint--tree-files dir))
- (n (length files)))
-(if (not files)
-(message "No .el files found.")
-  (message "Scanning %d file%s..." n (if (= n 1) "" "s"))
-  (relint--scan-files files dir dir (relint--get-error-buffer)
+  (let ((files (relint--tree-files dir)))
+(if files
+(relint--scan-files files dir dir (relint--get-error-buffer))
+  (message "No .el files found."
 
 ;;;###autoload
 (defun relint-current-buffer ()



[elpa] externals/relint a1ea26c 01/16: Check regexp arguments to more functions

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit a1ea26c4f7d8e6618834f04bb634f8ab1f36cb1a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check regexp arguments to more functions

  sort-regexp-fields
  delete-matching-lines (alias for keep-lines)
  delete-non-matching-lines (alias for flush-lines)
  count-matches (alias for how-many)
---
 relint.el   |  9 -
 test/2.elisp|  9 -
 test/2.expected | 55 +++
 3 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/relint.el b/relint.el
index b95ef5c..3b40d12 100644
--- a/relint.el
+++ b/relint.el
@@ -1860,7 +1860,8 @@ directly."
'posix-string-match
'search-forward-regexp 'search-backward-regexp
'kill-matching-buffers
-   'keep-lines 'flush-lines 'how-many)
+   'keep-lines 'flush-lines 'how-many
+   'delete-matching-lines 'delete-non-matching-lines 
'count-matches)
   ,re-arg . ,_)
 (unless (and (symbolp re-arg)
  (memq re-arg relint--checked-variables))
@@ -1899,6 +1900,12 @@ directly."
   ,_ ,_ ,re-arg . ,_)
 (relint--check-file-name-re re-arg (format "call to %s" (car form))
 pos (cons 3 path)))
+   (`(sort-regexp-fields ,_ ,record-arg ,key-arg . ,_)
+(let ((name (format "call to %s" (car form
+  (relint--check-re record-arg name pos (cons 2 path))
+  (let ((key-re (relint--eval-or-nil key-arg)))
+(when (and (stringp key-re) (not (equal key-re "\\&")))
+  (relint--check-re key-re name pos (cons 3 path))
(`(,(or 'skip-chars-forward 'skip-chars-backward)
   ,skip-arg . ,_)
 (let ((str (relint--get-string skip-arg)))
diff --git a/test/2.elisp b/test/2.elisp
index f069a33..36d338a 100644
--- a/test/2.elisp
+++ b/test/2.elisp
@@ -29,7 +29,10 @@
   (string-trim s "[yy]" "[zz]")
   (directory-files s nil "+1")
   (directory-files-and-attributes s nil "+2")
-  (directory-files-recursively s "+3"))
+  (directory-files-recursively s "+3")
+  (delete-matching-lines "+4")
+  (delete-non-matching-lines "+5")
+  (count-matches "+6"))
 
 ;; Test argument names as means of detecting regexps.
 (defun f2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
@@ -57,3 +60,7 @@
 (defun f7 ()
   (alpha beta :regexp "[11]")
   (gamma :regex "[22]" delta))
+
+(defun f8 ()
+  (sort-regexp-fields nil "^.*$x" "\\&" (point-min) (point-max))
+  (sort-regexp-fields nil "^.*$" "\\%" (point-min) (point-max)))
diff --git a/test/2.expected b/test/2.expected
index 347f31d..aa58eca 100644
--- a/test/2.expected
+++ b/test/2.expected
@@ -88,63 +88,78 @@
 2.elisp:32:35: In call to directory-files-recursively: Unescaped literal `+' 
(pos 0)
   "+3"
^
-2.elisp:45:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:33:27: In call to delete-matching-lines: Unescaped literal `+' (pos 0)
+  "+4"
+   ^
+2.elisp:34:31: In call to delete-non-matching-lines: Unescaped literal `+' 
(pos 0)
+  "+5"
+   ^
+2.elisp:35:19: In call to count-matches: Unescaped literal `+' (pos 0)
+  "+6"
+   ^
+2.elisp:48:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:45:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:48:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:45:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:48:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:45:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:48:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:45:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:48:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:46:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:49:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:46:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:49:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:46:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:49:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:46:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:49:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:46:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:49:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"

[elpa] externals/relint c8fd922 12/16: Minor looking-at optimisation

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit c8fd9222c36c1f45d32eeb2dcfdb70a956281f4a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Minor looking-at optimisation

Replace call to `looking-at` with `following-char` when only a single
character is matched: faster, and does not consume regexp cache.
---
 relint.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index 1b8a69e..5ab667e 100644
--- a/relint.el
+++ b/relint.el
@@ -2251,9 +2251,9 @@ STRING-START is the start of the string literal (first 
double quote)."
   (seq ";" (0+ nonl))
   (not (any ?\" ?\; ?? ?\\))
   (goto-char (match-end 0)))
-(when (looking-at (rx ?\"))
+(when (eq (following-char) ?\")
   (let ((string-start (point)))
-(goto-char (match-end 0))
+(forward-char)
 (while (not (looking-at (rx (or ?\" eot
   (when (looking-at
  (rx (1+ (or (seq ?\\ (any "0-9" "xuUN" "abfnrtv"



[elpa] externals/relint f0241bc 13/16: Increment version to 1.19

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit f0241bc960a3df9e0a6e03919b06e24ebd11b0f7
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.19
---
 relint.el | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 5ab667e..81d46be 100644
--- a/relint.el
+++ b/relint.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.18
+;; Version: 1.19
 ;; Package-Requires: ((xr "1.19") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
@@ -29,6 +29,12 @@
 
 ;;; News:
 
+;; Version 1.19
+;; - Progress indicator in `relint-directory'
+;; - Some performance improvements
+;; - Fix some false positives in the regexp provenance detector
+;; - Scan assignments to `font-lock-defaults' correctly
+;; - Recognise regexp arguments to functions in the s.el package
 ;; Version 1.18:
 ;; - New check for ineffective backslashes in all strings (not just regexps)
 ;; - Warnings emitted in order of their position in file or buffer



[elpa] externals/relint 29e5427 11/16: Recognise a few more `featurep` arguments

2020-11-30 Thread Mattias Engdegrd
branch: externals/relint
commit 29e5427b0b269a258bd14afbc50aaf86578ac37a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Recognise a few more `featurep` arguments

Assume that `font-lock` and `lisp-float-type` are always present.
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 81859ac..1b8a69e 100644
--- a/relint.el
+++ b/relint.el
@@ -943,7 +943,7 @@ not be evaluated safely."
((eq head 'featurep)
 (let ((arg (relint--eval (car body
   (cond ((eq arg 'xemacs) nil)
-((memq arg '(emacs mule)) t)
+((memq arg '(emacs mule font-lock lisp-float-type)) t)
 (t (throw 'relint-eval 'no-value)
 
;; Locally defined functions: try evaluating.



[elpa] externals/xr a444d8c 11/12: Explain why we are not using rx in one place

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit a444d8c03b5c431bbd0dd3b73e9c613e697b428a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Explain why we are not using rx in one place
---
 xr.el | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xr.el b/xr.el
index d314f9d..415686a 100644
--- a/xr.el
+++ b/xr.el
@@ -1705,6 +1705,8 @@ in SKIP-SET-STRING."
   "Escape non-printing characters in a string for maximum readability.
 If ESCAPE-PRINTABLE, also escape \\ and \", otherwise don't."
   (replace-regexp-in-string
+   ;; We don't use rx here because of bugs in dealing with raw chars
+   ;; prior to Emacs 27.1.
"[\x00-\x1f\"\\\x7f\x80-\xff][[:xdigit:]]?"
(lambda (s)
  (let* ((c (logand (string-to-char s) #xff))



[elpa] externals/xr 77ad0d6 04/12: syntax and category always match non-empty, for bos/eos anchor check

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 77ad0d63dedd19f20426921ae1013bf99feed6b8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

syntax and category always match non-empty, for bos/eos anchor check
---
 xr.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index c84895d..0f899fe 100644
--- a/xr.el
+++ b/xr.el
@@ -884,7 +884,7 @@ nil if RX only matches the empty string."
  (if (= n 0)
  (and (cl-some #'xr--matches-nonempty body) 'sometimes)
(xr--tristate-some #'xr--matches-nonempty body)))
-(`(,(or 'any 'not 'intersection) . ,_) 'always)
+(`(,(or 'any 'not 'intersection 'syntax 'category) . ,_) 'always)
 ((or 'ascii 'alnum 'alpha 'blank 'cntrl 'digit 'graph
  'lower 'multibyte 'nonascii 'print 'punct 'space
  'unibyte 'upper 'word 'xdigit



[elpa] externals/xr 461dce1 03/12: Remove dead function xr--matches-nonempty-only-p

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 461dce1434cd19bb95baf1a5f4c7112b6f9f4dd6
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Remove dead function xr--matches-nonempty-only-p
---
 xr.el | 23 ---
 1 file changed, 23 deletions(-)

diff --git a/xr.el b/xr.el
index aa5e7be..c84895d 100644
--- a/xr.el
+++ b/xr.el
@@ -444,29 +444,6 @@ UPPER may be nil, meaning infinity."
  (cl-every #'xr--matches-empty-p body))
 ("" t)))
 
-(defun xr--matches-nonempty-only-p (rx)
-  "Whether RX matches non-empty strings only."
-  (pcase rx
-((pred stringp) (> (length rx) 0))
-(`(,(or 'seq 'one-or-more '+? 'group) . ,body)
- (cl-some #'xr--matches-nonempty-only-p body))
-(`(or . ,body)
- (cl-every #'xr--matches-nonempty-only-p body))
-(`(group-n ,_ . ,body)
- (cl-some #'xr--matches-nonempty-only-p body))
-(`(repeat ,from ,_ . ,body)
- (and (> from 0)
-  (cl-some #'xr--matches-nonempty-only-p body)))
-(`(,(or '= '>=) ,n . ,body)
- (and (> n 0)
-  (cl-some #'xr--matches-nonempty-only-p body)))
-(`(,(or 'any 'not 'intersection) . ,_) t)
-((or 'ascii 'alnum 'alpha 'blank 'cntrl 'digit 'graph
- 'lower 'multibyte 'nonascii 'print 'punct 'space
- 'unibyte 'upper 'word 'xdigit
- 'nonl 'anything)
- t)))
-
 (defun xr--adjacent-subsumption (a b)
   "Check if A subsumes B, or vice versa, or not, assuming they are adjacent.
 Return `a-subsumes-b', `b-subsumes-a' or nil."



[elpa] externals/xr a655991 02/12: Use correct text quoting in message about . in file-matching regexp

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit a655991ce53966a61507dc25ed046e4deee37174
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use correct text quoting in message about . in file-matching regexp
---
 xr.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 6bbf5e7..aa5e7be 100644
--- a/xr.el
+++ b/xr.el
@@ -747,7 +747,8 @@ like (* (* X) ... (* X))."
   (when (and (eq purpose 'file)
  (not (looking-at (rx (any "?*+")
 (xr--report warnings (match-beginning 0)
-"Possibly unescaped `.' in file-matching regexp"))
+(format-message
+ "Possibly unescaped `.' in file-matching regexp")))
   (push 'nonl sequence))
 
  ;; various simple substitutions



[elpa] externals/xr 1c4934d 01/12: Add github auto-test infrastructure

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 1c4934dd1d3347cc179ca19b97de29cd4837c2aa
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add github auto-test infrastructure

Very experimental.
---
 .github/workflows/test.yml | 29 +
 Makefile   | 19 +++
 2 files changed, 48 insertions(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000..da6de74
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,29 @@
+name: test
+
+on:
+  push:
+paths-ignore:
+  - '**README*'
+  pull_request:
+paths-ignore:
+  - '**README*'
+
+jobs:
+  test:
+runs-on: ubuntu-latest
+strategy:
+  matrix:
+emacs_version:
+  - "26.3"
+  - snapshot
+steps:
+  - name: Set up Emacs
+uses: purcell/setup-emacs@master
+with:
+  version: ${{matrix.emacs_version}}
+
+  - name: Check out xr
+uses: actions/checkout@v2
+
+  - name: Test
+run: make build check
diff --git a/Makefile b/Makefile
new file mode 100644
index 000..e95b6c7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+EMACS=emacs
+EMFLAGS=-Q -batch -L .
+BYTECOMPFLAGS=--eval '(setq byte-compile-error-on-warn t)'
+
+EL=$(wildcard *.el)
+ELC=$(EL:.el=.elc)
+
+.PHONY: build check clean
+
+build: $(ELC)
+
+clean:
+   rm -f $(ELC)
+
+check:
+   $(EMACS) $(EMFLAGS) -l xr-test -f ert-run-tests-batch-and-exit
+
+%.elc: %.el
+   $(EMACS) $(EMFLAGS) $(BYTECOMPFLAGS) -f batch-byte-compile $^



[elpa] externals/xr ee8ac4a 08/12: Minor looking-at optimisation

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit ee8ac4a7b6ef7c9c3bb797b67e4797f17579be20
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Minor looking-at optimisation

Don't use `looking-at` for matching a single literal character; it is
much more expensive than using `following-char`, and consumes precious
regexp cache.
---
 xr.el | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/xr.el b/xr.el
index 0f899fe..0941309 100644
--- a/xr.el
+++ b/xr.el
@@ -111,11 +111,11 @@
(xr--escape-string (match-string 0) nil)
   (goto-char (match-end 0)))
  ;; Initial ]
- ((looking-at "]")
+ ((eq (following-char) ?\])
   (push (vector ?\] ?\] (point)) intervals)
   (forward-char 1)))
 
-(while (not (looking-at "]"))
+(while (not (eq (following-char) ?\]))
   (cond
;; character class
((looking-at (rx "[:" (group (* (not (any ":" ":]"))
@@ -153,7 +153,7 @@
  "Two-character range `%s'"
  (xr--escape-string (match-string 0) nil
   (goto-char (match-end 0
-   ((looking-at (rx eos))
+   ((eobp)
 (error "Unterminated character alternative"))
;; plain character (including ^ or -)
(t
@@ -509,7 +509,7 @@ like (* (* X) ... (* X))."
   (let ((item-start (point)))
 (cond
  ;; ^ - only special at beginning of sequence
- ((looking-at (rx "^"))
+ ((eq (following-char) ?^)
   (forward-char 1)
   (if (null sequence)
   (progn
@@ -522,7 +522,7 @@ like (* (* X) ... (* X))."
 (push "^" sequence)))
 
  ;; $ - only special at end of sequence
- ((looking-at (rx "$"))
+ ((eq (following-char) ?$)
   (forward-char 1)
   (if (looking-at (rx (or "\\|" "\\)" eos)))
   (progn
@@ -718,12 +718,12 @@ like (* (* X) ... (* X))."
 sequence))
 
  ;; not-newline
- ((looking-at (rx "."))
-  (goto-char (match-end 0))
+ ((eq (following-char) ?.)
+  (forward-char)
   ;; Assume that .* etc is intended.
   (when (and (eq purpose 'file)
  (not (looking-at (rx (any "?*+")
-(xr--report warnings (match-beginning 0)
+(xr--report warnings (1- (point))
 (format-message
  "Possibly unescaped `.' in file-matching regexp")))
   (push 'nonl sequence))
@@ -1438,7 +1438,7 @@ A-SETS and B-SETS are arguments to `any'."
 (xr--report warnings (point)
 (format-message "Suspect skip set framed in `[...]'")))
 
-  (let ((negated (looking-at (rx "^")))
+  (let ((negated (eq (following-char) ?^))
 (start-pos (point))
 (ranges nil)
 (classes nil))



[elpa] externals/xr c7c861f 07/12: Describe diagnostics in README (taken from relint/README)

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit c7c861f96ccc9359a844b7950be0b7f6dcf8376d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe diagnostics in README (taken from relint/README)

This duplicates the descriptions but makes more sense for xr as an
independent package.
---
 README | 196 +
 1 file changed, 196 insertions(+)

diff --git a/README b/README
index 2533d53..ee1dd89 100644
--- a/README
+++ b/README
@@ -16,6 +16,7 @@ arguments to skip-chars-forward and skip-chars-backward.
 
 The xr package can be used interactively or by other code as a library.
 
+
 * Example
 
   (xr-pp "\\`\\(?:[^^]\\|\\^\\(?: \\*\\|\\[\\)\\)")
@@ -27,12 +28,14 @@ The xr package can be used interactively or by other code 
as a library.
(seq "^"
 (or " *" "["
 
+
 * Installation
 
   From GNU ELPA (https://elpa.gnu.org/packages/xr.html):
 
 M-x package-install RET xr RET
 
+
 * Interface
 
   Functions parsing regexp strings:
@@ -51,6 +54,199 @@ The xr package can be used interactively or by other code 
as a library.
   
xr-pp-rx-to-str  --  pretty-print rx expression to string
   
+
+* What the diagnostics mean
+
+  - Unescaped literal 'X'
+
+A special character is taken literally because it occurs in a
+position where it does not need to be backslash-escaped. It is
+good style to do so anyway (assuming that it should occur as a
+literal character).
+
+  - Escaped non-special character 'X'
+  
+A character is backslash-escaped even though this is not necessary
+and does not turn it into a special sequence. Maybe the backslash
+was in error, or should be doubled if a literal backslash was
+expected.
+  
+  - Duplicated 'X' inside character alternative
+  
+A character occurs twice inside [...]; this is obviously
+pointless. In particular, backslashes are not special inside
+[...]; they have no escaping power, and do not need to be escaped
+in order to include a literal backslash.
+  
+  - Repetition of repetition
+  - Repetition of option
+  - Optional repetition
+  - Optional option
+  
+A repetition construct is applied to an expression that is already
+repeated, such as a*+ or \(x?\)?. These expressions can be written
+with a single repetition and often indicate a different mistake,
+perhaps a missing backslash.
+
+When a repetition construct is ? or ??, it is termed 'option'
+instead; the principle is the same.
+
+  - Reversed range 'Y-X' matches nothing
+
+The last character of a range precedes the first and therefore
+includes no characters at all (not even the endpoints). Most such
+ranges are caused by a misplaced hyphen.
+
+  - Character 'B' included in range 'A-C'
+
+A range includes a character that also occurs individually. This
+is often caused by a misplaced hyphen.
+
+  - Ranges 'A-M' and 'D-Z' overlap
+
+Two ranges have at least one character in common. This is often
+caused by a misplaced hyphen.
+
+  - Two-character range 'A-B'
+
+A range only consists of its two endpoints, since they have
+consecutive character codes. This is often caused by a misplaced
+hyphen.
+
+  - Duplicated character class '[:class:]'
+
+A character class occurs twice in a single character alternative
+or skip set.
+
+  - Duplicated alternative branch
+
+The same expression occurs in two different branches, like in
+A\|A. This has the effect of only including it once.
+
+  - Branch matches superset/subset of a previous branch
+
+A branch in an or-expression matches a superset or subset of what
+another branch matches, like in [ab]\|a. This means that one of
+the branches can be eliminated without changing the meaning of the
+regexp.
+
+  - Repetition subsumes/subsumed by preceding repetition
+
+An repeating expression matches a superset or subset of what the
+previous expression matches, in such a way that one of them is
+unnecessary. For example, [ab]+a* matches the same text as [ab]+,
+so the a* could be removed without changing the meaning of the
+regexp.
+
+  - First/last item in repetition subsumes last/first item (wrapped)
+
+The first and last items in a repeated sequence, being effectively
+adjacent, match a superset or subset of each other, which makes
+for an unexpected inefficiency. For example, \(?:a*c[ab]+\)* can
+be seen as a*c[ab]+a*c[ab]+... where the [ab]+a* in the middle is
+a slow way of writing [ab]+ which is made worse by the outer
+repetition. The general remedy is to move the subsumed item out of
+the repeated sequence, resulting in a*\(?:c[ab]+\)* in the example
+above.
+
+  - End-of-line anchor followed by non-newline
+  - Non-newline followed by line-start anchor
+
+A pattern that does not match a newline occurs right after an
+end-of-line anchor ($) or before a line-start anchor (^).
+

[elpa] externals/xr 9b69cc7 06/12: Run automatic tests on Emacs 27.1

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 9b69cc7ce9dd86482409f322fa567e390d629887
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Run automatic tests on Emacs 27.1
---
 .github/workflows/test.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index da6de74..24a4aed 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -15,6 +15,7 @@ jobs:
   matrix:
 emacs_version:
   - "26.3"
+  - "27.1"
   - snapshot
 steps:
   - name: Set up Emacs



[elpa] externals/xr 2a82e8d 12/12: Increment version to 1.20

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 2a82e8dc95bf4af7f451e7533ff14a749e4f42e4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.20
---
 xr.el | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 415686a..f3ffdb8 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.19
+;; Version: 1.20
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,10 @@
 
 ;;; News:
 
+;; Version 1.20:
+;; - Fix duplication removal in character alternatives, like [aaa]
+;; - All diagnostics are now described in the README file
+;; - Improved anchor conflict checks
 ;; Version 1.19:
 ;; - Added filename-specific checks; new PURPOSE argument to `xr-lint'
 ;; - Warn about wrapped subsumption, like \(A*C[AB]*\)+



[elpa] externals/xr 17d7599 05/12: Improved test coverage with some omitted cases

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 17d7599b472a54cdf334a6b91976fb3b14d72d1b
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Improved test coverage with some omitted cases
---
 xr-test.el | 47 ---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 95927ca..d62d02d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -29,6 +29,7 @@
  '(opt (or "ab" (seq (zero-or-more "c") "d")
   (should (equal (xr ".+")
  '(one-or-more nonl)))
+  (should-error (xr "b\\"))
   )
 
 (ert-deftest xr-repeat ()
@@ -57,6 +58,7 @@
   (should (equal (xr "a\\{1,\\}")
  '(>= 1 "a")))
   (should-error (xr "a\\{3,2\\}"))
+  (should-error (xr "a\\{1,2,3\\}"))
   )
 
 (ert-deftest xr-backref ()
@@ -69,6 +71,8 @@
   (should-error (xr "\\(?0:xy\\)"))
   (should (equal (xr "\\(?29:xy\\)")
  '(group-n 29 "xy")))
+  (should-error (xr "\\(c?"))
+  (should-error (xr "xy\\)"))
   )
 
 (ert-deftest xr-misc ()
@@ -96,6 +100,8 @@
(not (syntax comment-start)
   (should-error (xr "\\s"))
   (should-error (xr "\\S"))
+  (should-error (xr "\\sq"))
+  (should-error (xr "\\Sq"))
   )
 
 (ert-deftest xr-category ()
@@ -190,6 +196,7 @@
   (should-error (xr "[[::]]"))
   (should-error (xr "[[:=:]]"))
   (should-error (xr "[[:letter:]]"))
+  (should-error (xr "[a-f"))
   )
 
 (ert-deftest xr-empty ()
@@ -310,7 +317,16 @@
 " (not (any space\n"
 " (* (? (not cntrl)\n"
 "   blank\n"
-"   (| nonascii \"abcdef\"\n"
+"   (| nonascii \"abcdef\"\n")))
+(with-temp-buffer
+  (should (equal (xr-pp ".?\\|b+") nil))
+  (should (equal (buffer-string)
+ (concat
+  "(or (opt nonl)\n"
+  "(one-or-more \"b\"))\n"
+(with-temp-buffer
+  (should (equal (xr-skip-set-pp "^ac-nq\\-u") nil))
+  (should (equal (buffer-string) "(not (any \"c-n\" \"aqu-\"))\n"
   )
 
 (ert-deftest xr-dialect ()
@@ -339,6 +355,7 @@
  '(seq bol bos bow nonl eow eos eol)))
   (should (equal (xr "^\\`\\<.\\>\\'$" 'terse)
  '(: bol bos bow nonl eow eos eol)))
+  (should-error (xr "a" 'asdf))
   )
 
 (ert-deftest xr-lint ()
@@ -350,8 +367,9 @@
  (3 . "Unescaped literal `$'"
 (should (equal (xr-lint "^**$")
'((1 . "Unescaped literal `*'"
-(should (equal (xr-lint "a[[]")
-   '((3 . "Duplicated `\\' inside character alternative"
+(should (equal (xr-lint "a[[]b[d-g.d-g]c")
+   '((3 . "Duplicated `\\' inside character alternative")
+ (12 . "Duplicated `d-g' inside character alternative"
 (should (equal (xr-lint "\\{\\(+\\|?\\)\\[\\]\\}\\\t")
'((0  . "Escaped non-special character `{'")
  (4  . "Unescaped literal `+'")
@@ -413,6 +431,10 @@
'((2 . "Repetition of zero-width assertion")
  (5 . "Optional zero-width assertion")
  (13 . "Repetition of zero-width assertion"
+(should (equal
+ (xr-lint "\\`\\{2\\}\\(a\\|\\|b\\)\\{,8\\}")
+ '((2 . "Repetition of zero-width assertion")
+   (17 . "Repetition of expression matching an empty string"
 ))
 
 (ert-deftest xr-lint-repetition-of-empty ()
@@ -530,6 +552,18 @@
'((4 . "Branch matches subset of a previous branch"
 (should (equal (xr-lint "\\W\\|\f")
'((4 . "Branch matches subset of a previous branch"
+(should (equal (xr-lint "[[:punct:]]\\|!")
+   '((13 . "Branch matches subset of a previous branch"
+(should (equal (xr-lint "[[:ascii:]]\\|[^α-ω]")
+   '((13 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "[^a-f]\\|[h-z]")
+   '((8 . "Branch matches subset of a previous branch"
+(should (equal (xr-lint "[0-9]\\|\\S(")
+   '((7 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "a+\\|[ab]+")
+   '((4 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "[ab]?\\|a?")
+   '((7 . "Branch matches subset of a previous branch"
   ))
 
 (ert-deftest xr-lint-subsumed-repetition ()
@@ -644,6 +678,9 @@
'((10 . "End-of-line anchor followed by non-newline"
 (should (equal (xr-lint "\\(?:$\\|b\\)\\(\n\\|a\\)")
nil))
+(should (equal (xr-lint "\\(?3:$\\)[ab]\\(?2:^\\)")
+   '((8 . "End-of-line anchor followed by non-newline")
+ (12 . "Non-newline followed by line-start anchor"
 (should (equal 

[elpa] externals/xr 32546a7 10/12: Fix character alternative duplication removal

2020-11-30 Thread Mattias Engdegrd
branch: externals/xr
commit 32546a7c7eece83f486db88375b160fa050188af
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix character alternative duplication removal

Duplications such as "[a]" were not always removed correctly,
nor were some cases of overlapping character ranges.

Reported by Shigeru Fukaya.
---
 xr-test.el |  4 
 xr.el  | 80 ++
 2 files changed, 43 insertions(+), 41 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index d62d02d..90e5be2 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -197,6 +197,10 @@
   (should-error (xr "[[:=:]]"))
   (should-error (xr "[[:letter:]]"))
   (should-error (xr "[a-f"))
+  (should (equal (xr "[aa][bananabanana][-][a-ca-ca-c]")
+ '(seq "a" (any "abn") (any "a-c") (any "a-c"
+  (should (equal (xr "[a-fb-gc-h][a-fc-kh-p]")
+ '(seq (any "a-h") (any "a-p"
   )
 
 (ert-deftest xr-empty ()
diff --git a/xr.el b/xr.el
index 03ab308..d314f9d 100644
--- a/xr.el
+++ b/xr.el
@@ -192,47 +192,45 @@
   (while (cdr s)
 (let ((this (car s))
   (next (cadr s)))
-  (when (>= (aref this 1) (aref next 0))
-(let ((message
-   (cond
-;; Duplicate character: drop it and warn.
-((and (eq (aref this 0) (aref this 1))
-  (eq (aref next 0) (aref next 1)))
- (setcdr s (cddr s))
- (format-message
-  "Duplicated `%c' inside character alternative"
-  (aref this 0)))
-;; Duplicate range: drop it and warn.
-((and (eq (aref this 0) (aref next 0))
-  (eq (aref this 1) (aref next 1)))
- (setcdr s (cddr s))
- (format-message
-  "Duplicated `%c-%c' inside character alternative"
-  (aref this 0) (aref this 1)))
-;; Character in range: drop it and warn.
-((eq (aref this 0) (aref this 1))
- (setcar s next)
- (setcdr s (cddr s))
- (format-message
-  "Character `%c' included in range `%c-%c'"
-  (aref this 0) (aref next 0) (aref next 1)))
-;; Same but other way around.
-((eq (aref next 0) (aref next 1))
- (setcdr s (cddr s))
- (format-message
-  "Character `%c' included in range `%c-%c'"
-  (aref next 0) (aref this 0) (aref this 1)))
-;; Overlapping ranges: merge and warn.
-(t
- (let ((this-end (aref this 1)))
-   (aset this 1 (max (aref this 1) (aref next 1)))
-   (setcdr s (cddr s))
-   (format-message "Ranges `%c-%c' and `%c-%c' overlap"
-   (aref this 0) this-end
-   (aref next 0) (aref next 1)))
-  (xr--report warnings (max (aref this 2) (aref next 2))
-  (xr--escape-string message nil)
-(setq s (cdr s)))
+  (if (>= (aref this 1) (aref next 0))
+  ;; Overlap.
+  (let ((message
+ (cond
+  ;; Duplicate character: drop it and warn.
+  ((and (eq (aref this 0) (aref this 1))
+(eq (aref next 0) (aref next 1)))
+   (format-message
+"Duplicated `%c' inside character alternative"
+(aref this 0)))
+  ;; Duplicate range: drop it and warn.
+  ((and (eq (aref this 0) (aref next 0))
+(eq (aref this 1) (aref next 1)))
+   (format-message
+"Duplicated `%c-%c' inside character alternative"
+(aref this 0) (aref this 1)))
+  ;; Character in range: drop it and warn.
+  ((eq (aref this 0) (aref this 1))
+   (setcar s next)
+   (format-message
+"Character `%c' included in range `%c-%c'"
+(aref this 0) (aref next 0) (aref next 1)))
+  ;; Same but other way around.
+  ((eq (aref next 0) (aref next 1))
+   (format-message
+"Character `%c' included in range `%c-%c'"
+(aref next 0) (aref this 0) (aref this 1)))
+  ;; Overlapping ranges: merge and warn.
+  (t
+   (let ((this-end (aref this 1)))
+ (aset this 1 

[elpa] externals/xr updated (35dbbeb -> 2a82e8d)

2020-11-30 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  35dbbeb   Increment version to 1.19
   new  1c4934d   Add github auto-test infrastructure
   new  a655991   Use correct text quoting in message about . in 
file-matching regexp
   new  461dce1   Remove dead function xr--matches-nonempty-only-p
   new  77ad0d6   syntax and category always match non-empty, for bos/eos 
anchor check
   new  17d7599   Improved test coverage with some omitted cases
   new  9b69cc7   Run automatic tests on Emacs 27.1
   new  c7c861f   Describe diagnostics in README (taken from relint/README)
   new  ee8ac4a   Minor looking-at optimisation
   new  6f2e516   Comment update
   new  32546a7   Fix character alternative duplication removal
   new  a444d8c   Explain why we are not using rx in one place
   new  2a82e8d   Increment version to 1.20


Summary of changes:
 .github/workflows/test.yml |  30 +++
 Makefile   |  19 +
 README | 196 +
 xr-test.el |  51 +++-
 xr.el  | 140 ++--
 5 files changed, 354 insertions(+), 82 deletions(-)
 create mode 100644 .github/workflows/test.yml
 create mode 100644 Makefile



[elpa] externals/pspp-mode f087280: * pspp-mode.el: Simplify pspp--updown-list

2020-07-06 Thread Mattias Engdegrd
branch: externals/pspp-mode
commit f0872801dab7b5bedb1fe71252ebc59864a87e8c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

* pspp-mode.el: Simplify pspp--updown-list

(pspp--updown-list): Use mapcar instead of recursion.
(pspp--downcase-list, pspp--upcase-list): Remove.
---
 pspp-mode.el | 16 +---
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/pspp-mode.el b/pspp-mode.el
index 401d517..74ff594 100644
--- a/pspp-mode.el
+++ b/pspp-mode.el
@@ -60,24 +60,10 @@
   "Size of indent.")
 
 
-(defun pspp--downcase-list (l)
-  "Takes a list of strings and returns that list with all elements downcased"
-  (if l
-  (cons (downcase (car l)) (pspp--downcase-list (cdr l)))
-nil))
-
-
-(defun pspp--upcase-list (l)
-  "Takes a list of strings and returns that list with all elements upcased"
-  (if l
-  (cons (upcase (car l)) (pspp--upcase-list (cdr l)))
-nil))
-
-
 (defun pspp--updown-list (l)
   "Takes a list of strings and returns that list with all elements upcased
 and downcased"
-  (append (pspp--upcase-list l) (pspp--downcase-list l)))
+  (append (mapcar #'upcase l) (mapcar #'downcase l)))
 
 
 (defconst pspp-indenters



[elpa] externals/relint e35fa2e 09/11: Fix doc string predicate

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit e35fa2ed4e212286c6981bac0e9f1cc76962627f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix doc string predicate

String literals first in a list were incorrectly considered doc strings.
---
 relint.el| 3 ++-
 test/13.elisp| 3 ++-
 test/13.expected | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index f0557c4..3c6d05a 100644
--- a/relint.el
+++ b/relint.el
@@ -2145,7 +2145,8 @@ Return a list of (FORM . STARTING-POSITION)."
 (looking-at (rx ":documentation" symbol-end)
 (setq steps (1+ steps)))
   (or
-   (= steps 0)   ; `:documentation' parameter
+   (and (= steps 0)
+(looking-at (rx ":documentation")))
(and (= steps 3)
 (looking-at (rx (or "defun" "defmacro" "defsubst" "defalias"
 "defconst" "defvar" "defcustom"
diff --git a/test/13.elisp b/test/13.elisp
index 4c6fb35..58c1609 100644
--- a/test/13.elisp
+++ b/test/13.elisp
@@ -14,4 +14,5 @@
 and \a \b \f \n \r \t \v \d \e \s \^P"))
 
 (defun f2 ()
-  (re-search-forward "\$\.x\+\+"))
+  (re-search-forward "\$\.x\+\+")
+  '("bracketed \q string"))
diff --git a/test/13.expected b/test/13.expected
index fd69f6f..8c721d5 100644
--- a/test/13.expected
+++ b/test/13.expected
@@ -15,3 +15,4 @@
   "$.x++"
^
 13.elisp:17:30: Ineffective string escape `\+'
+13.elisp:18:16: Ineffective string escape `\q'



[elpa] externals/relint 6a86509 10/11: Tuned miscape filtering

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 6a865096791757c0034238f813910b87018a0e31
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Tuned miscape filtering

Instead of disabling the useless backslash check for all doc strings,
just ignore escaped ()[]' -- round and square brackets and apostrophe.
This catches more actual mistakes while avoiding most false positives.
---
 relint.el| 13 -
 test/13.elisp| 13 +++--
 test/13.expected | 38 --
 3 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/relint.el b/relint.el
index 3c6d05a..5124958 100644
--- a/relint.el
+++ b/relint.el
@@ -2164,20 +2164,15 @@ Return a list of (FORM . STARTING-POSITION)."
(and (= steps 4)
 (looking-at (rx (or "define-derived-mode"
 
-(defconst relint--miscape-ignore-left-round-bracket nil
-  "Whether to ignore specifically `\\(' in doc strings.")
-
-(defconst relint--miscape-ignore-all-doc-strings t
-  "Whether to ignore all stray backslashes in doc strings.")
-
 (defun relint--suspicious-backslash (string-start)
   "With point at an ineffective backslash, emit an warning unless filtered out.
 STRING-START is the start of the string literal (first double quote)."
   (let ((c (char-after (1+ (point)
+;; Filter out escaped round and square brackets and apostrophes
+;; inside doc strings, as well as anything in the leftmost column:
+;; common for historical reasons and less likely to be mistakes.
 (unless (or (bolp)
-(and (or (and relint--miscape-ignore-left-round-bracket
-  (eq c ?\())
- relint--miscape-ignore-all-doc-strings)
+(and (memq c '(?\( ?\) ?\[ ?\] ?\'))
  (relint--in-doc-string-p string-start)))
   (relint--warn (point) nil
 (format-message
diff --git a/test/13.elisp b/test/13.elisp
index 58c1609..1f8cb58 100644
--- a/test/13.elisp
+++ b/test/13.elisp
@@ -3,13 +3,14 @@
 ;; Test ineffective backslashes in strings
 
 (defun f1 ()
-  "doc string with \(silly\) bac\kslashes
-\[that we ignore\]"
+  "doc string:
+\! \( \) \[ \] \' all ignored
+not ignored: \{ \} \| \` \? \* \. \+ \; \q etc"
   (list
-   "\more \(bad things\)"
-   "long \
-\(with mistakes\)
-\{and so on\}"
+   "\more"
+   "not ignored: \( \) \[ \] \'"
+   "long string \;
+\; and so on"
"valid: \\ \" \x5e \172 \u1234 \u0041 \C-x \M-e \ \
 and \a \b \f \n \r \t \v \d \e \s \^P"))
 
diff --git a/test/13.expected b/test/13.expected
index 8c721d5..53a4568 100644
--- a/test/13.expected
+++ b/test/13.expected
@@ -1,18 +1,28 @@
-13.elisp:9:5: Ineffective string escape `\m'
-13.elisp:9:11: Ineffective string escape `\('
-13.elisp:9:23: Ineffective string escape `\)'
-13.elisp:10:10: Ineffective string escape `\<'
-13.elisp:10:18: Ineffective string escape `\>'
-13.elisp:11:16: Ineffective string escape `\)'
-13.elisp:12:12: Ineffective string escape `\}'
-13.elisp:17:23: In call to re-search-forward: Unescaped literal `$' (pos 0)
+13.elisp:8:14: Ineffective string escape `\{'
+13.elisp:8:17: Ineffective string escape `\}'
+13.elisp:8:20: Ineffective string escape `\|'
+13.elisp:8:23: Ineffective string escape `\`'
+13.elisp:8:26: Ineffective string escape `\?'
+13.elisp:8:29: Ineffective string escape `\*'
+13.elisp:8:32: Ineffective string escape `\.'
+13.elisp:8:35: Ineffective string escape `\+'
+13.elisp:8:38: Ineffective string escape `\;'
+13.elisp:8:41: Ineffective string escape `\q'
+13.elisp:10:5: Ineffective string escape `\m'
+13.elisp:11:18: Ineffective string escape `\('
+13.elisp:11:21: Ineffective string escape `\)'
+13.elisp:11:24: Ineffective string escape `\['
+13.elisp:11:27: Ineffective string escape `\]'
+13.elisp:11:30: Ineffective string escape `\''
+13.elisp:12:17: Ineffective string escape `\;'
+13.elisp:18:23: In call to re-search-forward: Unescaped literal `$' (pos 0)
   "$.x++"
^
-13.elisp:17:23: Ineffective string escape `\$'
-13.elisp:17:25: Ineffective string escape `\.'
-13.elisp:17:28: Ineffective string escape `\+'
-13.elisp:17:30: In call to re-search-forward: Repetition of repetition (pos 4)
+13.elisp:18:23: Ineffective string escape `\$'
+13.elisp:18:25: Ineffective string escape `\.'
+13.elisp:18:28: Ineffective string escape `\+'
+13.elisp:18:30: In call to re-search-forward: Repetition of repetition (pos 4)
   "$.x++"
^
-13.elisp:17:30: Ineffective string escape `\+'
-13.elisp:18:16: Ineffective string escape `\q'
+13.elisp:18:30: Ineffective string escape `\+'
+13.elisp:19:16: Ineffective string escape `\q'



[elpa] externals/relint 0d80c1f 07/11: Rename various 'miscape' identifiers

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 0d80c1f1bb7cce906f17a7cb4e3d6473a86612f2
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Rename various 'miscape' identifiers
---
 relint.el | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/relint.el b/relint.el
index ae94890..6c67dcc 100644
--- a/relint.el
+++ b/relint.el
@@ -2131,7 +2131,7 @@ Return a list of (FORM . STARTING-POSITION)."
   (push (cons form pos) forms
 (nreverse forms)))
 
-(defun relint--miscape-in-doc-string-p (pos)
+(defun relint--in-doc-string-p (pos)
   "Whether the string literal starting at POS is a doc string."
   (save-excursion
 (goto-char pos)
@@ -2169,7 +2169,7 @@ Return a list of (FORM . STARTING-POSITION)."
 (defconst relint--miscape-ignore-all-doc-strings t
   "Whether to ignore all stray backslashes in doc strings.")
 
-(defun relint--miscape-suspicious-backslash (string-start)
+(defun relint--suspicious-backslash (string-start)
   "With point at an ineffective backslash, emit an warning unless filtered out.
 STRING-START is the start of the string literal (first double quote)."
   (let ((c (char-after (1+ (point)
@@ -2177,13 +2177,13 @@ STRING-START is the start of the string literal (first 
double quote)."
 (and (or (and relint--miscape-ignore-left-round-bracket
   (eq c ?\())
  relint--miscape-ignore-all-doc-strings)
- (relint--miscape-in-doc-string-p string-start)))
+ (relint--in-doc-string-p string-start)))
   (relint--warn (point) nil
 (format-message
  "Ineffective string escape `\\%s'"
  (relint--escape-string (char-to-string c) nil))
 
-(defun relint--miscape-current-buffer ()
+(defun relint--check-for-misplaced-backslashes ()
   "Check for misplaced backslashes in the current buffer."
   (goto-char (point-min))
   (while (not (eobp))
@@ -2209,7 +2209,7 @@ STRING-START is the start of the string literal (first 
double quote)."
  (not (any ?\\ ?\"))
 (goto-char (match-end 0)))
   (when (eq (following-char) ?\\)
-(relint--miscape-suspicious-backslash string-start)
+(relint--suspicious-backslash string-start)
 (forward-char 2)))
 (unless (eobp)
   (forward-char 1))
@@ -2232,7 +2232,7 @@ STRING-START is the start of the string literal (first 
double quote)."
   (relint--check-form-recursively-1 (car form) (cdr form) nil))
 (dolist (form forms)
   (relint--check-form-recursively-2 (car form) nil (cdr form) nil))
-(relint--miscape-current-buffer)
+(relint--check-for-misplaced-backslashes)
 (let ((complaints (nreverse relint--complaints)))
   (cons
(sort complaints



[elpa] externals/relint 0627d4d 08/11: Simplify (and speed up) string scanning regexp

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 0627d4dbf56de54ddd0508a77d794a8b56ce34f9
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Simplify (and speed up) string scanning regexp

By trusting the strings to be lexically correct, we don't need an
elaborate pattern for handling \C-\M-something. This reduces backtracking.
---
 relint.el | 12 
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/relint.el b/relint.el
index 6c67dcc..f0557c4 100644
--- a/relint.el
+++ b/relint.el
@@ -2198,14 +2198,10 @@ STRING-START is the start of the string literal (first 
double quote)."
 (goto-char (match-end 0))
 (while (not (looking-at (rx (or ?\" eot
   (when (looking-at
- (rx (1+ (or (seq
-  ?\\ (any "0-9" "xuUN" "abfnrtv"
-   "des" "^" " "
-   ?\\ ?\n ?\"))
- (seq
-  (1+ ?\\ (any "CM") "-")
-  (or (not (any ?\\))
-  (seq ?\\ anything)))
+ (rx (1+ (or (seq ?\\ (any "0-9" "xuUN" "abfnrtv"
+   "des" "^" " "
+   ?\\ ?\n ?\"
+   "CM"))
  (not (any ?\\ ?\"))
 (goto-char (match-end 0)))
   (when (eq (following-char) ?\\)



[elpa] externals/relint a1c7bf5 06/11: Describe the ineffective backslash warning in README

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit a1c7bf56c03b0dac12a54c75e7183db9257497f1
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe the ineffective backslash warning in README
---
 README | 17 +
 1 file changed, 17 insertions(+)

diff --git a/README b/README
index 7d25c5e..98e8a1d 100644
--- a/README
+++ b/README
@@ -214,6 +214,23 @@ skip-syntax-backward.
 In general, A?, where A matches the empty string, can be
 simplified to just A.
 
+  - Ineffective string escape '\X'
+
+A backslash precedes a character that does not need escaping in a
+string literal (any string, not just regexps), like in "hot\-dog".
+
+If the backslash should be part of the string then it probably
+needs to be doubled; otherwise, it is pointless and should be
+removed to avoid confusion.
+
+In Emacs versions older than 27.1, a left round or square bracket,
+'(' or '[', at the very start of a line in a multi-line string
+could sometimes fool the Emacs-Lisp mode into believing it to be
+the start of a function, thus people sometimes precede such
+brackets with an otherwise unnecessary backslash. However, there
+is usually no reason to put backslashes before brackets in strings
+in general.
+
   - Suspect range '+-X' or 'X-+'
 
 A character range with '+' as one of its endpoints is more often an



[elpa] externals/relint 329df9c 02/11: Refactor framework

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 329df9c3c02d63b539997efa4e54d52b505ae494
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Refactor framework

Always scan an entire buffer and return the list of diagnostics
instead of printing them incrementally. This removes some special
cases, and permits us to get rid of the file parameter passed around
everywhere, as well as thunking.

This also speeds up checking substantially!
---
 relint-test.el |   2 +-
 relint.el  | 495 -
 2 files changed, 248 insertions(+), 249 deletions(-)

diff --git a/relint-test.el b/relint-test.el
index 1df5d66..2e00392 100644
--- a/relint-test.el
+++ b/relint-test.el
@@ -99,7 +99,7 @@ and a path."
 ;; The reference files (*.expected) are kept in the `grave' style,
 ;; to make the test independent of `text-quoting-style'.
 (let ((text-quoting-style 'grave))
-  (relint--scan-buffer (find-file-noselect file t) (current-buffer) t))
+  (relint--buffer (find-file-noselect file t) (current-buffer) t))
 (buffer-string)))
 
 (defun relint-test--read-file (file)
diff --git a/relint.el b/relint.el
index 959f57d..d4c261c 100644
--- a/relint.el
+++ b/relint.el
@@ -99,12 +99,6 @@
 (require 'xr)
 (require 'compile)
 (require 'cl-lib)
-(require 'thunk)
-
-(defvar relint--error-buffer)
-(defvar relint--quiet)
-(defvar relint--error-count)
-(defvar relint--suppression-count)
 
 (defun relint--get-error-buffer ()
   "Buffer to which errors are printed, or nil if noninteractive."
@@ -118,8 +112,8 @@
  (erase-buffer)))
  buf)))
 
-(defun relint--add-to-error-buffer (string)
-  (with-current-buffer relint--error-buffer
+(defun relint--add-to-error-buffer (error-buffer string)
+  (with-current-buffer error-buffer
 (goto-char (point-max))
 (let ((inhibit-read-only t))
   (insert string
@@ -244,19 +238,21 @@ or nil if no position could be determined."
 (forward-line -1))
   matched)))
 
-(defun relint--output-message (string)
-  (if relint--error-buffer
-  (relint--add-to-error-buffer (concat string "\n"))
+(defun relint--output-message (error-buffer string)
+  (if error-buffer
+  (relint--add-to-error-buffer error-buffer (concat string "\n"))
 (message "%s" string)))
 
-(defun relint--output-report (file expr-pos error-pos message str str-idx
-  severity)
+(cl-defun relint--output-report (error-buffer file
+ (message expr-pos error-pos
+  str str-idx severity))
   (let* ((pos (or error-pos expr-pos))
  (line (line-number-at-pos pos t))
  (col (save-excursion
 (goto-char pos)
 (1+ (current-column)
 (relint--output-message
+ error-buffer
  (concat
   (format "%s:%d:%d: " file line col)
   (and (eq severity 'error) "error: ")
@@ -265,25 +261,27 @@ or nil if no position could be determined."
   (and str (format "\n  %s" (relint--quote-string str)))
   (and str-idx (format "\n   %s" (relint--caret-string str str-idx)))
   
-(defvar relint--report-function #'relint--output-report
-  "Function accepting a found complaint, taking the arguments
-(FILE EXPR-POS ERROR-POS MESSAGE STRING STRING-IDX SEVERITY).")
+(defun relint--output-complaints (buffer file complaints error-buffer)
+  (with-current-buffer buffer
+(dolist (complaint complaints)
+  (relint--output-report error-buffer file complaint
 
-(defun relint--report (file start-pos path message str str-idx severity)
+(defvar relint--suppression-count)
+(defvar relint--complaints)
+
+(defun relint--report (start-pos path message str str-idx severity)
   (let* ((expr-pos (relint--pos-from-start-pos-path start-pos path))
  (error-pos (and str-idx (relint--string-pos expr-pos str-idx
 (if (relint--suppression expr-pos message)
 (setq relint--suppression-count (1+ relint--suppression-count))
-  (funcall relint--report-function
-   (thunk-force file) expr-pos error-pos message
-   str str-idx severity)))
-  (setq relint--error-count (1+ relint--error-count)))
+  (push (list message expr-pos error-pos str str-idx severity)
+relint--complaints
 
-(defun relint--warn (file start-pos path message  str str-idx)
-  (relint--report file start-pos path message str str-idx 'warning))
+(defun relint--warn (start-pos path message  str str-idx)
+  (relint--report start-pos path message str str-idx 'warning))
 
-(defun relint--err (file start-pos path message  str str-idx)
-  (relint--report file start-pos path message str str-idx 'error))
+(defun relint--err (start-pos path message  str str-idx)
+  (relint--report start-pos path message str str-idx 'error))
 
 (defun relint--escape-string (str escape-printable)
   (replace-regexp-in-string
@@ -311,31 +309,30 @@ or nil if no position could be 

[elpa] externals/relint 2de1106 04/11: Sort diagnostics by buffer position

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 2de1106c366fb25ec1b0d2036babd563a404eeba
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Sort diagnostics by buffer position

This is useful in order to intermingle the useless-backslash warnings
with those from the other checks.
---
 relint.el | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 73f32a5..ae94890 100644
--- a/relint.el
+++ b/relint.el
@@ -2233,7 +2233,19 @@ STRING-START is the start of the string literal (first 
double quote)."
 (dolist (form forms)
   (relint--check-form-recursively-2 (car form) nil (cdr form) nil))
 (relint--miscape-current-buffer)
-(cons (nreverse relint--complaints) relint--suppression-count)))
+(let ((complaints (nreverse relint--complaints)))
+  (cons
+   (sort complaints
+ ;; Sort by error position if available, expression position
+ ;; otherwise.
+ (lambda (a b)
+   (let ((expr-pos-a (nth 1 a))
+ (expr-pos-b (nth 1 b))
+ (error-pos-a (nth 2 a))
+ (error-pos-b (nth 2 b)))
+ (< (or error-pos-a expr-pos-a)
+(or error-pos-b expr-pos-b)
+   relint--suppression-count
 
 (defvar relint-last-target nil
   "The last file, directory or buffer on which relint was run.")



[elpa] externals/relint updated (a54960a -> 0c35e02)

2020-06-20 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  a54960a   Increment version to 1.17
   new  6bfba5c   Always output to stderr when running noninteractively
   new  329df9c   Refactor framework
   new  e8d8052   Add checking of ineffective backslashes in string literals
   new  2de1106   Sort diagnostics by buffer position
   new  1ea9b91   Add tests for ineffective backslash check
   new  a1c7bf5   Describe the ineffective backslash warning in README
   new  0d80c1f   Rename various 'miscape' identifiers
   new  0627d4d   Simplify (and speed up) string scanning regexp
   new  e35fa2e   Fix doc string predicate
   new  6a86509   Tuned miscape filtering
   new  0c35e02   Increment version to 1.18


Summary of changes:
 README   |  17 ++
 relint-test.el   |   2 +-
 relint.el| 609 ---
 test/13.elisp|  19 ++
 test/13.expected |  28 +++
 5 files changed, 416 insertions(+), 259 deletions(-)
 create mode 100644 test/13.elisp
 create mode 100644 test/13.expected



[elpa] externals/relint 1ea9b91 05/11: Add tests for ineffective backslash check

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 1ea9b91bb5c17f3aeac4a2263cd7a68011dc3055
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add tests for ineffective backslash check
---
 test/13.elisp| 17 +
 test/13.expected | 17 +
 2 files changed, 34 insertions(+)

diff --git a/test/13.elisp b/test/13.elisp
new file mode 100644
index 000..4c6fb35
--- /dev/null
+++ b/test/13.elisp
@@ -0,0 +1,17 @@
+;;; Relint test file 13  -*- emacs-lisp -*-
+
+;; Test ineffective backslashes in strings
+
+(defun f1 ()
+  "doc string with \(silly\) bac\kslashes
+\[that we ignore\]"
+  (list
+   "\more \(bad things\)"
+   "long \
+\(with mistakes\)
+\{and so on\}"
+   "valid: \\ \" \x5e \172 \u1234 \u0041 \C-x \M-e \ \
+and \a \b \f \n \r \t \v \d \e \s \^P"))
+
+(defun f2 ()
+  (re-search-forward "\$\.x\+\+"))
diff --git a/test/13.expected b/test/13.expected
new file mode 100644
index 000..fd69f6f
--- /dev/null
+++ b/test/13.expected
@@ -0,0 +1,17 @@
+13.elisp:9:5: Ineffective string escape `\m'
+13.elisp:9:11: Ineffective string escape `\('
+13.elisp:9:23: Ineffective string escape `\)'
+13.elisp:10:10: Ineffective string escape `\<'
+13.elisp:10:18: Ineffective string escape `\>'
+13.elisp:11:16: Ineffective string escape `\)'
+13.elisp:12:12: Ineffective string escape `\}'
+13.elisp:17:23: In call to re-search-forward: Unescaped literal `$' (pos 0)
+  "$.x++"
+   ^
+13.elisp:17:23: Ineffective string escape `\$'
+13.elisp:17:25: Ineffective string escape `\.'
+13.elisp:17:28: Ineffective string escape `\+'
+13.elisp:17:30: In call to re-search-forward: Repetition of repetition (pos 4)
+  "$.x++"
+   ^
+13.elisp:17:30: Ineffective string escape `\+'



[elpa] externals/relint e8d8052 03/11: Add checking of ineffective backslashes in string literals

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit e8d80524bf41980c765f045e07acf325837376f1
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add checking of ineffective backslashes in string literals

This is an experimental feature.

Check all string literals (not just those that are regexps) for
backslashes that do not escape something sensible; this is a frequent
source of mistakes for regexps in particular, and can indicate errors
in other strings as well.

Currently, all such occurrencies in doc strings are ignored since
those are mostly false positives.
---
 relint.el | 84 +++
 1 file changed, 84 insertions(+)

diff --git a/relint.el b/relint.el
index d4c261c..73f32a5 100644
--- a/relint.el
+++ b/relint.el
@@ -2131,6 +2131,89 @@ Return a list of (FORM . STARTING-POSITION)."
   (push (cons form pos) forms
 (nreverse forms)))
 
+(defun relint--miscape-in-doc-string-p (pos)
+  "Whether the string literal starting at POS is a doc string."
+  (save-excursion
+(goto-char pos)
+;; Go back to start of containing sexp, counting the steps.
+(let ((steps 0))
+  (while (and (not (bobp))
+  (ignore-errors
+(forward-sexp -1)
+t)
+  (not (and (= steps 0)
+(looking-at (rx ":documentation" symbol-end)
+(setq steps (1+ steps)))
+  (or
+   (= steps 0)   ; `:documentation' parameter
+   (and (= steps 3)
+(looking-at (rx (or "defun" "defmacro" "defsubst" "defalias"
+"defconst" "defvar" "defcustom"
+"autoload"
+"cl-defun" "cl-defmacro" "cl-defmethod"
+"ert-deftest"
+;; Specific to cc-mode
+"c-lang-defvar"
+;; Specific to gnus
+"defvoo"
+   (and (= steps 2)
+(looking-at (rx (or "define-major-mode" "define-minor-mode"
+;; Specific to cc-mode
+"c-lang-defconst"
+   (and (= steps 4)
+(looking-at (rx (or "define-derived-mode"
+
+(defconst relint--miscape-ignore-left-round-bracket nil
+  "Whether to ignore specifically `\\(' in doc strings.")
+
+(defconst relint--miscape-ignore-all-doc-strings t
+  "Whether to ignore all stray backslashes in doc strings.")
+
+(defun relint--miscape-suspicious-backslash (string-start)
+  "With point at an ineffective backslash, emit an warning unless filtered out.
+STRING-START is the start of the string literal (first double quote)."
+  (let ((c (char-after (1+ (point)
+(unless (or (bolp)
+(and (or (and relint--miscape-ignore-left-round-bracket
+  (eq c ?\())
+ relint--miscape-ignore-all-doc-strings)
+ (relint--miscape-in-doc-string-p string-start)))
+  (relint--warn (point) nil
+(format-message
+ "Ineffective string escape `\\%s'"
+ (relint--escape-string (char-to-string c) nil))
+
+(defun relint--miscape-current-buffer ()
+  "Check for misplaced backslashes in the current buffer."
+  (goto-char (point-min))
+  (while (not (eobp))
+(when (looking-at (rx (1+ (or (seq "?" (or (seq ?\\ anything)
+   (not (any ?\\
+  (seq "\\" anything)
+  (seq ";" (0+ nonl))
+  (not (any ?\" ?\; ?? ?\\))
+  (goto-char (match-end 0)))
+(when (looking-at (rx ?\"))
+  (let ((string-start (point)))
+(goto-char (match-end 0))
+(while (not (looking-at (rx (or ?\" eot
+  (when (looking-at
+ (rx (1+ (or (seq
+  ?\\ (any "0-9" "xuUN" "abfnrtv"
+   "des" "^" " "
+   ?\\ ?\n ?\"))
+ (seq
+  (1+ ?\\ (any "CM") "-")
+  (or (not (any ?\\))
+  (seq ?\\ anything)))
+ (not (any ?\\ ?\"))
+(goto-char (match-end 0)))
+  (when (eq (following-char) ?\\)
+(relint--miscape-suspicious-backslash string-start)
+(forward-char 2)))
+(unless (eobp)
+  (forward-char 1))
+
 (defun relint--scan-current-buffer ()
   (let* ((relint--suppression-count 0)
  (relint--complaints nil)
@@ -2149,6 +2232,7 @@ Return a list of (FORM . STARTING-POSITION)."
   (relint--check-form-recursively-1 (car form) (cdr form) nil))
 (dolist (form forms)
 

[elpa] externals/relint 6bfba5c 01/11: Always output to stderr when running noninteractively

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 6bfba5c46a542a1b6396717779a9cd6e65bb5848
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Always output to stderr when running noninteractively

Previously, relint-file, relint-directory and relint-current-buffer
always wrote to the *relint* buffer which may be less useful in such
cases (especially with the summary line going to stderr).

Reported/suggested by Paul Pogonyshev (bug #10).
---
 relint.el | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/relint.el b/relint.el
index 8134671..959f57d 100644
--- a/relint.el
+++ b/relint.el
@@ -107,14 +107,16 @@
 (defvar relint--suppression-count)
 
 (defun relint--get-error-buffer ()
-  (let ((buf (get-buffer-create "*relint*")))
-(with-current-buffer buf
-  (unless (eq major-mode 'relint-mode)
-(relint-mode))
-  (let ((inhibit-read-only t))
-(compilation-forget-errors)
-(erase-buffer)))
-buf))
+  "Buffer to which errors are printed, or nil if noninteractive."
+  (and (not noninteractive)
+   (let ((buf (get-buffer-create "*relint*")))
+ (with-current-buffer buf
+   (unless (eq major-mode 'relint-mode)
+ (relint-mode))
+   (let ((inhibit-read-only t))
+ (compilation-forget-errors)
+ (erase-buffer)))
+ buf)))
 
 (defun relint--add-to-error-buffer (string)
   (with-current-buffer relint--error-buffer



[elpa] externals/relint 0c35e02 11/11: Increment version to 1.18

2020-06-20 Thread Mattias Engdegrd
branch: externals/relint
commit 0c35e02cb81de58adb2eabc53fa51fa14340050d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.18
---
 relint.el | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 5124958..b95ef5c 100644
--- a/relint.el
+++ b/relint.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.17
+;; Version: 1.18
 ;; Package-Requires: ((xr "1.19") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
@@ -29,6 +29,10 @@
 
 ;;; News:
 
+;; Version 1.18:
+;; - New check for ineffective backslashes in all strings (not just regexps)
+;; - Warnings emitted in order of their position in file or buffer
+;; - Performance improvements
 ;; Version 1.17:
 ;; - Fixed message display on Emacs 26
 ;; Version 1.16:



[elpa] externals/relint 9eac0ae 4/5: Add tests for some uncovered rx warning cases

2020-05-10 Thread Mattias Engdegrd
branch: externals/relint
commit 9eac0ae7e122c520443992c058a4fdd7458402a8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add tests for some uncovered rx warning cases
---
 test/11.elisp| 7 ++-
 test/11.expected | 7 +++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/test/11.elisp b/test/11.elisp
index 8c48a39..d629a56 100644
--- a/test/11.elisp
+++ b/test/11.elisp
@@ -26,4 +26,9 @@
   ;; No error here.
   (rx (any "\000-\377" ?å) (any "\377" 255))
   ;; But here.
-  (rx (any "\000-\377" "\177" "\240")))
+  (rx (any "\000-\377" "\177" "\240"))
+
+  (rx (any "a-z" ?m))
+  (rx (any "a-f" "\000-\377"))
+  (rx (any "\240-\277" "\000-\377"))
+  )
diff --git a/test/11.expected b/test/11.expected
index bb0788f..2c0eb6b 100644
--- a/test/11.expected
+++ b/test/11.expected
@@ -52,3 +52,10 @@
 11.elisp:29:32: Character `\240' included in range `\200-\377' (pos 0)
   "\240"
^
+11.elisp:31:18: Character `m' included in range `a-z'
+11.elisp:32:19: Range `\000-\377' overlaps previous `a-f' (pos 0)
+  "\000-\377"
+   ^
+11.elisp:33:25: Range `\000-\377' overlaps previous `\240-\277' (pos 0)
+  "\000-\377"
+   ^



[elpa] externals/relint 762f3f8 3/5: Work around rx bug in Emacs 26

2020-05-10 Thread Mattias Engdegrd
branch: externals/relint
commit 762f3f8bd946c68ced3d5b6dc60dccf30ce0732e
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Work around rx bug in Emacs 26

Raw chars in string arguments to (any ...) forms weren't handled
correctly; use pairs with raw char values instead.
Found by Paul Pogonyshev (bug#9).
---
 relint.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index b946bf4..c90bcce 100644
--- a/relint.el
+++ b/relint.el
@@ -283,7 +283,8 @@ or nil if no position could be determined."
 
 (defun relint--escape-string (str escape-printable)
   (replace-regexp-in-string
-   (rx (any cntrl "\177-\377" ?\\ ?\"))
+   ;; Use pair notation for raw chars; "\200-\377" is buggy in Emacs 26.
+   (rx (any cntrl ?\177 (#x3fff80 . #x3f) ?\\ ?\"))
(lambda (s)
  (let ((c (logand (string-to-char s) #xff)))
(or (cdr (assq c '((?\b . "\\b")



[elpa] externals/relint a54960a 5/5: Increment version to 1.17

2020-05-10 Thread Mattias Engdegrd
branch: externals/relint
commit a54960a7059ff798a23383c87f123591a764c585
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.17
---
 relint.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index c90bcce..8134671 100644
--- a/relint.el
+++ b/relint.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.16
+;; Version: 1.17
 ;; Package-Requires: ((xr "1.19") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
@@ -29,6 +29,8 @@
 
 ;;; News:
 
+;; Version 1.17:
+;; - Fixed message display on Emacs 26
 ;; Version 1.16:
 ;; - Suppression comments now use regexp matching of messages
 ;; - New filename-specific checks in calls to `directory-files' etc



[elpa] externals/relint updated (a001a05 -> a54960a)

2020-05-10 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  a001a05   Increment version to 1.16
   new  0cbcadb   Add github auto-test infrastructure
   new  3cb19ed   Avoid byte-compilation warning in Emacs 26
   new  762f3f8   Work around rx bug in Emacs 26
   new  9eac0ae   Add tests for some uncovered rx warning cases
   new  a54960a   Increment version to 1.17


Summary of changes:
 .github/workflows/test.yml | 37 +
 Makefile   | 20 
 relint.el  | 11 ---
 test/11.elisp  |  7 ++-
 test/11.expected   |  7 +++
 5 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 .github/workflows/test.yml
 create mode 100644 Makefile



[elpa] externals/relint 0cbcadb 1/5: Add github auto-test infrastructure

2020-05-10 Thread Mattias Engdegrd
branch: externals/relint
commit 0cbcadba77d857d1e4f9a4fc4ef44a24176e3473
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add github auto-test infrastructure

From a suggestion by Paul Pogonyshev (bug#9).
---
 .github/workflows/test.yml | 37 +
 Makefile   | 20 
 2 files changed, 57 insertions(+)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000..3e23562
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,37 @@
+name: test
+
+on:
+  push:
+paths-ignore:
+  - '**README*'
+  pull_request:
+paths-ignore:
+  - '**README*'
+
+jobs:
+  test:
+runs-on: ubuntu-latest
+strategy:
+  matrix:
+emacs_version:
+  - "26.3"
+  - snapshot
+steps:
+  - name: Set up Emacs
+uses: purcell/setup-emacs@master
+with:
+  version: ${{matrix.emacs_version}}
+
+  - name: Check out relint
+uses: actions/checkout@v2
+with:
+  path: relint
+
+  - name: Check out xr
+uses: actions/checkout@v2
+with:
+  repository: mattiase/xr
+  path: xr
+
+  - name: Test
+run: make -C relint build check
diff --git a/Makefile b/Makefile
new file mode 100644
index 000..b143637
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+EMACS=emacs
+XRDIR=../xr
+EMFLAGS=-Q -batch -L . -L $(XRDIR)
+BYTECOMPFLAGS=--eval '(setq byte-compile-error-on-warn t)'
+
+EL=$(wildcard *.el)
+ELC=$(EL:.el=.elc)
+
+.PHONY: build check clean
+
+build: $(ELC)
+
+clean:
+   rm -f $(ELC)
+
+check:
+   $(EMACS) $(EMFLAGS) -l relint-test -f ert-run-tests-batch-and-exit
+
+%.elc: %.el
+   $(EMACS) $(EMFLAGS) $(BYTECOMPFLAGS) -f batch-byte-compile $^



[elpa] externals/relint 3cb19ed 2/5: Avoid byte-compilation warning in Emacs 26

2020-05-10 Thread Mattias Engdegrd
branch: externals/relint
commit 3cb19ed8966f5ab7a4577865def0ddba62d157e4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Avoid byte-compilation warning in Emacs 26

string-to-multibyte was marked obsolete in Emacs 26 (but no longer is).
---
 relint.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 0651d3b..b946bf4 100644
--- a/relint.el
+++ b/relint.el
@@ -1420,7 +1420,9 @@ than just to a surrounding or producing expression."
(push (cons arg arg) ranges))
 
   ((stringp arg)
-   (let* ((s (string-to-multibyte arg))
+   ;; `string-to-multibyte' was marked obsolete in Emacs 26,
+   ;; but no longer is.
+   (let* ((s (with-no-warnings (string-to-multibyte arg)))
   (j 0)
   (len (length s)))
  (while (< j len)



[elpa] externals/relint 9259a5c 03/21: Check some :value parameters in defcustom :type clauses

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 9259a5c5e82f75aa4efd20746c6d0887acd64e0f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check some :value parameters in defcustom :type clauses

For example, this catches

  :type '(string :value "some bad regexp")
---
 relint.el   | 13 +++--
 test/1.elisp| 13 +
 test/1.expected | 30 +-
 3 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index bc4a9af..d484116 100644
--- a/relint.el
+++ b/relint.el
@@ -1551,12 +1551,13 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 
 (defun relint--check-defcustom-type (type name file pos path)
   (pcase type
-(`(const . ,rest)
- ;; Skip keywords.
- (while (and rest (symbolp (car rest)))
-   (setq rest (cddr rest)))
- (when rest
-   (relint--check-re (car rest) name file pos path)))
+(`(,(or 'const 'string 'regexp) . ,rest)
+ (while (consp rest)
+   (cond ((eq (car rest) :value)
+  (relint--check-re (cadr rest) name file pos path))
+ ((not (cdr rest))
+  (relint--check-re (car rest) name file pos path)))
+   (setq rest (cddr rest
 (`(,(or 'choice 'radio) . ,choices)
  (dolist (choice choices)
(relint--check-defcustom-type choice name file pos path)
diff --git a/test/1.elisp b/test/1.elisp
index 865d21a..c00681a 100644
--- a/test/1.elisp
+++ b/test/1.elisp
@@ -75,6 +75,19 @@
   :group 'relint-test
   :type '(repeat regexp))
 
+(defcustom bad-custom-8 nil
+  "Doc"
+  :type '(choice (regexp :tag "*" :value "[11]")
+ (string :tag "+" :value "[22]")))
+
+(defcustom bad-custom-9-regexp nil
+  "Doc"
+  :type '(string :tag "+" :value "[33]"))
+
+(defcustom bad-custom-10 nil
+  "regular expression"
+  :type '(string :tag "+" "[44]"))
+
 ;; Special case.
 (defvar compilation-error-regexp-alist-alist
   '((aa "a^a" 1 2)
diff --git a/test/1.expected b/test/1.expected
index 8d1e997..4014a72 100644
--- a/test/1.expected
+++ b/test/1.expected
@@ -138,30 +138,42 @@
 1.elisp:73:35: In bad-custom-7: Duplicated `a' inside character alternative 
(pos 2)
   "[aa]"
..^
-1.elisp:80:11: In compilation-error-regexp-alist-alist (aa): Unescaped literal 
`^' (pos 1)
+1.elisp:80:9: In bad-custom-8: Duplicated `1' inside character alternative 
(pos 2)
+  "[11]"
+   ..^
+1.elisp:80:9: In bad-custom-8: Duplicated `2' inside character alternative 
(pos 2)
+  "[22]"
+   ..^
+1.elisp:85:9: In bad-custom-9-regexp: Duplicated `3' inside character 
alternative (pos 2)
+  "[33]"
+   ..^
+1.elisp:89:9: In bad-custom-10: Duplicated `4' inside character alternative 
(pos 2)
+  "[44]"
+   ..^
+1.elisp:93:11: In compilation-error-regexp-alist-alist (aa): Unescaped literal 
`^' (pos 1)
   "a^a"
.^
-1.elisp:81:11: In compilation-error-regexp-alist-alist (bb): Unescaped literal 
`$' (pos 1)
+1.elisp:94:11: In compilation-error-regexp-alist-alist (bb): Unescaped literal 
`$' (pos 1)
   "b$b"
.^
-1.elisp:86:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+1.elisp:99:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
   "1^"
.^
-1.elisp:87:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+1.elisp:100:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
   "2^"
.^
-1.elisp:88:12: In define-generic-mode my-mode: Repetition of repetition (pos 2)
+1.elisp:101:12: In define-generic-mode my-mode: Repetition of repetition (pos 
2)
   "b++"
..^
-1.elisp:94:6: In call to syntax-propertize-rules: Unescaped literal `$' (pos 0)
+1.elisp:107:6: In call to syntax-propertize-rules: Unescaped literal `$' (pos 
0)
   "$1$"
^
-1.elisp:95:8: In call to syntax-propertize-rules: Unescaped literal `^' (pos 2)
+1.elisp:108:8: In call to syntax-propertize-rules: Unescaped literal `^' (pos 
2)
   "^2^"
..^
-1.elisp:100:6: In call to syntax-propertize-precompile-rules: Unescaped 
literal `$' (pos 0)
+1.elisp:113:6: In call to syntax-propertize-precompile-rules: Unescaped 
literal `$' (pos 0)
   "$3$"
^
-1.elisp:101:8: In call to syntax-propertize-precompile-rules: Unescaped 
literal `^' (pos 2)
+1.elisp:114:8: In call to syntax-propertize-precompile-rules: Unescaped 
literal `^' (pos 2)
   "^4^"
..^



[elpa] externals/relint 09ef3df 05/21: Describe the new xr wrapped subsumption warning

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 09ef3dfa9c31317bf508ab18eb0d8f1e31c0b568
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe the new xr wrapped subsumption warning
---
 README | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/README b/README
index 944e665..3ca9499 100644
--- a/README
+++ b/README
@@ -122,6 +122,17 @@ skip-syntax-backward.
 so the a* could be removed without changing the meaning of the
 regexp.
 
+  - First/last item in repetition subsumes last/first item (wrapped)
+
+The first and last items in a repeated sequence, being effectively
+adjacent, match a superset or subset of each other, which makes
+for an unexpected inefficiency. For example, \(?:a*c[ab]+\)* can
+be seen as a*c[ab]+a*c[ab]+... where the [ab]+a* in the middle is
+a slow way of writing [ab]+ which is made worse by the outer
+repetition. The general remedy is to move the subsumed item out of
+the repeated sequence, resulting in a*\(?:c[ab]+\)* in the example
+above.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/relint 5d3f78d 19/21: Update xr messages ("repetition" changed to "option")

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 5d3f78da32b03b8926076c10426366e07fd0f318
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Update xr messages ("repetition" changed to "option")
---
 README | 14 +++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 34a7b5b..7d25c5e 100644
--- a/README
+++ b/README
@@ -71,11 +71,17 @@ skip-syntax-backward.
 in order to include a literal backslash.
   
   - Repetition of repetition
+  - Repetition of option
+  - Optional repetition
+  - Optional option
   
 A repetition construct is applied to an expression that is already
-repeated, such as a*+ (? counts as repetition here). Such
-expressions can be written with a single repetition and often
-indicate a different mistake, such as missing backslashes.
+repeated, such as a*+ or \(x?\)?. These expressions can be written
+with a single repetition and often indicate a different mistake,
+perhaps a missing backslash.
+
+When a repetition construct is ? or ??, it is termed 'option'
+instead; the principle is the same.
 
   - Reversed range 'Y-X' matches nothing
 
@@ -186,12 +192,14 @@ skip-syntax-backward.
 intended as part of a range.
 
   - Repetition of zero-width assertion
+  - Optional zero-width assertion
 
 A repetition operator was applied to a zero-width assertion, like
 ^ or \<, which is completely pointless. The error may be a missing
 escaping backslash.
 
   - Repetition of expression matching an empty string
+  - Optional expression matching an empty string
 
 A repetition operator was applied to a sub-expression that could
 match the empty string; this is not necessarily wrong, but such



[elpa] externals/relint f6d0fed 15/21: Describe the new file-specific warnings

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit f6d0fedd9bd876c741de17b7bb3db29983c338ab
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe the new file-specific warnings
---
 README | 16 
 1 file changed, 16 insertions(+)

diff --git a/README b/README
index f816349..34a7b5b 100644
--- a/README
+++ b/README
@@ -147,6 +147,22 @@ skip-syntax-backward.
 A pattern that only matches a non-empty string occurs right after
 an end-of-text anchor (\'). This combination can never match.
 
+  - Use \` instead of ^ in file-matching regexp
+  - Use \' instead of $ in file-matching regexp
+
+In a regexp used for matching a file name, newlines are usually
+not relevant. Line-start and line-end anchors should therefore
+probably be replaced with string-start and string-end,
+respectively. Otherwise, the regexp may fail for file names that
+do contain newlines.
+
+  - Possibly unescaped '.' in file-matching regexp
+
+In a regexp used for matching a file name, a naked dot is usually
+more likely to be a mistake (missing escaping backslash) than an
+actual intent to match any character except newline, since literal
+dots are very common in file name patterns.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/relint 96e26a5 02/21: Check keyword arguments :regexp and :regex

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 96e26a5f8f3967cf5b1e181831e94860f2be6c74
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check keyword arguments :regexp and :regex
---
 relint.el   | 8 +++-
 test/2.elisp| 4 
 test/2.expected | 6 ++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 567315c..bc4a9af 100644
--- a/relint.el
+++ b/relint.el
@@ -1965,11 +1965,17 @@ directly."
  ;; mutables since all args are evaluated once.
  (let ((index 0))
(while (consp form)
- (when (consp (car form))
+ (cond
+  ((consp (car form))
;; Check subforms with the assumption that nothing can be mutated,
;; since we don't really know what is evaluated when.
(relint--check-form-recursively-2
 (car form) nil file pos (cons index path)))
+  ((and (memq (car form) '(:regexp :regex))
+(consp (cdr form)))
+   (relint--check-re (cadr form)
+ (format "%s parameter" (car form))
+ file pos (cons (1+ index) path
  (setq form (cdr form))
  (setq index (1+ index)))
 
diff --git a/test/2.elisp b/test/2.elisp
index 1a2c4ea..a96cef0 100644
--- a/test/2.elisp
+++ b/test/2.elisp
@@ -50,3 +50,7 @@
 
 (defun f6 ()
   (f5 "[aa]" "[bb]" "[cc]" "[dd]" "[ee]"))
+
+(defun f7 ()
+  (alpha beta :regexp "[11]")
+  (gamma :regex "[22]" delta))
diff --git a/test/2.expected b/test/2.expected
index 0bde370..0dbcfc8 100644
--- a/test/2.expected
+++ b/test/2.expected
@@ -133,3 +133,9 @@
 2.elisp:52:31: In call to f5: Duplicated `d' inside character alternative (pos 
2)
   "[dd]"
..^
+2.elisp:55:26: In :regexp parameter: Duplicated `1' inside character 
alternative (pos 2)
+  "[11]"
+   ..^
+2.elisp:56:20: In :regex parameter: Duplicated `2' inside character 
alternative (pos 2)
+  "[22]"
+   ..^



[elpa] externals/relint a001a05 21/21: Increment version to 1.16

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit a001a05a1d692be22f7fac9233e8cc0102aebd30
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.16

Require xr 1.19
---
 relint.el | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index cbdd340..0651d3b 100644
--- a/relint.el
+++ b/relint.el
@@ -3,8 +3,8 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.15
-;; Package-Requires: ((xr "1.17") (emacs "26.1"))
+;; Version: 1.16
+;; Package-Requires: ((xr "1.19") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
 
@@ -29,6 +29,12 @@
 
 ;;; News:
 
+;; Version 1.16:
+;; - Suppression comments now use regexp matching of messages
+;; - New filename-specific checks in calls to `directory-files' etc
+;; - Check some keyword arguments (:regexp and :regex)
+;; - Improved rx checks
+;; - `relint-directory' now displays number of files found
 ;; Version 1.15:
 ;; - Improved position accuracy in various lists of regexps
 ;; - Check for mistake in rx `any' forms



[elpa] externals/relint eb178d5 06/21: Check assignments to imenu-generic-expression

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit eb178d5f9d529ccc29785e277683faa661e73be4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check assignments to imenu-generic-expression
---
 relint.el   | 16 +++-
 test/9.elisp|  5 +
 test/9.expected |  3 +++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 0c1653d..31f1887 100644
--- a/relint.el
+++ b/relint.el
@@ -1152,6 +1152,14 @@ or in the car of an element."
 (relint--check-re-string (car elem) ident file pos p)
form path))
 
+(defun relint--check-imenu-generic-expression (form name file pos path)
+  (relint--eval-list-iter
+   (lambda (elem elem-path literal)
+ (when (and (consp elem) (consp (cdr elem)) (stringp (cadr elem)))
+   (relint--check-re-string
+(cadr elem) name file pos (if literal (cons 1 elem-path) elem-path
+   form path))
+
 (defun relint--check-compilation-error-regexp-alist-alist (form name
file pos path)
   (relint--eval-list-iter
@@ -1701,6 +1709,9 @@ directly."
 ((memq name '(font-lock-defaults font-lock-keywords))
  (relint--check-font-lock-keywords expr name
file pos (cons i path)))
+((eq name 'imenu-generic-expression)
+ (relint--check-imenu-generic-expression
+  expr name file pos (cons i path)))
 (t
  ;; Invalidate the variable if it was local; otherwise, ignore.
  (let ((local (assq name relint--locals)))
@@ -1948,7 +1959,10 @@ directly."
(relint--check-re expr name file pos (cons 2 path)))
   ((memq name '(font-lock-defaults font-lock-keywords))
(relint--check-font-lock-keywords expr name
- file pos (cons 2 path)
+ file pos (cons 2 path)))
+  ((eq name 'imenu-generic-expression)
+   (relint--check-imenu-generic-expression
+expr name file pos (cons 2 path)
(`(define-generic-mode ,name ,_ ,_ ,font-lock-list ,auto-mode-list . ,_)
 (let ((origin (format "define-generic-mode %s" name)))
   (relint--check-font-lock-keywords font-lock-list origin
diff --git a/test/9.elisp b/test/9.elisp
index 322334f..4a37174 100644
--- a/test/9.elisp
+++ b/test/9.elisp
@@ -23,3 +23,8 @@
   (setq-local font-lock-defaults '(("[mm]" . tag)))
   (setq font-lock-defaults '(("[nn]" . tag)))
   (set (make-local-variable 'font-lock-defaults) '(("[oo]" . tag
+
+(defun test-9-ge ()
+  (setq-local imenu-generic-expression
+  '((nil "oh" 0)
+("*more*" "+a+" 0
diff --git a/test/9.expected b/test/9.expected
index ab3f06e..7bab898 100644
--- a/test/9.expected
+++ b/test/9.expected
@@ -43,3 +43,6 @@
 9.elisp:25:56: In font-lock-defaults (tag): Duplicated `o' inside character 
alternative (pos 2)
   "[oo]"
..^
+9.elisp:30:28: In imenu-generic-expression: Unescaped literal `+' (pos 0)
+  "+a+"
+   ^



[elpa] externals/relint cf2a2ae 14/21: Do file-specific checks on arguments to known functions

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit cf2a2ae075f132aab97a32fc4d0c8921068217bb
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Do file-specific checks on arguments to known functions

This includes directory-files, directory-files-and-attributes,
directory-files-recursively, load-history-filename-element,
and modify-coding-system-alist (with type = file).
---
 relint.el| 20 +++-
 test/12.elisp|  9 +
 test/12.expected | 15 +++
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/relint.el b/relint.el
index 03a9421..1adcaee 100644
--- a/relint.el
+++ b/relint.el
@@ -1887,7 +1887,6 @@ directly."
'posix-looking-at 'posix-search-backward 'posix-search-forward
'posix-string-match
'search-forward-regexp 'search-backward-regexp
-   'load-history-filename-element
'kill-matching-buffers
'keep-lines 'flush-lines 'how-many)
   ,re-arg . ,_)
@@ -1895,9 +1894,14 @@ directly."
  (memq re-arg relint--checked-variables))
   (relint--check-re re-arg (format "call to %s" (car form))
 file pos (cons 1 path
+   (`(load-history-filename-element ,re-arg)
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 1 path)))
+   (`(directory-files-recursively ,_ ,re-arg . ,_)
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 2 path)))
(`(,(or 'split-string 'split-string-and-unquote
-   'string-trim-left 'string-trim-right 'string-trim
-   'directory-files-recursively)
+   'string-trim-left 'string-trim-right 'string-trim)
   ,_ ,re-arg . ,rest)
 (unless (and (symbolp re-arg)
  (memq re-arg relint--checked-variables))
@@ -1921,8 +1925,8 @@ directly."
 file pos (cons 4 path))
(`(,(or 'directory-files 'directory-files-and-attributes)
   ,_ ,_ ,re-arg . ,_)
-(relint--check-re re-arg (format "call to %s" (car form))
-  file pos (cons 3 path)))
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 3 path)))
(`(,(or 'skip-chars-forward 'skip-chars-backward)
   ,skip-arg . ,_)
 (let ((str (relint--get-string skip-arg)))
@@ -2078,6 +2082,12 @@ directly."
(`(add-to-list 'auto-mode-alist ,elem . ,_)
 (relint--check-auto-mode-alist-expr
  elem (car form) file pos (cons 2 path)))
+   (`(modify-coding-system-alist ,type ,re-arg ,_)
+(funcall
+ (if (eq (relint--eval-or-nil type) 'file)
+ #'relint--check-file-name-re
+   #'relint--check-re)
+ re-arg (format "call to %s" (car form)) file pos (cons 2 path)))
(`(,name . ,args)
 (let ((alias (assq name relint--alias-defs)))
   (when alias
diff --git a/test/12.elisp b/test/12.elisp
index ea04551..04ea09c 100644
--- a/test/12.elisp
+++ b/test/12.elisp
@@ -14,3 +14,12 @@
 (setq auto-mode-alist (append '((".hh\\'" . some-mode)
 (".ii\\'" . some-mode))
   auto-mode-alist))
+
+;; File-matching regexp functions
+
+(defun f12 (d)
+  (directory-files d nil ".txt\\'")
+  (directory-files-and-attributes d nil "\\.pas$")
+  (directory-files-recursively d "^abc")
+  (modify-coding-system-alist 'file "\\.ml$" 'utf-8)
+  (modify-coding-system-alist 'process "+xx$" 'utf-8))
diff --git a/test/12.expected b/test/12.expected
index 6abea93..ecef078 100644
--- a/test/12.expected
+++ b/test/12.expected
@@ -22,3 +22,18 @@
 12.elisp:15:35: Possibly unescaped `.' in file-matching regexp (pos 0)
   ".ii\\'"
^
+12.elisp:21:27: Possibly unescaped `.' in file-matching regexp (pos 0)
+  ".txt\\'"
+   ^
+12.elisp:22:48: Use \' instead of $ in file-matching regexp (pos 5)
+  "\\.pas$"
+   ..^
+12.elisp:23:35: Use \` instead of ^ in file-matching regexp (pos 0)
+  "^abc"
+   ^
+12.elisp:24:43: Use \' instead of $ in file-matching regexp (pos 4)
+  "\\.ml$"
+   .^
+12.elisp:25:41: In call to modify-coding-system-alist: Unescaped literal `+' 
(pos 0)
+  "+xx$"
+   ^



[elpa] externals/relint a50ed0b 20/21: Don't escape printable chars in rx warnings

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit a50ed0b3c15339ae3979d3aa2ac61bf8bdf7a160
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't escape printable chars in rx warnings
---
 relint.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index b775b8a..cbdd340 100644
--- a/relint.el
+++ b/relint.el
@@ -1355,7 +1355,7 @@ character alternative: `[' followed by a 
regexp-generating expression."
(if (eq from to)
(char-to-string from)
  (format "%c-%c" from to))
-   t))
+   nil))
 
 (defun relint--intersecting-range (from to ranges)
   "Return a range in RANGES intersecting [FROM,TO], or nil if none.
@@ -1438,7 +1438,7 @@ than just to a surrounding or producing expression."
   file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
-   (relint--escape-string (format "%c-%c" from to) t))
+   (relint--escape-string (format "%c-%c" from to) 
nil))
   s j))
 ((= to (1+ from))
  (relint--warn



[elpa] externals/relint 326cfe2 11/21: Check calls to directory-files(-and-attributes)

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 326cfe24cd110e4cf7686b4a154c7bdb55a727e8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check calls to directory-files(-and-attributes)
---
 relint.el   |  4 
 test/2.elisp|  5 -
 test/2.expected | 49 +
 3 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/relint.el b/relint.el
index b17d451..6c81221 100644
--- a/relint.el
+++ b/relint.el
@@ -1844,6 +1844,10 @@ directly."
  (memq trim relint--checked-variables))
   (relint--check-re trim (format "call to %s" (car form))
 file pos (cons 4 path))
+   (`(,(or 'directory-files 'directory-files-and-attributes)
+  ,_ ,_ ,re-arg . ,_)
+(relint--check-re re-arg (format "call to %s" (car form))
+  file pos (cons 3 path)))
(`(,(or 'skip-chars-forward 'skip-chars-backward)
   ,skip-arg . ,_)
 (let ((str (relint--get-string skip-arg)))
diff --git a/test/2.elisp b/test/2.elisp
index a96cef0..f069a33 100644
--- a/test/2.elisp
+++ b/test/2.elisp
@@ -26,7 +26,10 @@
   (split-string-and-unquote s "[vv]")
   (string-trim-left s "[ww]")
   (string-trim-right s "[xx]")
-  (string-trim s "[yy]" "[zz]"))
+  (string-trim s "[yy]" "[zz]")
+  (directory-files s nil "+1")
+  (directory-files-and-attributes s nil "+2")
+  (directory-files-recursively s "+3"))
 
 ;; Test argument names as means of detecting regexps.
 (defun f2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
diff --git a/test/2.expected b/test/2.expected
index 0dbcfc8..347f31d 100644
--- a/test/2.expected
+++ b/test/2.expected
@@ -79,63 +79,72 @@
 2.elisp:29:28: In call to string-trim: Duplicated `z' inside character 
alternative (pos 2)
   "[zz]"
..^
-2.elisp:42:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:30:27: In call to directory-files: Unescaped literal `+' (pos 0)
+  "+1"
+   ^
+2.elisp:31:42: In call to directory-files-and-attributes: Unescaped literal 
`+' (pos 0)
+  "+2"
+   ^
+2.elisp:32:35: In call to directory-files-recursively: Unescaped literal `+' 
(pos 0)
+  "+3"
+   ^
+2.elisp:45:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:42:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:45:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:42:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:45:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:42:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:45:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:42:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:45:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:43:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:46:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:43:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:46:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:43:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:46:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:43:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:46:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:43:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:46:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:44:17: In call to m2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:47:17: In call to m2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:44:31: In call to m2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:47:31: In call to m2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:44:45: In call to m2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:47:45: In call to m2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:44:59: In call to m2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:47:59: In call to m2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:44:73: In call to m2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:47:73: In call to m2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:52:17: In call to f5: Duplicated `b' inside character alternative 

[elpa] externals/relint b694c09 07/21: Check split ASCII-raw ranges in rx correctly

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit b694c091dcb36ed4fd3a1f0d8f4a14cf9d5f9b74
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check split ASCII-raw ranges in rx correctly

Also make sure not to confuse raw bytes and U+0080-U+00FF.
---
 relint.el| 44 ++--
 test/11.elisp|  7 ++-
 test/11.expected |  6 ++
 3 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index 31f1887..d5b329e 100644
--- a/relint.el
+++ b/relint.el
@@ -1383,13 +1383,15 @@ than just to a surrounding or producing expression."
(push (cons arg arg) ranges))
 
   ((stringp arg)
-   (let ((j 0)
- (len (length arg)))
+   (let* ((s (string-to-multibyte arg))
+  (j 0)
+  (len (length s)))
  (while (< j len)
-   (let ((from (aref arg j)))
+   (let ((from (aref s j)))
  (if (and (< (+ j 2) len)
-  (eq (aref arg (1+ j)) ?-))
- (let ((to (aref arg (+ j 2
+  (eq (aref s (1+ j)) ?-))
+ ;; Range.
+ (let ((to (aref s (+ j 2
(cond
 ;; When people write "+-X" or "X-+" for some
 ;; X, they rarely mean a range.
@@ -1399,22 +1401,30 @@ than just to a surrounding or producing expression."
   file pos (if exact-path (cons i path) path)
   (format-message "Suspect range `%s'"
   (relint--pretty-range from to))
-  arg j))
+  s j))
 ((= to from)
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
(relint--escape-string (format "%c-%c" from to) t))
-  arg j))
+  s j))
 ((= to (1+ from))
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message "Two-character range `%s'"
   (relint--pretty-range from to))
-  arg j)))
-   (let ((overlap
-  (relint--intersecting-range from to ranges)))
+  s j)))
+   ;; Take care to split ASCII-raw ranges; they do not
+   ;; include anything in-between.
+   (let* ((split (and (<= from #x7f) (>= to #x3fff80)))
+  (overlap
+   (if split
+   (or (relint--intersecting-range
+from #x7f ranges)
+   (relint--intersecting-range
+#x3fff80 to ranges))
+ (relint--intersecting-range from to ranges
  (when overlap
(relint--warn
 file pos (if exact-path (cons i path) path)
@@ -1422,15 +1432,21 @@ than just to a surrounding or producing expression."
 (relint--pretty-range from to)
 (relint--pretty-range
  (car overlap) (cdr overlap)))
-arg j)))
-   (push (cons from to) ranges)
+s j))
+ (if split
+ (progn
+   (push (cons from #x7f) ranges)
+   (push (cons #x3fff80 to) ranges))
+   (push (cons from to) ranges)))
(setq j (+ j 3)))
+
+   ;; Single character.
(when (and (eq from ?-)
   (< 0 j (1- len)))
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message "Literal `-' not first or last")
-  arg j))
+  s j))
(let ((overlap
   (relint--intersecting-range from from ranges)))
  (when overlap
@@ -1443,7 +1459,7 @@ than just to a surrounding or producing expression."
"Character `%s' included in range `%s'"
(relint--pretty-range from from)
(relint--pretty-range (car overlap) (cdr overlap
-arg j)))
+  

[elpa] externals/relint 12a2b0f 08/21: Use regexp in suppression comments

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 12a2b0fafdba26526e2b166a322a6171fac19cc4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use regexp in suppression comments

This adds flexibility, in particular for coping with different quoting
styles.
---
 README   |  6 +++---
 relint.el| 10 +-
 test/6.elisp |  4 ++--
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/README b/README
index 3ca9499..7a355c4 100644
--- a/README
+++ b/README
@@ -265,10 +265,10 @@ skip-syntax-backward.
 
   To suppress such diagnostics, add a comment on the form
 
-;; relint suppression: MESSAGE
+;; relint suppression: REGEXP
 
-  on the line before the code where the error occurred. MESSAGE is a
-  substring of the message to be suppressed. Multiple suppression
+  on the line before the code where the error occurred. REGEXP
+  matches the message to be suppressed. Multiple suppression
   comment lines can precede a line of code to eliminate several
   complaints on the same line.
 
diff --git a/relint.el b/relint.el
index d5b329e..b17d451 100644
--- a/relint.el
+++ b/relint.el
@@ -209,9 +209,9 @@ or nil if no position could be determined."
   (save-excursion
 ;; On a preceding line, look for a comment on the form
 ;;
-;; relint suppression: SUBSTRING
+;; relint suppression: REGEXP
 ;;
-;; where SUBSTRING is a substring of MESSAGE. There can be
+;; where REGEXP matches MESSAGE. There can be
 ;; multiple suppression lines preceding a line of code with
 ;; several errors.
 (goto-char pos)
@@ -221,11 +221,11 @@ or nil if no position could be determined."
   (not (setq matched
  (and
   (looking-at (rx (0+ blank) (1+ ";") (0+ blank)
-  "relint suppression:" (0+ blank)
+  "relint suppression:" (1+ blank)
   (group (0+ nonl)
  (not (any "\n" blank)
-  (let ((substr (match-string 1)))
-(string-match-p (regexp-quote substr) message)
+  (let ((regexp (match-string 1)))
+(string-match-p regexp message)
   (looking-at (rx bol
   (0+ blank) (opt ";" (0+ nonl))
   eol))
diff --git a/test/6.elisp b/test/6.elisp
index ac07fc1..cbbdf4b 100644
--- a/test/6.elisp
+++ b/test/6.elisp
@@ -48,8 +48,8 @@
 
 ;; Test suppression
 (defun test-suppression ()
-  ;; relint suppression: Unescaped literal `$'
-  ;; relint suppression: Duplicated `a'
+  ;; relint suppression: Unescaped literal .\$
+  ;; relint suppression: Duplicated .a
   (looking-at "$[aa]"))
 
 ;; Test user-defined regexp-generating functions



[elpa] externals/relint ac75b62 04/21: Check rx-to-string, and the 'regexp' and 'eval' subforms

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit ac75b6211e1a9ee0e173641981310550d5193dd3
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check rx-to-string, and the 'regexp' and 'eval' subforms

This includes special treatment for backquoted forms.
---
 relint.el| 54 --
 test/11.elisp| 11 ++-
 test/11.expected | 21 +
 3 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index d484116..0c1653d 100644
--- a/relint.el
+++ b/relint.el
@@ -1328,8 +1328,10 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 (setq ranges (cdr ranges)))
   (car ranges))
 
-(defun relint--check-rx (item file pos path)
-  "Check the `rx' expression ITEM."
+(defun relint--check-rx (item file pos path exact-path)
+  "Check the `rx' expression ITEM.
+EXACT-PATH indicates whether PATH leads to ITEM exactly, rather
+than just to a surrounding or producing expression."
   (pcase item
 (`(,(or ': 'seq 'sequence 'and 'or '|
 'not 'intersection 'repeat '= '>= '**
@@ -1343,7 +1345,9 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
  ;; Form with subforms: recurse.
  (let ((i 1))
(dolist (arg args)
- (relint--check-rx arg file pos (cons i path))
+ (relint--check-rx arg file pos
+   (if exact-path (cons i path) path)
+   exact-path)
  (setq i (1+ i)
 
 (`(,(or 'any 'in 'char 'not-char) . ,args)
@@ -1360,7 +1364,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
(let ((overlap (relint--intersecting-range arg arg ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (if (eq (car overlap) (cdr overlap))
 (format-message "Duplicated character `%s'"
 (relint--pretty-range arg arg))
@@ -1384,20 +1388,20 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 ((or (eq from ?+)
  (eq to ?+))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Suspect range `%s'"
   (relint--pretty-range from to))
   arg j))
 ((= to from)
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
(relint--escape-string (format "%c-%c" from to) t))
   arg j))
 ((= to (1+ from))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Two-character range `%s'"
   (relint--pretty-range from to))
   arg j)))
@@ -1405,7 +1409,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
   (relint--intersecting-range from to ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (format-message "Range `%s' overlaps previous `%s'"
 (relint--pretty-range from to)
 (relint--pretty-range
@@ -1416,14 +1420,14 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
(when (and (eq from ?-)
   (< 0 j (1- len)))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Literal `-' not first or last")
   arg j))
(let ((overlap
   (relint--intersecting-range from from ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (if (eq (car overlap) (cdr overlap))
 (format-message "Duplicated character `%s'"
 (relint--pretty-range from from))
@@ -1444,7 +1448,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."

[elpa] externals/relint 4fcc322 16/21: Delay call to file-relative-name until needed

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 4fcc3220975815471242dff222d9316d58920c53
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Delay call to file-relative-name until needed

ENCODE_FILE and DECODE_FILE, present in many file and filename
manipulation primitives, are quite expensive and allocate a lot, even
when names are pure ASCII.

We don't actually need to call file-relative-name until there is a
diagnostic emitted for that file, so evaluate it lazily.

This should really be fixed in Emacs, but meanwhile this mitigation
doesn't hurt.
---
 relint.el | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index 1adcaee..e2eefcf 100644
--- a/relint.el
+++ b/relint.el
@@ -91,6 +91,7 @@
 (require 'xr)
 (require 'compile)
 (require 'cl-lib)
+(require 'thunk)
 
 (defvar relint--error-buffer)
 (defvar relint--quiet)
@@ -263,7 +264,8 @@ or nil if no position could be determined."
  (error-pos (and str-idx (relint--string-pos expr-pos str-idx
 (if (relint--suppression expr-pos message)
 (setq relint--suppression-count (1+ relint--suppression-count))
-  (funcall relint--report-function file expr-pos error-pos message
+  (funcall relint--report-function
+   (thunk-force file) expr-pos error-pos message
str str-idx severity)))
   (setq relint--error-count (1+ relint--error-count)))
 
@@ -2191,8 +2193,11 @@ Return a list of (FORM . STARTING-POSITION)."
   (with-temp-buffer
 (emacs-lisp-mode)
 (insert-file-contents file)
-(relint--scan-current-buffer (file-relative-name file base-dir
-
+;; Call file-relative-name lazily -- it is surprisingly expensive
+;; on macOS, and the result only used for diagnostics output.
+(relint--scan-current-buffer
+ (thunk-delay (file-relative-name file base-dir)
+
 (defvar relint-last-target nil
   "The last file, directory or buffer on which relint was run.")
 



[elpa] externals/relint 2eba4d7 09/21: Describe new bol/eol/eos warnings

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 2eba4d72e8592cd0891ee5652c5bdd323c72f5ea
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe new bol/eol/eos warnings
---
 README | 12 
 1 file changed, 12 insertions(+)

diff --git a/README b/README
index 7a355c4..777d9d0 100644
--- a/README
+++ b/README
@@ -133,6 +133,18 @@ skip-syntax-backward.
 the repeated sequence, resulting in a*\(?:c[ab]+\)* in the example
 above.
 
+  - End-of-line anchor followed by non-newline
+  - Non-newline followed by line-start anchor
+
+A pattern that does not match a newline occurs right after an
+end-of-line anchor ($) or before a line-start anchor (^).
+This combination can never match.
+
+  - End-of-text anchor followed by non-empty pattern
+
+A pattern that only matches a non-empty string occurs right after
+an end-of-text anchor (\'). This combination can never match.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/xr 35dbbeb 10/10: Increment version to 1.19

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit 35dbbebc86385e2d89668f42f4997a355e17ec04
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.19
---
 xr.el | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 560cfed..6bbf5e7 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.18
+;; Version: 1.19
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,11 @@
 
 ;;; News:
 
+;; Version 1.19:
+;; - Added filename-specific checks; new PURPOSE argument to `xr-lint'
+;; - Warn about wrapped subsumption, like \(A*C[AB]*\)+
+;; - Improved scope and accuracy of all subsumption checks
+;; - Warn about anchors in conflict with other expressions, like \(A$\)B
 ;; Version 1.18:
 ;; - Fix test broken in Emacs 26
 ;; Version 1.17:



[elpa] externals/relint 1bf7f25 13/21: Check auto-mode-alist with file-specific checks

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 1bf7f25a9fff55e177734ba14b41736ce77f9862
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check auto-mode-alist with file-specific checks

This also includes additions to auto-mode-alist via add-to-list or setq.
---
 relint.el| 55 ++-
 test/12.elisp| 16 
 test/12.expected | 24 
 3 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/relint.el b/relint.el
index 89c2461..03a9421 100644
--- a/relint.el
+++ b/relint.el
@@ -1090,13 +1090,16 @@ source."
 (when re
   (relint--check-re-string re name file pos path
 
-(defun relint--check-list (form name file pos path)
+(defun relint--check-list (form name file pos path is-file-name)
   "Check a list of regexps."
-  (relint--eval-list-iter
-   (lambda (elem elem-path _literal)
- (when (stringp elem)
-   (relint--check-re-string elem name file pos elem-path)))
-   form path))
+  (let ((check (if is-file-name
+   #'relint--check-file-name-re
+ #'relint--check-re-string)))
+(relint--eval-list-iter
+ (lambda (elem elem-path _literal)
+   (when (stringp elem)
+ (funcall check elem name file pos elem-path)))
+ form path)))
 
 (defun relint--check-list-any (form name file pos path)
   "Check a list of regexps or conses whose car is a regexp."
@@ -1215,6 +1218,24 @@ or in the car of an element."
   (relint--check-re re name file pos path)
   (relint--extra-file-name-re-checks re file pos path
 
+(defun relint--check-auto-mode-alist-expr (form name file pos path)
+  "Check a single element added to `auto-mode-alist'."
+  (pcase form
+(`(quote (,(and (pred stringp) str) . ,_))
+ (relint--check-file-name-re str name file pos (cons 0 (cons 1 path
+(_
+ (let ((val (relint--eval-or-nil form)))
+   (when (and (consp val) (stringp (car val)))
+ (relint--check-file-name-re (car val) name file pos path))
+
+(defun relint--check-auto-mode-alist (form name file pos path)
+  (relint--eval-list-iter
+   (lambda (elem elem-path literal)
+ (relint--check-file-name-re
+  (car elem) name
+  file pos (if literal (cons 0 elem-path) elem-path)))
+   form path))
+
 (defun relint--check-rules-list (form name file pos path)
   "Check a variable on `align-mode-rules-list' format"
   (relint--eval-list-iter
@@ -1663,7 +1684,7 @@ than just to a surrounding or producing expression."
  (relint--check-defcustom-type (relint--eval-or-nil type)
name file pos (cons index path)))
 (`(:options ,options)
- (relint--check-list options name file pos (cons index path
+ (relint--check-list options name file pos (cons index path) nil)))
   (setq index (+ index 2))
   (setq args (cddr args)
 
@@ -1772,6 +1793,14 @@ directly."
 ((eq name 'imenu-generic-expression)
  (relint--check-imenu-generic-expression
   expr name file pos (cons i path)))
+((eq name 'auto-mode-alist)
+ (pcase expr
+   (`(cons ,item auto-mode-alist)
+(relint--check-auto-mode-alist-expr
+ item name file pos (cons 1 (cons i path
+   (`(append ,items auto-mode-alist)
+(relint--check-auto-mode-alist
+ items name file pos (cons 1 (cons i path))
 (t
  ;; Invalidate the variable if it was local; otherwise, ignore.
  (let ((local (assq name relint--locals)))
@@ -1787,6 +1816,8 @@ directly."
 (`(push ,expr ,(and (pred symbolp) name))
  ;; Treat (push EXPR NAME) as (setq NAME (cons EXPR NAME)).
  (relint--check-form-recursively-2 expr mutables file pos (cons 1 path))
+ (when (eq name 'auto-mode-alist)
+   (relint--check-auto-mode-alist-expr expr name file pos (cons 1 path)))
  (let ((local (assq name relint--locals)))
(when local
  (setcdr local
@@ -1949,7 +1980,7 @@ directly."
"-list"))
   eos)
   (symbol-name name)))
-  (relint--check-list re-arg name file pos (cons 2 path))
+  (relint--check-list re-arg name file pos (cons 2 path) nil)
   (push name relint--checked-variables))
  ((string-match-p (rx "font-lock-keywords")
   (symbol-name name))
@@ -1960,6 +1991,9 @@ directly."
   (relint--check-compilation-error-regexp-alist-alist
re-arg name file pos (cons 2 path))
   (push name relint--checked-variables))
+ ((eq name 'auto-mode-alist)
+  (relint--check-auto-mode-alist
+   re-arg name file pos (cons 2 path)))
  ((string-match-p (rx (or "-regexp" "-regex" "-re" 

[elpa] externals/relint 008fad0 17/21: Repair relint-current-buffer after thunking file parameter

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 008fad0182055fde788b1df8757db49a299291b8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Repair relint-current-buffer after thunking file parameter
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index e2eefcf..ba10355 100644
--- a/relint.el
+++ b/relint.el
@@ -2272,7 +2272,7 @@ Diagnostics to ERROR-BUFFER. If QUIET, don't emit 
messages."
   (error "Relint: can only scan elisp code (use emacs-lisp-mode)"))
 (relint--init buffer default-directory error-buffer quiet)
 (save-excursion
-  (relint--scan-current-buffer (buffer-name
+  (relint--scan-current-buffer (thunk-delay (buffer-name)
   (relint--finish))
 
 



[elpa] externals/relint 8f49686 18/21: Move file-specific checks to xr

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 8f49686f268dc10e1074f1c344084e3f2bafc7ee
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Move file-specific checks to xr
---
 relint.el| 48 ++--
 test/12.expected | 24 
 2 files changed, 18 insertions(+), 54 deletions(-)

diff --git a/relint.el b/relint.el
index ba10355..b775b8a 100644
--- a/relint.el
+++ b/relint.el
@@ -320,6 +320,9 @@ or nil if no position could be determined."
 (defun relint--check-re-string (re name file pos path)
   (relint--check-string re #'xr-lint name file pos path))
   
+(defun relint--check-file-re-string (re name file pos path)
+  (relint--check-string re (lambda (x) (xr-lint x 'file)) name file pos path))
+  
 (defun relint--check-syntax-string (syntax name file pos path)
   (relint--check-string syntax #'relint--syntax-string-lint name file pos 
path))
 
@@ -1176,59 +1179,20 @@ or in the car of an element."
 file pos (if literal (cons 1 elem-path) elem-path
form path))
 
-(defun relint--extra-file-name-re-checks (string file pos path)
-  "Perform extra checks on STRING assuming it matches file names."
-
-  ;; It would be much easier to do these checks (and more) on the rx
-  ;; representation, but unfortunately xr doesn't return a
-  ;; location-annotated expression right now.
-  (let ((len (length string))
-(start 0))
-(while (and (< start len)
-;; Skip anything that is NOT one of . ^ $
-(string-match (rx (* (or (not (any "\\.$^["))
- (seq "\\" anything)
- (seq "[" (opt "^") (opt "]")
-  (* (not (any "]")))
-  "]"
-  string start))
-  (setq start (match-end 0))
-  (let* ((m (string-match (rx (or "^" "$" (seq "." (opt (any "*+?")
-  string start))
- (end (match-end 0)))
-(when (and m (= m start))
-  (pcase (match-string 0 string)
-("^" (relint--warn
-  file pos path
-  "Use \\` instead of ^ in file-matching regexp"
-  string start))
-("$" (relint--warn
-  file pos path
-  "Use \\' instead of $ in file-matching regexp"
-  string start))
-;; We assume that .* etc are intended.
-("." (relint--warn
-  file pos path
-  (format-message
-   "Possibly unescaped `.' in file-matching regexp")
-  string start)))
-  (setq start end))
-
 (defun relint--check-file-name-re (form name file pos path)
   (let ((re (relint--get-string form)))
 (when re
-  (relint--check-re re name file pos path)
-  (relint--extra-file-name-re-checks re file pos path
+  (relint--check-file-re-string re name file pos path
 
 (defun relint--check-auto-mode-alist-expr (form name file pos path)
   "Check a single element added to `auto-mode-alist'."
   (pcase form
 (`(quote (,(and (pred stringp) str) . ,_))
- (relint--check-file-name-re str name file pos (cons 0 (cons 1 path
+ (relint--check-file-re-string str name file pos (cons 0 (cons 1 path
 (_
  (let ((val (relint--eval-or-nil form)))
(when (and (consp val) (stringp (car val)))
- (relint--check-file-name-re (car val) name file pos path))
+ (relint--check-file-re-string (car val) name file pos path))
 
 (defun relint--check-auto-mode-alist (form name file pos path)
   (relint--eval-list-iter
diff --git a/test/12.expected b/test/12.expected
index ecef078..e0ab05b 100644
--- a/test/12.expected
+++ b/test/12.expected
@@ -1,37 +1,37 @@
-12.elisp:9:6: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:9:6: In define-generic-mode my-mode: Possibly unescaped `.' in 
file-matching regexp (pos 0)
   ".aa\\'"
^
-12.elisp:9:20: Use \' instead of $ in file-matching regexp (pos 4)
+12.elisp:9:20: In define-generic-mode my-mode: Use \' instead of $ in 
file-matching regexp (pos 4)
   "\\.bb$"
.^
-12.elisp:9:24: Use \` instead of ^ in file-matching regexp (pos 0)
+12.elisp:9:24: In define-generic-mode my-mode: Use \` instead of ^ in 
file-matching regexp (pos 0)
   "^cc.*dd"
^
-12.elisp:11:39: Use \' instead of $ in file-matching regexp (pos 4)
+12.elisp:11:39: In add-to-list: Use \' instead of $ in file-matching regexp 
(pos 4)
   "\\.ee$"
.^
-12.elisp:12:10: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:12:10: In auto-mode-alist: Possibly unescaped `.' in file-matching 
regexp (pos 0)
   ".ff\\'"
^
-12.elisp:13:32: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:13:32: In auto-mode-alist: Possibly unescaped `.' in file-matching 
regexp (pos 0)
   ".gg\\'"
^

[elpa] externals/relint cdd65ae 10/21: Add section about how relint works

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit cdd65ae90343eec0774a86741d8104a524b1aad8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add section about how relint works
---
 README | 36 +++-
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/README b/README
index 777d9d0..f816349 100644
--- a/README
+++ b/README
@@ -36,6 +36,7 @@ skip-syntax-backward.
 
 which returns a list of diagnostics.
 
+
 * Installation
 
   From GNU ELPA (https://elpa.gnu.org/packages/relint.html):
@@ -45,6 +46,7 @@ skip-syntax-backward.
   Relint requires the package xr (https://elpa.gnu.org/packages/xr.html);
   it will be installed automatically.
 
+
 * What the diagnostics mean
 
   - Unescaped literal 'X'
@@ -268,6 +270,7 @@ skip-syntax-backward.
 A string argument to skip-syntax-forward or skip-syntax-backward
 is empty or "^", neither of which makes sense.
 
+
 * Suppressing diagnostics
 
   While relint has been designed to avoid false positives, there may
@@ -284,11 +287,34 @@ skip-syntax-backward.
   comment lines can precede a line of code to eliminate several
   complaints on the same line.
 
+
+* How it works
+
+  Relint uses a combination of ad-hoc rules to locate regexps:
+
+  - Arguments to standard functions taking regexps as arguments,
+such as re-search-forward, or to user-defined functions
+whose arguments have regexp-sounding names (like 'regexp')
+
+  - Values of variables believed to be a regexp from their name
+(ending in '-regexp', for instance), from their doc string,
+or from their type (for defcustom forms)
+
+  - Assignment to certain standard variables, such as page-delimiter
+
+  It will then try to evaluate expressions statically as far as
+  possible, to arrive at strings which can be analysed. The regexp
+  analysis is done by the xr library.
+
+  This means that if relint complains about something that isn't
+  actually a regexp, some names in your code may be misleading.
+
+
 * Bugs
 
-  The recognition of regexps is done by ad-hoc rules; the simplistic
-  method employed means that many errors will go undetected.
+  The simplistic method employed means that many errors will go
+  undetected, but false warnings are usually rare.
 
-  Still, if you believe that a flawed regexp could have been
-  discovered but wasn't, please report it as a bug. Reports of false
-  positives and crashes are of course equally welcome.
+  If you believe that an error could have been discovered but wasn't,
+  or that an unwarranted complaint could be avoided, please report it
+  as a bug.



[elpa] externals/relint 636e172 12/21: Add filename-specific checks (unused so far)

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit 636e1725f985c6cf30de04cf1396a413dd89a598
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add filename-specific checks (unused so far)

This includes checks for ^ and $ (use \` and \' instead),
and for . (should probably be \.)
---
 relint.el | 44 
 1 file changed, 44 insertions(+)

diff --git a/relint.el b/relint.el
index 6c81221..89c2461 100644
--- a/relint.el
+++ b/relint.el
@@ -1171,6 +1171,50 @@ or in the car of an element."
 file pos (if literal (cons 1 elem-path) elem-path
form path))
 
+(defun relint--extra-file-name-re-checks (string file pos path)
+  "Perform extra checks on STRING assuming it matches file names."
+
+  ;; It would be much easier to do these checks (and more) on the rx
+  ;; representation, but unfortunately xr doesn't return a
+  ;; location-annotated expression right now.
+  (let ((len (length string))
+(start 0))
+(while (and (< start len)
+;; Skip anything that is NOT one of . ^ $
+(string-match (rx (* (or (not (any "\\.$^["))
+ (seq "\\" anything)
+ (seq "[" (opt "^") (opt "]")
+  (* (not (any "]")))
+  "]"
+  string start))
+  (setq start (match-end 0))
+  (let* ((m (string-match (rx (or "^" "$" (seq "." (opt (any "*+?")
+  string start))
+ (end (match-end 0)))
+(when (and m (= m start))
+  (pcase (match-string 0 string)
+("^" (relint--warn
+  file pos path
+  "Use \\` instead of ^ in file-matching regexp"
+  string start))
+("$" (relint--warn
+  file pos path
+  "Use \\' instead of $ in file-matching regexp"
+  string start))
+;; We assume that .* etc are intended.
+("." (relint--warn
+  file pos path
+  (format-message
+   "Possibly unescaped `.' in file-matching regexp")
+  string start)))
+  (setq start end))
+
+(defun relint--check-file-name-re (form name file pos path)
+  (let ((re (relint--get-string form)))
+(when re
+  (relint--check-re re name file pos path)
+  (relint--extra-file-name-re-checks re file pos path
+
 (defun relint--check-rules-list (form name file pos path)
   "Check a variable on `align-mode-rules-list' format"
   (relint--eval-list-iter



[elpa] externals/relint updated (83e677d -> a001a05)

2020-05-03 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  83e677d   Increment version to 1.15
   new  ba7b747   Display the number of files found in relint-directory
   new  96e26a5   Check keyword arguments :regexp and :regex
   new  9259a5c   Check some :value parameters in defcustom :type clauses
   new  ac75b62   Check rx-to-string, and the 'regexp' and 'eval' subforms
   new  09ef3df   Describe the new xr wrapped subsumption warning
   new  eb178d5   Check assignments to imenu-generic-expression
   new  b694c09   Check split ASCII-raw ranges in rx correctly
   new  12a2b0f   Use regexp in suppression comments
   new  2eba4d7   Describe new bol/eol/eos warnings
   new  cdd65ae   Add section about how relint works
   new  326cfe2   Check calls to directory-files(-and-attributes)
   new  636e172   Add filename-specific checks (unused so far)
   new  1bf7f25   Check auto-mode-alist with file-specific checks
   new  cf2a2ae   Do file-specific checks on arguments to known functions
   new  f6d0fed   Describe the new file-specific warnings
   new  4fcc322   Delay call to file-relative-name until needed
   new  008fad0   Repair relint-current-buffer after thunking file parameter
   new  8f49686   Move file-specific checks to xr
   new  5d3f78d   Update xr messages ("repetition" changed to "option")
   new  a50ed0b   Don't escape printable chars in rx warnings
   new  a001a05   Increment version to 1.16


Summary of changes:
 README   |  95 +---
 relint.el| 264 +--
 test/1.elisp |  13 +++
 test/1.expected  |  30 +--
 test/11.elisp|  16 +++-
 test/11.expected |  27 ++
 test/12.elisp|  25 ++
 test/12.expected |  39 
 test/2.elisp |   9 +-
 test/2.expected  |  51 +++
 test/6.elisp |   4 +-
 test/9.elisp |   5 ++
 test/9.expected  |   3 +
 13 files changed, 475 insertions(+), 106 deletions(-)
 create mode 100644 test/12.elisp
 create mode 100644 test/12.expected



[elpa] externals/relint ba7b747 01/21: Display the number of files found in relint-directory

2020-05-03 Thread Mattias Engdegrd
branch: externals/relint
commit ba7b7474ae08968d5a0341b9ce79757848ef759c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Display the number of files found in relint-directory
---
 relint.el | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index a53e2c0..567315c 100644
--- a/relint.el
+++ b/relint.el
@@ -2125,9 +2125,12 @@ Diagnostics to ERROR-BUFFER. If QUIET, don't emit 
messages."
   "Scan all *.el files in DIR for regexp-related errors."
   (interactive "DRelint directory: ")
   (message "Finding .el files in %s..." dir)
-  (let ((files (relint--tree-files dir)))
-(message "Scanning files...")
-(relint--scan-files files dir dir (relint--get-error-buffer
+  (let* ((files (relint--tree-files dir))
+ (n (length files)))
+(if (not files)
+(message "No .el files found.")
+  (message "Scanning %d file%s..." n (if (= n 1) "" "s"))
+  (relint--scan-files files dir dir (relint--get-error-buffer)
 
 ;;;###autoload
 (defun relint-current-buffer ()



[elpa] externals/xr d752aab 09/10: Use "option" instead of "repetition" in diagnostics for ? and ??

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit d752aabeae1c5f29fff810f43a3f96f34366603f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use "option" instead of "repetition" in diagnostics for ? and ??
---
 xr-test.el | 17 
 xr.el  | 94 +-
 2 files changed, 69 insertions(+), 42 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 175df15..95927ca 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -362,16 +362,21 @@
'((0 . "Escaped non-special character `}'")
  (4 . "Escaped non-special character `a'")
  (8 . "Escaped non-special character `%'"
-(should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*?\\{2,5\\}")
-   '((2  . "Repetition of repetition")
+(should (equal (xr-lint "a?+b+?\\(?:c*\\)*d\\{3\\}+e*?\\{2,5\\}")
+   '((2  . "Repetition of option")
  (14 . "Repetition of repetition")
  (25 . "Repetition of repetition"
 (should (equal (xr-lint "\\(a*\\)*\\(b+\\)*\\(c*\\)?\\(d+\\)?")
'((6 .  "Repetition of repetition")
  (13 . "Repetition of repetition")
- (20 . "Repetition of repetition"
+ (20 . "Optional repetition"
+(should (equal (xr-lint "\\(a?\\)+\\(b?\\)?")
+   '((6 . "Repetition of option")
+ (13 . "Optional option"
 (should (equal (xr-lint "\\(e*\\)\\{3\\}")
'((6 . "Repetition of repetition"
+(should (equal (xr-lint "\\(a?\\)\\{4,7\\}")
+   '((6 . "Repetition of option"
 (should (equal (xr-lint "[]-Qa-fz-t]")
'((1 . "Reversed range `]-Q' matches nothing")
  (7 . "Reversed range `z-t' matches nothing"
@@ -406,7 +411,7 @@
 "Literal `-' not first or last in character alternative"
 (should (equal (xr-lint "\\'*\\

[elpa] externals/xr d0b09e1 08/10: Add filename-specific checks

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit d0b09e1b49bc47641580604c34369d4fb0875a38
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add filename-specific checks

These were moved from relint since they arguably belong here.
xr-lint now takes an optional PURPOSE argument.
---
 xr-test.el |  9 +
 xr.el  | 54 +-
 2 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index c0c428d..175df15 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -651,6 +651,15 @@
nil))
 ))
 
+(ert-deftest xr-lint-file ()
+  (let ((text-quoting-style 'grave))
+(should (equal (xr-lint "a.b\\.c.*d.?e.+f." 'file)
+   '((1 . "Possibly unescaped `.' in file-matching regexp")
+ (15 . "Possibly unescaped `.' in file-matching regexp"
+(should (equal (xr-lint "^abc$" 'file)
+   '((0 . "Use \\` instead of ^ in file-matching regexp")
+ (4 . "Use \\' instead of $ in file-matching regexp"))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index a10be63..f50c4f2 100644
--- a/xr.el
+++ b/xr.el
@@ -521,7 +521,7 @@ like (* (* X) ... (* X))."
  "First item in repetition subsumes last item (wrapped)"
"Last item in repetition subsumes first item (wrapped)"
 
-(defun xr--parse-seq (warnings)
+(defun xr--parse-seq (warnings purpose)
   (let ((sequence nil)) ; reversed
 (while (not (looking-at (rx (or "\\|" "\\)" eos
   (let ((item-start (point)))
@@ -530,8 +530,12 @@ like (* (* X) ... (* X))."
  ((looking-at (rx "^"))
   (forward-char 1)
   (if (null sequence)
-  (push 'bol sequence)
-(xr--report warnings (match-beginning 0)
+  (progn
+(when (eq purpose 'file)
+  (xr--report warnings item-start
+  "Use \\` instead of ^ in file-matching regexp"))
+(push 'bol sequence))
+(xr--report warnings item-start
 (format-message "Unescaped literal `^'"))
 (push "^" sequence)))
 
@@ -539,8 +543,13 @@ like (* (* X) ... (* X))."
  ((looking-at (rx "$"))
   (forward-char 1)
   (if (looking-at (rx (or "\\|" "\\)" eos)))
-  (push 'eol sequence)
-(xr--report warnings (match-beginning 0)
+  (progn
+(when (eq purpose 'file)
+  (xr--report warnings item-start
+  "Use \\' instead of $ in file-matching regexp"))
+
+(push 'eol sequence))
+(xr--report warnings item-start
 (format-message "Unescaped literal `$'"))
 (push "$" sequence)))
 
@@ -682,7 +691,7 @@ like (* (* X) ... (* X))."
 (when (and question (not colon))
   (error "Invalid \\(? syntax"))
 (goto-char (match-end 0))
-(let* ((group (xr--parse-alt warnings))
+(let* ((group (xr--parse-alt warnings purpose))
;; simplify - group has an implicit seq
(operand (if (and (listp group) (eq (car group) 'seq))
 (cdr group)
@@ -706,14 +715,23 @@ like (* (* X) ... (* X))."
   (push (list 'backref (string-to-number (match-string 1)))
 sequence))
 
+ ;; not-newline
+ ((looking-at (rx "."))
+  (goto-char (match-end 0))
+  ;; Assume that .* etc is intended.
+  (when (and (eq purpose 'file)
+ (not (looking-at (rx (any "?*+")
+(xr--report warnings (match-beginning 0)
+"Possibly unescaped `.' in file-matching regexp"))
+  (push 'nonl sequence))
+
  ;; various simple substitutions
- ((looking-at (rx (or "." "\\w" "\\W" "\\`" "\\'" "\\="
+ ((looking-at (rx (or "\\w" "\\W" "\\`" "\\'" "\\="
   "\\b" "\\B" "\\<" "\\>")))
   (goto-char (match-end 0))
   (let ((sym (cdr (assoc
(match-string 0)
-   '(("." . nonl)
- ("\\w" . wordchar) ("\\W" . not-wordchar)
+   '(("\\w" . wordchar) ("\\W" . not-wordchar)
  ("\\`" . bos) ("\\'" . eos)
  ("\\=" . point)
  ("\\b" . word-boundary) ("\\B" . 
not-word-boundary)
@@ -1356,13 +1374,13 @@ A-SETS and B-SETS are arguments to `any'."
 
(_ (equal a b))
 
-(defun xr--parse-alt (warnings)
+(defun xr--parse-alt (warnings purpose)
   (let ((alternatives nil)) ; reversed
-(push (xr--parse-seq warnings) alternatives)
+(push 

[elpa] externals/xr f3b61ef 05/10: Fix false negative in empty string repetition check

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit f3b61ef7450afd7726e509509f5b3042af23a051
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix false negative in empty string repetition check

We forgot to check for non-greedy inner repetitions.
---
 xr-test.el | 14 ++
 xr.el  |  4 ++--
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 88e68f7..2724e0d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -404,16 +404,22 @@
  (xr-lint "[-A-Z][A-Z-][A-Z-a][^-A-Z][]-a][A-Z---.]")
  '((16 .
 "Literal `-' not first or last in character alternative"
-(should (equal
- (xr-lint "\\(?:a*b?\\)*\\(c\\|d\\|\\)+\\(^\\|e\\)*\\(?:\\)*")
- '((10 . "Repetition of expression matching an empty string")
-   (21 . "Repetition of expression matching an empty string"
 (should (equal (xr-lint "\\'*\\

[elpa] externals/xr 7160235 02/10: Refactor repetition subsumption check to avoid code duplication

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit 7160235fe06fdbd8814d9384f4239c9a6e8ad809
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Refactor repetition subsumption check to avoid code duplication
---
 xr-test.el |  2 +-
 xr.el  | 52 +---
 2 files changed, 10 insertions(+), 44 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 2001a39..a46cf60 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -602,7 +602,7 @@
  '((13 . "First item in repetition subsumes last item 
(wrapped)"
 (should (equal
  (xr-lint "\\(?3:a*xa*\\)\\{7\\}")
- '((14 . "First item in repetition subsumes last item 
(wrapped)"
+ '((14 . "Last item in repetition subsumes first item 
(wrapped)"
 ))
 
 (ert-deftest xr-skip-set ()
diff --git a/xr.el b/xr.el
index 985f4d8..3e09ac0 100644
--- a/xr.el
+++ b/xr.el
@@ -490,11 +490,11 @@ like (* (* X) ... (* X))."
   (when (cddr operands)
 (let* ((first (car operands))
(last (car (last operands)))
-   (subsumption (xr--adjacent-subsumption first last)))
+   (subsumption (xr--adjacent-subsumption last first)))
   (when subsumption
 (xr--report
  warnings pos
- (if (eq subsumption 'a-subsumes-b)
+ (if (eq subsumption 'b-subsumes-a)
  "First item in repetition subsumes last item (wrapped)"
"Last item in repetition subsumes first item (wrapped)"
 
@@ -743,48 +743,14 @@ like (* (* X) ... (* X))."
  (t (error "Backslash at end of regexp")))
 
 (when (and warnings (cdr sequence))
-  ;; Check for subsuming repetitions in sequence: (Rx X) (Ry Y)
-  ;; where Rx and Ry are repetition operators, and X and Y are 
operands.
-  ;; We conclude that (Rx X) subsumes (Ry Y), in the sense that the
-  ;; sequence is equivalent to just (Rx X), if:
-  ;;   X matches a superset of Y
-  ;;   and Rx can match infinitely many times
-  ;;   and Ry can match zero times
-  ;;   and Ry is non-greedy if Rx is non-greedy.
-  ;; Example: [ab]+a?
   (let* ((item (car sequence))
- (expr (and (consp item)
-(memq (car item)
-  '(zero-or-more one-or-more opt *? +? ??))
-(xr--make-seq (cdr item)
-(when expr
-  (let* ((prev-item (cadr sequence))
- (prev-expr
-  (and (consp prev-item)
-   (memq (car prev-item)
- '(zero-or-more one-or-more opt *? +? ??))
-   (xr--make-seq (cdr prev-item)
-(when prev-expr
-  (let ((op (car item))
-(prev-op (car prev-item)))
-;; Test the same condition twice, but mirrored.
-(cond
- ((and (memq op '(zero-or-more opt *? ??))
-   (memq prev-op '(zero-or-more one-or-more *? +?))
-   (not (and (memq prev-op '(*? +?))
- (memq op '(zero-or-more opt
-   (xr--superset-p prev-expr expr))
-  (xr--report
-   warnings item-start
-   "Repetition subsumed by preceding repetition"))
- ((and (memq prev-op '(zero-or-more opt *? ??))
-   (memq op '(zero-or-more one-or-more *? +?))
-   (not (and (memq op '(*? +?))
- (memq prev-op '(zero-or-more opt
-   (xr--superset-p expr prev-expr))
-  (xr--report
-   warnings item-start
-   "Repetition subsumes preceding repetition")))
+ (prev-item (cadr sequence))
+ (subsumption (xr--adjacent-subsumption prev-item item)))
+(when subsumption
+  (xr--report warnings item-start
+  (if (eq subsumption 'a-subsumes-b)
+  "Repetition subsumed by preceding repetition"
+"Repetition subsumes preceding repetition")))
 
 (let ((item-seq (xr--rev-join-seq sequence)))
   (cond ((null item-seq)



[elpa] externals/xr c98bb7b 03/10: Handle whitespace and word syntax subsumption in one place

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit c98bb7bcf319bca7c42038c51a92ed78f5e439d7
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Handle whitespace and word syntax subsumption in one place

Use the more elaborate code already in place for charsets.
---
 xr.el | 33 +
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/xr.el b/xr.el
index 3e09ac0..fa89862 100644
--- a/xr.el
+++ b/xr.el
@@ -1042,22 +1042,23 @@ A-SETS and B-SETS are arguments to `any'."
 
 (defun xr--syntax-superset-of-rx-p (syntax negated rx)
   "Whether SYNTAX, possibly NEGATED, is a superset of RX."
-  ;; Syntax tables vary, but we make a (quite conservative) guess.
-  (let* ((always-set
-   ;; Characters we think always will be in the syntax set.
-   '((whitespace " \t")
- (word "A-Za-z0-9")
- (open-parenthesis "([")
- (close-parenthesis "])")))
- (never-set
-   ;; Characters we think never will be in the syntax set.
-   '((whitespace "!-~")
- (punctuation "A-Za-z0-9")
- (open-parenthesis "\x00- A-Za-z0-9")
- (close-parenthesis "\x00- A-Za-z0-9")))
- (set (assq syntax (if negated never-set always-set
-(and set
- (xr--char-superset-of-rx-p (cdr set) nil rx
+  (cond
+   ((eq syntax 'whitespace) (xr--char-superset-of-rx-p '(space) negated rx))
+   ((eq syntax 'word)   (xr--char-superset-of-rx-p '(word) negated rx))
+   (t
+;; Syntax tables vary, but we make a fairly conservative guess.
+(let* ((always-set
+;; Characters we think always will be in the syntax set.
+'((open-parenthesis "([")
+  (close-parenthesis "])")))
+   (never-set
+;; Characters we think never will be in the syntax set.
+'((punctuation "A-Za-z0-9")   ; NOT the same as [:punct:]!
+  (open-parenthesis "\000-\037A-Za-z0-9" " \177")
+  (close-parenthesis "\000-\037A-Za-z0-9" " \177")))
+   (set (assq syntax (if negated never-set always-set
+  (and set
+   (xr--char-superset-of-rx-p (cdr set) nil rx))
 
 (defun xr--expand-strings (rx)
   "Expand strings to characters or seqs of characters.



[elpa] externals/xr c6e12b7 04/10: Handle \w and \W in subsumption checks

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit c6e12b71234c1009395d8b0c013db77d63834269
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Handle \w and \W in subsumption checks
---
 xr-test.el | 8 
 xr.el  | 6 +-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index a46cf60..88e68f7 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -509,6 +509,14 @@
 (should (equal (xr-lint "\\Ca\\|ü")
'((5 . "Branch matches subset of a previous branch"
 
+(should (equal (xr-lint "\\w\\|[^z-a]")
+   '((4 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "\\W\\|[^z-a]")
+   '((4 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "\\w\\|a")
+   '((4 . "Branch matches subset of a previous branch"
+(should (equal (xr-lint "\\W\\|\f")
+   '((4 . "Branch matches subset of a previous branch"
   ))
 
 (ert-deftest xr-lint-subsumed-repetition ()
diff --git a/xr.el b/xr.el
index fa89862..03b5f0a 100644
--- a/xr.el
+++ b/xr.el
@@ -1033,7 +1033,8 @@ A-SETS and B-SETS are arguments to `any'."
   (or (memq rx '(nonl anything
  ascii alnum alpha blank cntrl digit graph
  lower multibyte nonascii print punct space
- unibyte upper word xdigit))
+ unibyte upper word xdigit
+ wordchar not-wordchar))
   (characterp rx)
   (and (consp rx)
(or (memq (car rx) '(any category syntax))
@@ -1160,6 +1161,9 @@ A-SETS and B-SETS are arguments to `any'."
(`(not (syntax ,syn))
 (or (equal a b) (xr--syntax-superset-of-rx-p syn t b)))
 
+   ('wordchar (or (equal a b) (xr--syntax-superset-of-rx-p 'word nil b)))
+   ('not-wordchar (or (equal a b) (xr--syntax-superset-of-rx-p 'word t b)))
+
((or `(category ,_) `(not (category ,_)))
 (or (equal a b)
 (and (characterp b)



[elpa] externals/xr 21eab3c 06/10: Check for bol, eol and eos in conflict with other expressions

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit 21eab3c0f6593754b03f5d2a2a7c4f44c6744a75
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check for bol, eol and eos in conflict with other expressions
---
 xr-test.el |  12 +++
 xr.el  | 118 +++--
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 2724e0d..b426d30 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -619,6 +619,18 @@
  '((14 . "Last item in repetition subsumes first item 
(wrapped)"
 ))
 
+(ert-deftest xr-lint-bad-anchor ()
+  (let ((text-quoting-style 'grave))
+(should (equal (xr-lint "a\\(?:^b$\\)c")
+   '((1 . "Non-newline followed by line-start anchor")
+ (10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint ".\\(?:^$\\).")
+   '((1 . "Non-newline followed by line-start anchor")
+ (9 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\'b")
+   '((2 . "End-of-text anchor followed by non-empty 
pattern"
+))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index eccbf3f..6467624 100644
--- a/xr.el
+++ b/xr.el
@@ -439,6 +439,29 @@ UPPER may be nil, meaning infinity."
  (cl-every #'xr--matches-empty-p body))
 ("" t)))
 
+(defun xr--matches-nonempty-only-p (rx)
+  "Whether RX matches non-empty strings only."
+  (pcase rx
+((pred stringp) (> (length rx) 0))
+(`(,(or 'seq 'one-or-more '+? 'group) . ,body)
+ (cl-some #'xr--matches-nonempty-only-p body))
+(`(or . ,body)
+ (cl-every #'xr--matches-nonempty-only-p body))
+(`(group-n ,_ . ,body)
+ (cl-some #'xr--matches-nonempty-only-p body))
+(`(repeat ,from ,_ . ,body)
+ (and (> from 0)
+  (cl-some #'xr--matches-nonempty-only-p body)))
+(`(,(or '= '>=) ,n . ,body)
+ (and (> n 0)
+  (cl-some #'xr--matches-nonempty-only-p body)))
+(`(,(or 'any 'not 'intersection) . ,_) t)
+((or 'ascii 'alnum 'alpha 'blank 'cntrl 'digit 'graph
+ 'lower 'multibyte 'nonascii 'print 'punct 'space
+ 'unibyte 'upper 'word 'xdigit
+ 'nonl 'anything)
+ t)))
+
 (defun xr--adjacent-subsumption (a b)
   "Check if A subsumes B, or vice versa, or not, assuming they are adjacent.
 Return `a-subsumes-b', `b-subsumes-a' or nil."
@@ -742,7 +765,8 @@ like (* (* X) ... (* X))."
 
  (t (error "Backslash at end of regexp")))
 
-(when (and warnings (cdr sequence))
+(when (and warnings (cdr sequence)
+   (not (looking-at (rx (or (any "?*+") "\\{")
   (let* ((item (car sequence))
  (prev-item (cadr sequence))
  (subsumption (xr--adjacent-subsumption prev-item item)))
@@ -750,7 +774,27 @@ like (* (* X) ... (* X))."
   (xr--report warnings item-start
   (if (eq subsumption 'a-subsumes-b)
   "Repetition subsumed by preceding repetition"
-"Repetition subsumes preceding repetition")))
+"Repetition subsumes preceding repetition")))
+
+;; Check for anchors conflicting with previous/next character.
+(cond
+ ((and (xr--may-end-in-eol-p prev-item)
+   (not (xr--may-start-in-nl-p item)))
+  (xr--report warnings item-start
+  "End-of-line anchor followed by non-newline"))
+ ((and (xr--may-start-in-bol-p item)
+   (not (xr--may-end-in-nl-p prev-item)))
+  (xr--report warnings item-start
+  "Non-newline followed by line-start anchor"))
+ ((and (xr--may-end-in-eos-p prev-item)
+   (xr--matches-nonempty-only-p item))
+  (xr--report warnings item-start
+  "End-of-text anchor followed by non-empty pattern"))
+ ;; FIXME: We don't complain about non-empty followed by
+ ;; bos because it may be the start of unmatchable.
+ ;; We should really do these checks in a later pass,
+ ;; and maintain location information.
+ )
 
 (let ((item-seq (xr--rev-join-seq sequence)))
   (cond ((null item-seq)
@@ -760,6 +804,76 @@ like (* (* X) ... (* X))."
 (t 
  (cons 'seq item-seq))
 
+(defun xr--may-start-in-bol-p (item)
+  (pcase item
+('bol t)
+(`(,(or 'seq 'opt 'zero-or-more 'one-or-more ?? '*? '+? 'group) ,first . 
,_)
+ (xr--may-start-in-bol-p first))
+(`(group-n ,_ ,first . ,_)
+ (xr--may-start-in-bol-p first))
+(`(or . ,items) (cl-some #'xr--may-start-in-bol-p items
+
+(defun xr--may-end-in-eol-p (item)
+  (pcase item
+('eol t)
+(`(,(or 'seq 'opt 

[elpa] externals/xr updated (434b300 -> 35dbbeb)

2020-05-03 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  434b300   Increment version to 1.18
   new  e5b51bf   Add wrapped subsumption in repeated forms
   new  7160235   Refactor repetition subsumption check to avoid code 
duplication
   new  c98bb7b   Handle whitespace and word syntax subsumption in one place
   new  c6e12b7   Handle \w and \W in subsumption checks
   new  f3b61ef   Fix false negative in empty string repetition check
   new  21eab3c   Check for bol, eol and eos in conflict with other 
expressions
   new  c7e7557   Broaden anchor check to check more paths
   new  d0b09e1   Add filename-specific checks
   new  d752aab   Use "option" instead of "repetition" in diagnostics for ? 
and ??
   new  35dbbeb   Increment version to 1.19


Summary of changes:
 xr-test.el |  91 ++-
 xr.el  | 502 +++--
 2 files changed, 469 insertions(+), 124 deletions(-)



[elpa] externals/xr c7e7557 07/10: Broaden anchor check to check more paths

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit c7e7557db435cd6553c81592394de0358225f079
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Broaden anchor check to check more paths

Check both AB, A?B and AB? (but not A?B?) where A and B are an anchor
and conflicting expression, in some order.
---
 xr-test.el |  26 +++-
 xr.el  | 209 +
 2 files changed, 163 insertions(+), 72 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index b426d30..c0c428d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -621,14 +621,34 @@
 
 (ert-deftest xr-lint-bad-anchor ()
   (let ((text-quoting-style 'grave))
-(should (equal (xr-lint "a\\(?:^b$\\)c")
-   '((1 . "Non-newline followed by line-start anchor")
- (10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "a\\(?:^\\)")
+   '((1 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a?\\(?:^\\)")
+   '((2 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a\\(?:^\\|b\\)")
+   '((1 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a?\\(?:^\\|b\\)")
+   nil))
+(should (equal (xr-lint "\\(?:$\\)a")
+   '((7 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\)\\(\n\\|a\\)")
+   '((7 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\|b\\)a")
+   '((10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\|b\\)\\(\n\\|a\\)")
+   nil))
 (should (equal (xr-lint ".\\(?:^$\\).")
'((1 . "Non-newline followed by line-start anchor")
  (9 . "End-of-line anchor followed by non-newline"
 (should (equal (xr-lint "\\'b")
'((2 . "End-of-text anchor followed by non-empty 
pattern"
+(should (equal (xr-lint "\\'b?")
+   '((3 . "End-of-text anchor followed by non-empty 
pattern"
+(should (equal (xr-lint "\\(?:a\\|\\'\\)b")
+   '((11 .
+  "End-of-text anchor followed by non-empty pattern"
+(should (equal (xr-lint "\\(?:a\\|\\'\\)b?")
+   nil))
 ))
 
 (ert-deftest xr-skip-set ()
diff --git a/xr.el b/xr.el
index 6467624..a10be63 100644
--- a/xr.el
+++ b/xr.el
@@ -777,24 +777,41 @@ like (* (* X) ... (* X))."
 "Repetition subsumes preceding repetition")))
 
 ;; Check for anchors conflicting with previous/next character.
-(cond
- ((and (xr--may-end-in-eol-p prev-item)
-   (not (xr--may-start-in-nl-p item)))
-  (xr--report warnings item-start
-  "End-of-line anchor followed by non-newline"))
- ((and (xr--may-start-in-bol-p item)
-   (not (xr--may-end-in-nl-p prev-item)))
-  (xr--report warnings item-start
-  "Non-newline followed by line-start anchor"))
- ((and (xr--may-end-in-eos-p prev-item)
-   (xr--matches-nonempty-only-p item))
-  (xr--report warnings item-start
-  "End-of-text anchor followed by non-empty pattern"))
- ;; FIXME: We don't complain about non-empty followed by
- ;; bos because it may be the start of unmatchable.
- ;; We should really do these checks in a later pass,
- ;; and maintain location information.
- )
+;; To avoid false positives, we require that at least one
+;; of the items is present in all paths.
+(let ((prev-eol (xr--ends-with-sym 'eol prev-item)))
+  (when prev-eol
+(let ((this-nonl (xr--starts-with-nonl item)))
+  (when (and this-nonl
+ (or (eq prev-eol 'always)
+ (eq this-nonl 'always)))
+(xr--report
+ warnings item-start
+ "End-of-line anchor followed by non-newline")
+(let ((this-bol (xr--starts-with-sym 'bol item)))
+  (when this-bol
+(let ((prev-nonl (xr--ends-with-nonl prev-item)))
+  (when (and prev-nonl
+ (or (eq prev-nonl 'always)
+ (eq this-bol 'always)))
+(xr--report
+ warnings item-start
+ "Non-newline followed by line-start anchor")
+(let ((prev-eos (xr--ends-with-sym 'eos prev-item)))
+  (when prev-eos
+(let ((this-nonempty (xr--matches-nonempty item)))
+  (when (and this-nonempty
+   

[elpa] externals/xr e5b51bf 01/10: Add wrapped subsumption in repeated forms

2020-05-03 Thread Mattias Engdegrd
branch: externals/xr
commit e5b51bf5608720dddac10495950258a9cd07a178
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add wrapped subsumption in repeated forms

This check finds regexps like "\\(?:a*c[ab]*\\)+", where
the first and last item in a repeated sequence are considered
adjacent.
---
 xr-test.el | 13 
 xr.el  | 71 +-
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index 432b8af..2001a39 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -592,6 +592,19 @@
  (46 . "Repetition subsumed by preceding repetition"
 ))
 
+(ert-deftest xr-lint-wrapped-subsumption ()
+  (let ((text-quoting-style 'grave))
+(should (equal
+ (xr-lint "\\(?:a*x[ab]+\\)*")
+ '((14 . "Last item in repetition subsumes first item 
(wrapped)"
+(should (equal
+ (xr-lint "\\([ab]*xya?\\)+")
+ '((13 . "First item in repetition subsumes last item 
(wrapped)"
+(should (equal
+ (xr-lint "\\(?3:a*xa*\\)\\{7\\}")
+ '((14 . "First item in repetition subsumes last item 
(wrapped)"
+))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index 5e7a11f..985f4d8 100644
--- a/xr.el
+++ b/xr.el
@@ -439,6 +439,65 @@ UPPER may be nil, meaning infinity."
  (cl-every #'xr--matches-empty-p body))
 ("" t)))
 
+(defun xr--adjacent-subsumption (a b)
+  "Check if A subsumes B, or vice versa, or not, assuming they are adjacent.
+Return `a-subsumes-b', `b-subsumes-a' or nil."
+  ;; Check for subsuming repetitions in sequence: (Ra A) (Rb B)
+  ;; where Ra and Rb are repetition operators, and A and B are operands.
+  ;; We conclude that (Ra A) subsumes (Rb B), in the sense that the
+  ;; sequence is equivalent to just (Ra A), if:
+  ;;   A matches a superset of B
+  ;;   and Ra can match infinitely many times
+  ;;   and Rb can match zero times
+  ;;   and Rb is non-greedy if Ra is non-greedy.
+  ;; Example: [cd]+c?
+  (let ((a-expr (and (consp a)
+ (memq (car a)
+   '(zero-or-more one-or-more opt *? +? ??))
+ (xr--make-seq (cdr a)
+(when a-expr
+  (let ((b-expr (and (consp b)
+ (memq (car b)
+   '(zero-or-more one-or-more opt *? +? ??))
+ (xr--make-seq (cdr b)
+(when b-expr
+  (let ((a-op (car a))
+(b-op (car b)))
+;; Test the same condition twice, but mirrored.
+(cond
+ ((and (memq b-op '(zero-or-more opt *? ??))
+   (memq a-op '(zero-or-more one-or-more *? +?))
+   (not (and (memq a-op '(*? +?))
+ (memq b-op '(zero-or-more opt
+   (xr--superset-p a-expr b-expr))
+  'a-subsumes-b)
+ ((and (memq a-op '(zero-or-more opt *? ??))
+   (memq b-op '(zero-or-more one-or-more *? +?))
+   (not (and (memq b-op '(*? +?))
+ (memq a-op '(zero-or-more opt
+   (xr--superset-p b-expr a-expr))
+  'b-subsumes-a
+  
+(defun xr--check-wrap-around-repetition (operand pos warnings)
+  "Whether OPERAND has a wrap-around repetition subsumption case,
+like (* (* X) ... (* X))."
+  (when (and (consp operand)
+ (memq (car operand) '(seq group group-n)))
+(let* ((operands
+(if (eq (car operand) 'group-n)
+(cddr operand)
+  (cdr operand
+  (when (cddr operands)
+(let* ((first (car operands))
+   (last (car (last operands)))
+   (subsumption (xr--adjacent-subsumption first last)))
+  (when subsumption
+(xr--report
+ warnings pos
+ (if (eq subsumption 'a-subsumes-b)
+ "First item in repetition subsumes last item (wrapped)"
+   "Last item in repetition subsumes first item (wrapped)"
+
 (defun xr--parse-seq (warnings)
   (let ((sequence nil)) ; reversed
 (while (not (looking-at (rx (or "\\|" "\\)" eos
@@ -502,7 +561,11 @@ UPPER may be nil, meaning infinity."
  (not (equal operand "")))
 (xr--report
  warnings (match-beginning 0)
- "Repetition of expression matching an empty string"
+ "Repetition of expression matching an empty string")))
+  ;; (* (* X) ... (* X)) etc: wrap-around subsumption
+  (when (member operator '("*" "+" "*?" "+?"))
+(xr--check-wrap-around-repetition
+ operand (match-beginning 0) warnings)))
 

[elpa] externals/xr 15b867d 2/3: Fix test in Emacs 26 (bug #3)

2020-03-09 Thread Mattias Engdegrd
branch: externals/xr
commit 15b867d343a54102833743e0021ed5795a7d9631
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix test in Emacs 26 (bug #3)

The 'base' category was (or will be) introduced in Emacs 27; make sure
the tests don't actually use it in regexp matching.
Found by Lev Lamberov.
---
 xr-test.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index 397d8f4..432b8af 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -504,7 +504,7 @@
'((5 . "Branch matches subset of a previous branch"
 (should (equal (xr-lint "\\S-\\|x")
'((5 . "Branch matches subset of a previous branch"
-(should (equal (xr-lint "\\c.\\|a")
+(should (equal (xr-lint "\\cl\\|å")
'((5 . "Branch matches subset of a previous branch"
 (should (equal (xr-lint "\\Ca\\|ü")
'((5 . "Branch matches subset of a previous branch"



[elpa] externals/xr updated (7842512 -> 434b300)

2020-03-09 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/xr.

  from  7842512   Increment version to 1.17
   new  5394d8c   Simplify condition
   new  15b867d   Fix test in Emacs 26 (bug #3)
   new  434b300   Increment version to 1.18


Summary of changes:
 xr-test.el | 2 +-
 xr.el  | 7 ---
 2 files changed, 5 insertions(+), 4 deletions(-)



[elpa] externals/xr 434b300 3/3: Increment version to 1.18

2020-03-09 Thread Mattias Engdegrd
branch: externals/xr
commit 434b3000b0224875893f4feb411c1f65644f8c38
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.18
---
 xr.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index c8bd6d2..5e7a11f 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.17
+;; Version: 1.18
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,8 @@
 
 ;;; News:
 
+;; Version 1.18:
+;; - Fix test broken in Emacs 26
 ;; Version 1.17:
 ;; - Performance improvements
 ;; Version 1.16:



[elpa] externals/xr 5394d8c 1/3: Simplify condition

2020-03-09 Thread Mattias Engdegrd
branch: externals/xr
commit 5394d8c22bc37e332043a29f32614a1b496b4524
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Simplify condition
---
 xr.el | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/xr.el b/xr.el
index 772605e..c8bd6d2 100644
--- a/xr.el
+++ b/xr.el
@@ -1151,8 +1151,7 @@ A-SETS and B-SETS are arguments to `any'."
 (push seq alternatives)))
 (if (cdr alternatives)
 ;; Simplify (or nonl "\n") to anything
-(if (or (equal alternatives '(nonl "\n"))
-(equal alternatives '("\n" nonl)))
+(if (member alternatives '((nonl "\n") ("\n" nonl)))
 'anything
   (cons 'or (nreverse alternatives)))
   (car alternatives



[elpa] externals/relint 83e677d 7/7: Increment version to 1.15

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit 83e677d07a79b6f2c0232f0b03c14dd5e1539b1d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.15

Require xr 1.17.
---
 relint.el | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index 1149fee..a53e2c0 100644
--- a/relint.el
+++ b/relint.el
@@ -3,8 +3,8 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.14
-;; Package-Requires: ((xr "1.16") (emacs "26.1"))
+;; Version: 1.15
+;; Package-Requires: ((xr "1.17") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
 
@@ -29,6 +29,11 @@
 
 ;;; News:
 
+;; Version 1.15:
+;; - Improved position accuracy in various lists of regexps
+;; - Check for mistake in rx `any' forms
+;; - `relint-buffer' now also returns severity (warning, error)
+;; - Relint can now also check the *scratch* buffer
 ;; Version 1.14:
 ;; - Added `relint-buffer'
 ;; - Report error position inside string literals when possible



[elpa] externals/xr 7842512 3/3: Increment version to 1.17

2020-03-05 Thread Mattias Engdegrd
branch: externals/xr
commit 7842512a73d2a6dab3f100921be2a0733f77149d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.17
---
 xr.el | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index d5be9d8..772605e 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.16
+;; Version: 1.17
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,8 @@
 
 ;;; News:
 
+;; Version 1.17:
+;; - Performance improvements
 ;; Version 1.16:
 ;; - Translate [^\n] into nonl
 ;; - Better character class subset/superset analysis



[elpa] externals/relint 7dab4f2 4/7: Slight macro safety improvement

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit 7dab4f25800d3c016fc1a9d52ff59cfbad39905a
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Slight macro safety improvement

Use 'macroexpand-1' instead of 'macroexpand' to get better control
over macro expansion. Some of the 'safe' macros are still potential
loose cannons, since they may expand their arguments eagerly.
---
 relint.el | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index 612bd73..f231f28 100644
--- a/relint.el
+++ b/relint.el
@@ -711,11 +711,13 @@ not be evaluated safely."
   (delete-dups (copy-sequence arg
 
;; Safe macros that expand to pure code, and their auxiliary macros.
+   ;; FIXME: Some of these aren't actually safe at all, since they
+   ;; may expand their arguments eagerly, running arbitrary code!
((memq head '(when unless
  \` backquote-list*
  pcase pcase-let pcase-let* pcase--flip
- cl-case cl-loop cl-flet cl-flet* cl-labels))
-(relint--eval (macroexpand form)))
+ cl-case cl-loop cl-block cl-flet cl-flet* cl-labels))
+(relint--eval (macroexpand-1 form)))
 
;; catch: as long as nobody throws, this naïve code is fine.
((eq head 'catch)
@@ -1003,7 +1005,7 @@ evaluated are nil."
 (relint--eval-list (cadr form)))
 
((memq (car form) '(\` backquote-list*))
-(relint--eval-list (macroexpand form)))
+(relint--eval-list (macroexpand-1 form)))
 
((assq (car form) relint--safe-alternatives)
 (relint--eval-list (cons (cdr (assq (car form) relint--safe-alternatives))



[elpa] externals/relint 8956b21 6/7: Check for mistakes in rx 'any' forms

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit 8956b21a5213efd10f6b80216ae74b45b370cc2d
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check for mistakes in rx 'any' forms

These checks are similar to those done by xr in string regexps.
---
 README   |   5 ++
 relint.el| 153 +++
 test/11.elisp|  15 ++
 test/11.expected |  27 ++
 4 files changed, 200 insertions(+)

diff --git a/README b/README
index 25431d9..944e665 100644
--- a/README
+++ b/README
@@ -165,6 +165,11 @@ skip-syntax-backward.
 In general, A?, where A matches the empty string, can be
 simplified to just A.
 
+  - Suspect range '+-X' or 'X-+'
+
+A character range with '+' as one of its endpoints is more often an
+incorrect attempt to include both '+' and '-' in the set.
+
   - Unnecessarily escaped 'X'
 
 A character is backslash-escaped in a skip set despite not being
diff --git a/relint.el b/relint.el
index 47d9be2..1149fee 100644
--- a/relint.el
+++ b/relint.el
@@ -1306,6 +1306,153 @@ character alternative: `[' followed by a 
regexp-generating expression."
   (setq index (1+ index))
   (setq args (cdr args)
 
+(defun relint--pretty-range (from to)
+  (relint--escape-string
+   (if (eq from to)
+   (char-to-string from)
+ (format "%c-%c" from to))
+   t))
+
+(defun relint--intersecting-range (from to ranges)
+  "Return a range in RANGES intersecting [FROM,TO], or nil if none.
+RANGES is a list of (X . Y) representing the interval [X,Y]."
+  (while (and ranges
+  (let ((range (car ranges)))
+(not (and (<= from (cdr range))
+  (<= (car range) to)
+(setq ranges (cdr ranges)))
+  (car ranges))
+
+(defun relint--check-rx (item file pos path)
+  "Check the `rx' expression ITEM."
+  (pcase item
+(`(,(or ': 'seq 'sequence 'and 'or '|
+'not 'intersection 'repeat '= '>= '**
+'zero-or-more '0+ '* '*?
+'one-or-more '1+ '+ '+?
+'zero-or-one 'opt 'optional '\? ?\s '\?? ??
+'minimal-match 'maximal-match
+'group 'submatch
+'group-n 'submatch-n)
+   . ,args)
+ ;; Form with subforms: recurse.
+ (let ((i 1))
+   (dolist (arg args)
+ (relint--check-rx arg file pos (cons i path))
+ (setq i (1+ i)
+
+(`(,(or 'any 'in 'char 'not-char) . ,args)
+ ;; We don't bother checking for outright errors like "b-a", but
+ ;; look for mistakes that rx itself doesn't complain about. We
+ ;; assume a hand-written rx expression; machine-generated code
+ ;; can break these rules.
+ (let ((i 1)
+   (classes nil)
+   (ranges nil))
+   (dolist (arg args)
+ (cond
+  ((characterp arg)
+   (let ((overlap (relint--intersecting-range arg arg ranges)))
+ (when overlap
+   (relint--warn
+file pos (cons i path)
+(if (eq (car overlap) (cdr overlap))
+(format-message "Duplicated character `%s'"
+(relint--pretty-range arg arg))
+  (format-message "Character `%s' included in range `%s'"
+  (relint--pretty-range arg arg)
+  (relint--pretty-range (car overlap)
+(cdr overlap)))
+   (push (cons arg arg) ranges))
+
+  ((stringp arg)
+   (let ((j 0)
+ (len (length arg)))
+ (while (< j len)
+   (let ((from (aref arg j)))
+ (if (and (< (+ j 2) len)
+  (eq (aref arg (1+ j)) ?-))
+ (let ((to (aref arg (+ j 2
+   (cond
+;; When people write "+-X" or "X-+" for some
+;; X, they rarely mean a range.
+((or (eq from ?+)
+ (eq to ?+))
+ (relint--warn
+  file pos (cons i path)
+  (format-message "Suspect range `%s'"
+  (relint--pretty-range from to))
+  arg j))
+((= to from)
+ (relint--warn
+  file pos (cons i path)
+  (format-message
+   "Single-character range `%s'"
+   (relint--escape-string (format "%c-%c" from to) t))
+  arg j))
+((= to (1+ from))
+ (relint--warn
+  file pos (cons i path)
+  (format-message "Two-character range `%s'"
+  (relint--pretty-range from to))
+  arg j)))
+ 

[elpa] externals/relint updated (c2d3f3b -> 83e677d)

2020-03-05 Thread Mattias Engdegrd
mattiase pushed a change to branch externals/relint.

  from  c2d3f3b   Increment version to 1.14
   new  67f4363   Don't erase the *relint* buffer from relint-buffer
   new  fd43a5f   Permit relint-current-buffer in *scratch*
   new  feba965   Add severity field to tuple returned from relint-buffer
   new  7dab4f2   Slight macro safety improvement
   new  bc7f295   Better position accuracy in various lists of regexps
   new  8956b21   Check for mistakes in rx 'any' forms
   new  83e677d   Increment version to 1.15


Summary of changes:
 README   |   5 +
 relint-test.el   |  15 +-
 relint.el| 445 ++-
 test/1.expected  |  81 +-
 test/10.elisp|  19 +++
 test/10.expected |  30 
 test/11.elisp|  15 ++
 test/11.expected |  27 
 test/3.expected  |  16 +-
 test/9.expected  |   6 +-
 10 files changed, 501 insertions(+), 158 deletions(-)
 create mode 100644 test/10.elisp
 create mode 100644 test/10.expected
 create mode 100644 test/11.elisp
 create mode 100644 test/11.expected



[elpa] externals/xr 376fd03 2/3: Reduce consing in hot paths

2020-03-05 Thread Mattias Engdegrd
branch: externals/xr
commit 376fd031242b8f43274e0fe7a650b4ba61b36115
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Reduce consing in hot paths

Use more destructive operations and avoiding match-string where
unnecessary.
---
 xr.el | 24 
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/xr.el b/xr.el
index af73c71..d5be9d8 100644
--- a/xr.el
+++ b/xr.el
@@ -109,7 +109,7 @@
 (while (not (looking-at "]"))
   (cond
;; character class
-   ((looking-at (rx "[:" (group (*? anything)) ":]"))
+   ((looking-at (rx "[:" (group (* (not (any ":" ":]"))
 (let ((sym (intern (match-string 1
   (unless (memq sym
 '(ascii alnum alpha blank cntrl digit graph
@@ -123,9 +123,9 @@
 (push sym classes))
   (goto-char (match-end 0
;; character range
-   ((looking-at (rx (group (not (any "]"))) "-" (group (not (any "]")
-(let ((start (string-to-char (match-string 1)))
-  (end   (string-to-char (match-string 2
+   ((looking-at (rx (not (any "]")) "-" (not (any "]"
+(let ((start (char-after))
+  (end   (char-after (+ (point) 2
   (cond
((<= start end)
 (push (vector start end (point)) intervals))
@@ -272,7 +272,7 @@
   (when (memq ?- chars)
 (setq chars (cons ?- (delq ?- chars
   (let* ((set (cons 'any
-(append
+(nconc
  (and ranges
   (list (apply #'concat (nreverse ranges
  (and chars
@@ -283,14 +283,14 @@
   set
 
 (defun xr--rev-join-seq (sequence)
-  "Reverse a sequence, flatten any (seq ...) inside, and concatenate
-adjacent strings."
+  "Reverse SEQUENCE, flatten any (seq ...) inside, and concatenate
+adjacent strings. SEQUENCE is used destructively."
   (let ((result nil))
 (while sequence
   (let ((elem (car sequence))
 (rest (cdr sequence)))
 (cond ((and (consp elem) (eq (car elem) 'seq))
-   (setq sequence (append (reverse (cdr elem)) rest)))
+   (setq sequence (nconc (nreverse (cdr elem)) rest)))
   ((and (stringp elem) (stringp (car result)))
(setq result (cons (concat elem (car result)) (cdr result)))
(setq sequence rest))
@@ -572,7 +572,7 @@ UPPER may be nil, meaning infinity."
  ;; character alternative
  ((looking-at (rx "[" (opt (group "^"
   (goto-char (match-end 0))
-  (let ((negated (match-string 1)))
+  (let ((negated (match-beginning 1)))
 (push (xr--parse-char-alt negated warnings) sequence)))
 
  ;; group
@@ -580,9 +580,9 @@ UPPER may be nil, meaning infinity."
  (opt (opt (group (any "1-9")
   (zero-or-more digit)))
   (group ":")
-  (let ((question (match-string 1))
+  (let ((question (match-beginning 1))
 (number (match-string 2))
-(colon (match-string 3)))
+(colon (match-beginning 3)))
 (when (and question (not colon))
   (error "Invalid \\(? syntax"))
 (goto-char (match-end 0))
@@ -1152,7 +1152,7 @@ A-SETS and B-SETS are arguments to `any'."
 (if (or (equal alternatives '(nonl "\n"))
 (equal alternatives '("\n" nonl)))
 'anything
-  (cons 'or (reverse alternatives)))
+  (cons 'or (nreverse alternatives)))
   (car alternatives
 
 (defun xr--parse (re-string warnings)



[elpa] externals/relint bc7f295 5/7: Better position accuracy in various lists of regexps

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit bc7f295932f5fe5fadc45184b7ee38e47b74e9f2
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Better position accuracy in various lists of regexps
---
 relint.el| 173 ---
 test/1.expected  |  80 -
 test/10.elisp|  19 ++
 test/10.expected |  30 ++
 test/3.expected  |  16 ++---
 test/9.expected  |   6 +-
 6 files changed, 225 insertions(+), 99 deletions(-)

diff --git a/relint.el b/relint.el
index f231f28..47d9be2 100644
--- a/relint.el
+++ b/relint.el
@@ -146,7 +146,10 @@ and PATH is (3 0 1 2), then the returned position is right 
before G."
 (forward-sexp)
 (setq skip (1- skip)
   (setq p (cdr p
-  (relint--skip-whitespace))
+  (relint--skip-whitespace)
+  (when (looking-at (rx "."))
+(forward-char)
+(relint--skip-whitespace)))
 
 (defun relint--pos-from-start-pos-path (start-pos path)
   "Compute position from START-POS and PATH (reversed list of
@@ -1014,11 +1017,64 @@ evaluated are nil."
(t
 (relint--eval-or-nil form
 
-(defun relint--get-list (form)
-  "Convert something to a list, or nil."
-  (let ((val (relint--eval-list form)))
-(and (consp val) val)))
-  
+(defun relint--eval-list-iter (fun form path)
+  "Evaluate FORM to a list and call FUN for each non-nil element
+with (ELEM ELEM-PATH LITERAL) as arguments. ELEM-PATH is the best
+approximation to a path to ELEM and has the same base position as
+PATH; LITERAL is true if ELEM-PATH leads to a literal ELEM in the
+source."
+  (pcase form
+(`(quote ,arg)
+ (when (consp arg)
+   (let ((i 0)
+ (p (cons 1 path)))
+ (dolist (elem arg)
+   (when elem
+ (funcall fun elem (cons i p) t))
+   (setq i (1+ i))
+(`(list . ,args)
+ (let ((i 1))
+   (dolist (expr args)
+ (pcase expr
+   ((pred stringp)
+(funcall fun expr (cons i path) t))
+   (`(quote ,elem)
+(when elem
+  (funcall fun elem (cons 1 (cons i path)) t)))
+   (_ (let ((elem (relint--eval-or-nil expr)))
+(when elem
+  (funcall fun elem (cons i path) nil)
+ (setq i (1+ i)
+(`(append . ,args)
+ (let ((i 1))
+   (dolist (arg args)
+ (relint--eval-list-iter fun arg (cons i path))
+ (setq i (1+ i)
+(`(\` ,args)
+ (when (consp args)
+   (let ((i 0))
+ (let ((p0 (cons 1 path)))
+   (dolist (arg args)
+ (let* ((expanded (relint--eval-or-nil (list '\` arg)))
+(values (if (and (consp arg)
+ (eq (car arg) '\,@))
+expanded
+  (list expanded)))
+(p (cons i p0)))
+   (dolist (elem values)
+ (when elem
+   (funcall fun elem p (equal arg expanded)
+ (setq i (1+ i)))
+(`(eval-when-compile ,expr)
+ (relint--eval-list-iter fun expr (cons 1 path)))
+(_
+ ;; Fall back on `relint--eval-list', giving up on
+ ;; element-specific source position.
+ (let ((expr (relint--eval-list form)))
+   (when (consp expr)
+ (dolist (elem expr)
+   (funcall fun elem path nil)))
+
 (defun relint--get-string (form)
   "Convert something to a string, or nil."
   (let ((val (relint--eval-or-nil form)))
@@ -1031,72 +1087,93 @@ evaluated are nil."
 
 (defun relint--check-list (form name file pos path)
   "Check a list of regexps."
-  ;; Don't use dolist -- mustn't crash on improper lists.
-  (let ((l (relint--get-list form)))
-(while (consp l)
-  (when (stringp (car l))
-(relint--check-re-string (car l) name file pos path))
-  (setq l (cdr l)
+  (relint--eval-list-iter
+   (lambda (elem elem-path _literal)
+ (when (stringp elem)
+   (relint--check-re-string elem name file pos elem-path)))
+   form path))
 
 (defun relint--check-list-any (form name file pos path)
   "Check a list of regexps or conses whose car is a regexp."
-  (dolist (elem (relint--get-list form))
-(cond
- ((stringp elem)
-  (relint--check-re-string elem name file pos path))
- ((and (consp elem)
-   (stringp (car elem)))
-  (relint--check-re-string (car elem) name file pos path)
+  (relint--eval-list-iter
+   (lambda (elem elem-path literal)
+ (cond
+  ((stringp elem)
+   (relint--check-re-string elem name file pos elem-path))
+  ((and (consp elem)
+(stringp (car elem)))
+   (relint--check-re-string (car elem) name file pos
+(if literal (cons 0 elem-path) elem-path)
+   form path))
 
 (defun relint--check-alist-any (form name file pos path)
   "Check an alist whose cars or cdrs may be regexps."
-  (dolist (elem (relint--get-list form))
-(when 

[elpa] externals/relint 67f4363 1/7: Don't erase the *relint* buffer from relint-buffer

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit 67f43634438f25eb4a1cf99b5859dbf89e535d37
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't erase the *relint* buffer from relint-buffer

Since relint-buffer doesn't write to *relint*, that buffer should
remain untouched.
---
 relint.el | 31 +++
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/relint.el b/relint.el
index 04002bc..b23e219 100644
--- a/relint.el
+++ b/relint.el
@@ -226,9 +226,9 @@ or nil if no position could be determined."
   matched)))
 
 (defun relint--output-message (string)
-  (if (and noninteractive (not relint--error-buffer))
-  (message "%s" string)
-(relint--add-to-error-buffer (concat string "\n"
+  (if relint--error-buffer
+  (relint--add-to-error-buffer (concat string "\n"))
+(message "%s" string)))
 
 (defun relint--output-report (file expr-pos error-pos message str str-idx)
   (let* ((pos (or error-pos expr-pos))
@@ -1732,7 +1732,7 @@ directly."
  (setq index (1+ index)))
 
 (defun relint--show-errors ()
-  (unless (or noninteractive relint--quiet)
+  (unless (or noninteractive relint--quiet (not relint--error-buffer))
 (let ((pop-up-windows t))
   (display-buffer relint--error-buffer)
   (sit-for 0
@@ -1800,10 +1800,9 @@ Return a list of (FORM . STARTING-POSITION)."
   (setq relint--quiet quiet)
   (setq relint--error-count 0)
   (setq relint--suppression-count 0)
-  (if noninteractive
-  (setq relint--error-buffer error-buffer)
-(setq relint--error-buffer (or error-buffer (relint--get-error-buffer)))
-(with-current-buffer relint--error-buffer
+  (setq relint--error-buffer error-buffer)
+  (when error-buffer
+(with-current-buffer error-buffer
   (unless quiet
 (let ((inhibit-read-only t))
   (insert (format "Relint results for %s\n" target))
@@ -1849,8 +1848,8 @@ Return a list of (FORM . STARTING-POSITION)."
   "Mode for relint output."
   (setq-local relint-last-target nil))
 
-(defun relint--scan-files (files target base-dir)
-  (relint--init target base-dir nil nil)
+(defun relint--scan-files (files target base-dir error-buffer)
+  (relint--init target base-dir error-buffer nil)
   (dolist (file files)
 ;;(relint--output-message (format "Scanning %s" file))
 (relint--scan-file file base-dir))
@@ -1862,8 +1861,7 @@ Return a list of (FORM . STARTING-POSITION)."
 
 (defun relint--scan-buffer (buffer error-buffer quiet)
   "Scan BUFFER for regexp errors.
-Diagnostics to ERROR-BUFFER, or if nil to *relint*.
-If QUIET, don't emit messages."
+Diagnostics to ERROR-BUFFER. If QUIET, don't emit messages."
   (unless (eq (buffer-local-value 'major-mode buffer) 'emacs-lisp-mode)
 (error "Relint: can only scan elisp code (use emacs-lisp-mode)"))
   (relint--init buffer default-directory error-buffer quiet)
@@ -1877,7 +1875,8 @@ If QUIET, don't emit messages."
 (defun relint-file (file)
   "Scan FILE, an elisp file, for regexp-related errors."
   (interactive "fRelint elisp file: ")
-  (relint--scan-files (list file) file (file-name-directory file)))
+  (relint--scan-files (list file) file (file-name-directory file)
+  (relint--get-error-buffer)))
 
 ;;;###autoload
 (defun relint-directory (dir)
@@ -1886,14 +1885,14 @@ If QUIET, don't emit messages."
   (message "Finding .el files in %s..." dir)
   (let ((files (relint--tree-files dir)))
 (message "Scanning files...")
-(relint--scan-files files dir dir)))
+(relint--scan-files files dir dir (relint--get-error-buffer
 
 ;;;###autoload
 (defun relint-current-buffer ()
   "Scan the current buffer for regexp errors.
 The buffer must be in emacs-lisp-mode."
   (interactive)
-  (relint--scan-buffer (current-buffer) nil nil))
+  (relint--scan-buffer (current-buffer) (relint--get-error-buffer) nil))
 
 ;;;###autoload
 (defun relint-buffer (buffer)
@@ -1930,7 +1929,7 @@ complaining about was found, zero otherwise."
 (relint--tree-files arg)
   (list arg)))
   command-line-args-left)
-  nil default-directory)
+  nil default-directory nil)
   (setq command-line-args-left nil)
   (kill-emacs (if (> relint--error-count relint--suppression-count) 1 0)))
 



[elpa] externals/relint fd43a5f 2/7: Permit relint-current-buffer in *scratch*

2020-03-05 Thread Mattias Engdegrd
branch: externals/relint
commit fd43a5f0de6f22a2a126fcec3fd2632d11329638
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Permit relint-current-buffer in *scratch*

Allow any buffer whose major mode is derived from emacs-lisp-mode;
this includes lisp-interaction-mode.  Suggested by Steve Purcell.
---
 relint.el | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index b23e219..1575b73 100644
--- a/relint.el
+++ b/relint.el
@@ -1862,10 +1862,10 @@ Return a list of (FORM . STARTING-POSITION)."
 (defun relint--scan-buffer (buffer error-buffer quiet)
   "Scan BUFFER for regexp errors.
 Diagnostics to ERROR-BUFFER. If QUIET, don't emit messages."
-  (unless (eq (buffer-local-value 'major-mode buffer) 'emacs-lisp-mode)
-(error "Relint: can only scan elisp code (use emacs-lisp-mode)"))
-  (relint--init buffer default-directory error-buffer quiet)
   (with-current-buffer buffer
+(unless (derived-mode-p 'emacs-lisp-mode)
+  (error "Relint: can only scan elisp code (use emacs-lisp-mode)"))
+(relint--init buffer default-directory error-buffer quiet)
 (save-excursion
   (relint--scan-current-buffer (buffer-name
   (relint--finish))



  1   2   3   4   >