From fba1597a1813d4383f770e038e09f71c97b6b848 Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Mon, 21 Jul 2025 10:47:17 +0100
Subject: [PATCH 1/6] fix(tree-sitter): replace `lua-match` with `match` in
highlights
`lua-match` is specific to tree-sitter in Neovim. Currently these query
predicates are ignored so will highlight much more than they should.
---
src/textual/tree-sitter/highlights/css.scm | 4 ++--
src/textual/tree-sitter/highlights/python.scm | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/textual/tree-sitter/highlights/css.scm b/src/textual/tree-sitter/highlights/css.scm
index 19b0fbfdeb..61ad9c412e 100644
--- a/src/textual/tree-sitter/highlights/css.scm
+++ b/src/textual/tree-sitter/highlights/css.scm
@@ -57,9 +57,9 @@
(namespace_name) @namespace
((property_name) @type.definition
- (#lua-match? @type.definition "^[-][-]"))
+ (#match? @type.definition "^[-][-]"))
((plain_value) @type
- (#lua-match? @type "^[-][-]"))
+ (#match? @type "^[-][-]"))
[
(string_value)
diff --git a/src/textual/tree-sitter/highlights/python.scm b/src/textual/tree-sitter/highlights/python.scm
index 6f844b6135..3e7381b813 100644
--- a/src/textual/tree-sitter/highlights/python.scm
+++ b/src/textual/tree-sitter/highlights/python.scm
@@ -11,9 +11,9 @@
;; Identifier naming conventions
((identifier) @type
- (#lua-match? @type "^[A-Z].*[a-z]"))
+ (#match? @type "^[A-Z].*[a-z]"))
((identifier) @constant
- (#lua-match? @constant "^[A-Z][A-Z_0-9]*$"))
+ (#match? @constant "^[A-Z][A-Z_0-9]*$"))
((attribute
attribute: (identifier) @field)
@@ -59,12 +59,12 @@
((call
function: (identifier) @constructor)
- (#lua-match? @constructor "^[A-Z]"))
+ (#match? @constructor "^[A-Z]"))
((call
function: (attribute
attribute: (identifier) @constructor))
- (#lua-match? @constructor "^[A-Z]"))
+ (#match? @constructor "^[A-Z]"))
;; Decorators
From cc61b23ea8fb315df9ceef802bbb5c2c6712e334 Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Mon, 21 Jul 2025 11:09:01 +0100
Subject: [PATCH 2/6] fix: bump tree-sitter to v0.25.0
Bump tree-sitter to v0.25.0 and fix breaking change where
`Query.captures` has been moved to `QueryCursor.captures`.
NB: tree-sitter dropped support for Python 3.9 back in v0.24.0, so
syntax highlighting in Textual will now require Python >=3.10.
Fixes #5976
---
poetry.lock | 140 ++++++++----------
pyproject.toml | 34 ++---
.../document/_syntax_aware_document.py | 7 +-
3 files changed, 85 insertions(+), 96 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index ce8f992898..f926a42ff6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@@ -543,13 +543,13 @@ toml = ["tomli"]
[[package]]
name = "distlib"
-version = "0.3.9"
+version = "0.4.0"
description = "Distribution utilities"
optional = false
python-versions = "*"
files = [
- {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
- {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
+ {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"},
+ {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"},
]
[[package]]
@@ -2147,77 +2147,65 @@ files = [
[[package]]
name = "tree-sitter"
-version = "0.23.2"
+version = "0.25.0"
description = "Python bindings to the Tree-sitter parsing library"
optional = true
-python-versions = ">=3.9"
-files = [
- {file = "tree-sitter-0.23.2.tar.gz", hash = "sha256:66bae8dd47f1fed7bdef816115146d3a41c39b5c482d7bad36d9ba1def088450"},
- {file = "tree_sitter-0.23.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3a937f5d8727bc1c74c4bf2a9d1c25ace049e8628273016ad0d45914ae904e10"},
- {file = "tree_sitter-0.23.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2c7eae7fe2af215645a38660d2d57d257a4c461fe3ec827cca99a79478284e80"},
- {file = "tree_sitter-0.23.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a71d607595270b6870eaf778a1032d146b2aa79bfcfa60f57a82a7b7584a4c7"},
- {file = "tree_sitter-0.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe9b9ea7a0aa23b52fd97354da95d1b2580065bc12a4ac868f9164a127211d6"},
- {file = "tree_sitter-0.23.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d74d00a8021719eae14d10d1b1e28649e15d8b958c01c2b2c3dad7a2ebc4dbae"},
- {file = "tree_sitter-0.23.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6de18d8d8a7f67ab71f472d1fcb01cc506e080cbb5e13d52929e4b6fdce6bbee"},
- {file = "tree_sitter-0.23.2-cp310-cp310-win_amd64.whl", hash = "sha256:12b60dca70d2282af942b650a6d781be487485454668c7c956338a367b98cdee"},
- {file = "tree_sitter-0.23.2-cp310-cp310-win_arm64.whl", hash = "sha256:3346a4dd0447a42aabb863443b0fd8c92b909baf40ed2344fae4b94b625d5955"},
- {file = "tree_sitter-0.23.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91fda41d4f8824335cc43c64e2c37d8089c8c563bd3900a512d2852d075af719"},
- {file = "tree_sitter-0.23.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92b2b489d5ce54b41f94c6f23fbaf592bd6e84dc2877048fd1cb060480fa53f7"},
- {file = "tree_sitter-0.23.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64859bd4aa1567d0d6016a811b2b49c59d4a4427d096e3d8c84b2521455f62b7"},
- {file = "tree_sitter-0.23.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:614590611636044e071d3a0b748046d52676dbda3bc9fa431216231e11dd98f7"},
- {file = "tree_sitter-0.23.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:08466953c78ae57be61057188fb88c89791b0a562856010228e0ccf60e2ac453"},
- {file = "tree_sitter-0.23.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a33f03a562de91f7fd05eefcedd8994a06cd44c62f7aabace811ad82bc11cbd"},
- {file = "tree_sitter-0.23.2-cp311-cp311-win_amd64.whl", hash = "sha256:03b70296b569ef64f7b92b42ca5da9bf86d81bee2afd480bea35092687f51dae"},
- {file = "tree_sitter-0.23.2-cp311-cp311-win_arm64.whl", hash = "sha256:7cb4bb953ea7c0b50eeafc4454783e030357179d2a93c3dd5ebed2da5588ddd0"},
- {file = "tree_sitter-0.23.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a014498b6a9e6003fae8c6eb72f5927d62da9dcb72b28b3ce8cd15c6ff6a6572"},
- {file = "tree_sitter-0.23.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04f8699b131d4bcbe3805c37e4ef3d159ee9a82a0e700587625623999ba0ea53"},
- {file = "tree_sitter-0.23.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4471577df285059c71686ecb208bc50fb472099b38dcc8e849b0e86652891e87"},
- {file = "tree_sitter-0.23.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f342c925290dd4e20ecd5787ef7ae8749981597ab364783a1eb73173efe65226"},
- {file = "tree_sitter-0.23.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4e9e53d07dd076bede72e4f7d3a0173d7b9ad6576572dd86da008a740a9bb22"},
- {file = "tree_sitter-0.23.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8caebe65bc358759dac2500d8f8feed3aed939c4ade9a684a1783fe07bc7d5db"},
- {file = "tree_sitter-0.23.2-cp312-cp312-win_amd64.whl", hash = "sha256:fc5a72eb50d43485000dbbb309acb350467b7467e66dc747c6bb82ce63041582"},
- {file = "tree_sitter-0.23.2-cp312-cp312-win_arm64.whl", hash = "sha256:a0320eb6c7993359c5f7b371d22719ccd273f440d41cf1bd65dac5e9587f2046"},
- {file = "tree_sitter-0.23.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eff630dddee7ba05accb439b17e559e15ce13f057297007c246237ceb6306332"},
- {file = "tree_sitter-0.23.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4780ba8f3894f2dea869fad2995c2aceab3fd5ab9e6a27c45475d2acd7f7e84e"},
- {file = "tree_sitter-0.23.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b609460b8e3e256361fb12e94fae5b728cb835b16f0f9d590b5aadbf9d109b"},
- {file = "tree_sitter-0.23.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d070d8eaeaeb36cf535f55e5578fddbfc3bf53c1980f58bf1a99d57466b3b5"},
- {file = "tree_sitter-0.23.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:878580b2ad5054c410ba3418edca4d34c81cc26706114d8f5b5541688bc2d785"},
- {file = "tree_sitter-0.23.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:29224bdc2a3b9af535b7725e249d3ee291b2e90708e82832e73acc175e40dc48"},
- {file = "tree_sitter-0.23.2-cp313-cp313-win_amd64.whl", hash = "sha256:c58d89348162fbc3aea1fe6511a66ee189fc0e4e4bbe937026f29e4ecef17763"},
- {file = "tree_sitter-0.23.2-cp313-cp313-win_arm64.whl", hash = "sha256:0ff2037be5edab7801de3f6a721b9cf010853f612e2008ee454e0e0badb225a6"},
- {file = "tree_sitter-0.23.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a5db8e585205faef8bf219da77d8993e2ef04d08eda2e3c8ad7e4df8297ee344"},
- {file = "tree_sitter-0.23.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9dbd110a30cf28be5da734ae4cd0e9031768228dbf6a79f2973962aa51de4ec7"},
- {file = "tree_sitter-0.23.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569514b9a996a0fd458b3a891c46ca125298be0c03cf82f2b6f0c13d5d8f25dc"},
- {file = "tree_sitter-0.23.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a357ed98a74e47787b812df99a74a2c35c0fe11e55c2095cc01d1cad144ef552"},
- {file = "tree_sitter-0.23.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c2dfb8e8f760f4cc67888d03ef9e2dbd3353245f67f5efba375c2a14d944ac0e"},
- {file = "tree_sitter-0.23.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3ead958df87a21d706903987e665e9e0e5df7b2c5021ff69ea349826840adc6a"},
- {file = "tree_sitter-0.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:611cae16be332213c0e6ece72c0bfca202e30ff320a8b309b1526c6cb79ee4ba"},
- {file = "tree_sitter-0.23.2-cp39-cp39-win_arm64.whl", hash = "sha256:b848e0fdd522fbb8888cdb4f4d93f8fad97ae10d70c122fb922e51363c7febcd"},
+python-versions = ">=3.10"
+files = [
+ {file = "tree-sitter-0.25.0.tar.gz", hash = "sha256:15c88775cf24db06677bafe62df058a6457d8a6dde67baa48dd3723b905e79a6"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:05fa57c9d9f951e9e806689caff9a809e2a8c4477ee23ff41a5e65122bbeb4c3"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cd55cb2c2f311693694c6eee409b163246e9a809ede49371963ace8c93d77ad1"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5892ecb52b14b00605c6960af42d212c65610a0de3ae986208619fa42b676bad"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3ec6a4ac2170af965e5b41bb603a5b0406ca8d93dac83d388c2246f0eef606a"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d34bb4dda0518c07f6ea7880a463da338b2b72ce7c66bf32dc54f2ddcaf8463d"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:5aad12ceb86745946a74e63a3cf5e111684589acb3d647e5ce40637e89714c48"},
+ {file = "tree_sitter-0.25.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ea484eec5e6538fdbabdd3c737d5f5250602e12dc9a33ed3b8e6a400ca115be"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5409a3be1010a483a9a8d5c64fdd20de7ea3e9c0c080e91e492a10a659bcac40"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa1cd26faff9b3514e456cc0f4f0eb6b11bfdeec9a40ba8d55ee5a75d57566cb"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ddf745c668df39e4ef9a28fba4be4ecea990522e940b8e5bc656704c689b38ac"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b39e177822dda5b42f2b6235af0a66c92ab6f1674f07d0e7b51be73957193370"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:992cd17f97eae3245786160db4902f7b8106186aa18b9fcb873a86688e4d4dc8"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:14a138fe341348e7801c0afb580970597477fc68a0d0f6c780fc0a07eae2770e"},
+ {file = "tree_sitter-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:332e235eba90423edc6e83cc4a5dc60e91c03ace6c1d8729d0f2e0ca09210845"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d9efacce0140ad74f97e027fb4ae693debff05f6246f3e024937f9500a0e874a"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82b4a5535107d2b8feee085edcafa89858faa4e1a98e94cfe1740c0ca8c28d84"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c613372545490dfba3b3e7d934fda1156e3d16b27c0335c65a92f2b4fa6af5da"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a90c815a354594d3147012ce470cfc797695ab768e29198815e147ef3c165"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f0b01b5068f1888af223021ba461480df28c76f39893c8113aae2154a2b81fd"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:1807bd1dae1f50721d65b270e6ffa85de84234ae39f98f4da702db56c2627e23"},
+ {file = "tree_sitter-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:7848be6aeab5c1d62d649506d80d0e463727cb1bb55f423e88bf317db0be8d67"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:689a19d51103f727a545ec9ba9cd377267445859838c38ec55d159dc57e82e8a"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86288b218ef958dcafe40030d6d70c99baffaf808bd81b49de160f9724fc0ba4"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5241610319177ee2f68b8e719bf1e1b309155e126d9cd567ff84f20878d7e5d0"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae1553d652a54926f80dc0a42fba07db110bb1a3ebaf47d1c4c64f8d44dd8207"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ccac581551407a73a519b872553973598b69d3d237ffaf32408fb38ecb775484"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:d58e912869514ebb441b15c22a13a9c78f1b69be15f6a42b1d18e3f790e5d6ba"},
+ {file = "tree_sitter-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:a1b8302161fa8da52cfafcd7575fa7d5806a9608a0b51c7a1fe45bfe70b62d46"},
]
[package.extras]
-docs = ["sphinx (>=7.3,<8.0)", "sphinx-book-theme"]
-tests = ["tree-sitter-html (>=0.23.0)", "tree-sitter-javascript (>=0.23.0)", "tree-sitter-json (>=0.23.0)", "tree-sitter-python (>=0.23.0)", "tree-sitter-rust (>=0.23.0)"]
+docs = ["sphinx (>=8.1,<9.0)", "sphinx-book-theme"]
+tests = ["tree-sitter-html (>=0.23.2)", "tree-sitter-javascript (>=0.23.1)", "tree-sitter-json (>=0.24.8)", "tree-sitter-python (>=0.23.6)", "tree-sitter-rust (>=0.23.2)"]
[[package]]
name = "tree-sitter-bash"
-version = "0.23.3"
+version = "0.25.0"
description = "Bash grammar for tree-sitter"
optional = true
-python-versions = ">=3.9"
+python-versions = ">=3.10"
files = [
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c1ee7a46fcbfca9937d01056be756631762f53c5afdb8c4ab64eb9fed060896b"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5a090118e887bf667d82ae445794906186216f5500e0d2cd58eb499f7502dc57"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4b5dde719291eea3a81b1f9ece6afeee2deadc2b2f769bee92f955da7595cf"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff7bffc3d594e7f1054de051e19df1b24082963598a175dda64083c6b3eea1a"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4427baccbd7549a2ebb1859b6d42cdab0739c05d53c2b3daad9cadc069a7b3f6"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-win_amd64.whl", hash = "sha256:525c5cce28a7c5624fb016ac8f3ae33d32968567b718f7878c6351229d2e8394"},
- {file = "tree_sitter_bash-0.23.3-cp39-abi3-win_arm64.whl", hash = "sha256:1f703d1bf6235355f6c900be64bf9f61fc4b1d0cfed6829b4eeb74a6b41ea910"},
- {file = "tree_sitter_bash-0.23.3.tar.gz", hash = "sha256:7b15ed89a1ea8e3e3c2399758746413e464d4c1c3a6d3b75d643ae2bc2fb356b"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:1120152dc21e5d6a542207e95f3d474089e63f057696dbbcd563e5050e997dcf"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:437f3b5cbdb6e1dd81a0d0044ad190655238548d34c8ea3d78958ee896f5984d"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd82f006078ddd6c4406be7ab4e04013daafe65a8979a2ad1d3180f6483eccd7"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26434f942e391d6cc62ec2e43ce0a622a8c1feb6e62c1ca020493df79952d413"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2532d8d5892f09f43716cdc1e8efcf16cf54062b8216a4c29babaf7abff56fdc"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:7f60510341200356ea15e8ad5eb0ffc0d495c6c23bdb31255fecd39b214d9326"},
+ {file = "tree_sitter_bash-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:0347c1d8fe0c7814ef98f8a65189426d2895efd2b8b00022e7ff32741e1165ac"},
+ {file = "tree_sitter_bash-0.25.0.tar.gz", hash = "sha256:6b6410ea5f54abe8780e4b260b01adbfec3a0729907c7a62a3448f670010e72e"},
]
[package.extras]
-core = ["tree-sitter (>=0.22,<1.0)"]
+core = ["tree-sitter (>=0.24,<1.0)"]
[[package]]
name = "tree-sitter-css"
@@ -2482,23 +2470,23 @@ core = ["tree-sitter (>=0.22,<1.0)"]
[[package]]
name = "tree-sitter-yaml"
-version = "0.7.0"
+version = "0.7.1"
description = "YAML grammar for tree-sitter"
optional = true
-python-versions = ">=3.9"
+python-versions = ">=3.10"
files = [
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e21553ac190ae05bf82796df8beb4d9158ba195b5846018cb36fbc3a35bd0679"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:c022054f1f9b54201082ea83073a6c24c42d0436ad8ee99ff2574cba8f928c28"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cd1725142f19e41c51d27c99cfc60780f596e069eb181cfa6433d993a19aa3d"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d1b268378254f75bb27396d83c96d886ccbfcda6bd8c2778e94e3e1d2459085"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:27c2e7f4f49ddf410003abbb82a7b00ec77ea263d8ef08dbce1a15d293eed2fd"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-win_amd64.whl", hash = "sha256:98dce0d6bc376f842cfb1d3c32512eea95b37e61cd2c87074bb4b05c999917c8"},
- {file = "tree_sitter_yaml-0.7.0-cp39-abi3-win_arm64.whl", hash = "sha256:f0f8d8e05fa8e70f08d0f18a209d6026e171844f4ea7090e7c779b9c375b3a31"},
- {file = "tree_sitter_yaml-0.7.0.tar.gz", hash = "sha256:9c8bb17d9755c3b0e757260917240c0d19883cd3b59a5d74f205baa8bf8435a4"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0256632914d6eb21819f21a85bab649505496ac01fac940eb08a410669346822"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf9dd2649392e1f28a20f920f49acd9398cfb872876e338aa84562f8f868dc4d"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94eb8fcb1ac8e43f7da47e63880b6f283524460153f08420a167c1721e42b08a"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30410089828ebdece9abf3aa16b2e172b84cf2fd90a2b7d8022f6ed8cde90ecb"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:219af34f4b35b5c16f25426cc3f90cf725fbba17c9592f78504086e67787be09"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-win_amd64.whl", hash = "sha256:550645223d68b7d6b4cfedf4972754724e64d369ec321fa33f57d3ca54cafc7c"},
+ {file = "tree_sitter_yaml-0.7.1-cp310-abi3-win_arm64.whl", hash = "sha256:298ade69ad61f76bb3e50ced809650ec30521a51aa2708166b176419ccb0a6ba"},
+ {file = "tree_sitter_yaml-0.7.1.tar.gz", hash = "sha256:2cea5f8d4ca4d10439bd7d9e458c61b330cb33cf7a92e4ef1d428e10e1ab7e2c"},
]
[package.extras]
-core = ["tree-sitter (>=0.22,<1.0)"]
+core = ["tree-sitter (>=0.24,<1.0)"]
[[package]]
name = "types-setuptools"
@@ -2566,13 +2554,13 @@ zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "virtualenv"
-version = "20.31.2"
+version = "20.32.0"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.8"
files = [
- {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"},
- {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"},
+ {file = "virtualenv-20.32.0-py3-none-any.whl", hash = "sha256:2c310aecb62e5aa1b06103ed7c2977b81e042695de2697d01017ff0f1034af56"},
+ {file = "virtualenv-20.32.0.tar.gz", hash = "sha256:886bf75cadfdc964674e6e33eb74d787dff31ca314ceace03ca5810620f4ecf0"},
]
[package.dependencies]
@@ -2768,4 +2756,4 @@ syntax = ["tree-sitter", "tree-sitter-bash", "tree-sitter-css", "tree-sitter-go"
[metadata]
lock-version = "2.0"
python-versions = "^3.8.1"
-content-hash = "1876ad2e2a1494788a7a7c9a7f75d424c41502b520a7a00d253233cfd430cdc0"
+content-hash = "3fec532b2878d98a500d0f61b66aa8d350a046898cf91ed75e5f70c31f97521c"
diff --git a/pyproject.toml b/pyproject.toml
index 6b5b43890e..e6e74d98ca 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -52,24 +52,24 @@ typing-extensions = "^4.4.0"
platformdirs = ">=3.6.0,<5"
# start of [syntax] extras
-# Require tree-sitter >= 0.23.0 and python >= 3.9
+# Require tree-sitter >= 0.25.0 and python >= 3.10
# Windows, MacOS and Linux binary wheels are available for all of the languages below.
-tree-sitter = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-python = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-markdown = { version = ">=0.3.0", optional = true, python = ">=3.9"}
-tree-sitter-json = { version = ">=0.24.0", optional = true, python = ">=3.9" }
-tree-sitter-toml = { version = ">=0.6.0", optional = true, python = ">=3.9" }
-tree-sitter-yaml = { version = ">=0.6.0", optional = true, python = ">=3.9" }
-tree-sitter-html = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-css = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-javascript = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-rust = { version = ">=0.23.0,<=0.23.2", optional = true, python = ">=3.9" }
-tree-sitter-go = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-regex = { version = ">=0.24.0", optional = true, python = ">=3.9" }
-tree-sitter-xml = { version = ">=0.7.0", optional = true, python = ">=3.9" }
-tree-sitter-sql = { version = ">=0.3.0,<0.3.8", optional = true, python = ">=3.9" }
-tree-sitter-java = { version = ">=0.23.0", optional = true, python = ">=3.9" }
-tree-sitter-bash = { version = ">=0.23.0", optional = true, python = ">=3.9" }
+tree-sitter = { version = ">=0.25.0", optional = true, python = ">=3.10" }
+tree-sitter-python = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-markdown = { version = ">=0.3.0", optional = true, python = ">=3.10"}
+tree-sitter-json = { version = ">=0.24.0", optional = true, python = ">=3.10" }
+tree-sitter-toml = { version = ">=0.6.0", optional = true, python = ">=3.10" }
+tree-sitter-yaml = { version = ">=0.6.0", optional = true, python = ">=3.10" }
+tree-sitter-html = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-css = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-javascript = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-rust = { version = ">=0.23.0,<=0.23.2", optional = true, python = ">=3.10" }
+tree-sitter-go = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-regex = { version = ">=0.24.0", optional = true, python = ">=3.10" }
+tree-sitter-xml = { version = ">=0.7.0", optional = true, python = ">=3.10" }
+tree-sitter-sql = { version = ">=0.3.0,<0.3.8", optional = true, python = ">=3.10" }
+tree-sitter-java = { version = ">=0.23.0", optional = true, python = ">=3.10" }
+tree-sitter-bash = { version = ">=0.23.0", optional = true, python = ">=3.10" }
# end of [syntax] extras
pygments = "^2.19.2"
diff --git a/src/textual/document/_syntax_aware_document.py b/src/textual/document/_syntax_aware_document.py
index 00305dcec2..301db7afdc 100644
--- a/src/textual/document/_syntax_aware_document.py
+++ b/src/textual/document/_syntax_aware_document.py
@@ -1,7 +1,7 @@
from __future__ import annotations
try:
- from tree_sitter import Language, Node, Parser, Query, Tree
+ from tree_sitter import Language, Node, Parser, Query, QueryCursor, Tree
TREE_SITTER = True
except ImportError:
@@ -60,7 +60,7 @@ def prepare_query(self, query: str) -> Query | None:
Returns:
The prepared query.
"""
- return self.language.query(query)
+ return Query(self.language, query)
def query_syntax_tree(
self,
@@ -88,7 +88,8 @@ def query_syntax_tree(
if end_point is not None:
captures_kwargs["end_point"] = end_point
- captures = query.captures(self._syntax_tree.root_node, **captures_kwargs)
+ cursor = QueryCursor(query)
+ captures = cursor.captures(self._syntax_tree.root_node, **captures_kwargs)
return captures
def replace_range(self, start: Location, end: Location, text: str) -> EditResult:
From 90048cc38e4c59896ead4498ea4ccab264c646ee Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Mon, 21 Jul 2025 11:21:23 +0100
Subject: [PATCH 3/6] ci: update python versions for syntax dependencies and
tests
Update Python versions for syntax dependencies and tests in CI, as
tree-sitter no longer supports Python 3.9.
---
.github/workflows/pythonpackage.yml | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml
index 32f2e0a2b5..54d5a26d0f 100644
--- a/.github/workflows/pythonpackage.yml
+++ b/.github/workflows/pythonpackage.yml
@@ -35,18 +35,18 @@ jobs:
cache: "poetry"
- name: Install dependencies
run: poetry install --no-interaction --extras syntax
- if: ${{ matrix.python-version != '3.8' }}
- - name: Install dependencies for 3.8
+ if: ${{ matrix.python-version != '3.8' && matrix.python-version != '3.9' }}
+ - name: Install dependencies for 3.8 and 3.9
run: poetry install --no-interaction
- if: ${{ matrix.python-version == '3.8' }}
- - name: Test with pytest (Py39+ - with syntax highlighting)
+ if: ${{ matrix.python-version == '3.8' || matrix.python-version == '3.9' }}
+ - name: Test with pytest (Py310+ - with syntax highlighting)
run: |
poetry run pytest tests -v --cov=./src/textual --cov-report=xml:./coverage.xml --cov-report term-missing
- if: ${{ matrix.python-version != '3.8' }}
- - name: Test with pytest (Py38 - without syntax highlighting)
+ if: ${{ matrix.python-version != '3.8' && matrix.python-version != '3.9' }}
+ - name: Test with pytest (Py39 - without syntax highlighting)
run: |
poetry run pytest tests -v --cov=./src/textual --cov-report=xml:./coverage.xml --cov-report term-missing -m 'not syntax'
- if: ${{ matrix.python-version == '3.8' }}
+ if: ${{ matrix.python-version == '3.8' || matrix.python-version == '3.9' }}
- name: Upload snapshot report
if: always()
uses: actions/upload-artifact@v4
From 4a0915d6fc6418b9b6184e4971755d4df9c0877c Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Tue, 22 Jul 2025 14:33:11 +0100
Subject: [PATCH 4/6] fix(tree-sitter): remove name argument from Language
Remove the `name` argument from `Language` initialization, as this was
removed back in tree-sitter v0.22.0.
---
src/textual/_tree_sitter.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/textual/_tree_sitter.py b/src/textual/_tree_sitter.py
index 9d099c109b..5f92e2c146 100644
--- a/src/textual/_tree_sitter.py
+++ b/src/textual/_tree_sitter.py
@@ -1,9 +1,9 @@
from __future__ import annotations
+
from importlib import import_module
from textual import log
-
try:
from tree_sitter import Language
@@ -24,9 +24,9 @@ def get_language(language_name: str) -> Language | None:
if language_name == "xml":
# xml uses language_xml() instead of language()
# it's the only outlier amongst the languages in the `textual[syntax]` extra
- language = Language(module.language_xml(), name=language_name)
+ language = Language(module.language_xml())
else:
- language = Language(module.language(), name=language_name)
+ language = Language(module.language())
except (OSError, AttributeError):
log.warning(f"Could not load language {language_name!r}.")
return None
From 8df2db8b089be711b1b2efde650d66bc3c331ca5 Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Tue, 22 Jul 2025 19:15:04 +0100
Subject: [PATCH 5/6] fix(document): fix point range in query_syntax_tree
Fix the handling of the optional point range in `query_syntax_tree`,
where the range arguments were removed from `Query.captures` back in
tree-sitter v0.23.0.
It doesn't look like Textual ever actually used these range arguments,
but perhaps they were included to allow future improvements or to be
used by other developers.
---
.../document/_syntax_aware_document.py | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/textual/document/_syntax_aware_document.py b/src/textual/document/_syntax_aware_document.py
index 301db7afdc..67120cbb7a 100644
--- a/src/textual/document/_syntax_aware_document.py
+++ b/src/textual/document/_syntax_aware_document.py
@@ -10,6 +10,8 @@
from textual.document._document import Document, EditResult, Location, _utf8_encode
+_UINT32_MAX = 0xFFFFFFFF
+
class SyntaxAwareDocumentError(Exception):
"""General error raised when SyntaxAwareDocument is used incorrectly."""
@@ -82,14 +84,17 @@ def query_syntax_tree(
Returns:
A tuple containing the nodes and text captured by the query.
"""
- captures_kwargs = {}
- if start_point is not None:
- captures_kwargs["start_point"] = start_point
- if end_point is not None:
- captures_kwargs["end_point"] = end_point
-
cursor = QueryCursor(query)
- captures = cursor.captures(self._syntax_tree.root_node, **captures_kwargs)
+
+ if start_point is not None or end_point is not None:
+ if start_point is None:
+ start_point = (0, 0)
+ if end_point is None:
+ end_point = (_UINT32_MAX, _UINT32_MAX)
+
+ cursor.set_point_range(start_point, end_point)
+
+ captures = cursor.captures(self._syntax_tree.root_node)
return captures
def replace_range(self, start: Location, end: Location, text: str) -> EditResult:
From 1f70760f45a622c8e3ffb0e3a0215d1ee5fbac86 Mon Sep 17 00:00:00 2001
From: TomJGooding <101601846+TomJGooding@users.noreply.github.com>
Date: Wed, 23 Jul 2025 15:18:00 +0100
Subject: [PATCH 6/6] test(snapshots): update text area snapshots
Update the text area snapshots due to syntax highlighting changes after
bumping tree-sitter to 0.25.0.
---
...test_text_area_language_rendering[css].svg | 320 ++++++------
...est_text_area_language_rendering[java].svg | 468 ++++++++---------
...xt_area_language_rendering[javascript].svg | 362 +++++++-------
...t_text_area_language_rendering[python].svg | 366 +++++++-------
...est_text_area_language_rendering[rust].svg | 470 +++++++++---------
.../test_text_area_themes[css].svg | 74 ++-
.../test_text_area_themes[dracula].svg | 70 +--
.../test_text_area_themes[github_light].svg | 73 +--
.../test_text_area_themes[monokai].svg | 72 +--
.../test_text_area_themes[vscode_dark].svg | 72 ++-
10 files changed, 1172 insertions(+), 1175 deletions(-)
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[css].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[css].svg
index 44ac0c0411..1d61cc6b0a 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[css].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[css].svg
@@ -19,330 +19,330 @@
font-weight: 700;
}
- .terminal-2526263208-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-2526263208-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-2526263208-r1 { fill: #121212 }
-.terminal-2526263208-r2 { fill: #0178d4 }
-.terminal-2526263208-r3 { fill: #c5c8c6 }
-.terminal-2526263208-r4 { fill: #c2c2bf }
-.terminal-2526263208-r5 { fill: #272822 }
-.terminal-2526263208-r6 { fill: #75715e }
-.terminal-2526263208-r7 { fill: #f8f8f2 }
-.terminal-2526263208-r8 { fill: #90908a }
-.terminal-2526263208-r9 { fill: #a6e22e }
-.terminal-2526263208-r10 { fill: #ae81ff }
-.terminal-2526263208-r11 { fill: #e6db74 }
-.terminal-2526263208-r12 { fill: #f92672 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #c2c2bf }
+.terminal-r5 { fill: #272822 }
+.terminal-r6 { fill: #75715e }
+.terminal-r7 { fill: #f8f8f2 }
+.terminal-r8 { fill: #90908a }
+.terminal-r9 { fill: #a6e22e }
+.terminal-r10 { fill: #ae81ff }
+.terminal-r11 { fill: #e6db74 }
+.terminal-r12 { fill: #f92672 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊ 1 /* This is a comment in CSS */▎
-▊ 2 ▎
-▊ 3 /* Basic selectors and properties */▎
-▊ 4 body { ▎
-▊ 5 font-family: Arial, sans-serif; ▎
-▊ 6 background-color: #f4f4f4; ▎
-▊ 7 margin: 0; ▎
-▊ 8 padding: 0; ▎
-▊ 9 } ▎
-▊10 ▎
-▊11 /* Class and ID selectors */▎
-▊12 .header { ▎
-▊13 background-color: #333; ▎
-▊14 color: #fff; ▎
-▊15 padding: 10px0; ▎
-▊16 text-align: center; ▎
-▊17 } ▎
-▊18 ▎
-▊19 #logo { ▎
-▊20 font-size: 24px; ▎
-▊21 font-weight: bold; ▎
-▊22 } ▎
-▊23 ▎
-▊24 /* Descendant and child selectors */▎
-▊25 .navul { ▎
-▊26 list-style-type: none; ▎
-▊27 padding: 0; ▎
-▊28 } ▎
-▊29 ▎
-▊30 .nav > li { ▎
-▊31 display: inline-block; ▎
-▊32 margin-right: 10px; ▎
-▊33 } ▎
-▊34 ▎
-▊35 /* Pseudo-classes */▎
-▊36 a:hover { ▎
-▊37 text-decoration: underline; ▎
-▊38 } ▎
-▊39 ▎
-▊40 input:focus { ▎
-▊41 border-color: #007BFF; ▎
-▊42 } ▎
-▊43 ▎
-▊44 /* Media query */▎
-▊45 @media (max-width: 768px) { ▎
-▊46 body { ▎
-▊47 font-size: 16px; ▎
-▊48 } ▎
-▊49 ▎
-▊50 .header { ▎
-▊51 padding: 5px0; ▎
-▊52 } ▎
-▊53 } ▎
-▊54 ▎
-▊55 /* Keyframes animation */▎
-▊56 @keyframes slideIn { ▎
-▊57 from { ▎
-▊58 transform: translateX(-100%); ▎
-▊59 } ▎
-▊60 to { ▎
-▊61 transform: translateX(0); ▎
-▊62 } ▎
-▊63 } ▎
-▊64 ▎
-▊65 .slide-in-element { ▎
-▊66 animation: slideIn0.5sforwards; ▎
-▊67 } ▎
-▊68 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊ 1 /* This is a comment in CSS */▎
+▊ 2 ▎
+▊ 3 /* Basic selectors and properties */▎
+▊ 4 body { ▎
+▊ 5 font-family: Arial, sans-serif; ▎
+▊ 6 background-color: #f4f4f4; ▎
+▊ 7 margin: 0; ▎
+▊ 8 padding: 0; ▎
+▊ 9 } ▎
+▊10 ▎
+▊11 /* Class and ID selectors */▎
+▊12 .header { ▎
+▊13 background-color: #333; ▎
+▊14 color: #fff; ▎
+▊15 padding: 10px0; ▎
+▊16 text-align: center; ▎
+▊17 } ▎
+▊18 ▎
+▊19 #logo { ▎
+▊20 font-size: 24px; ▎
+▊21 font-weight: bold; ▎
+▊22 } ▎
+▊23 ▎
+▊24 /* Descendant and child selectors */▎
+▊25 .navul { ▎
+▊26 list-style-type: none; ▎
+▊27 padding: 0; ▎
+▊28 } ▎
+▊29 ▎
+▊30 .nav > li { ▎
+▊31 display: inline-block; ▎
+▊32 margin-right: 10px; ▎
+▊33 } ▎
+▊34 ▎
+▊35 /* Pseudo-classes */▎
+▊36 a:hover { ▎
+▊37 text-decoration: underline; ▎
+▊38 } ▎
+▊39 ▎
+▊40 input:focus { ▎
+▊41 border-color: #007BFF; ▎
+▊42 } ▎
+▊43 ▎
+▊44 /* Media query */▎
+▊45 @media (max-width: 768px) { ▎
+▊46 body { ▎
+▊47 font-size: 16px; ▎
+▊48 } ▎
+▊49 ▎
+▊50 .header { ▎
+▊51 padding: 5px0; ▎
+▊52 } ▎
+▊53 } ▎
+▊54 ▎
+▊55 /* Keyframes animation */▎
+▊56 @keyframes slideIn { ▎
+▊57 from { ▎
+▊58 transform: translateX(-100%); ▎
+▊59 } ▎
+▊60 to { ▎
+▊61 transform: translateX(0); ▎
+▊62 } ▎
+▊63 } ▎
+▊64 ▎
+▊65 .slide-in-element { ▎
+▊66 animation: slideIn 0.5s forwards; ▎
+▊67 } ▎
+▊68 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[java].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[java].svg
index 02656c7fec..bf808befa2 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[java].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[java].svg
@@ -19,476 +19,476 @@
font-weight: 700;
}
- .terminal-1303054993-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-1303054993-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-1303054993-r1 { fill: #121212 }
-.terminal-1303054993-r2 { fill: #0178d4 }
-.terminal-1303054993-r3 { fill: #c5c8c6 }
-.terminal-1303054993-r4 { fill: #c2c2bf }
-.terminal-1303054993-r5 { fill: #272822 }
-.terminal-1303054993-r6 { fill: #f92672 }
-.terminal-1303054993-r7 { fill: #f8f8f2 }
-.terminal-1303054993-r8 { fill: #a6e22e }
-.terminal-1303054993-r9 { fill: #90908a }
-.terminal-1303054993-r10 { fill: #75715e }
-.terminal-1303054993-r11 { fill: #ae81ff }
-.terminal-1303054993-r12 { fill: #e6db74 }
-.terminal-1303054993-r13 { fill: #66d9ef;font-style: italic; }
-.terminal-1303054993-r14 { fill: #003054 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #c2c2bf }
+.terminal-r5 { fill: #272822 }
+.terminal-r6 { fill: #f92672 }
+.terminal-r7 { fill: #f8f8f2 }
+.terminal-r8 { fill: #90908a }
+.terminal-r9 { fill: #75715e }
+.terminal-r10 { fill: #a6e22e }
+.terminal-r11 { fill: #ae81ff }
+.terminal-r12 { fill: #e6db74 }
+.terminal-r13 { fill: #66d9ef;font-style: italic; }
+.terminal-r14 { fill: #003054 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊ 1 importjava.util.ArrayList; ▎
-▊ 2 importjava.util.HashMap; ▎
-▊ 3 importjava.util.List; ▎
-▊ 4 importjava.util.Map; ▎
-▊ 5 ▎
-▊ 6 // Classes and interfaces▎
-▊ 7 interfaceShape { ▎
-▊ 8 double getArea(); ▎
-▊ 9 } ▎
-▊ 10 ▎
-▊ 11 classRectangleimplementsShape { ▎
-▊ 12 privatedouble width; ▎
-▊ 13 privatedouble height; ▎
-▊ 14 ▎
-▊ 15 publicRectangle(double width, double height) { ▎
-▊ 16 this.width = width; ▎
-▊ 17 this.height = height; ▎
-▊ 18 } ▎
-▊ 19 ▎
-▊ 20 @Override ▎
-▊ 21 publicdouble getArea() { ▎
-▊ 22 return width * height; ▎
-▊ 23 } ▎
-▊ 24 } ▎
-▊ 25 ▎
-▊ 26 // Enums▎
-▊ 27 enumDaysOfWeek { ▎
-▊ 28 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ▎
-▊ 29 } ▎
-▊ 30 ▎
-▊ 31 publicclassMain { ▎
-▊ 32 // Constants▎
-▊ 33 privatestaticfinaldouble PI = 3.14159; ▎
-▊ 34 ▎
-▊ 35 // Methods▎
-▊ 36 publicstaticint sum(int a, int b) { ▎
-▊ 37 return a + b; ▎
-▊ 38 } ▎
-▊ 39 ▎
-▊ 40 publicstaticvoid main(String[] args) { ▎
-▊ 41 // Variables▎
-▊ 42 String name = "John"; ▎
-▊ 43 int age = 30; ▎
-▊ 44 boolean isStudent = true; ▎
-▊ 45 ▎
-▊ 46 // Printing variables▎
-▊ 47 System.out.println("Hello, " + name + "! You are " + age + " ye▎
-▊ 48 ▎
-▊ 49 // Conditional statements▎
-▊ 50 if (age >= 18 && isStudent) { ▎
-▊ 51 System.out.println("You are an adult student."); ▎
-▊ 52 } elseif (age >= 18) { ▎
-▊ 53 System.out.println("You are an adult."); ▎
-▊ 54 } else { ▎
-▊ 55 System.out.println("You are a minor."); ▎
-▊ 56 } ▎
-▊ 57 ▎
-▊ 58 // Arrays▎
-▊ 59 int[] numbers = {1, 2, 3, 4, 5}; ▎
-▊ 60 System.out.println("Numbers: " + Arrays.toString(numbers)); ▎
-▊ 61 ▎
-▊ 62 // Lists▎
-▊ 63 List<String> fruits = newArrayList<>(); ▎
-▊ 64 fruits.add("apple"); ▎
-▊ 65 fruits.add("banana"); ▎
-▊ 66 fruits.add("orange"); ▎
-▊ 67 System.out.println("Fruits: " + fruits); ▎
-▊ 68 ▎
-▊ 69 // Loops▎
-▊ 70 for (int num : numbers) { ▎
-▊ 71 System.out.println("Number: " + num); ▎
-▊ 72 } ▎
-▊ 73 ▎
-▊ 74 // Hash maps▎
-▊ 75 Map<String, Integer> scores = newHashMap<>(); ▎
-▊ 76 scores.put("Alice", 100); ▎
-▊ 77 scores.put("Bob", 80); ▎
-▊ 78 System.out.println("Alice's score: " + scores.get("Alice")); ▎
-▊ 79 ▎
-▊ 80 // Exception handling▎
-▊ 81 try { ▎
-▊ 82 int result = 10 / 0; ▎
-▊ 83 } catch (ArithmeticException e) { ▎
-▊ 84 System.out.println("Error: " + e.getMessage()); ▎
-▊ 85 } ▎
-▊ 86 ▎
-▊ 87 // Instantiating objects▎
-▊ 88 Rectangle rect = newRectangle(10, 20); ▎
-▊ 89 System.out.println("Rectangle area: " + rect.getArea()); ▎
-▊ 90 ▎
-▊ 91 // Enums▎
-▊ 92 DaysOfWeek today = DaysOfWeek.MONDAY; ▎
-▊ 93 System.out.println("Today is " + today); ▎
-▊ 94 ▎
-▊ 95 // Calling methods▎
-▊ 96 int sum = sum(5, 10); ▎
-▊ 97 System.out.println("Sum: " + sum); ▎
-▊ 98 ▎
-▊ 99 // Ternary operator▎
-▊100 String message = age >= 18 ? "You are an adult." : "You are a m▎
-▊101 System.out.println(message); ▎
-▊102 } ▎
-▊103 } ▎
-▊104 ▎
-▊▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊ 1 import java.util.ArrayList; ▎
+▊ 2 import java.util.HashMap; ▎
+▊ 3 import java.util.List; ▎
+▊ 4 import java.util.Map; ▎
+▊ 5 ▎
+▊ 6 // Classes and interfaces▎
+▊ 7 interfaceShape { ▎
+▊ 8 double getArea(); ▎
+▊ 9 } ▎
+▊ 10 ▎
+▊ 11 classRectangleimplementsShape { ▎
+▊ 12 privatedouble width; ▎
+▊ 13 privatedouble height; ▎
+▊ 14 ▎
+▊ 15 publicRectangle(double width, double height) { ▎
+▊ 16 this.width = width; ▎
+▊ 17 this.height = height; ▎
+▊ 18 } ▎
+▊ 19 ▎
+▊ 20 @Override ▎
+▊ 21 publicdouble getArea() { ▎
+▊ 22 return width * height; ▎
+▊ 23 } ▎
+▊ 24 } ▎
+▊ 25 ▎
+▊ 26 // Enums▎
+▊ 27 enumDaysOfWeek { ▎
+▊ 28 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY ▎
+▊ 29 } ▎
+▊ 30 ▎
+▊ 31 publicclassMain { ▎
+▊ 32 // Constants▎
+▊ 33 privatestaticfinaldouble PI = 3.14159; ▎
+▊ 34 ▎
+▊ 35 // Methods▎
+▊ 36 publicstaticint sum(int a, int b) { ▎
+▊ 37 return a + b; ▎
+▊ 38 } ▎
+▊ 39 ▎
+▊ 40 publicstaticvoid main(String[] args) { ▎
+▊ 41 // Variables▎
+▊ 42 String name = "John"; ▎
+▊ 43 int age = 30; ▎
+▊ 44 boolean isStudent = true; ▎
+▊ 45 ▎
+▊ 46 // Printing variables▎
+▊ 47 System.out.println("Hello, " + name + "! You are " + age + " ye▎
+▊ 48 ▎
+▊ 49 // Conditional statements▎
+▊ 50 if (age >= 18 && isStudent) { ▎
+▊ 51 System.out.println("You are an adult student."); ▎
+▊ 52 } elseif (age >= 18) { ▎
+▊ 53 System.out.println("You are an adult."); ▎
+▊ 54 } else { ▎
+▊ 55 System.out.println("You are a minor."); ▎
+▊ 56 } ▎
+▊ 57 ▎
+▊ 58 // Arrays▎
+▊ 59 int[] numbers = {1, 2, 3, 4, 5}; ▎
+▊ 60 System.out.println("Numbers: " + Arrays.toString(numbers)); ▎
+▊ 61 ▎
+▊ 62 // Lists▎
+▊ 63 List<String> fruits = newArrayList<>(); ▎
+▊ 64 fruits.add("apple"); ▎
+▊ 65 fruits.add("banana"); ▎
+▊ 66 fruits.add("orange"); ▎
+▊ 67 System.out.println("Fruits: " + fruits); ▎
+▊ 68 ▎
+▊ 69 // Loops▎
+▊ 70 for (int num : numbers) { ▎
+▊ 71 System.out.println("Number: " + num); ▎
+▊ 72 } ▎
+▊ 73 ▎
+▊ 74 // Hash maps▎
+▊ 75 Map<String, Integer> scores = newHashMap<>(); ▎
+▊ 76 scores.put("Alice", 100); ▎
+▊ 77 scores.put("Bob", 80); ▎
+▊ 78 System.out.println("Alice's score: " + scores.get("Alice")); ▎
+▊ 79 ▎
+▊ 80 // Exception handling▎
+▊ 81 try { ▎
+▊ 82 int result = 10 / 0; ▎
+▊ 83 } catch (ArithmeticException e) { ▎
+▊ 84 System.out.println("Error: " + e.getMessage()); ▎
+▊ 85 } ▎
+▊ 86 ▎
+▊ 87 // Instantiating objects▎
+▊ 88 Rectangle rect = newRectangle(10, 20); ▎
+▊ 89 System.out.println("Rectangle area: " + rect.getArea()); ▎
+▊ 90 ▎
+▊ 91 // Enums▎
+▊ 92 DaysOfWeek today = DaysOfWeek.MONDAY; ▎
+▊ 93 System.out.println("Today is " + today); ▎
+▊ 94 ▎
+▊ 95 // Calling methods▎
+▊ 96 int sum = sum(5, 10); ▎
+▊ 97 System.out.println("Sum: " + sum); ▎
+▊ 98 ▎
+▊ 99 // Ternary operator▎
+▊100 String message = age >= 18 ? "You are an adult." : "You are a m▎
+▊101 System.out.println(message); ▎
+▊102 } ▎
+▊103 } ▎
+▊104 ▎
+▊▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[javascript].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[javascript].svg
index 645ea326fa..210ce01926 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[javascript].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[javascript].svg
@@ -19,371 +19,371 @@
font-weight: 700;
}
- .terminal-2506662657-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-2506662657-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-2506662657-r1 { fill: #121212 }
-.terminal-2506662657-r2 { fill: #0178d4 }
-.terminal-2506662657-r3 { fill: #c5c8c6 }
-.terminal-2506662657-r4 { fill: #c2c2bf }
-.terminal-2506662657-r5 { fill: #272822 }
-.terminal-2506662657-r6 { fill: #75715e }
-.terminal-2506662657-r7 { fill: #f8f8f2 }
-.terminal-2506662657-r8 { fill: #90908a }
-.terminal-2506662657-r9 { fill: #f92672 }
-.terminal-2506662657-r10 { fill: #e6db74 }
-.terminal-2506662657-r11 { fill: #ae81ff }
-.terminal-2506662657-r12 { fill: #66d9ef;font-style: italic; }
-.terminal-2506662657-r13 { fill: #a6e22e }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #c2c2bf }
+.terminal-r5 { fill: #272822 }
+.terminal-r6 { fill: #75715e }
+.terminal-r7 { fill: #f8f8f2 }
+.terminal-r8 { fill: #90908a }
+.terminal-r9 { fill: #f92672 }
+.terminal-r10 { fill: #e6db74 }
+.terminal-r11 { fill: #ae81ff }
+.terminal-r12 { fill: #66d9ef;font-style: italic; }
+.terminal-r13 { fill: #a6e22e }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊ 1 // Variable declarations▎
-▊ 2 const name = "John"; ▎
-▊ 3 let age = 30; ▎
-▊ 4 var isStudent = true; ▎
-▊ 5 ▎
-▊ 6 // Template literals▎
-▊ 7 console.log(`Hello, ${name}! You are ${age} years old.`); ▎
-▊ 8 ▎
-▊ 9 // Conditional statements▎
-▊10 if (age >= 18 && isStudent) { ▎
-▊11 console.log("You are an adult student."); ▎
-▊12 } elseif (age >= 18) { ▎
-▊13 console.log("You are an adult."); ▎
-▊14 } else { ▎
-▊15 console.log("You are a minor."); ▎
-▊16 } ▎
-▊17 ▎
-▊18 // Arrays and array methods▎
-▊19 const numbers = [1, 2, 3, 4, 5]; ▎
-▊20 const doubledNumbers = numbers.map((num) => num * 2); ▎
-▊21 console.log("Doubled numbers:", doubledNumbers); ▎
-▊22 ▎
-▊23 // Objects▎
-▊24 const person = { ▎
-▊25 firstName: "John", ▎
-▊26 lastName: "Doe", ▎
-▊27 getFullName() { ▎
-▊28 return`${this.firstName}${this.lastName}`; ▎
-▊29 }, ▎
-▊30 }; ▎
-▊31 console.log("Full name:", person.getFullName()); ▎
-▊32 ▎
-▊33 // Classes▎
-▊34 class Rectangle { ▎
-▊35 constructor(width, height) { ▎
-▊36 this.width = width; ▎
-▊37 this.height = height; ▎
-▊38 } ▎
-▊39 ▎
-▊40 getArea() { ▎
-▊41 return this.width * this.height; ▎
-▊42 } ▎
-▊43 } ▎
-▊44 const rectangle = new Rectangle(5, 3); ▎
-▊45 console.log("Rectangle area:", rectangle.getArea()); ▎
-▊46 ▎
-▊47 // Async/Await and Promises▎
-▊48 asyncfunctionfetchData() { ▎
-▊49 try { ▎
-▊50 const response = awaitfetch("https://api.example.com/data"); ▎
-▊51 const data = await response.json(); ▎
-▊52 console.log("Fetched data:", data); ▎
-▊53 } catch (error) { ▎
-▊54 console.error("Error:", error); ▎
-▊55 } ▎
-▊56 } ▎
-▊57 fetchData(); ▎
-▊58 ▎
-▊59 // Arrow functions▎
-▊60 constgreet = (name) => { ▎
-▊61 console.log(`Hello, ${name}!`); ▎
-▊62 }; ▎
-▊63 greet("Alice"); ▎
-▊64 ▎
-▊65 // Destructuring assignment▎
-▊66 const [a, b, ...rest] = [1, 2, 3, 4, 5]; ▎
-▊67 console.log(a, b, rest); ▎
-▊68 ▎
-▊69 // Spread operator▎
-▊70 const arr1 = [1, 2, 3]; ▎
-▊71 const arr2 = [4, 5, 6]; ▎
-▊72 const combinedArr = [...arr1, ...arr2]; ▎
-▊73 console.log("Combined array:", combinedArr); ▎
-▊74 ▎
-▊75 // Ternary operator▎
-▊76 const message = age >= 18 ? "You are an adult." : "You are a minor."; ▎
-▊77 console.log(message); ▎
-▊78 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊ 1 // Variable declarations▎
+▊ 2 const name = "John"; ▎
+▊ 3 let age = 30; ▎
+▊ 4 var isStudent = true; ▎
+▊ 5 ▎
+▊ 6 // Template literals▎
+▊ 7 console.log(`Hello, ${name}! You are ${age} years old.`); ▎
+▊ 8 ▎
+▊ 9 // Conditional statements▎
+▊10 if (age >= 18 && isStudent) { ▎
+▊11 console.log("You are an adult student."); ▎
+▊12 } elseif (age >= 18) { ▎
+▊13 console.log("You are an adult."); ▎
+▊14 } else { ▎
+▊15 console.log("You are a minor."); ▎
+▊16 } ▎
+▊17 ▎
+▊18 // Arrays and array methods▎
+▊19 const numbers = [1, 2, 3, 4, 5]; ▎
+▊20 const doubledNumbers = numbers.map((num) => num * 2); ▎
+▊21 console.log("Doubled numbers:", doubledNumbers); ▎
+▊22 ▎
+▊23 // Objects▎
+▊24 const person = { ▎
+▊25 firstName: "John", ▎
+▊26 lastName: "Doe", ▎
+▊27 getFullName() { ▎
+▊28 return`${this.firstName}${this.lastName}`; ▎
+▊29 }, ▎
+▊30 }; ▎
+▊31 console.log("Full name:", person.getFullName()); ▎
+▊32 ▎
+▊33 // Classes▎
+▊34 class Rectangle { ▎
+▊35 constructor(width, height) { ▎
+▊36 this.width = width; ▎
+▊37 this.height = height; ▎
+▊38 } ▎
+▊39 ▎
+▊40 getArea() { ▎
+▊41 return this.width * this.height; ▎
+▊42 } ▎
+▊43 } ▎
+▊44 const rectangle = new Rectangle(5, 3); ▎
+▊45 console.log("Rectangle area:", rectangle.getArea()); ▎
+▊46 ▎
+▊47 // Async/Await and Promises▎
+▊48 asyncfunctionfetchData() { ▎
+▊49 try { ▎
+▊50 const response = awaitfetch("https://api.example.com/data"); ▎
+▊51 const data = await response.json(); ▎
+▊52 console.log("Fetched data:", data); ▎
+▊53 } catch (error) { ▎
+▊54 console.error("Error:", error); ▎
+▊55 } ▎
+▊56 } ▎
+▊57 fetchData(); ▎
+▊58 ▎
+▊59 // Arrow functions▎
+▊60 constgreet = (name) => { ▎
+▊61 console.log(`Hello, ${name}!`); ▎
+▊62 }; ▎
+▊63 greet("Alice"); ▎
+▊64 ▎
+▊65 // Destructuring assignment▎
+▊66 const [a, b, ...rest] = [1, 2, 3, 4, 5]; ▎
+▊67 console.log(a, b, rest); ▎
+▊68 ▎
+▊69 // Spread operator▎
+▊70 const arr1 = [1, 2, 3]; ▎
+▊71 const arr2 = [4, 5, 6]; ▎
+▊72 const combinedArr = [...arr1, ...arr2]; ▎
+▊73 console.log("Combined array:", combinedArr); ▎
+▊74 ▎
+▊75 // Ternary operator▎
+▊76 const message = age >= 18 ? "You are an adult." : "You are a minor."; ▎
+▊77 console.log(message); ▎
+▊78 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[python].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[python].svg
index 92ffdc54f9..104f19603d 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[python].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[python].svg
@@ -19,375 +19,375 @@
font-weight: 700;
}
- .terminal-202856356-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-202856356-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-202856356-r1 { fill: #121212 }
-.terminal-202856356-r2 { fill: #0178d4 }
-.terminal-202856356-r3 { fill: #c5c8c6 }
-.terminal-202856356-r4 { fill: #c2c2bf }
-.terminal-202856356-r5 { fill: #272822 }
-.terminal-202856356-r6 { fill: #f92672 }
-.terminal-202856356-r7 { fill: #f8f8f2 }
-.terminal-202856356-r8 { fill: #90908a }
-.terminal-202856356-r9 { fill: #75715e }
-.terminal-202856356-r10 { fill: #e6db74 }
-.terminal-202856356-r11 { fill: #ae81ff }
-.terminal-202856356-r12 { fill: #a6e22e }
-.terminal-202856356-r13 { fill: #003054 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #c2c2bf }
+.terminal-r5 { fill: #272822 }
+.terminal-r6 { fill: #f92672 }
+.terminal-r7 { fill: #f8f8f2 }
+.terminal-r8 { fill: #90908a }
+.terminal-r9 { fill: #75715e }
+.terminal-r10 { fill: #e6db74 }
+.terminal-r11 { fill: #ae81ff }
+.terminal-r12 { fill: #a6e22e }
+.terminal-r13 { fill: #003054 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊ 1 import math ▎
-▊ 2 from os import path ▎
-▊ 3 ▎
-▊ 4 # I'm a comment :)▎
-▊ 5 ▎
-▊ 6 string_var = "Hello, world!"▎
-▊ 7 int_var = 42▎
-▊ 8 float_var = 3.14▎
-▊ 9 complex_var = 1 + 2j▎
-▊10 ▎
-▊11 list_var = [1, 2, 3, 4, 5] ▎
-▊12 tuple_var = (1, 2, 3, 4, 5) ▎
-▊13 set_var = {1, 2, 3, 4, 5} ▎
-▊14 dict_var = {"a": 1, "b": 2, "c": 3} ▎
-▊15 ▎
-▊16 deffunction_no_args(): ▎
-▊17 return"No arguments"▎
-▊18 ▎
-▊19 deffunction_with_args(a, b): ▎
-▊20 return a + b ▎
-▊21 ▎
-▊22 deffunction_with_default_args(a=0, b=0): ▎
-▊23 return a * b ▎
-▊24 ▎
-▊25 lambda_func = lambda x: x**2▎
-▊26 ▎
-▊27 if int_var == 42: ▎
-▊28 print("It's the answer!") ▎
-▊29 elif int_var < 42: ▎
-▊30 print("Less than the answer.") ▎
-▊31 else: ▎
-▊32 print("Greater than the answer.") ▎
-▊33 ▎
-▊34 for index, value inenumerate(list_var): ▎
-▊35 print(f"Index: {index}, Value: {value}") ▎
-▊36 ▎
-▊37 counter = 0▎
-▊38 while counter < 5: ▎
-▊39 print(f"Counter value: {counter}") ▎
-▊40 counter += 1▎
-▊41 ▎
-▊42 squared_numbers = [x**2for x inrange(10) if x % 2 == 0] ▎
-▊43 ▎
-▊44 try: ▎
-▊45 result = 10 / 0▎
-▊46 except ZeroDivisionError: ▎
-▊47 print("Cannot divide by zero!") ▎
-▊48 finally: ▎
-▊49 print("End of try-except block.") ▎
-▊50 ▎
-▊51 classAnimal: ▎
-▊52 def__init__(self, name): ▎
-▊53 self.name = name ▎
-▊54 ▎
-▊55 defspeak(self): ▎
-▊56 raiseNotImplementedError("Subclasses must implement this method▎
-▊57 ▎
-▊58 classDog(Animal): ▎
-▊59 defspeak(self): ▎
-▊60 returnf"{self.name} says Woof!"▎
-▊61 ▎
-▊62 deffibonacci(n): ▎
-▊63 a, b = 0, 1▎
-▊64 for _ inrange(n): ▎
-▊65 yield a ▎
-▊66 a, b = b, a + b ▎
-▊67 ▎
-▊68 for num infibonacci(5): ▎
-▊69 print(num) ▎
-▊70 ▎
-▊71 withopen('test.txt', 'w') as f: ▎
-▊72 f.write("Testing with statement.") ▎
-▊73 ▎
-▊74 @my_decorator ▎
-▊75 defsay_hello(): ▎
-▊76 print("Hello!") ▎
-▊77 ▎
-▊78 say_hello() ▎
-▊79 ▎
-▊▎▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊ 1 import math ▎
+▊ 2 from os import path ▎
+▊ 3 ▎
+▊ 4 # I'm a comment :)▎
+▊ 5 ▎
+▊ 6 string_var = "Hello, world!"▎
+▊ 7 int_var = 42▎
+▊ 8 float_var = 3.14▎
+▊ 9 complex_var = 1 + 2j▎
+▊10 ▎
+▊11 list_var = [1, 2, 3, 4, 5] ▎
+▊12 tuple_var = (1, 2, 3, 4, 5) ▎
+▊13 set_var = {1, 2, 3, 4, 5} ▎
+▊14 dict_var = {"a": 1, "b": 2, "c": 3} ▎
+▊15 ▎
+▊16 deffunction_no_args(): ▎
+▊17 return"No arguments"▎
+▊18 ▎
+▊19 deffunction_with_args(a, b): ▎
+▊20 return a + b ▎
+▊21 ▎
+▊22 deffunction_with_default_args(a=0, b=0): ▎
+▊23 return a * b ▎
+▊24 ▎
+▊25 lambda_func = lambda x: x**2▎
+▊26 ▎
+▊27 if int_var == 42: ▎
+▊28 print("It's the answer!") ▎
+▊29 elif int_var < 42: ▎
+▊30 print("Less than the answer.") ▎
+▊31 else: ▎
+▊32 print("Greater than the answer.") ▎
+▊33 ▎
+▊34 for index, value inenumerate(list_var): ▎
+▊35 print(f"Index: {index}, Value: {value}") ▎
+▊36 ▎
+▊37 counter = 0▎
+▊38 while counter < 5: ▎
+▊39 print(f"Counter value: {counter}") ▎
+▊40 counter += 1▎
+▊41 ▎
+▊42 squared_numbers = [x**2for x inrange(10) if x % 2 == 0] ▎
+▊43 ▎
+▊44 try: ▎
+▊45 result = 10 / 0▎
+▊46 exceptZeroDivisionError: ▎
+▊47 print("Cannot divide by zero!") ▎
+▊48 finally: ▎
+▊49 print("End of try-except block.") ▎
+▊50 ▎
+▊51 classAnimal: ▎
+▊52 def__init__(self, name): ▎
+▊53 self.name = name ▎
+▊54 ▎
+▊55 defspeak(self): ▎
+▊56 raiseNotImplementedError("Subclasses must implement this method▎
+▊57 ▎
+▊58 classDog(Animal): ▎
+▊59 defspeak(self): ▎
+▊60 returnf"{self.name} says Woof!"▎
+▊61 ▎
+▊62 deffibonacci(n): ▎
+▊63 a, b = 0, 1▎
+▊64 for _ inrange(n): ▎
+▊65 yield a ▎
+▊66 a, b = b, a + b ▎
+▊67 ▎
+▊68 for num infibonacci(5): ▎
+▊69 print(num) ▎
+▊70 ▎
+▊71 withopen('test.txt', 'w') as f: ▎
+▊72 f.write("Testing with statement.") ▎
+▊73 ▎
+▊74 @my_decorator ▎
+▊75 defsay_hello(): ▎
+▊76 print("Hello!") ▎
+▊77 ▎
+▊78 say_hello() ▎
+▊79 ▎
+▊▎▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[rust].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[rust].svg
index 5552dc5849..da8e8479f7 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[rust].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_language_rendering[rust].svg
@@ -19,479 +19,479 @@
font-weight: 700;
}
- .terminal-1133178079-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-1133178079-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-1133178079-r1 { fill: #121212 }
-.terminal-1133178079-r2 { fill: #0178d4 }
-.terminal-1133178079-r3 { fill: #c5c8c6 }
-.terminal-1133178079-r4 { fill: #c2c2bf }
-.terminal-1133178079-r5 { fill: #272822 }
-.terminal-1133178079-r6 { fill: #f92672 }
-.terminal-1133178079-r7 { fill: #f8f8f2 }
-.terminal-1133178079-r8 { fill: #a6e22e }
-.terminal-1133178079-r9 { fill: #90908a }
-.terminal-1133178079-r10 { fill: #75715e }
-.terminal-1133178079-r11 { fill: #66d9ef;font-style: italic; }
-.terminal-1133178079-r12 { fill: #e6db74 }
-.terminal-1133178079-r13 { fill: #003054 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #c2c2bf }
+.terminal-r5 { fill: #272822 }
+.terminal-r6 { fill: #f92672 }
+.terminal-r7 { fill: #f8f8f2 }
+.terminal-r8 { fill: #90908a }
+.terminal-r9 { fill: #75715e }
+.terminal-r10 { fill: #66d9ef;font-style: italic; }
+.terminal-r11 { fill: #a6e22e }
+.terminal-r12 { fill: #e6db74 }
+.terminal-r13 { fill: #003054 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊ 1 usestd::collections::HashMap; ▎
-▊ 2 ▎
-▊ 3 // Constants▎
-▊ 4 const PI: f64 = 3.14159; ▎
-▊ 5 ▎
-▊ 6 // Structs▎
-▊ 7 structRectangle { ▎
-▊ 8 width: u32, ▎
-▊ 9 height: u32, ▎
-▊ 10 } ▎
-▊ 11 ▎
-▊ 12 implRectangle { ▎
-▊ 13 fnarea(&self) -> u32 { ▎
-▊ 14 self.width * self.height ▎
-▊ 15 } ▎
-▊ 16 } ▎
-▊ 17 ▎
-▊ 18 // Enums▎
-▊ 19 enumResult<T, E> { ▎
-▊ 20 Ok(T), ▎
-▊ 21 Err(E), ▎
-▊ 22 } ▎
-▊ 23 ▎
-▊ 24 // Functions▎
-▊ 25 fngreet(name: &str) { ▎
-▊ 26 println!("Hello, {}!", name); ▎
-▊ 27 } ▎
-▊ 28 ▎
-▊ 29 fnmain() { ▎
-▊ 30 // Variables▎
-▊ 31 let name = "John"; ▎
-▊ 32 letmut age = 30; ▎
-▊ 33 let is_student = true; ▎
-▊ 34 ▎
-▊ 35 // Printing variables▎
-▊ 36 println!("Hello, {}! You are {} years old.", name, age); ▎
-▊ 37 ▎
-▊ 38 // Conditional statements▎
-▊ 39 if age >= 18 && is_student { ▎
-▊ 40 println!("You are an adult student."); ▎
-▊ 41 } elseif age >= 18 { ▎
-▊ 42 println!("You are an adult."); ▎
-▊ 43 } else { ▎
-▊ 44 println!("You are a minor."); ▎
-▊ 45 } ▎
-▊ 46 ▎
-▊ 47 // Arrays▎
-▊ 48 let numbers = [1, 2, 3, 4, 5]; ▎
-▊ 49 println!("Numbers: {:?}", numbers); ▎
-▊ 50 ▎
-▊ 51 // Vectors▎
-▊ 52 letmut fruits = vec!["apple", "banana", "orange"]; ▎
-▊ 53 fruits.push("grape"); ▎
-▊ 54 println!("Fruits: {:?}", fruits); ▎
-▊ 55 ▎
-▊ 56 // Loops▎
-▊ 57 for num in &numbers { ▎
-▊ 58 println!("Number: {}", num); ▎
-▊ 59 } ▎
-▊ 60 ▎
-▊ 61 // Pattern matching▎
-▊ 62 let result = Result::Ok(42); ▎
-▊ 63 match result { ▎
-▊ 64 Result::Ok(value) => println!("Value: {}", value), ▎
-▊ 65 Result::Err(error) => println!("Error: {:?}", error), ▎
-▊ 66 } ▎
-▊ 67 ▎
-▊ 68 // Ownership and borrowing▎
-▊ 69 let s1 = String::from("hello"); ▎
-▊ 70 let s2 = s1.clone(); ▎
-▊ 71 println!("s1: {}, s2: {}", s1, s2); ▎
-▊ 72 ▎
-▊ 73 // References▎
-▊ 74 let rect = Rectangle { ▎
-▊ 75 width: 10, ▎
-▊ 76 height: 20, ▎
-▊ 77 }; ▎
-▊ 78 println!("Rectangle area: {}", rect.area()); ▎
-▊ 79 ▎
-▊ 80 // Hash maps▎
-▊ 81 letmut scores = HashMap::new(); ▎
-▊ 82 scores.insert("Alice", 100); ▎
-▊ 83 scores.insert("Bob", 80); ▎
-▊ 84 println!("Alice's score: {}", scores["Alice"]); ▎
-▊ 85 ▎
-▊ 86 // Closures▎
-▊ 87 let square = |num: i32| num * num; ▎
-▊ 88 println!("Square of 5: {}", square(5)); ▎
-▊ 89 ▎
-▊ 90 // Traits▎
-▊ 91 traitPrintable { ▎
-▊ 92 fnprint(&self); ▎
-▊ 93 } ▎
-▊ 94 ▎
-▊ 95 implPrintableforRectangle { ▎
-▊ 96 fnprint(&self) { ▎
-▊ 97 println!("Rectangle: width={}, height={}", self.width, self▎
-▊ 98 } ▎
-▊ 99 } ▎
-▊100 rect.print(); ▎
-▊101 ▎
-▊102 // Modules▎
-▊103 greet("Alice"); ▎
-▊104 } ▎
-▊105 ▎
-▊▎▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊ 1 use std::collections::HashMap; ▎
+▊ 2 ▎
+▊ 3 // Constants▎
+▊ 4 const PI: f64 = 3.14159; ▎
+▊ 5 ▎
+▊ 6 // Structs▎
+▊ 7 structRectangle { ▎
+▊ 8 width: u32, ▎
+▊ 9 height: u32, ▎
+▊ 10 } ▎
+▊ 11 ▎
+▊ 12 implRectangle { ▎
+▊ 13 fnarea(&self) -> u32 { ▎
+▊ 14 self.width * self.height ▎
+▊ 15 } ▎
+▊ 16 } ▎
+▊ 17 ▎
+▊ 18 // Enums▎
+▊ 19 enumResult<T, E> { ▎
+▊ 20 Ok(T), ▎
+▊ 21 Err(E), ▎
+▊ 22 } ▎
+▊ 23 ▎
+▊ 24 // Functions▎
+▊ 25 fngreet(name: &str) { ▎
+▊ 26 println!("Hello, {}!", name); ▎
+▊ 27 } ▎
+▊ 28 ▎
+▊ 29 fnmain() { ▎
+▊ 30 // Variables▎
+▊ 31 let name = "John"; ▎
+▊ 32 letmut age = 30; ▎
+▊ 33 let is_student = true; ▎
+▊ 34 ▎
+▊ 35 // Printing variables▎
+▊ 36 println!("Hello, {}! You are {} years old.", name, age); ▎
+▊ 37 ▎
+▊ 38 // Conditional statements▎
+▊ 39 if age >= 18 && is_student { ▎
+▊ 40 println!("You are an adult student."); ▎
+▊ 41 } elseif age >= 18 { ▎
+▊ 42 println!("You are an adult."); ▎
+▊ 43 } else { ▎
+▊ 44 println!("You are a minor."); ▎
+▊ 45 } ▎
+▊ 46 ▎
+▊ 47 // Arrays▎
+▊ 48 let numbers = [1, 2, 3, 4, 5]; ▎
+▊ 49 println!("Numbers: {:?}", numbers); ▎
+▊ 50 ▎
+▊ 51 // Vectors▎
+▊ 52 letmut fruits = vec!["apple", "banana", "orange"]; ▎
+▊ 53 fruits.push("grape"); ▎
+▊ 54 println!("Fruits: {:?}", fruits); ▎
+▊ 55 ▎
+▊ 56 // Loops▎
+▊ 57 for num in &numbers { ▎
+▊ 58 println!("Number: {}", num); ▎
+▊ 59 } ▎
+▊ 60 ▎
+▊ 61 // Pattern matching▎
+▊ 62 let result = Result::Ok(42); ▎
+▊ 63 match result { ▎
+▊ 64 Result::Ok(value) => println!("Value: {}", value), ▎
+▊ 65 Result::Err(error) => println!("Error: {:?}", error), ▎
+▊ 66 } ▎
+▊ 67 ▎
+▊ 68 // Ownership and borrowing▎
+▊ 69 let s1 = String::from("hello"); ▎
+▊ 70 let s2 = s1.clone(); ▎
+▊ 71 println!("s1: {}, s2: {}", s1, s2); ▎
+▊ 72 ▎
+▊ 73 // References▎
+▊ 74 let rect = Rectangle { ▎
+▊ 75 width: 10, ▎
+▊ 76 height: 20, ▎
+▊ 77 }; ▎
+▊ 78 println!("Rectangle area: {}", rect.area()); ▎
+▊ 79 ▎
+▊ 80 // Hash maps▎
+▊ 81 letmut scores = HashMap::new(); ▎
+▊ 82 scores.insert("Alice", 100); ▎
+▊ 83 scores.insert("Bob", 80); ▎
+▊ 84 println!("Alice's score: {}", scores["Alice"]); ▎
+▊ 85 ▎
+▊ 86 // Closures▎
+▊ 87 let square = |num: i32| num * num; ▎
+▊ 88 println!("Square of 5: {}", square(5)); ▎
+▊ 89 ▎
+▊ 90 // Traits▎
+▊ 91 traitPrintable { ▎
+▊ 92 fnprint(&self); ▎
+▊ 93 } ▎
+▊ 94 ▎
+▊ 95 implPrintableforRectangle { ▎
+▊ 96 fnprint(&self) { ▎
+▊ 97 println!("Rectangle: width={}, height={}", self.width, self▎
+▊ 98 } ▎
+▊ 99 } ▎
+▊100 rect.print(); ▎
+▊101 ▎
+▊102 // Modules▎
+▊103 greet("Alice"); ▎
+▊104 } ▎
+▊105 ▎
+▊▎▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[css].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[css].svg
index 0d6b98a198..490993e813 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[css].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[css].svg
@@ -19,84 +19,82 @@
font-weight: 700;
}
- .terminal-1378439235-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-1378439235-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-1378439235-r1 { fill: #121212 }
-.terminal-1378439235-r2 { fill: #0178d4 }
-.terminal-1378439235-r3 { fill: #c5c8c6 }
-.terminal-1378439235-r4 { fill: #71716e }
-.terminal-1378439235-r5 { fill: #569cd6 }
-.terminal-1378439235-r6 { fill: #f8f8f2 }
-.terminal-1378439235-r7 { fill: #dcdcaa }
-.terminal-1378439235-r8 { fill: #cccccc }
-.terminal-1378439235-r9 { fill: #9cdcfe }
-.terminal-1378439235-r10 { fill: #999997;font-weight: bold }
-.terminal-1378439235-r11 { fill: #b5cea8 }
-.terminal-1378439235-r12 { fill: #7daf9c }
-.terminal-1378439235-r13 { fill: #4ec9b0 }
-.terminal-1378439235-r14 { fill: #ce9178 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #71716e }
+.terminal-r5 { fill: #569cd6 }
+.terminal-r6 { fill: #f8f8f2 }
+.terminal-r7 { fill: #dcdcaa }
+.terminal-r8 { fill: #cccccc }
+.terminal-r9 { fill: #999997;font-weight: bold }
+.terminal-r10 { fill: #b5cea8 }
+.terminal-r11 { fill: #7daf9c }
+.terminal-r12 { fill: #ce9178 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊1 defhello(name):▎
-▊2 x=123▎
-▊3 whilenotFalse:▎
-▊4 print("hello "+name)▎
-▊5 continue▎
-▊6 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊1 defhello(name):▎
+▊2 x =123▎
+▊3 whilenotFalse:▎
+▊4 print("hello "+ name)▎
+▊5 continue▎
+▊6 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[dracula].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[dracula].svg
index 2ec01a5ea3..c46632b650 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[dracula].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[dracula].svg
@@ -19,81 +19,81 @@
font-weight: 700;
}
- .terminal-789685810-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-789685810-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-789685810-r1 { fill: #121212 }
-.terminal-789685810-r2 { fill: #0178d4 }
-.terminal-789685810-r3 { fill: #c5c8c6 }
-.terminal-789685810-r4 { fill: #6272a4 }
-.terminal-789685810-r5 { fill: #ff79c6 }
-.terminal-789685810-r6 { fill: #f8f8f2 }
-.terminal-789685810-r7 { fill: #c2c2bf;font-weight: bold }
-.terminal-789685810-r8 { fill: #bd93f9 }
-.terminal-789685810-r9 { fill: #282a36 }
-.terminal-789685810-r10 { fill: #50fa7b }
-.terminal-789685810-r11 { fill: #f1fa8c }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #6272a4 }
+.terminal-r5 { fill: #ff79c6 }
+.terminal-r6 { fill: #f8f8f2 }
+.terminal-r7 { fill: #50fa7b }
+.terminal-r8 { fill: #c2c2bf;font-weight: bold }
+.terminal-r9 { fill: #bd93f9 }
+.terminal-r10 { fill: #282a36 }
+.terminal-r11 { fill: #f1fa8c }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊1 def hello(name):▎
-▊2 x = 123▎
-▊3 whilenotFalse: ▎
-▊4 print("hello " + name) ▎
-▊5 continue▎
-▊6 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊1 defhello(name):▎
+▊2 x = 123▎
+▊3 whilenotFalse: ▎
+▊4 print("hello " + name) ▎
+▊5 continue▎
+▊6 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[github_light].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[github_light].svg
index 8def597c67..0b33d27723 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[github_light].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[github_light].svg
@@ -19,83 +19,84 @@
font-weight: 700;
}
- .terminal-3341902079-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-3341902079-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-3341902079-r1 { fill: #121212 }
-.terminal-3341902079-r2 { fill: #0178d4 }
-.terminal-3341902079-r3 { fill: #c5c8c6 }
-.terminal-3341902079-r4 { fill: #bbbbbb }
-.terminal-3341902079-r5 { fill: #cf222e }
-.terminal-3341902079-r6 { fill: #24292e }
-.terminal-3341902079-r7 { fill: #6639bb }
-.terminal-3341902079-r8 { fill: #a4a4a4 }
-.terminal-3341902079-r9 { fill: #7daf9c }
-.terminal-3341902079-r10 { fill: #0450ae }
-.terminal-3341902079-r11 { fill: #d73a49 }
-.terminal-3341902079-r12 { fill: #fafbfc }
-.terminal-3341902079-r13 { fill: #093069 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #bbbbbb }
+.terminal-r5 { fill: #cf222e }
+.terminal-r6 { fill: #24292e }
+.terminal-r7 { fill: #6639bb }
+.terminal-r8 { fill: #a4a4a4 }
+.terminal-r9 { fill: #e36209 }
+.terminal-r10 { fill: #0450ae }
+.terminal-r11 { fill: #d73a49 }
+.terminal-r12 { fill: #fafbfc }
+.terminal-r13 { fill: #7daf9c }
+.terminal-r14 { fill: #093069 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
+
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊1 defhello(name):▎
-▊2 x=123▎
-▊3 whilenotFalse: ▎
-▊4 print("hello "+name) ▎
-▊5 continue▎
-▊6 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊1 defhello(name):▎
+▊2 x=123▎
+▊3 whilenotFalse: ▎
+▊4 print("hello "+name) ▎
+▊5 continue▎
+▊6 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[monokai].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[monokai].svg
index f69e242c44..3e94f22d02 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[monokai].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[monokai].svg
@@ -19,82 +19,82 @@
font-weight: 700;
}
- .terminal-2677119763-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-2677119763-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-2677119763-r1 { fill: #121212 }
-.terminal-2677119763-r2 { fill: #0178d4 }
-.terminal-2677119763-r3 { fill: #c5c8c6 }
-.terminal-2677119763-r4 { fill: #90908a }
-.terminal-2677119763-r5 { fill: #f92672 }
-.terminal-2677119763-r6 { fill: #f8f8f2 }
-.terminal-2677119763-r7 { fill: #c2c2bf }
-.terminal-2677119763-r8 { fill: #ae81ff }
-.terminal-2677119763-r9 { fill: #272822 }
-.terminal-2677119763-r10 { fill: #66d9ef;font-style: italic; }
-.terminal-2677119763-r11 { fill: #a6e22e }
-.terminal-2677119763-r12 { fill: #e6db74 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #90908a }
+.terminal-r5 { fill: #f92672 }
+.terminal-r6 { fill: #f8f8f2 }
+.terminal-r7 { fill: #a6e22e }
+.terminal-r8 { fill: #c2c2bf }
+.terminal-r9 { fill: #ae81ff }
+.terminal-r10 { fill: #272822 }
+.terminal-r11 { fill: #66d9ef;font-style: italic; }
+.terminal-r12 { fill: #e6db74 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊1 def hello(name):▎
-▊2 x = 123▎
-▊3 whilenotFalse: ▎
-▊4 print("hello " + name) ▎
-▊5 continue▎
-▊6 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊1 defhello(name):▎
+▊2 x = 123▎
+▊3 whilenotFalse: ▎
+▊4 print("hello " + name) ▎
+▊5 continue▎
+▊6 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[vscode_dark].svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[vscode_dark].svg
index 1185984e0c..43710bef03 100644
--- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[vscode_dark].svg
+++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_text_area_themes[vscode_dark].svg
@@ -19,83 +19,81 @@
font-weight: 700;
}
- .terminal-2571030914-matrix {
+ .terminal-matrix {
font-family: Fira Code, monospace;
font-size: 20px;
line-height: 24.4px;
font-variant-east-asian: full-width;
}
- .terminal-2571030914-title {
+ .terminal-title {
font-size: 18px;
font-weight: bold;
font-family: arial;
}
- .terminal-2571030914-r1 { fill: #121212 }
-.terminal-2571030914-r2 { fill: #0178d4 }
-.terminal-2571030914-r3 { fill: #c5c8c6 }
-.terminal-2571030914-r4 { fill: #6e7681 }
-.terminal-2571030914-r5 { fill: #569cd6 }
-.terminal-2571030914-r6 { fill: #cccccc }
-.terminal-2571030914-r7 { fill: #dcdcaa }
-.terminal-2571030914-r8 { fill: #9cdcfe }
-.terminal-2571030914-r9 { fill: #b5cea8 }
-.terminal-2571030914-r10 { fill: #1e1e1e }
-.terminal-2571030914-r11 { fill: #7daf9c }
-.terminal-2571030914-r12 { fill: #4ec9b0 }
-.terminal-2571030914-r13 { fill: #ce9178 }
+ .terminal-r1 { fill: #121212 }
+.terminal-r2 { fill: #0178d4 }
+.terminal-r3 { fill: #c5c8c6 }
+.terminal-r4 { fill: #6e7681 }
+.terminal-r5 { fill: #569cd6 }
+.terminal-r6 { fill: #cccccc }
+.terminal-r7 { fill: #dcdcaa }
+.terminal-r8 { fill: #b5cea8 }
+.terminal-r9 { fill: #1e1e1e }
+.terminal-r10 { fill: #7daf9c }
+.terminal-r11 { fill: #ce9178 }
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- TextAreaSnapshot
+ TextAreaSnapshot
-
-
-
- ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
-▊1 defhello(name):▎
-▊2 x = 123▎
-▊3 whilenotFalse: ▎
-▊4 print("hello " + name) ▎
-▊5 continue▎
-▊6 ▎
-▊▎
-▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎
+
+
+
+ ▊▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▎
+▊1 defhello(name):▎
+▊2 x = 123▎
+▊3 whilenotFalse: ▎
+▊4 print("hello " + name) ▎
+▊5 continue▎
+▊6 ▎
+▊▎
+▊▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▎