branch: externals/ess
commit 8030e29de88c1f234184278e9839d7a78d3ddc6c
Author: Max Pger <[email protected]>
Commit: GitHub <[email protected]>
Extended support for function shorthand notation (#1282)
* Implement font-locking for functions defined or specified (anonymous)
using the backslash shorthand notation. Ensure extensibility by
creating variables `ess-R-keystrings' and `ess-r--non-fn-kstrs' as
complements to `ess-R-keywords' and `ess-r--non-fn-kwds'. Adjust
`ess-r--find-fl-keyword' accordingly. Fixes #1278.
Add question mark (shortcut to help) to both `ess-R-keystrings' and
`ess-r--non-fn-kstrs'.
* Function shorthand notation `\()' to trigger font-locking of function name
* Add R function shorthand notation `\()' to
`ess--r-s-function-pattern'. Allows function defined with the
shorthand notation to be recognized as functions by e.g.
`ess-r-beginning-of-function'.
* Make the ESS-R 'keystrings' variable private by applying the 'two
hyphens' convention and remove reference made to it from the docstring of
`ess-R-keywords'.
Set it to lowercase.
* Add R shorthand notation for `function' to font-locking/fontification
tests, excluding test related to backquoted function definition fontification.
* Adjust `ess-r-font-lock-syntactic-face-function' so that it supports R
function shorthand notation. Allows e.g. backquoted function names to be
font-locked.
* Fix fontification of names of functions defined using R function
shorthand notation.
---
doc/newfeat.texi | 9 +++++++++
lisp/ess-custom.el | 12 +++++++++++-
lisp/ess-r-mode.el | 29 +++++++++++++++++++++++++----
lisp/ess-utils.el | 2 +-
test/ess-test-r-fontification.el | 8 +++++---
5 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/doc/newfeat.texi b/doc/newfeat.texi
index ab2bc19b74..adc15e695c 100644
--- a/doc/newfeat.texi
+++ b/doc/newfeat.texi
@@ -1,6 +1,15 @@
@comment @itemize @w{}
@comment @item
+Changes and New Features in development version:
+@itemize @bullet
+
+@item ESS[R]: The shorthand notation for lambda functions
+and the question mark are now fontified as keywords.
+Contributed by Maxime Pettinger.
+
+@end itemize
+
Changes and New Features in 24.01.1:
@itemize @bullet
diff --git a/lisp/ess-custom.el b/lisp/ess-custom.el
index 4982a19e3c..d783fe5bcc 100644
--- a/lisp/ess-custom.el
+++ b/lisp/ess-custom.el
@@ -2052,6 +2052,15 @@ See also function `ess-create-object-name-db'.")
"recover" "browser")
"Reserved words or special functions in the R language.")
+(defvar ess-r--keystrings
+ '("\\" "\?")
+ "Reserved non-word strings or special functions whose names
+include special characters in the R language.
+
+Similar font-locking usage as `ess-R-keywords', but dedicated to
+strings that should not be treated as `words’ by `regexp-opt' in
+`ess-r--find-fl-keyword'.")
+
(defvar ess-S-keywords
(append ess-R-keywords '("terminate")))
@@ -2088,7 +2097,8 @@ See also function `ess-create-object-name-db'.")
(defvar ess-R-function-name-regexp
(concat "\\(" "\\sw+" "\\)"
"[ \t]*" "\\(<-\\)"
- "[ \t\n]*" "function\\b"))
+ "[ \t\n]*" "\\(function\\b\\|\\(\\\\[ \t\n(]+\\)\\)"))
+;; "[ \t\n(]+" after "\\\\" since cannot use "\\b" to bound a non-word
(defvar ess-S-function-name-regexp
ess-R-function-name-regexp)
diff --git a/lisp/ess-r-mode.el b/lisp/ess-r-mode.el
index bd9027105b..47165c2bcf 100644
--- a/lisp/ess-r-mode.el
+++ b/lisp/ess-r-mode.el
@@ -372,7 +372,7 @@ namespace.")
(ess-goto-char string-end)
(ess-looking-at "<-")
(ess-goto-char (match-end 0))
- (ess-looking-at "function\\b" t)))
+ (ess-looking-at "function\\b\\|\\\\" t)))
font-lock-function-name-face)
((save-excursion
(and (cdr (assq 'ess-fl-keyword:fun-calls
ess-R-font-lock-keywords))
@@ -394,23 +394,44 @@ namespace.")
font-lock-comment-face))
(defvar ess-r--non-fn-kwds
- '("in" "else" "break" "next" "repeat"))
+ '("in" "else" "break" "next" "repeat")
+ "Reserved words that should not be treated as names of special
+functions by `ess-r--find-fl-keyword'; such reserved words do
+not need to be followed by an open parenthesis to trigger
+font-locking.
+See also `ess-r--non-fn-kstrs'.")
+
+(defvar ess-r--non-fn-kstrs
+ '("\?")
+ "Reserved non-word strings that should not be treated as names of
+special functions by `ess-r--find-fl-keyword'; such reserved
+strings do not need to be followed by an open parenthesis to
+trigger font-locking.
+See also `ess-r--non-fn-kwds'.")
(defvar-local ess-r--keyword-regexp nil)
(defun ess-r--find-fl-keyword (limit)
- "Search for R keyword and set the match data.
+ "Search for R keyword or keystring and set the match data.
To be used as part of `font-lock-defaults' keywords."
(unless ess-r--keyword-regexp
- (let (fn-kwds non-fn-kwds)
+ (let (fn-kwds non-fn-kwds fn-kstrs non-fn-kstrs)
(dolist (kw ess-R-keywords)
(if (member kw ess-r--non-fn-kwds)
(push kw non-fn-kwds)
(push kw fn-kwds)))
+ (dolist (kw ess-r--keystrings)
+ (if (member kw ess-r--non-fn-kstrs)
+ (push kw non-fn-kstrs)
+ (push kw fn-kstrs)))
(setq ess-r--keyword-regexp
(concat "\\("
(regexp-opt non-fn-kwds 'words)
+ "\\|"
+ (regexp-opt non-fn-kstrs t)
"\\)\\|\\("
(regexp-opt fn-kwds 'words)
+ "\\|"
+ (regexp-opt fn-kstrs t)
"\\)"))))
(let (out)
(while (and (not out)
diff --git a/lisp/ess-utils.el b/lisp/ess-utils.el
index 9808475382..395e2af58e 100644
--- a/lisp/ess-utils.el
+++ b/lisp/ess-utils.el
@@ -807,7 +807,7 @@ Copied almost verbatim from gnus-utils.el (but with test
for mac added)."
"\\(" space "\\s<.*\\s>\\)*" ; whitespace, comment
;; FIXME: in principle we should skip 'definition *= *' here
- space "function\\s-*(" ; whitespace, function keyword,
parenthesis
+ space "\\(function\\|\\\\\\)\\s-*(" ; whitespace, function
keyword, parenthesis
)))
`(,part-1 ,part-2))
"Partial regex for matching functions.
diff --git a/test/ess-test-r-fontification.el b/test/ess-test-r-fontification.el
index f2db93d50f..f25560856b 100644
--- a/test/ess-test-r-fontification.el
+++ b/test/ess-test-r-fontification.el
@@ -57,6 +57,7 @@
¶while ¶for ¶if ¶switch ¶function ¶return ¶on.exit ¶stop
¶tryCatch ¶withRestarts ¶invokeRestart ¶recover ¶browser
¶message ¶warning ¶signalCondition ¶withCallingHandlers
+¶\\
"
(should (not (face-at-point))))
@@ -66,7 +67,7 @@
¶while() ¶for() ¶if() ¶function()
¶switch() ¶return() ¶on.exit() ¶stop() ¶tryCatch()
¶withRestarts() ¶invokeRestart() ¶recover() ¶browser()
-¶.Defunct()
+¶.Defunct() ¶\\(\\\\\\)()
"
(should (eq (face-at-point) 'ess-keyword-face))
@@ -75,7 +76,7 @@
while¶() for¶() if¶() function¶()
switch¶() return¶() on.exit¶() stop¶() tryCatch¶()
withRestarts¶() invokeRestart¶() recover¶() browser¶()
-.Defunct¶()
+.Defunct¶() \\(\\\\\\)¶()
"
(should (not (face-at-point)))
@@ -95,7 +96,7 @@ message¶() warning¶() signalCondition¶()
withCallingHandlers¶()
(etest-deftest ess-test-r-fontification-keywords-simple-test ()
"Simple keywords are always fontified."
- :case "¶else ¶break ¶next ¶repeat"
+ :case "¶else ¶break ¶next ¶repeat ¶\?"
(should (eq (face-at-point) 'ess-keyword-face)))
(etest-deftest ess-test-r-fontification-keywords-in-test ()
@@ -154,6 +155,7 @@ message¶() warning¶() signalCondition¶()
withCallingHandlers¶()
¶`[.foo` <- function(...) NULL
¶\"[.foo\" <- function(...) NULL
"
+
(should (eq (face-at-point) 'font-lock-function-name-face))
(with-ess-disabled-font-lock-keyword 'ess-R-fl-keyword:fun-defs