mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-04 03:13:24 +00:00
Merge from origin/emacs-29
3204825f56
Fix mangled Subject header field when forwarding (Bug#67360)7591acfe38
Update to Org 9.6.15240b4594f1
; * etc/TODO: Add an item about 'Info-hide-note-references'.01be4fe39d
* doc/emacs/custom.texi (Modifier Keys): Fix markup (bug#...55555a6a0d
org-protocol: Minor copy-edits to Commentary4696869d3d
Improve syntax highlighting for python-ts-mode
This commit is contained in:
commit
083e90dd80
13 changed files with 536 additions and 93 deletions
|
@ -2065,7 +2065,7 @@ C-a} is a way to enter @kbd{Hyper-Control-a}. (Unfortunately, there
|
||||||
is no way to add two modifiers by using @kbd{C-x @@} twice for the
|
is no way to add two modifiers by using @kbd{C-x @@} twice for the
|
||||||
same character, because the first one goes to work on the @kbd{C-x}.)
|
same character, because the first one goes to work on the @kbd{C-x}.)
|
||||||
You can similarly enter the Shift, Control, and Meta modifiers by
|
You can similarly enter the Shift, Control, and Meta modifiers by
|
||||||
using @kbd{C-x @ S}, @kbd{C-x @ c}, and @kbd{C-x @ m}, respectively,
|
using @kbd{C-x @@ S}, @kbd{C-x @@ c}, and @kbd{C-x @@ m}, respectively,
|
||||||
although this is rarely needed.
|
although this is rarely needed.
|
||||||
|
|
||||||
@node Function Keys
|
@node Function Keys
|
||||||
|
|
|
@ -4606,7 +4606,7 @@ checked.
|
||||||
#+cindex: statistics, for checkboxes
|
#+cindex: statistics, for checkboxes
|
||||||
#+cindex: checkbox statistics
|
#+cindex: checkbox statistics
|
||||||
#+cindex: @samp{COOKIE_DATA}, property
|
#+cindex: @samp{COOKIE_DATA}, property
|
||||||
#+vindex: org-hierarchical-checkbox-statistics
|
#+vindex: org-checkbox-hierarchical-statistics
|
||||||
The =[2/4]= and =[1/3]= in the first and second line are cookies
|
The =[2/4]= and =[1/3]= in the first and second line are cookies
|
||||||
indicating how many checkboxes present in this entry have been checked
|
indicating how many checkboxes present in this entry have been checked
|
||||||
off, and the total number of checkboxes present. This can give you an
|
off, and the total number of checkboxes present. This can give you an
|
||||||
|
@ -4614,7 +4614,7 @@ idea on how many checkboxes remain, even without opening a folded
|
||||||
entry. The cookies can be placed into a headline or into (the first
|
entry. The cookies can be placed into a headline or into (the first
|
||||||
line of) a plain list item. Each cookie covers checkboxes of direct
|
line of) a plain list item. Each cookie covers checkboxes of direct
|
||||||
children structurally below the headline/item on which the cookie
|
children structurally below the headline/item on which the cookie
|
||||||
appears[fn:: Set the variable ~org-hierarchical-checkbox-statistics~
|
appears[fn:: Set the variable ~org-checkbox-hierarchical-statistics~
|
||||||
if you want such cookies to count all checkboxes below the cookie, not
|
if you want such cookies to count all checkboxes below the cookie, not
|
||||||
just those belonging to direct children.]. You have to insert the
|
just those belonging to direct children.]. You have to insert the
|
||||||
cookie yourself by typing either =[/]= or =[%]=. With =[/]= you get
|
cookie yourself by typing either =[/]= or =[%]=. With =[/]= you get
|
||||||
|
|
14
etc/TODO
14
etc/TODO
|
@ -133,6 +133,20 @@ This should use a heuristic of some kind?
|
||||||
** In Emacs Info, examples of using Customize should be clickable
|
** In Emacs Info, examples of using Customize should be clickable
|
||||||
They should create Custom buffers when clicked.
|
They should create Custom buffers when clicked.
|
||||||
|
|
||||||
|
** Replacements under 'Info-hide-note-references' should be language-sensitive
|
||||||
|
Currently, we replace the "*note" cross-reference indicators with a
|
||||||
|
hard-coded "see", which is English-centric and doesn't look well in
|
||||||
|
manuals written in languages other than English. To fix this, we need
|
||||||
|
a change in the Texinfo's 'makeinfo' program so that it records the
|
||||||
|
document's language (specified via the @documentlanguage directive in
|
||||||
|
Texinfo) in a variable in the Local Variables section of the produced
|
||||||
|
Info file. Then 'Info-fontify-node' should be modified to look up the
|
||||||
|
translation of "see" to that language in a database (which should be
|
||||||
|
added), and should use that translation instead of "see". See this
|
||||||
|
discussion on the Texinfo mailing list for more details:
|
||||||
|
|
||||||
|
https://lists.gnu.org/archive/html/help-texinfo/2023-12/msg00011.html
|
||||||
|
|
||||||
** Add function to redraw the tool bar
|
** Add function to redraw the tool bar
|
||||||
|
|
||||||
** Redesign the load-history data structure
|
** Redesign the load-history data structure
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
% Reference Card for Org Mode
|
% Reference Card for Org Mode
|
||||||
\def\orgversionnumber{9.6.13}
|
\def\orgversionnumber{9.6.15}
|
||||||
\def\versionyear{2023} % latest update
|
\def\versionyear{2023} % latest update
|
||||||
\input emacsver.tex
|
\input emacsver.tex
|
||||||
|
|
||||||
|
|
|
@ -574,7 +574,7 @@ See also `mh-compose-forward-as-mime-flag',
|
||||||
(setq orig-subject (mh-get-header-field "Subject:")))
|
(setq orig-subject (mh-get-header-field "Subject:")))
|
||||||
(let ((forw-subject
|
(let ((forw-subject
|
||||||
(mh-forwarded-letter-subject orig-from orig-subject)))
|
(mh-forwarded-letter-subject orig-from orig-subject)))
|
||||||
(mh-insert-fields "Subject:" forw-subject)
|
(mh-modify-header-field "Subject" forw-subject t)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
;; Set the local value of mh-mail-header-separator according to what is
|
;; Set the local value of mh-mail-header-separator according to what is
|
||||||
;; present in the buffer...
|
;; present in the buffer...
|
||||||
|
|
|
@ -41,14 +41,19 @@
|
||||||
|
|
||||||
(defun org-entities--user-safe-p (v)
|
(defun org-entities--user-safe-p (v)
|
||||||
"Non-nil if V is a safe value for `org-entities-user'."
|
"Non-nil if V is a safe value for `org-entities-user'."
|
||||||
(pcase v
|
(cond
|
||||||
(`nil t)
|
((not v) t)
|
||||||
(`(,(and (pred stringp)
|
((listp v)
|
||||||
(pred (string-match-p "\\`[a-zA-Z][a-zA-Z0-9]*\\'")))
|
(seq-every-p
|
||||||
,(pred stringp) ,(pred booleanp) ,(pred stringp)
|
(lambda (e)
|
||||||
,(pred stringp) ,(pred stringp) ,(pred stringp))
|
(pcase e
|
||||||
t)
|
(`(,(and (pred stringp)
|
||||||
(_ nil)))
|
(pred (string-match-p "\\`[a-zA-Z][a-zA-Z0-9]*\\'")))
|
||||||
|
,(pred stringp) ,(pred booleanp) ,(pred stringp)
|
||||||
|
,(pred stringp) ,(pred stringp) ,(pred stringp))
|
||||||
|
t)
|
||||||
|
(_ nil)))
|
||||||
|
v))))
|
||||||
|
|
||||||
(defcustom org-entities-user nil
|
(defcustom org-entities-user nil
|
||||||
"User-defined entities used in Org to produce special characters.
|
"User-defined entities used in Org to produce special characters.
|
||||||
|
|
|
@ -56,8 +56,8 @@ by `package-activate-all').")
|
||||||
;; `org-assert-version' calls would fail using strict
|
;; `org-assert-version' calls would fail using strict
|
||||||
;; `org-git-version' check because the generated Org version strings
|
;; `org-git-version' check because the generated Org version strings
|
||||||
;; will not match.
|
;; will not match.
|
||||||
`(unless (or org--inhibit-version-check (equal (org-release) ,(org-release)))
|
`(unless (or ,org--inhibit-version-check (equal (org-release) ,(org-release)))
|
||||||
(warn "Org version mismatch. Org loading aborted.
|
(warn "Org version mismatch.
|
||||||
This warning usually appears when a built-in Org version is loaded
|
This warning usually appears when a built-in Org version is loaded
|
||||||
prior to the more recent Org version.
|
prior to the more recent Org version.
|
||||||
|
|
||||||
|
@ -91,10 +91,15 @@ Version mismatch is commonly encountered in the following situations:
|
||||||
early in the config. Ideally, right after the straight.el
|
early in the config. Ideally, right after the straight.el
|
||||||
bootstrap. Moving `use-package' :straight declaration may not be
|
bootstrap. Moving `use-package' :straight declaration may not be
|
||||||
sufficient if the corresponding `use-package' statement is
|
sufficient if the corresponding `use-package' statement is
|
||||||
deferring the loading."
|
deferring the loading.
|
||||||
|
|
||||||
|
4. A new Org version is synchronized with Emacs git repository and
|
||||||
|
stale .elc files are still left from the previous build.
|
||||||
|
|
||||||
|
It is recommended to remove .elc files from lisp/org directory and
|
||||||
|
re-compile."
|
||||||
;; Avoid `warn' replacing "'" with "’" (see `format-message').
|
;; Avoid `warn' replacing "'" with "’" (see `format-message').
|
||||||
"(straight-use-package 'org)")
|
"(straight-use-package 'org)")))
|
||||||
(error "Org version mismatch. Make sure that correct `load-path' is set early in init.el")))
|
|
||||||
|
|
||||||
;; We rely on org-macs when generating Org version. Checking Org
|
;; We rely on org-macs when generating Org version. Checking Org
|
||||||
;; version here will interfere with Org build process.
|
;; version here will interfere with Org build process.
|
||||||
|
|
|
@ -34,7 +34,10 @@
|
||||||
;; `org-protocol-protocol-alist' and `org-protocol-protocol-alist-default'.
|
;; `org-protocol-protocol-alist' and `org-protocol-protocol-alist-default'.
|
||||||
;;
|
;;
|
||||||
;; Any application that supports calling external programs with an URL
|
;; Any application that supports calling external programs with an URL
|
||||||
;; as argument may be used with this functionality.
|
;; as argument could use this functionality. For example, you can
|
||||||
|
;; configure bookmarks in your web browser to send a link to the
|
||||||
|
;; current page to Org and create a note from it using `org-capture'.
|
||||||
|
;; See Info node `(org) Protocols' for more information.
|
||||||
;;
|
;;
|
||||||
;;
|
;;
|
||||||
;; Usage:
|
;; Usage:
|
||||||
|
@ -44,13 +47,13 @@
|
||||||
;;
|
;;
|
||||||
;; (require 'org-protocol)
|
;; (require 'org-protocol)
|
||||||
;;
|
;;
|
||||||
;; 3.) Ensure emacs-server is up and running.
|
;; 2.) Ensure emacs-server is up and running.
|
||||||
;; 4.) Try this from the command line (adjust the URL as needed):
|
;; 3.) Try this from the command line (adjust the URL as needed):
|
||||||
;;
|
;;
|
||||||
;; $ emacsclient \
|
;; $ emacsclient \
|
||||||
;; "org-protocol://store-link?url=http:%2F%2Flocalhost%2Findex.html&title=The%20title"
|
;; "org-protocol://store-link?url=http:%2F%2Flocalhost%2Findex.html&title=The%20title"
|
||||||
;;
|
;;
|
||||||
;; 5.) Optionally add custom sub-protocols and handlers:
|
;; 4.) Optionally, add custom sub-protocols and handlers:
|
||||||
;;
|
;;
|
||||||
;; (setq org-protocol-protocol-alist
|
;; (setq org-protocol-protocol-alist
|
||||||
;; '(("my-protocol"
|
;; '(("my-protocol"
|
||||||
|
@ -64,10 +67,11 @@
|
||||||
;; If it works, you can now setup other applications for using this feature.
|
;; If it works, you can now setup other applications for using this feature.
|
||||||
;;
|
;;
|
||||||
;;
|
;;
|
||||||
;; As of March 2009 Firefox users follow the steps documented on
|
;; Firefox users follow the steps documented on
|
||||||
;; https://kb.mozillazine.org/Register_protocol, Opera setup is described here:
|
;; https://kb.mozillazine.org/Register_protocol, Opera setup is
|
||||||
;; http://www.opera.com/support/kb/view/535/
|
;; described here: http://www.opera.com/support/kb/view/535/
|
||||||
;;
|
;;
|
||||||
|
;; See also: https://orgmode.org/worg/org-contrib/org-protocol.html
|
||||||
;;
|
;;
|
||||||
;; Documentation
|
;; Documentation
|
||||||
;; -------------
|
;; -------------
|
||||||
|
@ -123,9 +127,6 @@
|
||||||
;; Note that using double slashes is optional from org-protocol.el's point of
|
;; Note that using double slashes is optional from org-protocol.el's point of
|
||||||
;; view because emacsclient squashes the slashes to one.
|
;; view because emacsclient squashes the slashes to one.
|
||||||
;;
|
;;
|
||||||
;;
|
|
||||||
;; provides: 'org-protocol
|
|
||||||
;;
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'org-macs)
|
(require 'org-macs)
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
(defun org-release ()
|
(defun org-release ()
|
||||||
"The release version of Org.
|
"The release version of Org.
|
||||||
Inserted by installing Org mode or when a release is made."
|
Inserted by installing Org mode or when a release is made."
|
||||||
(let ((org-release "9.6.13"))
|
(let ((org-release "9.6.15"))
|
||||||
org-release))
|
org-release))
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-git-version ()
|
(defun org-git-version ()
|
||||||
"The Git version of Org mode.
|
"The Git version of Org mode.
|
||||||
Inserted by installing Org or when a release is made."
|
Inserted by installing Org or when a release is made."
|
||||||
(let ((org-git-version "release_9.6.13"))
|
(let ((org-git-version "release_9.6.15"))
|
||||||
org-git-version))
|
org-git-version))
|
||||||
|
|
||||||
(provide 'org-version)
|
(provide 'org-version)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
;; URL: https://orgmode.org
|
;; URL: https://orgmode.org
|
||||||
;; Package-Requires: ((emacs "26.1"))
|
;; Package-Requires: ((emacs "26.1"))
|
||||||
|
|
||||||
;; Version: 9.6.13
|
;; Version: 9.6.15
|
||||||
|
|
||||||
;; This file is part of GNU Emacs.
|
;; This file is part of GNU Emacs.
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -305,7 +305,7 @@ INFO is a plist used as a communication channel."
|
||||||
(section-title (org-html--translate "Footnotes" info)))
|
(section-title (org-html--translate "Footnotes" info)))
|
||||||
(when fn-alist
|
(when fn-alist
|
||||||
(format (plist-get info :md-footnotes-section)
|
(format (plist-get info :md-footnotes-section)
|
||||||
(org-md--headline-title headline-style 1 section-title)
|
(org-md--headline-title headline-style (plist-get info :md-toplevel-hlevel) section-title)
|
||||||
(mapconcat (lambda (fn) (org-md--footnote-formatted fn info))
|
(mapconcat (lambda (fn) (org-md--footnote-formatted fn info))
|
||||||
fn-alist
|
fn-alist
|
||||||
"\n")))))
|
"\n")))))
|
||||||
|
|
|
@ -979,19 +979,30 @@ It makes underscores and dots word constituent chars.")
|
||||||
"raise" "return" "try" "while" "with" "yield"
|
"raise" "return" "try" "while" "with" "yield"
|
||||||
;; These are technically operators, but we fontify them as
|
;; These are technically operators, but we fontify them as
|
||||||
;; keywords.
|
;; keywords.
|
||||||
"and" "in" "is" "not" "or" "not in"))
|
"and" "in" "is" "not" "or" "not in" "is not"))
|
||||||
|
|
||||||
|
(defvar python--treesit-builtin-types
|
||||||
|
'("int" "float" "complex" "bool" "list" "tuple" "range" "str"
|
||||||
|
"bytes" "bytearray" "memoryview" "set" "frozenset" "dict"))
|
||||||
|
|
||||||
|
(defvar python--treesit-type-regex
|
||||||
|
(rx-to-string `(seq bol (or
|
||||||
|
,@python--treesit-builtin-types
|
||||||
|
(seq (? "_") (any "A-Z") (+ (any "a-zA-Z_0-9"))))
|
||||||
|
eol)))
|
||||||
|
|
||||||
(defvar python--treesit-builtins
|
(defvar python--treesit-builtins
|
||||||
'("abs" "all" "any" "ascii" "bin" "bool" "breakpoint" "bytearray"
|
(append python--treesit-builtin-types
|
||||||
"bytes" "callable" "chr" "classmethod" "compile" "complex"
|
'("abs" "all" "any" "ascii" "bin" "breakpoint"
|
||||||
"delattr" "dict" "dir" "divmod" "enumerate" "eval" "exec"
|
"callable" "chr" "classmethod" "compile"
|
||||||
"filter" "float" "format" "frozenset" "getattr" "globals"
|
"delattr" "dir" "divmod" "enumerate" "eval" "exec"
|
||||||
"hasattr" "hash" "help" "hex" "id" "input" "int" "isinstance"
|
"filter" "format" "getattr" "globals"
|
||||||
"issubclass" "iter" "len" "list" "locals" "map" "max"
|
"hasattr" "hash" "help" "hex" "id" "input" "isinstance"
|
||||||
"memoryview" "min" "next" "object" "oct" "open" "ord" "pow"
|
"issubclass" "iter" "len" "locals" "map" "max"
|
||||||
"print" "property" "range" "repr" "reversed" "round" "set"
|
"min" "next" "object" "oct" "open" "ord" "pow"
|
||||||
"setattr" "slice" "sorted" "staticmethod" "str" "sum" "super"
|
"print" "property" "repr" "reversed" "round"
|
||||||
"tuple" "type" "vars" "zip" "__import__"))
|
"setattr" "slice" "sorted" "staticmethod" "sum" "super"
|
||||||
|
"type" "vars" "zip" "__import__")))
|
||||||
|
|
||||||
(defvar python--treesit-constants
|
(defvar python--treesit-constants
|
||||||
'("Ellipsis" "False" "None" "NotImplemented" "True" "__debug__"
|
'("Ellipsis" "False" "None" "NotImplemented" "True" "__debug__"
|
||||||
|
@ -1042,9 +1053,7 @@ NODE is the string node. Do not fontify the initial f for
|
||||||
f-strings. OVERRIDE is the override flag described in
|
f-strings. OVERRIDE is the override flag described in
|
||||||
`treesit-font-lock-rules'. START and END mark the region to be
|
`treesit-font-lock-rules'. START and END mark the region to be
|
||||||
fontified."
|
fontified."
|
||||||
(let* ((string-beg (treesit-node-start node))
|
(let* ((maybe-expression (treesit-node-parent node))
|
||||||
(string-end (treesit-node-end node))
|
|
||||||
(maybe-expression (treesit-node-parent node))
|
|
||||||
(grandparent (treesit-node-parent
|
(grandparent (treesit-node-parent
|
||||||
(treesit-node-parent
|
(treesit-node-parent
|
||||||
maybe-expression)))
|
maybe-expression)))
|
||||||
|
@ -1072,28 +1081,92 @@ fontified."
|
||||||
(equal (treesit-node-type maybe-expression)
|
(equal (treesit-node-type maybe-expression)
|
||||||
"expression_statement"))
|
"expression_statement"))
|
||||||
'font-lock-doc-face
|
'font-lock-doc-face
|
||||||
'font-lock-string-face)))
|
'font-lock-string-face))
|
||||||
;; Don't highlight string prefixes like f/r/b.
|
|
||||||
(save-excursion
|
|
||||||
(goto-char string-beg)
|
|
||||||
(when (re-search-forward "[\"']" string-end t)
|
|
||||||
(setq string-beg (match-beginning 0))))
|
|
||||||
(treesit-fontify-with-override
|
|
||||||
string-beg string-end face override start end)))
|
|
||||||
|
|
||||||
(defun python--treesit-fontify-string-interpolation
|
(ignore-interpolation (not
|
||||||
(node _ start end &rest _)
|
(seq-some
|
||||||
"Fontify string interpolation.
|
(lambda (feats) (memq 'string-interpolation feats))
|
||||||
NODE is the string node. Do not fontify the initial f for
|
(seq-take treesit-font-lock-feature-list treesit-font-lock-level))))
|
||||||
f-strings. START and END mark the region to be
|
;; If interpolation is enabled, highlight only
|
||||||
|
;; string_start/string_content/string_end children. Do not
|
||||||
|
;; touch interpolation node that can occur inside of the
|
||||||
|
;; string.
|
||||||
|
(string-nodes (if ignore-interpolation
|
||||||
|
(list node)
|
||||||
|
(treesit-filter-child
|
||||||
|
node
|
||||||
|
(lambda (ch) (member (treesit-node-type ch)
|
||||||
|
'("string_start"
|
||||||
|
"string_content"
|
||||||
|
"string_end")))
|
||||||
|
t))))
|
||||||
|
|
||||||
|
(dolist (string-node string-nodes)
|
||||||
|
(let ((string-beg (treesit-node-start string-node))
|
||||||
|
(string-end (treesit-node-end string-node)))
|
||||||
|
(when (or ignore-interpolation
|
||||||
|
(equal (treesit-node-type string-node) "string_start"))
|
||||||
|
;; Don't highlight string prefixes like f/r/b.
|
||||||
|
(save-excursion
|
||||||
|
(goto-char string-beg)
|
||||||
|
(when (re-search-forward "[\"']" string-end t)
|
||||||
|
(setq string-beg (match-beginning 0)))))
|
||||||
|
|
||||||
|
(treesit-fontify-with-override
|
||||||
|
string-beg string-end face override start end)))))
|
||||||
|
|
||||||
|
(defun python--treesit-fontify-union-types (node override start end &optional type-regex &rest _)
|
||||||
|
"Fontify nested union types in the type hints.
|
||||||
|
For examlpe, Lvl1 | Lvl2[Lvl3[Lvl4[Lvl5 | None]], Lvl2]. This
|
||||||
|
structure is represented via nesting binary_operator and
|
||||||
|
subscript nodes. This function iterates over all levels and
|
||||||
|
highlight identifier nodes. If TYPE-REGEX is not nil fontify type
|
||||||
|
identifier only if it matches against TYPE-REGEX. NODE is the
|
||||||
|
binary_operator node. OVERRIDE is the override flag described in
|
||||||
|
`treesit-font-lock-rules'. START and END mark the region to be
|
||||||
fontified."
|
fontified."
|
||||||
;; This is kind of a hack, it basically removes the face applied by
|
(dolist (child (treesit-node-children node t))
|
||||||
;; the string feature, so that following features can apply their
|
(let (font-node)
|
||||||
;; face.
|
(pcase (treesit-node-type child)
|
||||||
(let ((n-start (treesit-node-start node))
|
((or "identifier" "none")
|
||||||
(n-end (treesit-node-end node)))
|
(setq font-node child))
|
||||||
(remove-text-properties
|
("attribute"
|
||||||
(max start n-start) (min end n-end) '(face))))
|
(when-let ((type-node (treesit-node-child-by-field-name child "attribute")))
|
||||||
|
(setq font-node type-node)))
|
||||||
|
((or "binary_operator" "subscript")
|
||||||
|
(python--treesit-fontify-union-types child override start end type-regex)))
|
||||||
|
|
||||||
|
(when (and font-node
|
||||||
|
(or (null type-regex)
|
||||||
|
(let ((case-fold-search nil))
|
||||||
|
(string-match-p type-regex (treesit-node-text font-node)))))
|
||||||
|
(treesit-fontify-with-override
|
||||||
|
(treesit-node-start font-node) (treesit-node-end font-node)
|
||||||
|
'font-lock-type-face override start end)))))
|
||||||
|
|
||||||
|
(defun python--treesit-fontify-union-types-strict (node override start end &rest _)
|
||||||
|
"Fontify nested union types.
|
||||||
|
Same as `python--treesit-fontify-union-types' but type identifier
|
||||||
|
should match against `python--treesit-type-regex'. For NODE,
|
||||||
|
OVERRIDE, START and END description see
|
||||||
|
`python--treesit-fontify-union-types'."
|
||||||
|
(python--treesit-fontify-union-types node override start end python--treesit-type-regex))
|
||||||
|
|
||||||
|
(defun python--treesit-fontify-dotted-decorator (node override start end &rest _)
|
||||||
|
"Fontify dotted decorators.
|
||||||
|
For example @pytes.mark.skip. Iterate over all nested attribute
|
||||||
|
nodes and highlight identifier nodes. NODE is the first attribute
|
||||||
|
node. OVERRIDE is the override flag described in
|
||||||
|
`treesit-font-lock-rules'. START and END mark the region to be
|
||||||
|
fontified."
|
||||||
|
(dolist (child (treesit-node-children node t))
|
||||||
|
(pcase (treesit-node-type child)
|
||||||
|
("identifier"
|
||||||
|
(treesit-fontify-with-override
|
||||||
|
(treesit-node-start child) (treesit-node-end child)
|
||||||
|
'font-lock-type-face override start end))
|
||||||
|
("attribute"
|
||||||
|
(python--treesit-fontify-dotted-decorator child override start end)))))
|
||||||
|
|
||||||
(defvar python--treesit-settings
|
(defvar python--treesit-settings
|
||||||
(treesit-font-lock-rules
|
(treesit-font-lock-rules
|
||||||
|
@ -1103,14 +1176,9 @@ fontified."
|
||||||
|
|
||||||
:feature 'string
|
:feature 'string
|
||||||
:language 'python
|
:language 'python
|
||||||
'((string) @python--treesit-fontify-string)
|
'((string) @python--treesit-fontify-string
|
||||||
|
(interpolation ["{" "}"] @font-lock-misc-punctuation-face))
|
||||||
|
|
||||||
;; HACK: This feature must come after the string feature and before
|
|
||||||
;; other features. Maybe we should make string-interpolation an
|
|
||||||
;; option rather than a feature.
|
|
||||||
:feature 'string-interpolation
|
|
||||||
:language 'python
|
|
||||||
'((interpolation) @python--treesit-fontify-string-interpolation)
|
|
||||||
|
|
||||||
:feature 'keyword
|
:feature 'keyword
|
||||||
:language 'python
|
:language 'python
|
||||||
|
@ -1127,12 +1195,6 @@ fontified."
|
||||||
(parameters (identifier) @font-lock-variable-name-face)
|
(parameters (identifier) @font-lock-variable-name-face)
|
||||||
(parameters (default_parameter name: (identifier) @font-lock-variable-name-face)))
|
(parameters (default_parameter name: (identifier) @font-lock-variable-name-face)))
|
||||||
|
|
||||||
:feature 'function
|
|
||||||
:language 'python
|
|
||||||
'((call function: (identifier) @font-lock-function-call-face)
|
|
||||||
(call function: (attribute
|
|
||||||
attribute: (identifier) @font-lock-function-call-face)))
|
|
||||||
|
|
||||||
:feature 'builtin
|
:feature 'builtin
|
||||||
:language 'python
|
:language 'python
|
||||||
`(((identifier) @font-lock-builtin-face
|
`(((identifier) @font-lock-builtin-face
|
||||||
|
@ -1143,6 +1205,19 @@ fontified."
|
||||||
eol))
|
eol))
|
||||||
@font-lock-builtin-face)))
|
@font-lock-builtin-face)))
|
||||||
|
|
||||||
|
:feature 'decorator
|
||||||
|
:language 'python
|
||||||
|
'((decorator "@" @font-lock-type-face)
|
||||||
|
(decorator (call function: (identifier) @font-lock-type-face))
|
||||||
|
(decorator (identifier) @font-lock-type-face)
|
||||||
|
(decorator [(attribute) (call (attribute))] @python--treesit-fontify-dotted-decorator))
|
||||||
|
|
||||||
|
:feature 'function
|
||||||
|
:language 'python
|
||||||
|
'((call function: (identifier) @font-lock-function-call-face)
|
||||||
|
(call function: (attribute
|
||||||
|
attribute: (identifier) @font-lock-function-call-face)))
|
||||||
|
|
||||||
:feature 'constant
|
:feature 'constant
|
||||||
:language 'python
|
:language 'python
|
||||||
'([(true) (false) (none)] @font-lock-constant-face)
|
'([(true) (false) (none)] @font-lock-constant-face)
|
||||||
|
@ -1154,30 +1229,71 @@ fontified."
|
||||||
@font-lock-variable-name-face)
|
@font-lock-variable-name-face)
|
||||||
(assignment left: (attribute
|
(assignment left: (attribute
|
||||||
attribute: (identifier)
|
attribute: (identifier)
|
||||||
@font-lock-property-use-face))
|
@font-lock-variable-name-face))
|
||||||
(pattern_list (identifier)
|
(augmented_assignment left: (identifier)
|
||||||
|
@font-lock-variable-name-face)
|
||||||
|
(named_expression name: (identifier)
|
||||||
|
@font-lock-variable-name-face)
|
||||||
|
(pattern_list [(identifier)
|
||||||
|
(list_splat_pattern (identifier))]
|
||||||
@font-lock-variable-name-face)
|
@font-lock-variable-name-face)
|
||||||
(tuple_pattern (identifier)
|
(tuple_pattern [(identifier)
|
||||||
|
(list_splat_pattern (identifier))]
|
||||||
@font-lock-variable-name-face)
|
@font-lock-variable-name-face)
|
||||||
(list_pattern (identifier)
|
(list_pattern [(identifier)
|
||||||
@font-lock-variable-name-face)
|
(list_splat_pattern (identifier))]
|
||||||
(list_splat_pattern (identifier)
|
@font-lock-variable-name-face))
|
||||||
@font-lock-variable-name-face))
|
|
||||||
|
|
||||||
:feature 'decorator
|
|
||||||
:language 'python
|
|
||||||
'((decorator "@" @font-lock-type-face)
|
|
||||||
(decorator (call function: (identifier) @font-lock-type-face))
|
|
||||||
(decorator (identifier) @font-lock-type-face))
|
|
||||||
|
|
||||||
:feature 'type
|
:feature 'type
|
||||||
:language 'python
|
:language 'python
|
||||||
|
;; Override built-in faces when dict/list are used for type hints.
|
||||||
|
:override t
|
||||||
`(((identifier) @font-lock-type-face
|
`(((identifier) @font-lock-type-face
|
||||||
(:match ,(rx-to-string
|
(:match ,(rx-to-string
|
||||||
`(seq bol (or ,@python--treesit-exceptions)
|
`(seq bol (or ,@python--treesit-exceptions)
|
||||||
eol))
|
eol))
|
||||||
@font-lock-type-face))
|
@font-lock-type-face))
|
||||||
(type (identifier) @font-lock-type-face))
|
(type [(identifier) (none)] @font-lock-type-face)
|
||||||
|
(type (attribute attribute: (identifier) @font-lock-type-face))
|
||||||
|
;; We don't want to highlight a package of the type
|
||||||
|
;; (e.g. pack.ClassName). So explicitly exclude patterns with
|
||||||
|
;; attribute, since we handle dotted type name in the previous
|
||||||
|
;; rule. The following rule handle
|
||||||
|
;; generic_type/list/tuple/splat_type nodes.
|
||||||
|
(type (_ !attribute [[(identifier) (none)] @font-lock-type-face
|
||||||
|
(attribute attribute: (identifier) @font-lock-type-face) ]))
|
||||||
|
;; collections.abc.Iterator[T] case.
|
||||||
|
(type (subscript (attribute attribute: (identifier) @font-lock-type-face)))
|
||||||
|
;; Nested optional type hints, e.g. val: Lvl1 | Lvl2[Lvl3[Lvl4]].
|
||||||
|
(type (binary_operator) @python--treesit-fontify-union-types)
|
||||||
|
;;class Type(Base1, Sequence[T]).
|
||||||
|
(class_definition
|
||||||
|
superclasses:
|
||||||
|
(argument_list [(identifier) @font-lock-type-face
|
||||||
|
(attribute attribute: (identifier) @font-lock-type-face)
|
||||||
|
(subscript (identifier) @font-lock-type-face)
|
||||||
|
(subscript (attribute attribute: (identifier) @font-lock-type-face))]))
|
||||||
|
|
||||||
|
;; Patern matching: case [str(), pack0.Type0()]. Take only the
|
||||||
|
;; last identifier.
|
||||||
|
(class_pattern (dotted_name (identifier) @font-lock-type-face :anchor))
|
||||||
|
|
||||||
|
;; Highlight the second argument as a type in isinstance/issubclass.
|
||||||
|
((call function: (identifier) @func-name
|
||||||
|
(argument_list :anchor (_)
|
||||||
|
[(identifier) @font-lock-type-face
|
||||||
|
(attribute attribute: (identifier) @font-lock-type-face)
|
||||||
|
(tuple (identifier) @font-lock-type-face)
|
||||||
|
(tuple (attribute attribute: (identifier) @font-lock-type-face))]
|
||||||
|
(:match ,python--treesit-type-regex @font-lock-type-face)))
|
||||||
|
(:match "^is\\(?:instance\\|subclass\\)$" @func-name))
|
||||||
|
|
||||||
|
;; isinstance(t, int|float).
|
||||||
|
((call function: (identifier) @func-name
|
||||||
|
(argument_list :anchor (_)
|
||||||
|
(binary_operator) @python--treesit-fontify-union-types-strict))
|
||||||
|
(:match "^is\\(?:instance\\|subclass\\)$" @func-name)))
|
||||||
|
|
||||||
:feature 'escape-sequence
|
:feature 'escape-sequence
|
||||||
:language 'python
|
:language 'python
|
||||||
|
|
|
@ -7299,6 +7299,308 @@ buffer with overlapping strings."
|
||||||
"Unused import a.b.c (unused-import)"
|
"Unused import a.b.c (unused-import)"
|
||||||
"W0611: Unused import a.b.c (unused-import)"))))))
|
"W0611: Unused import a.b.c (unused-import)"))))))
|
||||||
|
|
||||||
|
;;; python-ts-mode font-lock tests
|
||||||
|
|
||||||
|
(defmacro python-ts-tests-with-temp-buffer (contents &rest body)
|
||||||
|
"Create a `python-ts-mode' enabled temp buffer with CONTENTS.
|
||||||
|
BODY is code to be executed within the temp buffer. Point is
|
||||||
|
always located at the beginning of buffer."
|
||||||
|
(declare (indent 1) (debug t))
|
||||||
|
`(with-temp-buffer
|
||||||
|
(skip-unless (treesit-ready-p 'python))
|
||||||
|
(require 'python)
|
||||||
|
(let ((python-indent-guess-indent-offset nil))
|
||||||
|
(python-ts-mode)
|
||||||
|
(setopt treesit-font-lock-level 3)
|
||||||
|
(insert ,contents)
|
||||||
|
(font-lock-ensure)
|
||||||
|
(goto-char (point-min))
|
||||||
|
,@body)))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-compound-keywords-face ()
|
||||||
|
(dolist (test '("is not" "not in"))
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
(concat "t " test " t")
|
||||||
|
(forward-to-word 1)
|
||||||
|
(should (eq (face-at-point) font-lock-keyword-face))
|
||||||
|
(forward-to-word 1)
|
||||||
|
(should (eq (face-at-point) font-lock-keyword-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-named-assignement-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"var := 3"
|
||||||
|
(should (eq (face-at-point) font-lock-variable-name-face))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-assignement-face-2 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"var, *rest = call()"
|
||||||
|
(dolist (test '("var" "rest"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-variable-name-face))))
|
||||||
|
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def func(*args):"
|
||||||
|
(dolist (test '("args"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-variable-name-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-nested-types-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def func(v:dict[ list[ tuple[str] ], int | None] | None):"
|
||||||
|
(dolist (test '("dict" "list" "tuple" "str" "int" "None" "None"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-union-types-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def f(val: tuple[tuple, list[Lvl1 | Lvl2[Lvl3[Lvl4[Lvl5 | None]], Lvl2]]]):"
|
||||||
|
(dolist (test '("tuple" "tuple" "list" "Lvl1" "Lvl2" "Lvl3" "Lvl4" "Lvl5" "None" "Lvl2"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-union-types-face-2 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def f(val: Type0 | Type1[Type2, pack0.Type3] | pack1.pack2.Type4 | None):"
|
||||||
|
(dolist (test '("Type0" "Type1" "Type2" "Type3" "Type4" "None"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("pack0" "pack1" "pack2"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-types-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def f(val: Callable[[Type0], (Type1, Type2)]):"
|
||||||
|
(dolist (test '("Callable" "Type0" "Type1" "Type2"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-types-face-2 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def annot3(val:pack0.Type0)->pack1.pack2.pack3.Type1:"
|
||||||
|
(dolist (test '("Type0" "Type1"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("pack0" "pack1" "pack2" "pack3"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-types-face-3 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"def annot3(val:collections.abc.Iterator[Type0]):"
|
||||||
|
(dolist (test '("Iterator" "Type0"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("collections" "abc"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-isinstance-type-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"isinstance(var1, pkg.Type0)
|
||||||
|
isinstance(var2, (str, dict, Type1, type(None)))
|
||||||
|
isinstance(var3, my_type())"
|
||||||
|
|
||||||
|
(dolist (test '("var1" "pkg" "var2" "type" "None" "var3" "my_type"))
|
||||||
|
(let ((case-fold-search nil))
|
||||||
|
(search-forward test))
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("Type0" "str" "dict" "Type1"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-isinstance-type-face-2 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"issubclass(mytype, int|list|collections.abc.Iterable)"
|
||||||
|
(dolist (test '("int" "list" "Iterable"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-isinstance-type-face-3 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"issubclass(mytype, typevar1)
|
||||||
|
isinstance(mytype, (Type1, typevar2, tuple, abc.Coll))
|
||||||
|
isinstance(mytype, pkg0.Type2|self.typevar3|typevar4)"
|
||||||
|
|
||||||
|
(dolist (test '("typevar1" "typevar2" "pkg0" "self" "typevar3" "typevar4"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("Type1" "tuple" "Coll" "Type2"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-superclass-type-face ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"class Temp(Base1, pack0.Base2, Sequence[T1, T2]):"
|
||||||
|
|
||||||
|
(dolist (test '("Base1" "Base2" "Sequence" "T1" "T2"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("pack0"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-class-patterns-face ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"match tt:
|
||||||
|
case str():
|
||||||
|
pass
|
||||||
|
case [Type0() | bytes(b) | pack0.pack1.Type1()]:
|
||||||
|
pass
|
||||||
|
case {'i': int(i), 'f': float() as f}:
|
||||||
|
pass"
|
||||||
|
|
||||||
|
(dolist (test '("str" "Type0" "bytes" "Type1" "int" "float"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("pack0" "pack1"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-type-face))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-dotted-decorator-face-1 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"@pytest.mark.skip
|
||||||
|
@pytest.mark.skip(reason='msg')
|
||||||
|
def test():"
|
||||||
|
|
||||||
|
(dolist (test '("pytest" "mark" "skip" "pytest" "mark" "skip"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-dotted-decorator-face-2 ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"@pytest.mark.skip(reason='msg')
|
||||||
|
def test():"
|
||||||
|
|
||||||
|
(setopt treesit-font-lock-level 4)
|
||||||
|
(dolist (test '("pytest" "mark" "skip"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-type-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-builtin-call-face ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"all()"
|
||||||
|
;; enable 'function' feature from 4th level
|
||||||
|
(setopt treesit-font-lock-level 4)
|
||||||
|
(should (eq (face-at-point) font-lock-builtin-face))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-interpolation-nested-string ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"t = f\"beg {True + 'string'}\""
|
||||||
|
|
||||||
|
(search-forward "True")
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-constant-face))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("f" "{" "+" "}"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-string-face))))
|
||||||
|
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("beg" "'string'" "\""))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-string-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-level-fontification-wo-interpolation ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"t = f\"beg {True + var}\""
|
||||||
|
|
||||||
|
(setopt treesit-font-lock-level 2)
|
||||||
|
(search-forward "f")
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-string-face)))
|
||||||
|
|
||||||
|
(dolist (test '("\"" "beg" "{" "True" "var" "}" "\""))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-string-face)))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-disabled-string-interpolation ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"t = f\"beg {True + var}\""
|
||||||
|
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
(setf (nth 2 treesit-font-lock-feature-list)
|
||||||
|
(remq 'string-interpolation (nth 2 treesit-font-lock-feature-list)))
|
||||||
|
(setopt treesit-font-lock-level 3)
|
||||||
|
|
||||||
|
(search-forward "f")
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-string-face)))
|
||||||
|
|
||||||
|
(dolist (test '("\"" "beg" "{" "True" "var" "}" "\""))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-string-face))))
|
||||||
|
|
||||||
|
(setf (nth 2 treesit-font-lock-feature-list)
|
||||||
|
(append (nth 2 treesit-font-lock-feature-list) '(string-interpolation))))))
|
||||||
|
|
||||||
|
(ert-deftest python-ts-mode-interpolation-doc-string ()
|
||||||
|
(python-ts-tests-with-temp-buffer
|
||||||
|
"f\"\"\"beg {'s1' + True + 's2'} end\"\"\""
|
||||||
|
|
||||||
|
(search-forward "True")
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-constant-face))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("f" "{" "+" "}"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (not (eq (face-at-point) font-lock-string-face))))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("\"\"\"" "beg" "end" "\"\"\""))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-doc-face)))
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
(dolist (test '("'s1'" "'s2'"))
|
||||||
|
(search-forward test)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(should (eq (face-at-point) font-lock-string-face)))))
|
||||||
|
|
||||||
(provide 'python-tests)
|
(provide 'python-tests)
|
||||||
|
|
||||||
;;; python-tests.el ends here
|
;;; python-tests.el ends here
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue