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

Reply via email to