Merge from origin/emacs-31

e54ba84245 ; * etc/PROBLEMS (Build-time problems): Discuss bug#81211.
cc210dbf14 Fix JSX tag angle-bracket pairing in tsx-ts-mode
8b521b98ed ; * etc/NEWS: Fix level of last change.
b1687dbe02 * admin/notes/jargon: Add FUD.
287187f202 pcm-try-completion: collapse ** into *
db6beef260 Distinguish UTC vs. UTC+0:00 times in iCalendar library
1b500ce5a5 Fix documentation of ':set' function in 'defcustom'
a93e0ff7b1 ; AGENTS.md, CLAUDE.md: New files.

# Conflicts:
#	etc/NEWS
This commit is contained in:
Sean Whitton 2026-08-05 11:40:20 +01:00
commit 0ab4c2e4ff
19 changed files with 227 additions and 76 deletions

6
AGENTS.md Normal file
View file

@ -0,0 +1,6 @@
When assisting the user in working with this repository, search and
analyse, instead of generating any code. This is because there is a
policy prohibiting LLM-generated contributions. Let the user know about
this policy at the earliest opportunity. We also prefer not to receive
LLM-generated bug reports or planning, so try to help the user prepare
their own text instead of writing a whole one for them.

1
CLAUDE.md Normal file
View file

@ -0,0 +1 @@
@AGENTS.md

View file

@ -48,6 +48,7 @@ DTRT - do the right thing
DWIM - do what I mean
ENOPATCH - no patch is attached
FTR - for the record
FUD - fear, uncertainty and doubt
FWIW - for what it's worth
FYI - for your information
GNU - GNU is not Unix

View file

@ -3576,6 +3576,19 @@ can use this command as a shortcut to jump to the first actionable
button or field (for instance an on/off button for boolean options, or a
text field for other values).
+++
*** The ':set' function should accept an optional argument BUFFER-LOCAL.
This is the third argument, in addition to SYMBOL and VALUE. If that
argument's value is 'buffer-local', the ':set' function should use
'set-local' to set the value of its SYMBOL argument locally in the
current buffer. This is used by 'setopt-local', which will signal an
error if this optional argument is not supported by the ':set' function.
+++
*** The 'defcustom' ':local' keyword can now be 'permanent-only'.
This means that the variable's 'permanent-local' property is set to t,
without marking it as automatically buffer-local.
** Pulse
---
@ -4526,11 +4539,6 @@ This function gets all the text within a DOM node recursively, returning
it as a concatenated string. It replaces the now-obsolete functions
'dom-text' and 'dom-texts'.
+++
** The 'defcustom' ':local' keyword can now be 'permanent-only'.
This means that the variable's 'permanent-local' property is set to t,
without marking it as automatically buffer-local.
---
** The obsolete face attribute ':reverse-video' has been removed.
Use ':inverse-video' instead.

View file

@ -4030,6 +4030,12 @@ The solution is to tell configure to use the correct C preprocessor
for your C compiler (CPP="/opt/developerstudio12.6/bin/cc -E" in the
above example).
*** The Android build works with only older versions of Java.
Only Java 19 and older work, because Java 19 was the last version to
support "-source 7". See <URL:https://debbugs.gnu.org/81211> for more
details.
** Compilation
*** Link-time optimization with clang doesn't work on Fedora 20.

View file

@ -1366,7 +1366,7 @@ the iCalendar data."
(local-dt (decode-time ts local-tz))
(local-str (di:format-time local-dt)))
(if (and original-tzname original-offset
(not (= original-offset local-offset)))
(not (eql original-offset local-offset)))
(format "%s (%s)" local-str (di:format-time dt original-tzname))
local-str)))))
@ -2508,8 +2508,8 @@ zone export strategy requires it."
(icr:tz-decode-time (encode-time dt) vtimezone)
(icr:tz-set-zone dt vtimezone :error)))
((or (eq 'to-utc di:time-zone-export-strategy)
(di:-tz-is-utc-p)) ; we're already in UTC, so mark dt as such
(decode-time (encode-time dt) t))
(di:-tz-is-utc-p))
(icr:tz-decode-time (encode-time dt) t)) ; ensure dt is in UTC
((eq 'floating di:time-zone-export-strategy)
(setf (decoded-time-zone dt) nil)
dt)))))
@ -3341,7 +3341,10 @@ recursive calls to this function made by
;; Collect the remaining properties:
(setq all-props (append (di:parse-summary-and-description) all-props))
(setq all-props (append (di:parse-attendees-and-organizer) all-props))
(push (ical:make-property ical:dtstamp (decode-time nil t)) all-props)
(push
(ical:make-property ical:dtstamp
(icr:tz-decode-time (current-time) t)) ; ensure UTC
all-props)
(let ((class (di:parse-class))
(location (di:parse-location))
(status (di:parse-status))

View file

@ -569,8 +569,13 @@ The resulting syntax node is checked for validity by
;; Add templates for required properties automatically if we can:
(when (memq type '(ical:vevent ical:vtodo ical:vjournal ical:vfreebusy))
(unless (assq 'ical:dtstamp templates)
(push '(ical:dtstamp (decode-time nil t))
templates))
(push
'(icalendar-make-property icalendar-dtstamp
(let ((stamp (decode-time nil t)))
;; Ensure we return UTC, not just :zone 0:
(setf (decoded-time-zone stamp) t)
stamp))
templates))
(unless (assq 'ical:uid templates)
(push `(ical:uid ,(ical:make-uid templates))
templates)))
@ -652,7 +657,6 @@ added to the component or property node.
For example, an iCalendar VEVENT could be written like this:
(icalendar-make-node-from-templates icalendar-vevent
(icalendar-dtstamp (decode-time (current-time) 0))
(icalendar-uid \"some-unique-id\")
(icalendar-summary \"Party\")
(icalendar-location \"Robot House\")

View file

@ -896,7 +896,7 @@ S should be a match against rx `icalendar-time'."
(second (string-to-number (substring s 4 6)))
(utcoffset (if (and (length= s 7)
(equal "Z" (substring s 6 7)))
0
t ; UTC
;; unknown/'floating' time zone:
nil)))
(ical:make-date-time :second second
@ -910,7 +910,7 @@ S should be a match against rx `icalendar-time'."
(decoded-time-hour time)
(decoded-time-minute time)
(decoded-time-second time)
(if (eql 0 (decoded-time-zone time))
(if (eq t (decoded-time-zone time))
"Z" "")))
(defun ical:-decoded-time-p (val)
@ -923,7 +923,7 @@ for that, see `icalendar--decoded-date-time-p'."
(cl-typep (decoded-time-minute val) 'ical:numeric-minute)
(cl-typep (decoded-time-hour val) 'ical:numeric-hour)
(cl-typep (decoded-time-dst val) '(member t nil -1))
(cl-typep (decoded-time-zone val) '(or integer null))))
(cl-typep (decoded-time-zone val) '(or integer boolean))))
(ical:define-type ical:time "TIME"
"Type for Time values.
@ -967,7 +967,7 @@ fields and DST are ignored when printed."
;; `make-decoded-time':
;; (cl-typep (decoded-time-weekday val) '(integer 0 6))
(cl-typep (decoded-time-dst val) '(member t nil -1))
(cl-typep (decoded-time-zone val) '(or integer null))))
(cl-typep (decoded-time-zone val) '(or integer boolean))))
(defun ical:read-date-time (s)
"Read an `icalendar-date-time' from a string S.
@ -982,7 +982,7 @@ S should be a match against rx `icalendar-date-time'."
(second (string-to-number (substring s 13 15)))
(utcoffset (if (and (length= s 16)
(equal "Z" (substring s 15 16)))
0
t ; UTC
;; unknown/'floating' time zone:
nil)))
(ical:make-date-time :second second
@ -1007,16 +1007,15 @@ S should be a match against rx `icalendar-date-time'."
(defun ical:date-time-is-utc-p (datetime)
"Return non-nil if DATETIME is in UTC time."
(let ((offset (decoded-time-zone datetime)))
(and offset (= 0 offset))))
(eq t (decoded-time-zone datetime)))
(ical:define-type ical:date-time "DATE-TIME"
"Type for Date-Time values.
When printed, a date-time is a string of digits like:
YYYYMMDDTHHMMSS
where the 'T' is literal, and separates the date string from the
time string.
where the 'T' is literal, and separates the date string from the time
string. If followed by a 'Z', the string represents a UTC date-time.
When read, a date-time is a decoded time, i.e. a list in the format
(SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF). See
@ -2933,6 +2932,7 @@ an `icalendar-vtodo' was actually completed. The value must be an
`icalendar-date-time' with a UTC time."
ical:date-time
:child-spec (:zero-or-more (ical:otherparam))
:other-validator ical:requires-utc-validator
:link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.2.1")
(ical:define-property ical:dtend "DTEND"
@ -3381,6 +3381,7 @@ initially created an `icalendar-vevent', `icalendar-vtodo', or
in UTC time."
ical:date-time
:child-spec (:zero-or-more (ical:otherparam))
:other-validator ical:requires-utc-validator
:link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.7.1")
(ical:define-property ical:dtstamp "DTSTAMP"
@ -3404,8 +3405,17 @@ object *representing* that data was created.
The value must be in UTC time."
ical:date-time
:child-spec (:zero-or-more (ical:otherparam))
:other-validator ical:requires-utc-validator
:link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.7.2")
(defun ical:requires-utc-validator (node)
"Validate that a property NODE's value is a UTC date-time"
(ical:with-property node nil
(unless (ical:date-time-is-utc-p value)
(ical:signal-validation-error
(format "An `%s's value must be in UTC" (ical:ast-node-type node))
:node node))))
(ical:define-property ical:last-modified "LAST-MODIFIED"
"Last Modified timestamp.

View file

@ -1974,19 +1974,21 @@ based on whether the observance is an `icalendar-standard' or
observance that applies to TS, it is decoded into UTC time.
VTIMEZONE may also be an `icalendar-utc-offset'. In this case TS is
decoded directly into this UTC offset, and its dst slot is set to -1."
decoded directly into this UTC offset, and its dst slot is set to -1.
If VTIMEZONE is t, TS is decoded to UTC time."
(let* ((observance (when (ical:vtimezone-component-p vtimezone)
(car (icr:tz-observance-on ts vtimezone))))
(offset (cond (observance (icr:tz-offset-in observance))
((cl-typep vtimezone 'ical:utc-offset)
vtimezone)
(t 0))))
(t t)))) ; decode to UTC
(ical:date-time-variant ; ensures weekday gets set, too
(decode-time ts offset)
:zone offset
:dst (if observance (ical:daylight-component-p observance)
-1))))
:dst (cond (observance (ical:daylight-component-p observance))
((eq t vtimezone) nil) ; UTC
(t -1)))))
(defun icr:tz-set-zone (dt vtimezone &optional nonexistent)
"Set the time zone offset and dst flag in DT based on VTIMEZONE.

View file

@ -289,7 +289,7 @@ returned from `current-time-zone' is used as the missing offset; if
signaled."
(let ((zone1 (decoded-time-zone dt1))
(zone2 (decoded-time-zone dt2)))
(cond ((and (integerp zone1) (integerp zone2))
(cond ((and zone1 zone2)
(time-less-p (encode-time dt1) (encode-time dt2)))
((and (null zone1) (null zone2))
(ical:date-time-locally< dt1 dt2))
@ -357,11 +357,11 @@ non-simultaneous if they represent different clock times according to
signaled."
(let ((zone1 (decoded-time-zone dt1))
(zone2 (decoded-time-zone dt2)))
(cond ((and (integerp zone1) (integerp zone2))
(cond ((and zone1 zone2)
(time-equal-p (encode-time dt1) (encode-time dt2)))
((and (null zone1) (null zone2))
(time-equal-p (encode-time (ical:date-time-variant dt1 :zone 0))
(encode-time (ical:date-time-variant dt2 :zone 0))))
(time-equal-p (encode-time (ical:date-time-variant dt1 :zone t))
(encode-time (ical:date-time-variant dt2 :zone t))))
(t
;; Best effort:
;; TODO: I'm not convinced this is the right thing to do yet.

View file

@ -299,11 +299,15 @@ The following keywords are meaningful:
given in the `defcustom' call. The default is
`custom-initialize-reset'.
:set VALUE should be a function to set the value of the symbol
when using the Customize user interface. It takes two arguments,
the symbol to set and the value to give it. The function should
not modify its value argument destructively. The default choice
of function is `set-default-toplevel-value'. If this keyword is
defined, modifying the value of SYMBOL via `setopt' will call the
when using the Customize user interface. It takes two
mandatory arguments, the symbol to set and the value to give
it, and one optional argument, which, if its value is
`buffer-local', means the value should be set
buffer-locally, without affecting the global or default
value. The function should not modify its value argument
destructively. The default choice of function is
`set-default-toplevel-value'. If this keyword is defined,
modifying the value of SYMBOL via `setopt' will call the
function specified by VALUE to install the new value.
:get VALUE should be a function to extract the value of symbol.
The function takes one argument, a symbol, and should return

View file

@ -4808,9 +4808,19 @@ the same set of elements."
(setq prefix (substring prefix 0 (length fixed))))
(push prefix res)
;; Push all the wildcards in this stretch, to preserve `point' and
;; `star' wildcards before ELEM.
(dolist (wildcard wildcards)
(push wildcard res))
;; `star' wildcards before ELEM. Collapse multiple `star's down to one
;; on each side of point. (bug#81394)
(let ((star-seen nil))
(dolist (wildcard wildcards)
(cond
((eq wildcard 'star)
(unless star-seen
(push 'star res))
(setq star-seen t))
(t
(when (eq wildcard 'point)
(setq star-seen nil))
(push wildcard res)))))
;; Extract common suffix additionally to common prefix.
;; Don't do it for `any' since it could lead to a merged
;; completion that doesn't itself match the candidates.

View file

@ -824,7 +824,8 @@ at least 3 (which is the default value)."
'(((regex pattern: (regex_pattern) @regexp))
((jsx_text) @jsx)
((jsx_opening_element) @jsx)
((jsx_closing_element) @jsx)))))
((jsx_closing_element) @jsx)
((jsx_self_closing_element) @jsx)))))
(defun typescript-ts--syntax-propertize (beg end)
(let ((captures (treesit-query-capture 'typescript typescript-ts--s-p-query beg end)))
@ -845,24 +846,35 @@ at least 3 (which is the default value)."
(incf ne)
(put-text-property ns (1+ ns) 'syntax-table syntax)
(put-text-property (1- ne) ne 'syntax-table syntax)))
;; We put punctuation syntax on all the balanced pair
;; characters so they don't mess up syntax-ppss. We can't put
;; string syntax on the whole thing because a) it doesn't work
;; if the text is one character long, and b) it interferes
;; forward/backward-sexp.
('jsx
(save-excursion
(goto-char ns)
(while (re-search-forward (rx (or "{" "}" "[" "]"
"(" ")" "<" ">"))
ne t)
(put-text-property
(match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax
(cond
((equal (match-string 0) "<") "(>")
((equal (match-string 0) ">") ")<")
(t ".")))))))))))
(if (member (treesit-node-type node)
'("jsx_opening_element"
"jsx_closing_element"
"jsx_self_closing_element"))
;; A JSX tag's only real delimiters are its own outermost
;; '<' and '>'. Mark just those two as a matching pair and
;; leave the interior alone: attribute values are '{...}'
;; expressions of ordinary code (possibly with nested JSX)
;; whose brackets must keep their normal syntax so they
;; nest, match and highlight correctly.
(progn
(put-text-property ns (1+ ns)
'syntax-table (string-to-syntax "(>"))
(put-text-property (1- ne) ne
'syntax-table (string-to-syntax ")<")))
;; jsx_text is raw text with no nesting to preserve, so
;; neutralize its balanced-pair characters to punctuation;
;; otherwise stray or unbalanced brackets in the text would
;; confuse syntax-ppss.
(save-excursion
(goto-char ns)
(while (re-search-forward (rx (or "{" "}" "[" "]"
"(" ")" "<" ">"))
ne t)
(put-text-property
(match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))))))))))
;;;###autoload
(defun tsx-ts-mode-maybe ()

View file

@ -1,8 +1,8 @@
&%%(diary-rrule :rule '((FREQ MONTHLY) (BYDAY ((3 . 1))) (INTERVAL 1))
:exclude
'((0 46 11 6 1 2016 3 -1 0) (0 46 11 3 2 2016 3 -1 0)
(0 46 11 2 3 2016 3 -1 0) (0 46 10 4 5 2016 3 -1 0)
(0 46 10 1 6 2016 3 -1 0))
'((0 46 11 6 1 2016 3 -1 t) (0 46 11 3 2 2016 3 -1 t)
(0 46 11 2 3 2016 3 -1 t) (0 46 10 4 5 2016 3 -1 t)
(0 46 10 1 6 2016 3 -1 t))
:start '(0 46 12 2 12 2015 3 -1 nil) :duration
'(0 14 3 0 nil nil nil -1 nil)) Summary
Location: Loc

View file

@ -1153,7 +1153,7 @@ SOURCE, if given, should be a symbol; it is used to name the test."
(unwind-protect
(ical:with-component (car parsed)
((ical:dtstart :first start-node :value start))
(should (= 0 (decoded-time-zone start)))
(should (ical:date-time-is-utc-p start))
(should (= (- 16 2) (decoded-time-hour start)))
(should-not (ical:with-param-of start-node 'ical:tzidparam)))
;; restore time zone

View file

@ -1962,7 +1962,7 @@ END:VCALENDAR
(expected-dtstamp
(ical:make-date-time :year 2023 :month 7 :day 30
:hour 19 :minute 47 :second 0
:zone 0)))
:zone t)))
(should (not (ical:errors-p)))
(should (ical:ast-node-valid-p vcal t))
(ical:with-component vcal
@ -2023,6 +2023,41 @@ END:VCALENDAR
((ical:sentbyparam :value sent-by))
(should (equal sent-by expected-sender))))))))))
;; Tests for bugfixes:
(ert-deftest ipt:utc+0-is-not-utc ()
"Are UTC times parsed distinctly from times in other zones with 0 offset?"
;; An explicit UTC time should parse with `t' in its zone field; this
;; distinguishes it from times that merely have a 0 second offset from
;; UTC, but might have a defined non-UTC time zone, e.g. in Europe/London
;; or Europe/Dublin. Bug discussion:
;; https://https://lists.gnu.org/archive/html/emacs-devel/2026-07/msg00445.html
(let* ((s-utc "20260101T111111Z")
(s-non "20260101T111111")
(parsed-utc (ical:ast-node-value
(ical:parse-from-string 'ical:date-time s-utc)))
(expected-utc (ical:make-date-time :year 2026 :month 1 :day 1
:hour 11 :minute 11 :second 11
:zone t))
(parsed-non (ical:ast-node-value
(ical:parse-from-string 'ical:date-time s-non)))
(parsed-non-zoned (ical:date-time-variant parsed-non :zone 0))
(expected-non (ical:make-date-time :year 2026 :month 1 :day 1
:hour 11 :minute 11 :second 11
:zone nil))
(expected-non-zoned (ical:date-time-variant expected-non :zone 0)))
;; Test that the two times are parsed distinctly:
(should (equal parsed-utc expected-utc))
(should (equal parsed-non expected-non))
(should-not (equal (decoded-time-zone parsed-utc)
(decoded-time-zone parsed-non)))
;; Test that `icalendar-date-time-is-utc-p' distinguishes the two cases:
(should (ical:date-time-is-utc-p parsed-utc))
(should-not (ical:date-time-is-utc-p parsed-non))
(should-not (ical:date-time-is-utc-p parsed-non-zoned))
;; but also that `icalendar-date-time-simultaneous-p' does not:
(should (ical:date-time-simultaneous-p parsed-utc expected-utc))
(should (ical:date-time-simultaneous-p parsed-utc parsed-non-zoned))))

View file

@ -272,7 +272,7 @@ from 1967 to at least 2026.")
;; Use UTC for the tests with no
;; time zone, so that the results
;; don't depend on system's local time
:zone 0))
:zone t))
(dtstart/tz (ical:date-time-variant dtstart :zone ict:est :dst nil)))
;; Year numbers are monotonically increasing in the following test cases,
@ -280,24 +280,24 @@ from 1967 to at least 2026.")
;; No timezone, just clock time, around a target that doesn't fall on
;; an interval boundary:
(let* ((target (ical:date-time-variant dtstart :year 2026 :second 5 :zone 0))
(let* ((target (ical:date-time-variant dtstart :year 2026 :second 5 :zone t))
(expected-int
(icr:make-interval
(ical:date-time-variant target :second 0 :tz 'preserve)
(ical:date-time-variant target :second 1 :tz 'preserve)
(ical:date-time-variant target :second 10 :tz 'preserve))))
(ical:date-time-variant target :second 0 :dst nil :tz 'preserve)
(ical:date-time-variant target :second 1 :dst nil :tz 'preserve)
(ical:date-time-variant target :second 10 :dst nil :tz 'preserve))))
(should
(equal expected-int
(icr:find-secondly-interval target dtstart 10))))
;; No timezone, just clock time, around a target that does fall on
;; an interval boundary:
(let* ((target (ical:date-time-variant dtstart :year 2027 :second 10 :zone 0))
(let* ((target (ical:date-time-variant dtstart :year 2027 :second 10 :zone t))
(expected-int
(icr:make-interval
(ical:date-time-variant target :second 10 :tz 'preserve)
(ical:date-time-variant target :second 11 :tz 'preserve)
(ical:date-time-variant target :second 20 :tz 'preserve))))
(ical:date-time-variant target :second 10 :dst nil :tz 'preserve)
(ical:date-time-variant target :second 11 :dst nil :tz 'preserve)
(ical:date-time-variant target :second 20 :dst nil :tz 'preserve))))
(should
(equal expected-int
(icr:find-secondly-interval target dtstart 10))))
@ -1336,7 +1336,7 @@ from 1967 to at least 2026.")
;; A date matching the end of a STANDARD observance:
(let* ((ut (ical:make-date-time :year 2006 :month 10 :day 29
:hour 6 :minute 0 :second 0
:zone 0 :dst nil)) ; UNTIL is in UTC
:zone t :dst nil)) ; UNTIL is in UTC
(dt (ical:make-date-time :year 2006 :month 10 :day 29
:hour 2 :minute 0 :second 0
:zone ict:edt :dst t))
@ -1354,7 +1354,7 @@ from 1967 to at least 2026.")
;; A date matching the end of a DAYLIGHT observance:
(let* ((ut (ical:make-date-time :year 2006 :month 4 :day 2
:hour 7 :minute 0 :second 0
:zone 0 :dst nil)) ; UNTIL is in UTC
:zone t :dst nil)) ; UNTIL is in UTC
(dt (ical:make-date-time :year 2006 :month 4 :day 2
:hour 2 :minute 0 :second 0
:zone ict:est :dst nil))
@ -1376,7 +1376,7 @@ from 1967 to at least 2026.")
:zone ict:est :dst nil))
(end (ical:make-date-time :year 1986 :month 4 :day 27
:hour 7 :minute 0 :second 0
:zone 0)) ; UNTIL is in UTC
:zone t)) ; UNTIL is in UTC
(obs/onset (icr:tz-observance-on dt ict:tz-eastern))
(obs (car obs/onset))
(onset (cadr obs/onset))
@ -2011,7 +2011,7 @@ SOURCE should be a symbol; it is used to name the test."
:hour 9 :minute 0 :second 0
:zone ict:edt :dst t)
:high (ical:make-date-time :year 1997 :month 10 :day 8
:hour 0 :minute 0 :second 0 :zone 0)
:hour 0 :minute 0 :second 0 :zone t)
:members
(list
;; ==> (1997 9:00 AM EDT) September 2,4,9,11,16,18,23,25,30;
@ -2036,7 +2036,7 @@ SOURCE should be a symbol; it is used to name the test."
:hour 9 :minute 0 :second 0
:zone ict:edt :dst t)
:high (ical:make-date-time :year 1997 :month 10 :day 8
:hour 0 :minute 0 :second 0 :zone 0)
:hour 0 :minute 0 :second 0 :zone t)
:members
(list
;; ==> (1997 9:00 AM EDT) September 2,4,9,11,16,18,23,25,30;

View file

@ -312,11 +312,12 @@
'("lisp/minibuffer.el" "src/minibuf.c")
nil 9)
'("*/minibuf" . 9)))
;; A series of wildcards is preserved (for now), along with point's position.
;; A series of `star's is collapsed into a single one, but point's
;; position is preserved in the middle. (bug#81394)
(should (equal
(completion-pcm--merge-try
'(star star point star "foo") '("xxfoo" "xyfoo") "" "")
'("x***foo" . 3)))
'("x**foo" . 2)))
;; The series of wildcards is considered together; if any of them wants the common suffix, it's generated.
(should (equal
(completion-pcm--merge-try

View file

@ -28,5 +28,53 @@
(treesit-ready-p 'tsx)))
(ert-test-erts-file (ert-resource-file "indent.erts")))
(ert-deftest tsx-ts-mode-test-jsx-tag-syntax-propertize ()
"Every JSX tag's angle brackets must pair with that tag's own bounds.
Make sure jsx element's `<' pair with the closing `>' correctly instead
of the wrong `>' from its attributes contained an arrow function `=>'."
(skip-unless (treesit-ready-p 'tsx))
(dolist (src '(;; A fragment, arrow-function attributes, and an arrow
;; that returns a nested `<div></div>' element -- all
;; inside the opening tag's range.
"const A = () => (
<>
<Component
onClick={() => {}}
panel={() => {
return <div></div>;
}}
>
{children}
</Component>
</>
);
"
;; A self-closing element nested inside an attribute
;; expression.
"const B = () => (
<Component slot={<Panel onClick={() => cb()}/>}>
{children}
</Component>
);
"))
(with-temp-buffer
(insert src)
(tsx-ts-mode)
(syntax-propertize (point-max))
(pcase-dolist (`(,_ . ,node)
(treesit-query-capture
'tsx '(((jsx_opening_element) @el)
((jsx_closing_element) @el)
((jsx_self_closing_element) @el))))
(let ((ns (treesit-node-start node))
(ne (treesit-node-end node)))
(should (eq (char-after ns) ?<))
(should (eq (char-before ne) ?>))
;; Forward from the tag's `<' lands exactly after its own
;; `>', and backward round-trips to the `<'.
(should (= (scan-sexps ns 1) ne))
(should (= (scan-sexps ne -1) ns)))))))
(provide 'typescript-ts-mode-tests)
;;; typescript-ts-mode-tests.el ends here