Repository: spyder-ide/spyder

Issue:
Syntax highlight new Python 3.10 statements is missing
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [X] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [ ] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [X] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [ ] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [ ] Tried basic troubleshooting (if a bug/error)
    * [X] Restarted Spyder
    * [ ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [ ] Tried the other applicable steps from the Troubleshooting Guide
* [X] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description
When I started to use the new structural pattern matching statement that is introduced with Python 3.10 (See https://docs.python.org/3.10/whatsnew/3.10.html#pep-634-structural-pattern-matching), I noticed that the syntax highlighting of the "match" and the "case" part is not right. I think the Spyder components should be updated to support the new Python 3.10 statements.

### What steps reproduce the problem?

Take an existing Python script or make a new one and insert 
```python
import time as tm

for idx in range(5):
	match idx:
		case 0:
			print('First phase')
		case 1:
			print('Second phase')
		case 2:
			print('Taking a break')
			tm.sleep(3)
		case 3:
			print('Third phase')
		case _:
			print(f'{idx}-th phase')

``` 

### What is the expected output? What do you see instead?

The expected output is that in the code "match" and "case" and "_" are highlighted the same as the usual statements like "class" and "if". Currently they are highlighted as if they were variable names.

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 5.4.3  (pip)
* Python version: 3.10.11 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.9
* Operating System: Windows 10

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
No special dependencies this time.
```



Discussion:
Hey @TBSenseo, thanks for reporting. You're totally right, we need to add those new builtins to our syntax highlighter code.

We'll do that for our next version (5.4.4), to be released in a couple of weeks.

Resolving patch:
diff --git a/spyder/utils/syntaxhighlighters.py b/spyder/utils/syntaxhighlighters.py
--- a/spyder/utils/syntaxhighlighters.py
+++ b/spyder/utils/syntaxhighlighters.py
@@ -505,7 +505,7 @@ def get_code_cell_name(text):
 class PythonSH(BaseSH):
     """Python Syntax Highlighter"""
     # Syntax highlighting rules:
-    add_kw = ['async', 'await']
+    add_kw = ['async', 'await', 'match', 'case']
     PROG = re.compile(make_python_patterns(additional_keywords=add_kw), re.S)
     IDPROG = re.compile(r"\s+(\w+)", re.S)
     ASPROG = re.compile(r"\b(as)\b")


Test patch:
diff --git a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
--- a/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
+++ b/spyder/plugins/ipythonconsole/tests/test_ipythonconsole.py
@@ -25,6 +25,7 @@
 from IPython.core import release as ipy_release
 from IPython.core.application import get_ipython_dir
 from flaky import flaky
+import numpy as np
 from packaging.version import parse
 import pytest
 from qtpy.QtCore import Qt
@@ -83,7 +84,8 @@ def test_banners(ipyconsole, qtbot):
        "open interval ..."]),
      ("vectorize",
       ["pyfunc", "otype", "signature"],
-      ["Generalized function class.<br>",
+      ["Returns an object that acts like pyfunc, but takes arrays as<br>input."
+       "<br>",
        "Define a vectorized function which takes a nested sequence ..."]),
      ("absolute",
       ["x", "/", "out"],
@@ -91,6 +93,8 @@ def test_banners(ipyconsole, qtbot):
     )
 @pytest.mark.skipif(not os.name == 'nt',
                     reason="Times out on macOS and fails on Linux")
+@pytest.mark.skipif(parse(np.__version__) < parse('1.25.0'),
+                    reason="Documentation for np.vectorize is different")
 def test_get_calltips(ipyconsole, qtbot, function, signature, documentation):
     """Test that calltips show the documentation."""
     shell = ipyconsole.get_current_shellwidget()