cperl-mode.el: Update for the current Perl version 5.040

* etc/NEWS: Announce new features of cperl-mode.

* lisp/progmodes/cperl-mode.el (cperl-menu): Add toggle for extra
paired delimiters.
(defconst): new rx expressions `cperl--sub-name-generated-rx' and
`cperl--field-declaration-rx'
(cperl--imenu-entries-rx): Use the new expressions
(cperl--extra-paired-delimiters): New variable holding the paired
delimiters for Perl 5.36 and newer
(cperl-imenu-sub-keywords): Add autogenerated methods to imenu
(cperl-init-faces): Add the __CLASS__ token, builtin constants,
and attributes for field declarations.
(cperl-short-docs): Add __CLASS__ to one-line docs.
(cperl-extra-paired-delimiters-mode): new minor mode to handle
non-ASCII paired delimiters.

* test/lisp/progmodes/cperl-mode-tests.el
(cperl-test-fontify-builtin-constants): new test.
(cperl-test-fontify-class): New test clauses for attributes.
(cperl-test-field-declaration-rx): new test.
(cperl-test-autogenerated-reader-rx): new unit test for the rx
expression.
(cperl-test-extra-delimiters): new test.
(cperl-test-imenu-index): new clauses for imenu capture of
autogenerated methods.

* test/lisp/progmodes/cperl-mode-resources/grammar.pl: Add
examples for Perl 5.40 syntax.

* test/lisp/progmodes/cperl-mode-resources/extra-delimiters.pl:
New resource for non-ASCII paired delimiters.
This commit is contained in:
Harald Jörg 2024-06-10 12:19:04 +02:00
parent 5416889873
commit 060c48435f
6 changed files with 599 additions and 23 deletions

View file

@ -1657,9 +1657,9 @@ fit on fewer lines without negatively impacting readability.
CPerl mode fontifies subroutine signatures like variable declarations
which makes them visually distinct from subroutine prototypes.
*** Syntax of Perl up to version 5.38 is supported.
*** Syntax of Perl up to version 5.40 is supported.
CPerl mode supports the new keywords for exception handling and the
object oriented syntax which were added in Perl 5.36 and 5.38.
object oriented syntax which were added in Perl 5.36, 5.38 and 5.40.
*** New user option 'cperl-fontify-trailer'.
This user option takes the values 'perl-code' or 'comment' and treats
@ -1673,6 +1673,11 @@ This command sets the indentation style for the current buffer. To
change the default style, either use the user option with the same name
or use the command 'cperl-set-style'.
*** New minor mode cperl-extra-paired-delimiters-mode
Perl 5.36 and newer allows using more than 200 non-ASCII paired
delimiters for quote-like constructs, eg. "q«text»". Use this minor
mode in buffers where this feature is activated.
*** Commands using the Perl info page are obsolete.
The Perl documentation in info format is no longer distributed with
Perl or on CPAN since more than 10 years. Perl documentation can be

View file

