From 81de1e7d4d272d2c163b6fc94b3d4d92b596caed Mon Sep 17 00:00:00 2001 From: Jon Denning Date: Thu, 21 Apr 2022 12:30:14 +1000 Subject: Text Editor: add Python 3.10 soft keywords to `builtinfunc` list Python 3.10 has added "soft keywords" [0] to their list of identifiers. This patch adds these soft keywords to the list of builtin functions that the text editor searches for when highlighting Python code. The only soft keywords that Python 3.10 current has are: `match`, `case`, and `_`, but more will likely be added in future versions. Currently, the `_` soft keyword is ignored from highlighting. It is a wildcard matching pattern when used with `case` (similar to `default` for `switch`es in C/C++), but `_` is far more often used in other contexts where highlighting the `_` might seem strange. For example, ignoring elements when unpacking tuples (`_, g, _, a = color`). This patch also updates the commented Python code for creating the list of keywords, for convenience. Before: {F13012878} After: {F13012880} Example from PEP-636 [1] Note: These soft keywords are only reserved under specific contexts. However, in order for the text editor to know when the keywords are used in the appropriate contexts, the text editor would need a full-blown Python grammar [2] parser. So, for now, these keywords are simply added in along with the other keywords in order to highlight them in the text editor. [0]: https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords [1]: https://peps.python.org/pep-0636/#matching-specific-values [2]: https://docs.python.org/3/reference/grammar.html Ref D14707 --- source/blender/editors/space_text/text_format_py.c | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 4048e181fde..6658ac5a83c 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -33,24 +33,33 @@ static int txtfmt_py_find_builtinfunc(const char *string) int i, len; /* list is from... * ", ".join(['"%s"' % kw - * for kw in __import__("keyword").kwlist - * if kw not in {"False", "None", "True", "def", "class"}]) + * for kw in sorted(__import__("keyword").kwlist + __import__("keyword").softkwlist) + * if kw not in {"False", "None", "True", "def", "class", "_"}]) * * ... and for this code: - * print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw - * for kw in __import__("keyword").kwlist - * if kw not in {"False", "None", "True", "def", "class"}])) + * import keyword + * ignore = {"False", "None", "True", "def", "class", "_"} + * keywords = sorted(set(keyword.kwlist + keyword.softkwlist) - ignore) + * longest = max(len(kw) for kw in keywords) + * first = 'if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;' + * middle = '} else if (STR_LITERAL_STARTSWITH(string, "%s",%s len)) { i = len;' + * last = '} else %s { i = 0;' + * print("\n".join([(first if i==0 else middle) % (kw, ' '*(longest - len(kw))) + * for (i, kw) in enumerate(keywords)]) + "\n" + + * last % (' '*(longest-2)) + "\n" + + * "}") */ /* Keep aligned args for readability. */ /* clang-format off */ - if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; + if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len; - } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "elif", len)) { i = len; @@ -65,6 +74,7 @@ static int txtfmt_py_find_builtinfunc(const char *string) } else if (STR_LITERAL_STARTSWITH(string, "in", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "is", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) { i = len; + } else if (STR_LITERAL_STARTSWITH(string, "match", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "not", len)) { i = len; } else if (STR_LITERAL_STARTSWITH(string, "or", len)) { i = len; -- cgit v1.2.3