@ -1130,6 +1130,7 @@ Unless KEEP, removes the old indentation."
["Auto newline" cperl-toggle-auto-newline t]
["Electric parens" cperl-toggle-electric t]
["Electric keywords" cperl-toggle-abbrev t]
["Extra paired delimiters" cperl-extra-paired-delimiters-mode t]
["Fix whitespace on indent" cperl-toggle-construct-fix t]
["Auto-help on Perl constructs" cperl-toggle-autohelp t]
["Auto fill" auto-fill-mode t])
@ -1436,6 +1437,33 @@ Contains three groups: One to distinguish lexical from \"normal\"
subroutines, for the keyword \"sub\" or \"method\", and one for
the subroutine name.")
(defconst cperl--sub-name-generated-rx
`(sequence symbol-start
(optional (group-n 3 unmatchable))
;; autogenerated methods are not lexicals, so enforce the
;; first capture group to be nil
"field"
,cperl--ws+-rx
(or
(sequence (in "$%@")
(group-n 2 ,cperl--basic-identifier-rx)
(1+ (not (in ";={")))
":"
(group-n 1 "reader")
(not "("))
(sequence ,cperl--basic-variable-rx
(1+ (not (in ";={")))
":"
(group-n 1 "reader")
"("
(group-n 2 ,cperl--basic-identifier-rx)
")")))
"A regular expression to capture autogenerated reader methods.
The name of the method is either the field name without its sigil, or
given in parentheses after the \":reader\" keyword.")
;; I don't dare to think about :writer where the generated name does
;; not even occur in the text.
(defconst cperl--block-declaration-rx
`(sequence
(or "class" "method" "package" "sub")
@ -1445,16 +1473,16 @@ the subroutine name.")
Used for indentation. These declarations introduce a block which
does not need a semicolon to terminate the statement.")
;;; Initializer blocks are not (yet) part of the Perl core.
;; (defconst cperl--field-declaration-rx
;; `(sequence
;; "field"
;; (1+ ,cperl--ws-or-comment-rx)
;; ,cperl--basic-variable-rx)
;; "A regular expression to find a declaration for a field.
;; Used for indentation. These declarations allow an initializer
;; block which does not need a semicolon to terminate the
;; statement.")
(defconst cperl--field-declaration-rx
`(sequence
"field"
(1+ ,cperl--ws-or-comment-rx)
,cperl--basic-variable-rx
(optional (sequence ,cperl--ws+-rx ,cperl--attribute-list-rx))
)
"A regular expression to find a declaration for a field.
Fields can have attributes for fontification, and even for imenu because
for example \":reader\" implicitly declares a method.")
(defconst cperl--pod-heading-rx
`(sequence line-start
@ -1470,6 +1498,7 @@ heading text.")
`(or ,cperl--package-for-imenu-rx
,cperl--class-for-imenu-rx
,cperl--sub-name-for-imenu-rx
,cperl--sub-name-generated-rx
,cperl--pod-heading-rx)
"A regular expression to collect stuff that goes into the `imenu' index.
Covers packages and classes, subroutines and methods, and POD headings.")
@ -3351,10 +3380,333 @@ fontified. Do nothing if BEGIN and END are equal. If
(put-text-property begin end 'face (if string 'font-lock-string-face
'font-lock-comment-face)))))
(defvar cperl-starters '(( ?\( . ?\) )
( ?\[ . ?\] )
( ?\{ . ?\} )
( ?\< . ?\> )))
(defvar cperl--basic-paired-delimiters '(( ?\( . ?\) )
( ?\[ . ?\] )
( ?\{ . ?\} )
( ?\< . ?\> )))
;; -------- The following definition is generated code from "perlop"
;; https://metacpan.org/release/HAARG/perl-5.40.0/view/pod/perlop.pod
(defvar cperl--extra-paired-delimiters '(( ?\N{U+0028} . ?\N{U+0029} )
( ?\N{U+003C} . ?\N{U+003E} )
( ?\N{U+005B} . ?\N{U+005D} )
( ?\N{U+007B} . ?\N{U+007D} )
( ?\N{U+00AB} . ?\N{U+00BB} )
( ?\N{U+00BB} . ?\N{U+00AB} )
( ?\N{U+0F3A} . ?\N{U+0F3B} )
( ?\N{U+0F3C} . ?\N{U+0F3D} )
( ?\N{U+169B} . ?\N{U+169C} )
( ?\N{U+2018} . ?\N{U+2019} )
( ?\N{U+2019} . ?\N{U+2018} )
( ?\N{U+201C} . ?\N{U+201D} )
( ?\N{U+201D} . ?\N{U+201C} )
( ?\N{U+2035} . ?\N{U+2032} )
( ?\N{U+2036} . ?\N{U+2033} )
( ?\N{U+2037} . ?\N{U+2034} )
( ?\N{U+2039} . ?\N{U+203A} )
( ?\N{U+203A} . ?\N{U+2039} )
( ?\N{U+2045} . ?\N{U+2046} )
( ?\N{U+204D} . ?\N{U+204C} )
( ?\N{U+207D} . ?\N{U+207E} )
( ?\N{U+208D} . ?\N{U+208E} )
( ?\N{U+2192} . ?\N{U+2190} )
( ?\N{U+219B} . ?\N{U+219A} )
( ?\N{U+219D} . ?\N{U+219C} )
( ?\N{U+21A0} . ?\N{U+219E} )
( ?\N{U+21A3} . ?\N{U+21A2} )
( ?\N{U+21A6} . ?\N{U+21A4} )
( ?\N{U+21AA} . ?\N{U+21A9} )
( ?\N{U+21AC} . ?\N{U+21AB} )
( ?\N{U+21B1} . ?\N{U+21B0} )
( ?\N{U+21B3} . ?\N{U+21B2} )
( ?\N{U+21C0} . ?\N{U+21BC} )
( ?\N{U+21C1} . ?\N{U+21BD} )
( ?\N{U+21C9} . ?\N{U+21C7} )
( ?\N{U+21CF} . ?\N{U+21CD} )
( ?\N{U+21D2} . ?\N{U+21D0} )
( ?\N{U+21DB} . ?\N{U+21DA} )
( ?\N{U+21DD} . ?\N{U+21DC} )
( ?\N{U+21E2} . ?\N{U+21E0} )
( ?\N{U+21E5} . ?\N{U+21E4} )
( ?\N{U+21E8} . ?\N{U+21E6} )
( ?\N{U+21F4} . ?\N{U+2B30} )
( ?\N{U+21F6} . ?\N{U+2B31} )
( ?\N{U+21F8} . ?\N{U+21F7} )
( ?\N{U+21FB} . ?\N{U+21FA} )
( ?\N{U+21FE} . ?\N{U+21FD} )
( ?\N{U+2208} . ?\N{U+220B} )
( ?\N{U+2209} . ?\N{U+220C} )
( ?\N{U+220A} . ?\N{U+220D} )
( ?\N{U+2264} . ?\N{U+2265} )
( ?\N{U+2266} . ?\N{U+2267} )
( ?\N{U+2268} . ?\N{U+2269} )
( ?\N{U+226A} . ?\N{U+226B} )
( ?\N{U+226E} . ?\N{U+226F} )
( ?\N{U+2270} . ?\N{U+2271} )
( ?\N{U+2272} . ?\N{U+2273} )
( ?\N{U+2274} . ?\N{U+2275} )
( ?\N{U+227A} . ?\N{U+227B} )
( ?\N{U+227C} . ?\N{U+227D} )
( ?\N{U+227E} . ?\N{U+227F} )
( ?\N{U+2280} . ?\N{U+2281} )
( ?\N{U+2282} . ?\N{U+2283} )
( ?\N{U+2284} . ?\N{U+2285} )
( ?\N{U+2286} . ?\N{U+2287} )
( ?\N{U+2288} . ?\N{U+2289} )
( ?\N{U+228A} . ?\N{U+228B} )
( ?\N{U+22A3} . ?\N{U+22A2} )
( ?\N{U+22A6} . ?\N{U+2ADE} )
( ?\N{U+22A8} . ?\N{U+2AE4} )
( ?\N{U+22A9} . ?\N{U+2AE3} )
( ?\N{U+22B0} . ?\N{U+22B1} )
( ?\N{U+22D0} . ?\N{U+22D1} )
( ?\N{U+22D6} . ?\N{U+22D7} )
( ?\N{U+22D8} . ?\N{U+22D9} )
( ?\N{U+22DC} . ?\N{U+22DD} )
( ?\N{U+22DE} . ?\N{U+22DF} )
( ?\N{U+22E0} . ?\N{U+22E1} )
( ?\N{U+22E6} . ?\N{U+22E7} )
( ?\N{U+22E8} . ?\N{U+22E9} )
( ?\N{U+22F2} . ?\N{U+22FA} )
( ?\N{U+22F3} . ?\N{U+22FB} )
( ?\N{U+22F4} . ?\N{U+22FC} )
( ?\N{U+22F6} . ?\N{U+22FD} )
( ?\N{U+22F7} . ?\N{U+22FE} )
( ?\N{U+2308} . ?\N{U+2309} )
( ?\N{U+230A} . ?\N{U+230B} )
( ?\N{U+2326} . ?\N{U+232B} )
( ?\N{U+2348} . ?\N{U+2347} )
( ?\N{U+23ED} . ?\N{U+23EE} )
( ?\N{U+261B} . ?\N{U+261A} )
( ?\N{U+261E} . ?\N{U+261C} )
( ?\N{U+269E} . ?\N{U+269F} )
( ?\N{U+2768} . ?\N{U+2769} )
( ?\N{U+276A} . ?\N{U+276B} )
( ?\N{U+276C} . ?\N{U+276D} )
( ?\N{U+276E} . ?\N{U+276F} )
( ?\N{U+2770} . ?\N{U+2771} )
( ?\N{U+2772} . ?\N{U+2773} )
( ?\N{U+2774} . ?\N{U+2775} )
( ?\N{U+27C3} . ?\N{U+27C4} )
( ?\N{U+27C5} . ?\N{U+27C6} )
( ?\N{U+27C8} . ?\N{U+27C9} )
( ?\N{U+27DE} . ?\N{U+27DD} )
( ?\N{U+27E6} . ?\N{U+27E7} )
( ?\N{U+27E8} . ?\N{U+27E9} )
( ?\N{U+27EA} . ?\N{U+27EB} )
( ?\N{U+27EC} . ?\N{U+27ED} )
( ?\N{U+27EE} . ?\N{U+27EF} )
( ?\N{U+27F4} . ?\N{U+2B32} )
( ?\N{U+27F6} . ?\N{U+27F5} )
( ?\N{U+27F9} . ?\N{U+27F8} )
( ?\N{U+27FC} . ?\N{U+27FB} )
( ?\N{U+27FE} . ?\N{U+27FD} )
( ?\N{U+27FF} . ?\N{U+2B33} )
( ?\N{U+2900} . ?\N{U+2B34} )
( ?\N{U+2901} . ?\N{U+2B35} )
( ?\N{U+2903} . ?\N{U+2902} )
( ?\N{U+2905} . ?\N{U+2B36} )
( ?\N{U+2907} . ?\N{U+2906} )
( ?\N{U+290D} . ?\N{U+290C} )
( ?\N{U+290F} . ?\N{U+290E} )
( ?\N{U+2910} . ?\N{U+2B37} )
( ?\N{U+2911} . ?\N{U+2B38} )
( ?\N{U+2914} . ?\N{U+2B39} )
( ?\N{U+2915} . ?\N{U+2B3A} )
( ?\N{U+2916} . ?\N{U+2B3B} )
( ?\N{U+2917} . ?\N{U+2B3C} )
( ?\N{U+2918} . ?\N{U+2B3D} )
( ?\N{U+291A} . ?\N{U+2919} )
( ?\N{U+291C} . ?\N{U+291B} )
( ?\N{U+291E} . ?\N{U+291D} )
( ?\N{U+2920} . ?\N{U+291F} )
( ?\N{U+2933} . ?\N{U+2B3F} )
( ?\N{U+2937} . ?\N{U+2936} )
( ?\N{U+2945} . ?\N{U+2946} )
( ?\N{U+2947} . ?\N{U+2B3E} )
( ?\N{U+2953} . ?\N{U+2952} )
( ?\N{U+2957} . ?\N{U+2956} )
( ?\N{U+295B} . ?\N{U+295A} )
( ?\N{U+295F} . ?\N{U+295E} )
( ?\N{U+2964} . ?\N{U+2962} )
( ?\N{U+296C} . ?\N{U+296A} )
( ?\N{U+296D} . ?\N{U+296B} )
( ?\N{U+2971} . ?\N{U+2B40} )
( ?\N{U+2972} . ?\N{U+2B41} )
( ?\N{U+2974} . ?\N{U+2B4B} )
( ?\N{U+2975} . ?\N{U+2B42} )
( ?\N{U+2979} . ?\N{U+297B} )
( ?\N{U+2983} . ?\N{U+2984} )
( ?\N{U+2985} . ?\N{U+2986} )
( ?\N{U+2987} . ?\N{U+2988} )
( ?\N{U+2989} . ?\N{U+298A} )
( ?\N{U+298B} . ?\N{U+298C} )
( ?\N{U+298D} . ?\N{U+2990} )
( ?\N{U+298F} . ?\N{U+298E} )
( ?\N{U+2991} . ?\N{U+2992} )
( ?\N{U+2993} . ?\N{U+2994} )
( ?\N{U+2995} . ?\N{U+2996} )
( ?\N{U+2997} . ?\N{U+2998} )
( ?\N{U+29A8} . ?\N{U+29A9} )
( ?\N{U+29AA} . ?\N{U+29AB} )
( ?\N{U+29B3} . ?\N{U+29B4} )
( ?\N{U+29C0} . ?\N{U+29C1} )
( ?\N{U+29D8} . ?\N{U+29D9} )
( ?\N{U+29DA} . ?\N{U+29DB} )
( ?\N{U+29FC} . ?\N{U+29FD} )
( ?\N{U+2A79} . ?\N{U+2A7A} )
( ?\N{U+2A7B} . ?\N{U+2A7C} )
( ?\N{U+2A7D} . ?\N{U+2A7E} )
( ?\N{U+2A7F} . ?\N{U+2A80} )
( ?\N{U+2A81} . ?\N{U+2A82} )
( ?\N{U+2A83} . ?\N{U+2A84} )
( ?\N{U+2A85} . ?\N{U+2A86} )
( ?\N{U+2A87} . ?\N{U+2A88} )
( ?\N{U+2A89} . ?\N{U+2A8A} )
( ?\N{U+2A8D} . ?\N{U+2A8E} )
( ?\N{U+2A95} . ?\N{U+2A96} )
( ?\N{U+2A97} . ?\N{U+2A98} )
( ?\N{U+2A99} . ?\N{U+2A9A} )
( ?\N{U+2A9B} . ?\N{U+2A9C} )
( ?\N{U+2A9D} . ?\N{U+2A9E} )
( ?\N{U+2A9F} . ?\N{U+2AA0} )
( ?\N{U+2AA1} . ?\N{U+2AA2} )
( ?\N{U+2AA6} . ?\N{U+2AA7} )
( ?\N{U+2AA8} . ?\N{U+2AA9} )
( ?\N{U+2AAA} . ?\N{U+2AAB} )
( ?\N{U+2AAC} . ?\N{U+2AAD} )
( ?\N{U+2AAF} . ?\N{U+2AB0} )
( ?\N{U+2AB1} . ?\N{U+2AB2} )
( ?\N{U+2AB3} . ?\N{U+2AB4} )
( ?\N{U+2AB5} . ?\N{U+2AB6} )
( ?\N{U+2AB7} . ?\N{U+2AB8} )
( ?\N{U+2AB9} . ?\N{U+2ABA} )
( ?\N{U+2ABB} . ?\N{U+2ABC} )
( ?\N{U+2ABD} . ?\N{U+2ABE} )
( ?\N{U+2ABF} . ?\N{U+2AC0} )
( ?\N{U+2AC1} . ?\N{U+2AC2} )
( ?\N{U+2AC3} . ?\N{U+2AC4} )
( ?\N{U+2AC5} . ?\N{U+2AC6} )
( ?\N{U+2AC7} . ?\N{U+2AC8} )
( ?\N{U+2AC9} . ?\N{U+2ACA} )
( ?\N{U+2ACB} . ?\N{U+2ACC} )
( ?\N{U+2ACF} . ?\N{U+2AD0} )
( ?\N{U+2AD1} . ?\N{U+2AD2} )
( ?\N{U+2AD5} . ?\N{U+2AD6} )
( ?\N{U+2AE5} . ?\N{U+22AB} )
( ?\N{U+2AF7} . ?\N{U+2AF8} )
( ?\N{U+2AF9} . ?\N{U+2AFA} )
( ?\N{U+2B46} . ?\N{U+2B45} )
( ?\N{U+2B47} . ?\N{U+2B49} )
( ?\N{U+2B48} . ?\N{U+2B4A} )
( ?\N{U+2B4C} . ?\N{U+2973} )
( ?\N{U+2B62} . ?\N{U+2B60} )
( ?\N{U+2B6C} . ?\N{U+2B6A} )
( ?\N{U+2B72} . ?\N{U+2B70} )
( ?\N{U+2B7C} . ?\N{U+2B7A} )
( ?\N{U+2B86} . ?\N{U+2B84} )
( ?\N{U+2B8A} . ?\N{U+2B88} )
( ?\N{U+2B95} . ?\N{U+2B05} )
( ?\N{U+2B9A} . ?\N{U+2B98} )
( ?\N{U+2B9E} . ?\N{U+2B9C} )
( ?\N{U+2BA1} . ?\N{U+2BA0} )
( ?\N{U+2BA3} . ?\N{U+2BA2} )
( ?\N{U+2BA9} . ?\N{U+2BA8} )
( ?\N{U+2BAB} . ?\N{U+2BAA} )
( ?\N{U+2BB1} . ?\N{U+2BB0} )
( ?\N{U+2BB3} . ?\N{U+2BB2} )
( ?\N{U+2BEE} . ?\N{U+2BEC} )
( ?\N{U+2E02} . ?\N{U+2E03} )
( ?\N{U+2E03} . ?\N{U+2E02} )
( ?\N{U+2E04} . ?\N{U+2E05} )
( ?\N{U+2E05} . ?\N{U+2E04} )
( ?\N{U+2E09} . ?\N{U+2E0A} )
( ?\N{U+2E0A} . ?\N{U+2E09} )
( ?\N{U+2E0C} . ?\N{U+2E0D} )
( ?\N{U+2E0D} . ?\N{U+2E0C} )
( ?\N{U+2E11} . ?\N{U+2E10} )
( ?\N{U+2E1C} . ?\N{U+2E1D} )
( ?\N{U+2E1D} . ?\N{U+2E1C} )
( ?\N{U+2E20} . ?\N{U+2E21} )
( ?\N{U+2E21} . ?\N{U+2E20} )
( ?\N{U+2E22} . ?\N{U+2E23} )
( ?\N{U+2E24} . ?\N{U+2E25} )
( ?\N{U+2E26} . ?\N{U+2E27} )
( ?\N{U+2E28} . ?\N{U+2E29} )
( ?\N{U+2E36} . ?\N{U+2E37} )
( ?\N{U+2E42} . ?\N{U+201E} )
( ?\N{U+2E55} . ?\N{U+2E56} )
( ?\N{U+2E57} . ?\N{U+2E58} )
( ?\N{U+2E59} . ?\N{U+2E5A} )
( ?\N{U+2E5B} . ?\N{U+2E5C} )
( ?\N{U+A9C1} . ?\N{U+A9C2} )
( ?\N{U+FD3E} . ?\N{U+FD3F} )
( ?\N{U+FF62} . ?\N{U+FF63} )
( ?\N{U+FFEB} . ?\N{U+FFE9} )
( ?\N{U+1D103} . ?\N{U+1D102} )
( ?\N{U+1D106} . ?\N{U+1D107} )
( ?\N{U+1F57B} . ?\N{U+1F57D} )
( ?\N{U+1F599} . ?\N{U+1F598} )
( ?\N{U+1F59B} . ?\N{U+1F59A} )
( ?\N{U+1F59D} . ?\N{U+1F59C} )
( ?\N{U+1F5E6} . ?\N{U+1F5E7} )
( ?\N{U+1F802} . ?\N{U+1F800} )
( ?\N{U+1F806} . ?\N{U+1F804} )
( ?\N{U+1F80A} . ?\N{U+1F808} )
( ?\N{U+1F812} . ?\N{U+1F810} )
( ?\N{U+1F816} . ?\N{U+1F814} )
( ?\N{U+1F81A} . ?\N{U+1F818} )
( ?\N{U+1F81E} . ?\N{U+1F81C} )
( ?\N{U+1F822} . ?\N{U+1F820} )
( ?\N{U+1F826} . ?\N{U+1F824} )
( ?\N{U+1F82A} . ?\N{U+1F828} )
( ?\N{U+1F82E} . ?\N{U+1F82C} )
( ?\N{U+1F832} . ?\N{U+1F830} )
( ?\N{U+1F836} . ?\N{U+1F834} )
( ?\N{U+1F83A} . ?\N{U+1F838} )
( ?\N{U+1F83E} . ?\N{U+1F83C} )
( ?\N{U+1F842} . ?\N{U+1F840} )
( ?\N{U+1F846} . ?\N{U+1F844} )
( ?\N{U+1F852} . ?\N{U+1F850} )
( ?\N{U+1F862} . ?\N{U+1F860} )
( ?\N{U+1F86A} . ?\N{U+1F868} )
( ?\N{U+1F872} . ?\N{U+1F870} )
( ?\N{U+1F87A} . ?\N{U+1F878} )
( ?\N{U+1F882} . ?\N{U+1F880} )
( ?\N{U+1F892} . ?\N{U+1F890} )
( ?\N{U+1F896} . ?\N{U+1F894} )
( ?\N{U+1F89A} . ?\N{U+1F898} )
( ?\N{U+1F8A1} . ?\N{U+1F8A0} )
( ?\N{U+1F8A3} . ?\N{U+1F8A2} )
( ?\N{U+1F8A5} . ?\N{U+1F8A6} )
( ?\N{U+1F8A7} . ?\N{U+1F8A4} )
( ?\N{U+1F8A9} . ?\N{U+1F8A8} )
( ?\N{U+1F8AB} . ?\N{U+1F8AA} ))
"Full list of paired delimiters for quote-like constructs.
As an experimental feature, Perl uses these under \"feature
\='extra_paired_delimiters\='\" or in feature bundles of Perl 5.40 or
newer. To activate the extra delimiters, switch on the minor mode
`cperl-extra-paired-delimiters-mode'. This is also available from the
\"Perl\" menu in section \"Toggle...\".
The character pairs available are:
(), <>, [], {}, «», »«, , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
⬿, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ⩿,
, , , , , , , , , , , , , , , , , , ,
, , , , , , ⪿, , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , , ,
, , , , , , ﴿, , , 𝄃𝄂, 𝄆𝄇, 🕻🕽, 🖙🖘, 🖛🖚, 🖝🖜, 🗦🗧, 🠂🠀, 🠆🠄, 🠊🠈,
🠒🠐, 🠖🠔, 🠚🠘, 🠞🠜, 🠢🠠, 🠦🠤, 🠪🠨, 🠮🠬, 🠲🠰, 🠶🠴, 🠺🠸, 🠾🠼, 🡂🡀, 🡆🡄, 🡒🡐, 🡢🡠, 🡪🡨, 🡲🡰, 🡺🡸,
🢂🢀, 🢒🢐, 🢖🢔, 🢚🢘, 🢡🢠, 🢣🢢, 🢥🢦, 🢧🢤, 🢩🢨, 🢫🢪")
;; --------End of generated code
(defvar cperl-starters cperl--basic-paired-delimiters)
(defun cperl-cached-syntax-table (st)
"Get a syntax table cached in ST, or create and cache into ST a syntax table.
@ -5672,7 +6024,8 @@ indentation and initial hashes. Behaves usually outside of comment."
;; The following lists are used for categorizing the entries found by
;; `cperl-imenu--create-perl-index'.
(defvar cperl-imenu-package-keywords '("package" "class" "role"))
(defvar cperl-imenu-sub-keywords '("sub" "method" "function" "fun"))
(defvar cperl-imenu-sub-keywords '("sub" "method" "function" "fun"
"reader")) ;; for autogenerated
(defvar cperl-imenu-pod-keywords '("=head"))
(defun cperl-imenu--create-perl-index ()
@ -5973,7 +6326,7 @@ functions (which they are not). Inherits from `default'.")
(concat
"\\(^\\|[^$@%&\\]\\)\\<\\("
(regexp-opt
'("CORE" "__FILE__" "__LINE__" "__SUB__" "__PACKAGE__"
'("CORE" "__FILE__" "__LINE__" "__SUB__" "__PACKAGE__" "__CLASS__"
"abs" "accept" "alarm" "and" "atan2"
"bind" "binmode" "bless" "caller"
"chdir" "chmod" "chown" "chr" "chroot" "close"
@ -6087,7 +6440,7 @@ functions (which they are not). Inherits from `default'.")
;; 1=my_etc, 2=white? 3=(+white? 4=white? 5=var
;; -------- variable declarations
;; (matcher (subexp facespec) ...
`(,(rx (sequence (or "state" "my" "local" "our" "field"))
`(,(rx (sequence (or "state" "my" "local" "our"))
(eval cperl--ws*-rx)
(opt (group (sequence "(" (eval cperl--ws*-rx))))
(group
@ -6137,6 +6490,44 @@ functions (which they are not). Inherits from `default'.")
(forward-char -2)) ; disable continued expr
nil
(1 font-lock-variable-name-face)))
;; -------- builtin constants with and without package prefix
;; (matcher subexp facespec)
`(,(rx (or space (in "=<>-"))
(group (optional "&")
(optional "builtin::")
(or "inf" "nan")
symbol-end))
1 'font-lock-constant-face)
;; -------- field declarations
`(,(rx "field"
(eval cperl--ws+-rx)
(group (eval cperl--basic-variable-rx))
(optional (sequence
(eval cperl--ws+-rx)
(group (eval cperl--attribute-list-rx)))))
(1 font-lock-variable-name-face)
;; -------- optional attributes
;; (anchored-matcher pre-form post-form subex-highlighters)
(,(rx
(group (optional ":" (eval cperl--ws*-rx))
(eval cperl--basic-identifier-rx))
(optional "("
(group (eval cperl--basic-identifier-rx))
")"))
;; pre-form: Define range for anchored matcher
(if (match-beginning 2)
(progn
(goto-char (match-beginning 2))
(match-end 2))
;; If there's no attribute list in match 2, set a short
;; limit to the search for the anchored matcher,
;; otherwise it might interpret stuff from the
;; initializer expression as attribute.
(1+ (point)))
nil
(1 font-lock-constant-face)
(2 font-lock-string-face nil t) ; lax match, value is optional
))
;; ----- foreach my $foo (
;; (matcher subexp facespec)
`(,(rx symbol-start "for" (opt "each")
@ -7773,6 +8164,7 @@ x= ... Repetition assignment.
\\u Upcase the next character. See also \\U and \\l, ucfirst.
\\x Hex character, e.g. \\x1b.
... ^ ... Bitwise exclusive or.
__CLASS__ The class of an object in construction
__DATA__ Ends program source.
__END__ Ends program source.
ADJUST {...} Callback for object creation
@ -8984,6 +9376,24 @@ do extra unwind via `cperl-unwind-to-safe'."
"Text property which inhibits refontification.")
(make-obsolete-variable 'cperl-do-not-fontify nil "28.1")
;;; Minor mode for optional Perl features
(define-minor-mode cperl-extra-paired-delimiters-mode
"Toggle treatment of extra paired delimiters in Perl.
Many non-ASCII paired delimiters can be used for quote-like constructs
by activating the feature \"extra_paired_delimiters\" either explicitly
or as part of the Perl 5.40 feature bundle. This command allows
`cperl-mode' to recognize the same set of paired delimiters, see the
variable `cperl--extra-paired-delimiters'."
:group 'cperl
:lighter "«»"
:interactive (cperl-mode)
(if cperl-extra-paired-delimiters-mode
(progn
(setq-local cperl-starters cperl--extra-paired-delimiters)
(cperl-find-pods-heres (point-min) (point-max)))
(setq-local cperl-starters cperl--basic-paired-delimiters)
(cperl-find-pods-heres (point-min) (point-max))))
(provide 'cperl-mode)
;;; cperl-mode.el ends here

View file

@ -0,0 +1,23 @@
use utf8;
my $string_with_strange_delimiters = q«a»;
my $printed = 0;
label:
print $string_with_strange_delimiters;
$printed = 1;
# With cperl-extra-delimiters-mode=on the previous lines are a label
# and a a print statement. This line here is a comment. Without
# cperl-extra-delimiters-mode, all this is part of the variable
# declaration.
# Perl will print hist an "a" if called like this:
# perl -M5.040 extra.pl
# ...and, if called without that -M switch,
# perl extra.pl
# will print everything until here: «;
$printed or print $string_with_strange_delimiters;
my $sanity = "eventually recovered.";

View file

@ -194,4 +194,16 @@ package Class::Class;
}
}
=head1 Perl 5.40 brings new stuff
The __CLASS__ token (only for fontification) and the :reader
method-generator for classes are available with Perl 5.40.
=cut
class With::Readers {
field $simple;
field $auto_reader :reader;
field $named_reader :reader(named);
}
1;

View file

@ -16,4 +16,8 @@
}
}
class D {
field $decorated :param :reader(get_decoration);
field $no_attributes = not_an(attribute)
}
say "done!";

View file

@ -216,6 +216,39 @@ attributes, prototypes and signatures."
'font-lock-variable-name-face)))
(goto-char end-of-sub))))))
(ert-deftest cperl-test-fontify-builtin-constants ()
"Test fontificiation of the floating point constants \"nan\" and \"inf\"."
(skip-unless (eq cperl-test-mode #'cperl-mode))
(let ((constants '("my $min=-builtin::inf;"
"my $unknown = builtin::nan;"
"if ($big == inf) {"
"my $with_ampersand = &inf")))
(dolist (code constants)
(with-temp-buffer
(insert code)
(goto-char (point-min))
(funcall cperl-test-mode)
(font-lock-ensure)
(search-forward-regexp "&?\\(builtin::\\)?\\(inf\\|nan\\)")
(should (equal (get-text-property (match-beginning 0) 'face)
'font-lock-constant-face)))))
;; Also, test some things that are not these constants
(let ((lookalikes '(("sub inf { ... }" . font-lock-function-name-face)
("my $inf = 1E6;" . font-lock-variable-name-face)
("$object->inf;" . cperl-method-call))))
(dolist (doppelganger lookalikes)
(let ((code (car doppelganger))
(face (cdr doppelganger)))
(with-temp-buffer
(insert code)
(goto-char (point-min))
(funcall cperl-test-mode)
(font-lock-ensure)
(search-forward-regexp "&?\\(builtin::\\)?\\(inf\\|nan\\)")
(should (equal (get-text-property (match-beginning 0) 'face)
face)))))))
(ert-deftest cperl-test-fontify-class ()
"Test fontification of the various elements in a Perl class."
(skip-unless (eq cperl-test-mode #'cperl-mode))
@ -241,6 +274,24 @@ attributes, prototypes and signatures."
'font-lock-variable-name-face))
(should (equal (get-text-property (match-beginning 1) 'face)
'font-lock-variable-name-face))
;; Fields
(goto-char (point-min))
(search-forward-regexp "\\(field\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
'font-lock-keyword-face))
(search-forward-regexp "\\(decorated\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
'font-lock-variable-name-face))
(search-forward-regexp "\\(:param\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
'font-lock-constant-face))
(search-forward-regexp "\\(get_decoration\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
'font-lock-string-face))
;; Initializers are no attributes
(search-forward-regexp "\\(not_an\\)")
(should-not (equal (get-text-property (match-beginning 1) 'face)
'font-lock-constant-face))
)))
(ert-deftest cperl-test-fontify-special-variables ()
@ -516,7 +567,7 @@ Also includes valid cases with whitespace in strange places."
valid invalid)))
(ert-deftest cperl-test-attribute-list-rx ()
"Test attributes and attribute lists"
"Test attributes and attribute lists."
(skip-unless (eq cperl-test-mode #'cperl-mode))
(let ((valid
'(":" ":foo" ": bar()" ":baz(quux):"
@ -533,7 +584,26 @@ Also includes valid cases with whitespace in strange places."
(cperl-test--validate-regexp (rx (eval cperl--attribute-list-rx))
valid invalid)))
(ert-deftest cperl-test-prototype-rx ()
(ert-deftest cperl-test-field-declaration-rx ()
"Test field declarations with and without attributes."
(skip-unless (eq cperl-test-mode #'cperl-mode))
(let ((valid
'("field $fold"
"field @many"
"field %ofStrawberries"
"field $required :param"
"field $renamed :param(alias)"
"field $readable : param reader(get_readable)"))
(invalid
'("field name" ; missing sigil
"field $else::where" ; invalid qualification
"field &code"))) ; invalid sigil
(cperl-test--validate-regexp (rx (eval cperl--field-declaration-rx))
valid invalid)))
(ert-deftest cperl-test-prototype-rx ()
"Test subroutine prototypes"
(skip-unless (eq cperl-test-mode #'cperl-mode))
(let ((valid
@ -562,6 +632,21 @@ Also includes valid cases with whitespace in strange places."
(cperl-test--validate-regexp (rx (eval cperl--signature-rx))
valid invalid)))
(ert-deftest cperl-test-autogenerated-reader-rx ()
(let ((code-examples '("field $name :reader;"
"field $field :reader(name);"
"field $name :param :reader;"
"field $field :param :reader(name);"
"field $field :reader(name) :param;"
"field $field :reader(name) = 'value';")))
(dolist (code code-examples)
(with-temp-buffer
(insert code)
(goto-char (point-min))
(search-forward-regexp (rx (eval cperl--sub-name-generated-rx)))
(should (string= (match-string 1) "reader"))
(should (string= (match-string 2) "name"))))))
;;; Test unicode identifier in various places
(defun cperl--test-unicode-setup (code string)
@ -604,7 +689,7 @@ point after the first occurrence of STRING (no regexp!)."
(goto-char (point-min))
(search-forward "-34")
(beginning-of-defun)
(should (looking-at "sub")))))
(should (looking-at "sub")))))
(ert-deftest cperl-test-unicode-varname ()
(with-temp-buffer
@ -827,6 +912,41 @@ perl-mode generally does not stringify bareword hash keys."
(insert word)
(should (string= word (cperl-word-at-point-hard)))))))
(ert-deftest cperl-test-extra-delimiters ()
"Test whether cperl-mode can process unicode delimiters.
The minor mode `cperl-extra-paired-delimiters-mode' controls whether we
have extra paired delimiters."
(skip-unless (eq cperl-test-mode #'cperl-mode))
(with-temp-buffer
(insert-file-contents (ert-resource-file "extra-delimiters.pl"))
(funcall cperl-test-mode)
(cperl-extra-paired-delimiters-mode t)
(font-lock-ensure)
(goto-char (point-min))
(search-forward-regexp "\\(label:\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-constant-face))
(search-forward-regexp "\\(comment\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-comment-face))
(search-forward-regexp "\\(sanity\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-variable-name-face))
;; Now switch off the minor mode and redo
(cperl-extra-paired-delimiters-mode -1)
(font-lock-ensure)
(goto-char (point-min))
(search-forward-regexp "\\(label:\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-string-face))
(search-forward-regexp "\\(comment\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-string-face))
(search-forward-regexp "\\(sanity\\)")
(should (equal (get-text-property (match-beginning 1) 'face)
font-lock-variable-name-face))))
;;; Function test: Building an index for imenu
(ert-deftest cperl-test-imenu-index ()
@ -853,7 +973,9 @@ created by CPerl mode, so skip it for Perl mode."
"Package::in_package_again"
"Erdős::Number::erdős_number"
"Class::Class::init"
"Class::Inner::init_again")))
"Class::Inner::init_again"
"With::Readers::auto_reader"
"With::Readers::named")))
(dolist (sub expected)
(should (assoc-string sub index)))))))