Repository: alecthomas/chroma
Pull request #823 (2023-08-20 16:20:06)

Add more hlsl file extensions
To match GitHub's linguist https://github.com/github-linguist/linguist/blob/916bd8f3df802fa98b0ea85539e67bd0b88ef158/lib/linguist/languages.yml#L2623


Patch:
diff --git a/lexer.go b/lexer.go
index 4a1bd0f..0f12fcc 100644
--- a/lexer.go
+++ b/lexer.go
@@ -57,6 +57,26 @@ type Config struct {
 	//
 	// If this is 0 it will be treated as a default of 1.
 	Priority float32 `xml:"priority,omitempty"`
+
+	// Analyse is a list of regexes to match against the input.
+	//
+	// If a match is found, the score is returned if single attribute is set to true,
+	// otherwise the sum of all the score of matching patterns will be
+	// used as the final score.
+	Analyse *AnalyseConfig `xml:"analyse,omitempty"`
+}
+
+// AnalyseConfig defines the list of regexes analysers.
+type AnalyseConfig struct {
+	Regexes []RegexConfig `xml:"regex,omitempty"`
+	// If true, the score is returned despite other matches.
+	Single bool `xml:"single,attr"`
+}
+
+// RegexConfig defines a single regex pattern and its score in case of match.
+type RegexConfig struct {
+	Pattern string  `xml:"pattern,attr"`
+	Score   float32 `xml:"score,attr"`
 }
 
 // Token output to formatter.
diff --git a/lexers/c.go b/lexers/c.go
deleted file mode 100644
index 4ed2dd5..0000000
--- a/lexers/c.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package lexers
-
-import (
-	"regexp"
-
-	. "github.com/alecthomas/chroma/v2" // nolint
-)
-
-var (
-	cAnalyserIncludeRe = regexp.MustCompile(`(?m)^\s*#include [<"]`)
-	cAnalyserIfdefRe   = regexp.MustCompile(`(?m)^\s*#ifn?def `)
-)
-
-// C lexer.
-var C = Register(MustNewXMLLexer(
-	embedded,
-	"embedded/c.xml",
-).SetConfig(
-	&Config{
-		Name:      "C",
-		Aliases:   []string{"c"},
-		Filenames: []string{"*.c", "*.h", "*.idc", "*.x[bp]m"},
-		MimeTypes: []string{"text/x-chdr", "text/x-csrc", "image/x-xbitmap", "image/x-xpixmap"},
-		EnsureNL:  true,
-		Priority:  0.1,
-	},
-).SetAnalyser(func(text string) float32 {
-	if cAnalyserIncludeRe.MatchString(text) {
-		return 0.1
-	}
-
-	if cAnalyserIfdefRe.MatchString(text) {
-		return 0.1
-	}
-
-	return 0
-}))
diff --git a/lexers/cpp.go b/lexers/cpp.go
deleted file mode 100644
index 322481d..0000000
--- a/lexers/cpp.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package lexers
-
-import (
-	"regexp"
-
-	. "github.com/alecthomas/chroma/v2" // nolint
-)
-
-var (
-	cppAnalyserIncludeRe   = regexp.MustCompile(`#include <[a-z_]+>`)
-	cppAnalyserNamespaceRe = regexp.MustCompile(`using namespace `)
-)
-
-var CPP = Register(MustNewXMLLexer(
-	embedded,
-	"embedded/c++.xml",
-).SetConfig(
-	&Config{
-		Name:      "C++",
-		Aliases:   []string{"cpp", "c++"},
-		Filenames: []string{"*.cpp", "*.hpp", "*.c++", "*.h++", "*.cc", "*.hh", "*.cxx", "*.hxx", "*.C", "*.H", "*.cp", "*.CPP", "*.cppm", "*.ixx", "*.tpp"},
-		MimeTypes: []string{"text/x-c++hdr", "text/x-c++src"},
-		Priority:  0.1,
-		EnsureNL:  true,
-	},
-)).SetAnalyser(func(text string) float32 {
-	if cppAnalyserIncludeRe.MatchString(text) {
-		return 0.2
-	}
-
-	if cppAnalyserNamespaceRe.MatchString(text) {
-		return 0.4
-	}
-
-	return 0
-})
diff --git a/lexers/embedded/bashsession.xml b/lexers/embedded/bashsession.xml
index b9b55e0..1859744 100644
--- a/lexers/embedded/bashsession.xml
+++ b/lexers/embedded/bashsession.xml
@@ -1,6 +1,6 @@
 <lexer>
   <config>
-    <name>BashSession</name>
+    <name>Bash Session</name>
     <alias>bash-session</alias>
     <alias>console</alias>
     <alias>shell-session</alias>
diff --git a/lexers/embedded/c++.xml b/lexers/embedded/c++.xml
index e8702c5..a6bfb11 100644
--- a/lexers/embedded/c++.xml
+++ b/lexers/embedded/c++.xml
@@ -15,9 +15,14 @@
     <filename>*.H</filename>
     <filename>*.cp</filename>
     <filename>*.CPP</filename>
+    <filename>*.tpp</filename>
     <mime_type>text/x-c++hdr</mime_type>
     <mime_type>text/x-c++src</mime_type>
     <ensure_nl>true</ensure_nl>
+    <analyse single="true">
+      <regex pattern="#include &lt;[a-z_]+>" score="0.2" />
+      <regex pattern="using namespace " score="0.4" />
+    </analyse>
   </config>
   <rules>
     <state name="classname">
diff --git a/lexers/embedded/c.xml b/lexers/embedded/c.xml
index f941802..da57298 100644
--- a/lexers/embedded/c.xml
+++ b/lexers/embedded/c.xml
@@ -11,6 +11,10 @@
     <mime_type>image/x-xbitmap</mime_type>
     <mime_type>image/x-xpixmap</mime_type>
     <ensure_nl>true</ensure_nl>
+    <analyse single="true" >
+      <regex pattern="(?m)^\s*#include &lt;" score="0.1" />
+      <regex pattern="(?m)^\s*#ifn?def " score="0.1" />
+    </analyse>
   </config>
   <rules>
     <state name="statement">
diff --git a/lexers/embedded/clojure.xml b/lexers/embedded/clojure.xml
index ee83a6a..967ba39 100644
--- a/lexers/embedded/clojure.xml
+++ b/lexers/embedded/clojure.xml
@@ -3,9 +3,12 @@
     <name>Clojure</name>
     <alias>clojure</alias>
     <alias>clj</alias>
+    <alias>edn</alias>
     <filename>*.clj</filename>
+    <filename>*.edn</filename>
     <mime_type>text/x-clojure</mime_type>
     <mime_type>application/x-clojure</mime_type>
+    <mime_type>application/edn</mime_type>
   </config>
   <rules>
     <state name="root">
@@ -65,4 +68,4 @@
       </rule>
     </state>
   </rules>
-</lexer>
\ No newline at end of file
+</lexer>
diff --git a/lexers/embedded/gas.xml b/lexers/embedded/gas.xml
index 1feda85..7557bce 100644
--- a/lexers/embedded/gas.xml
+++ b/lexers/embedded/gas.xml
@@ -6,6 +6,7 @@
     <filename>*.s</filename>
     <filename>*.S</filename>
     <mime_type>text/x-gas</mime_type>
+    <priority>0.1</priority>
   </config>
   <rules>
     <state name="punctuation">
diff --git a/lexers/embedded/gdscript.xml b/lexers/embedded/gdscript.xml
index fb75fc8..242aa63 100644
--- a/lexers/embedded/gdscript.xml
+++ b/lexers/embedded/gdscript.xml
@@ -6,53 +6,78 @@
     <filename>*.gd</filename>
     <mime_type>text/x-gdscript</mime_type>
     <mime_type>application/x-gdscript</mime_type>
+    <priority>0.1</priority>
+    <analyse single="true">
+      <regex pattern="^@" score="0.4"/>
+    </analyse>
   </config>
   <rules>
-    <state name="builtins">
-      <rule pattern="(?&lt;!\.)(instance_from_id|nearest_po2|print_stack|type_exist|rand_range|linear2db|var2bytes|dict2inst|randomize|bytes2var|rand_seed|db2linear|inst2dict|printerr|printraw|decimals|preload|deg2rad|str2var|stepify|var2str|convert|weakref|fposmod|funcref|rad2deg|dectime|printt|is_inf|is_nan|assert|Color8|typeof|ColorN|prints|floor|atan2|yield|randf|print|range|clamp|round|randi|sqrt|tanh|cosh|ceil|ease|acos|load|fmod|lerp|seed|sign|atan|sinh|hash|asin|sin|str|cos|tan|pow|exp|min|abs|log|max)\b">
-        <token type="NameBuiltin"/>
-      </rule>
-      <rule pattern="(?&lt;!\.)(self|false|true|PI|NAN|INF)\b">
-        <token type="NameBuiltinPseudo"/>
+    <state name="dqs">
+      <rule pattern="&#34;">
+        <token type="LiteralStringDouble"/>
+        <pop depth="1"/>
       </rule>
-      <rule pattern="(?&lt;!\.)(Physics2DShapeQueryParameters|PhysicsShapeQueryParameters|Physics2DDirectBodyStateSW|NavigationPolygonInstance|ResourceInteractiveLoader|Physics2DDirectSpaceState|Physics2DShapeQueryResult|Physics2DTestMotionResult|InputEventJoystickButton|InputEventJoystickMotion|Physics2DDirectBodyState|PhysicsDirectBodyStateSW|PhysicsShapeQueryResult|PhysicsDirectSpaceState|SpatialSound2DServerSW|PackedDataContainerRef|NavigationMeshInstance|ResourceImportMetadata|PhysicsDirectBodyState|ConcavePolygonShape2D|CanvasItemShaderGraph|EditorScenePostImport|InputEventScreenTouch|InputEventMouseButton|InputEventMouseMotion|SpatialSound2DServer|AudioStreamOGGVorbis|VisibilityNotifier2D|InputEventScreenDrag|ConvexPolygonShape2D|SpatialSoundServerSW|ParticleAttractor2D|PackedDataContainer|SpatialStreamPlayer|RenderTargetTexture|AnimationTreePlayer|ConcavePolygonShape|InstancePlaceholder|MaterialShaderGraph|AudioStreamPlayback|VisibilityEnabler2D|SpatialSamplePlayer|DampedSpringJoint2D|InterpolatedCamera|ConvexPolygonShape|ConfirmationDialog|SpatialSoundServer|BakedLightInstance|ParallaxBackground|CollisionPolygon2D|CanvasItemMaterial|VisibilityNotifier|EditorImportPlugin|VideoStreamTheora|TouchScreenButton|ResourcePreloader|OccluderPolygon2D|BakedLightSampler|CollisionObject2D|RemoteTransform2D|PolygonPathFinder|StyleBoxImageMask|NavigationPolygon|TranslationServer|MultiMeshInstance|ImmediateGeometry|Physics2DServerSW|ColorPickerButton|VisibilityEnabler|PHashTranslation|RectangleShape2D|DirectionalLight|AnimatedSprite3D|WorldEnvironment|CollisionShape2D|EventStreamChibi|InputEventAction|CollisionPolygon|AudioStreamSpeex|EditorFileDialog|GeometryInstance|Generic6DOFJoint|PacketPeerStream|CanvasItemShader|KinematicBody2D|StyleBoxTexture|PhysicsServerSW|VSplitContainer|CenterContainer|GDFunctionState|AudioStreamOpus|TextureProgress|MarginContainer|CollisionObject|LightOccluder2D|AnimationPlayer|HSplitContainer|ScrollContainer|SoundRoomParams|Physics2DServer|MaterialShader|ShaderMaterial|ViewportSprite|SplitContainer|AudioStreamMPC|VisualInstance|PanelContainer|BackBufferCopy|SamplePlayer2D|CanvasModulate|ResourceLoader|CapsuleShape2D|ReferenceFrame|NavigationMesh|CollisionShape|ConeTwistJoint|ProximityGroup|AnimatedSprite|SegmentShape2D|BoneAttachment|RichTextLabel|CircleShape2D|VBoxContainer|PacketPeerUDP|SpatialPlayer|TextureButton|KinematicBody|SoundPlayer2D|PhysicsServer|ParallaxLayer|InputEventKey|GrooveJoint2D|PhysicsBody2D|FixedMaterial|GridContainer|HBoxContainer|StreamPeerSSL|StyleBoxEmpty|StreamPeerTCP|SampleLibrary|GDNativeClass|AudioServerSW|ResourceSaver|SpriteBase3D|StreamPlayer|AtlasTexture|VisualServer|SamplePlayer|StyleBoxFlat|StaticBody2D|SpriteFrames|MeshDataTool|MeshInstance|Vector3Array|BoxContainer|TabContainer|HButtonArray|LargeTexture|Navigation2D|WindowDialog|EditorScript|EditorPlugin|TextureFrame|AcceptDialog|ImageTexture|CapsuleShape|VehicleWheel|VButtonArray|Vector2Array|InputDefault|OptionButton|PathFollow2D|VehicleBody|ColorPicker|PopupDialog|ProgressBar|CanvasLayer|Translation|Environment|EventPlayer|VideoPlayer|EventStream|VideoStream|ButtonGroup|Particles2D|Patch9Frame|ButtonArray|SurfaceTool|MeshLibrary|PackedScene|PhysicsBody|AudioStream|Performance|StringArray|AudioServer|RigidBody2D|LineShape2D|SliderJoint|SphereShape|ShaderGraph|CheckButton|StreamPeer|FileDialog|PathFollow|SceneState|RoomBounds|Dictionary|VSeparator|PacketPeer|VScrollBar|MenuButton|HTTPClient|PinJoint2D|BakedLight|PlaneShape|InputEvent|BaseButton|HSeparator|HScrollBar|Navigation|PopupPanel|StaticBody|Position2D|Position3D|ToolButton|HingeJoint|CanvasItem|RayShape2D|ColorArray|ConfigFile|TCP_Server|RayCast2D|ColorRamp|SpotLight|RealArray|GraphNode|Container|Reference|PopupMenu|Separator|Polygon2D|MultiMesh|Semaphore|Transform|OmniLight|GraphEdit|Particles|Animation|Marshalls|SceneTree|RigidBody|XMLParser|PathRemap|ScrollBar|Directory|PCKPacker|RawArray|TextEdit|MainLoop|TreeItem|StyleBox|Material|Geometry|Matrix32|Resource|UndoRedo|RayShape|TestCube|ItemList|CheckBox|Camera2D|Skeleton|Sprite3D|Viewport|NodePath|IntArray|BoxShape|PinJoint|InputMap|LineEdit|GDScript|Vector3|TileMap|HSlider|Spatial|SpinBox|World2D|IP_Unix|Curve2D|Curve3D|WeakRef|GridMap|Matrix3|VSlider|CubeMap|Joint2D|Globals|Shape2D|Texture|Control|TileSet|Light2D|FuncRef|Vector2|RayCast|Script|Node2D|Button|BitMap|Sample|Object|String|Shader|Area2D|Slider|Sprite|Thread|Path2D|Camera|Portal|float|Theme|World|YSort|Shape|Joint|Mutex|Tween|RegEx|Label|Rect2|Array|Plane|Light|Range|Color|Input|Popup|Panel|Timer|Image|Area|Quad|bool|AABB|Quat|File|Tabs|Path|Font|Tree|Room|Mesh|Node|RID|int|Nil|IP|OS)\b">
-        <token type="NameException"/>
+      <rule>
+        <include state="strings_double"/>
       </rule>
     </state>
-    <state name="sqs">
-      <rule pattern="&#39;">
-        <token type="LiteralStringSingle"/>
+    <state name="tdqs">
+      <rule pattern="&#34;&#34;&#34;">
+        <token type="LiteralStringDouble"/>
         <pop depth="1"/>
       </rule>
-      <rule pattern="\\\\|\\&#39;|\\\n">
-        <token type="LiteralStringEscape"/>
-      </rule>
       <rule>
-        <include state="strings-single"/>
+        <include state="strings_double"/>
       </rule>
     </state>
-    <state name="stringescape">
-      <rule pattern="\\([\\abfnrtv&#34;\&#39;]|\n|N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})">
-        <token type="LiteralStringEscape"/>
+    <state name="keywords">
+      <rule pattern="(?&lt;!\w)(PI|TAU|NAN|INF|true|false)\b">
+        <token type="KeywordConstant"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(is|in|as|not|or|and)\b">
+        <token type="OperatorWord"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(var|const|enum|signal|static)\b">
+        <token type="KeywordDeclaration"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(if|elif|else|for|while|match|break|continue|pass|return|breakpoint|await|yield|super)\b">
+        <token type="Keyword"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(self)\b">
+        <token type="NameBuiltinPseudo"/>
       </rule>
     </state>
-    <state name="classname">
-      <rule pattern="[a-zA-Z_]\w*">
-        <token type="NameClass"/>
+    <state name="builtin_funcs">
+      <rule pattern="(?&lt;!\w)(assert|char|convert|dict_to_inst|get_stack|inst_to_dict|is_instance_of|len|load|preload|print_debug|print_stack|range|type_exists)\b">
+        <token type="NameBuiltin"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(abs[fi]?|acos|asin|atan2?|bezier_(derivative|interpolate)|bytes_to_var(_with_objects)?|ceil[fi]?|clamp[fi]?|cosh?|cubic_interpolate(_angle)?(_in_time)?|db_to_linear|deg_to_rad|ease|error_string|exp|floor[fi]?|fmod|fposmod|hash|instance_from_id|inverse_lerp|is_equal_approx|is_finite|is_instance(_id)?_valid|is_nan|is_same|is_zero_approx|lerp|lerp_angle|lerpf|linear_to_db|log|max[fi]?|min[fi]?|move_toward|nearest_po2|pingpong|posmod|pow|print|print_rich|print_verbose|printerr|printraw|prints|printt|push_error|push_warning|rad_to_deg|rand_from_seed|randf|randf_range|randfn|randi|randi_range|randomize|remap|rid_allocate_id|rid_from_int64|round[fi]?|seed|sign[fi]?|sinh?|smoothstep|snapped[fi]?|sqrt|step_decimals|str|str_to_var|tanh?|typeof|var_to_bytes(_with_objects)?|var_to_str|weakref|wrap[fi]?)\b">
+        <token type="NameBuiltin"/>
+      </rule>
+    </state>
+    <state name="tsqs">
+      <rule pattern="&#39;&#39;&#39;">
+        <token type="LiteralStringSingle"/>
         <pop depth="1"/>
       </rule>
+      <rule>
+        <include state="strings_single"/>
+      </rule>
     </state>
-    <state name="strings-single">
-      <rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsux%]">
+    <state name="strings_single">
+      <rule>
+        <include state="strings"/>
+      </rule>
+      <rule pattern="\{[^\\\&#39;\n]+\}">
         <token type="LiteralStringInterpol"/>
       </rule>
-      <rule pattern="[^\\\&#39;&#34;%\n]+">
+      <rule pattern="[^\\\&#39;\{%]+">
         <token type="LiteralStringSingle"/>
       </rule>
-      <rule pattern="[\&#39;&#34;\\]">
+      <rule pattern="%">
         <token type="LiteralStringSingle"/>
       </rule>
-      <rule pattern="%">
+      <rule pattern="{">
         <token type="LiteralStringSingle"/>
       </rule>
     </state>
@@ -61,205 +86,174 @@
         <token type="NameFunction"/>
         <pop depth="1"/>
       </rule>
-      <rule>
-        <pop depth="1"/>
-      </rule>
     </state>
     <state name="numbers">
-      <rule pattern="(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?">
+      <rule pattern="(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?">
         <token type="LiteralNumberFloat"/>
       </rule>
-      <rule pattern="\d+[eE][+-]?[0-9]+j?">
+      <rule pattern="\d+[eE][+-]?[0-9]+">
         <token type="LiteralNumberFloat"/>
       </rule>
-      <rule pattern="0[xX][a-fA-F0-9]+">
+      <rule pattern="0x[a-fA-F0-9]+">
         <token type="LiteralNumberHex"/>
       </rule>
-      <rule pattern="\d+j?">
+      <rule pattern="0b[01]+">
+        <token type="LiteralNumberBin"/>
+      </rule>
+      <rule pattern="\d+">
         <token type="LiteralNumberInteger"/>
       </rule>
     </state>
-    <state name="tdqs">
-      <rule pattern="&#34;&#34;&#34;">
-        <token type="LiteralStringDouble"/>
+    <state name="sqs">
+      <rule pattern="&#39;">
+        <token type="LiteralStringSingle"/>
         <pop depth="1"/>
       </rule>
       <rule>
-        <include state="strings-double"/>
+        <include state="strings_single"/>
       </rule>
-      <rule pattern="\n">
+    </state>
+    <state name="classname">
+      <rule pattern="[a-zA-Z_]\w*">
+        <token type="NameClass"/>
+        <pop depth="1"/>
+      </rule>
+    </state>
+    <state name="annotations">
+      <rule pattern="^\s*@export(_category|_color_no_alpha|_dir|_enum|_exp_easing|_file|_flags((_2d|_3d)(_navigation|_physics|_render)|_avoidance)?|_global(_file|_dir)|_group|_multiline|_node_path|_placeholder|_range|_subgroup)?">
+        <token type="NameDecorator"/>
+      </rule>
+      <rule pattern="^\s*@(icon|onready|rpc|tool|warning_ignore)">
+        <token type="NameDecorator"/>
+      </rule>
+    </state>
+    <state name="types">
+      <rule pattern="(?&lt;!\w)(null|void|bool|int|float)\b">
+        <token type="KeywordType"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(String(Name)?|NodePath|Vector[234]i?|Rect2|Transform[23]D|Plane|Quaternion|AABB|Basis|Color8?|RID|Object|(Packed(Byte|Int(32|64)|Float(32|64)|String|Vector(2|3)|Color))?Array|Dictionary|Signal|Callable)\b">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(Node|AcceptDialog|AnimatableBody2D|AnimatableBody3D|AnimatedSprite2D|AnimatedSprite3D|AnimationPlayer|AnimationTree|Area2D|Area3D|AspectRatioContainer|AudioListener2D|AudioListener3D|AudioStreamPlayer|AudioStreamPlayer2D|AudioStreamPlayer3D|BackBufferCopy|BaseButton|Bone2D|BoneAttachment3D|BoxContainer|Button|Camera2D|Camera3D|CanvasGroup|CanvasItem|CanvasLayer|CanvasModulate|CenterContainer|CharacterBody2D|CharacterBody3D|CheckBox|CheckButton|CodeEdit|CollisionObject2D|CollisionObject3D|CollisionPolygon2D|CollisionPolygon3D|CollisionShape2D|CollisionShape3D|ColorPicker|ColorPickerButton|ColorRect|ConeTwistJoint3D|ConfirmationDialog|Container|Control|CPUParticles2D|CPUParticles3D|CSGBox3D|CSGCombiner3D|CSGCylinder3D|CSGMesh3D|CSGPolygon3D|CSGPrimitive3D|CSGShape3D|CSGSphere3D|CSGTorus3D|DampedSpringJoint2D|Decal|DirectionalLight2D|DirectionalLight3D|EditorCommandPalette|EditorFileDialog|EditorFileSystem|EditorInspector|EditorPlugin|EditorProperty|EditorResourcePicker|EditorResourcePreview|EditorScriptPicker|EditorSpinSlider|FileDialog|FileSystemDock|FlowContainer|FogVolume|Generic6DOFJoint3D|GeometryInstance3D|GPUParticles2D|GPUParticles3D|GPUParticlesAttractor3D|GPUParticlesAttractorBox3D|GPUParticlesAttractorSphere3D|GPUParticlesAttractorVectorField3D|GPUParticlesCollision3D|GPUParticlesCollisionBox3D|GPUParticlesCollisionHeightField3D|GPUParticlesCollisionSDF3D|GPUParticlesCollisionSphere3D|GraphEdit|GraphNode|GridContainer|GridMap|GrooveJoint2D|HBoxContainer|HFlowContainer|HingeJoint3D|HScrollBar|HSeparator|HSlider|HSplitContainer|HTTPRequest|ImporterMeshInstance3D|InstancePlaceholder|ItemList|Joint2D|Joint3D|Label|Label3D|Light2D|Light3D|LightmapGI|LightmapProbe|LightOccluder2D|Line2D|LineEdit|LinkButton|MarginContainer|Marker2D|Marker3D|MenuBar|MenuButton|MeshInstance2D|MeshInstance3D|MissingNode|MultiMeshInstance2D|MultiMeshInstance3D|MultiplayerSpawner|MultiplayerSynchronizer|NavigationAgent2D|NavigationAgent3D|NavigationLink2D|NavigationLink3D|NavigationObstacle2D|NavigationObstacle3D|NavigationRegion2D|NavigationRegion3D|NinePatchRect|Node2D|Node3D|OccluderInstance3D|OmniLight3D|OpenXRHand|OptionButton|Panel|PanelContainer|ParallaxBackground|ParallaxLayer|Path2D|Path3D|PathFollow2D|PathFollow3D|PhysicalBone2D|PhysicalBone3D|PhysicsBody2D|PhysicsBody3D|PinJoint2D|PinJoint3D|PointLight2D|Polygon2D|Popup|PopupMenu|PopupPanel|ProgressBar|Range|RayCast2D|RayCast3D|ReferenceRect|ReflectionProbe|RemoteTransform2D|RemoteTransform3D|ResourcePreloader|RichTextLabel|RigidBody2D|RigidBody3D|RootMotionView|ScriptCreateDialog|ScriptEditor|ScriptEditorBase|ScrollBar|ScrollContainer|Separator|ShaderGlobalsOverride|ShapeCast2D|ShapeCast3D|Skeleton2D|Skeleton3D|SkeletonIK3D|Slider|SliderJoint3D|SoftBody3D|SpinBox|SplitContainer|SpotLight3D|SpringArm3D|Sprite2D|Sprite3D|SpriteBase3D|StaticBody2D|StaticBody3D|SubViewport|SubViewportContainer|TabBar|TabContainer|TextEdit|TextureButton|TextureProgressBar|TextureRect|TileMap|Timer|TouchScreenButton|Tree|VBoxContainer|VehicleBody3D|VehicleWheel3D|VFlowContainer|VideoStreamPlayer|Viewport|VisibleOnScreenEnabler2D|VisibleOnScreenEnabler3D|VisibleOnScreenNotifier2D|VisibleOnScreenNotifier3D|VisualInstance3D|VoxelGI|VScrollBar|VSeparator|VSlider|VSplitContainer|Window|WorldEnvironment|XRAnchor3D|XRCamera3D|XRController3D|XRNode3D|XROrigin3D)\b">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(Resource|AnimatedTexture|Animation|AnimationLibrary|AnimationNode|AnimationNodeAdd2|AnimationNodeAdd3|AnimationNodeAnimation|AnimationNodeBlend2|AnimationNodeBlend3|AnimationNodeBlendSpace1D|AnimationNodeBlendSpace2D|AnimationNodeBlendTree|AnimationNodeOneShot|AnimationNodeOutput|AnimationNodeStateMachine|AnimationNodeStateMachinePlayback|AnimationNodeStateMachineTransition|AnimationNodeSub2|AnimationNodeSync|AnimationNodeTimeScale|AnimationNodeTimeSeek|AnimationNodeTransition|AnimationRootNode|ArrayMesh|ArrayOccluder3D|AtlasTexture|AudioBusLayout|AudioEffect|AudioEffectAmplify|AudioEffectBandLimitFilter|AudioEffectBandPassFilter|AudioEffectCapture|AudioEffectChorus|AudioEffectCompressor|AudioEffectDelay|AudioEffectDistortion|AudioEffectEQ|AudioEffectEQ10|AudioEffectEQ21|AudioEffectEQ6|AudioEffectFilter|AudioEffectHighPassFilter|AudioEffectHighShelfFilter|AudioEffectLimiter|AudioEffectLowPassFilter|AudioEffectLowShelfFilter|AudioEffectNotchFilter|AudioEffectPanner|AudioEffectPhaser|AudioEffectPitchShift|AudioEffectRecord|AudioEffectReverb|AudioEffectSpectrumAnalyzer|AudioEffectStereoEnhance|AudioStream|AudioStreamGenerator|AudioStreamMicrophone|AudioStreamMP3|AudioStreamOggVorbis|AudioStreamPolyphonic|AudioStreamRandomizer|AudioStreamWAV|BaseMaterial3D|BitMap|BoneMap|BoxMesh|BoxOccluder3D|BoxShape3D|ButtonGroup|CameraAttributes|CameraAttributesPhysical|CameraAttributesPractical|CameraTexture|CanvasItemMaterial|CanvasTexture|CapsuleMesh|CapsuleShape2D|CapsuleShape3D|CircleShape2D|CodeHighlighter|CompressedCubemap|CompressedCubemapArray|CompressedTexture2D|CompressedTexture2DArray|CompressedTexture3D|CompressedTextureLayered|ConcavePolygonShape2D|ConcavePolygonShape3D|ConvexPolygonShape2D|ConvexPolygonShape3D|CryptoKey|CSharpScript|Cubemap|CubemapArray|Curve|Curve2D|Curve3D|CurveTexture|CurveXYZTexture|CylinderMesh|CylinderShape3D|EditorNode3DGizmoPlugin|EditorSettings|EditorSyntaxHighlighter|Environment|FastNoiseLite|FogMaterial|Font|FontFile|FontVariation|GDExtension|GDScript|GLTFAccessor|GLTFAnimation|GLTFBufferView|GLTFCamera|GLTFDocument|GLTFDocumentExtension|GLTFDocumentExtensionConvertImporterMesh|GLTFLight|GLTFMesh|GLTFNode|GLTFPhysicsBody|GLTFPhysicsShape|GLTFSkeleton|GLTFSkin|GLTFSpecGloss|GLTFState|GLTFTexture|GLTFTextureSampler|Gradient|GradientTexture1D|GradientTexture2D|HeightMapShape3D|Image|ImageTexture|ImageTexture3D|ImageTextureLayered|ImmediateMesh|ImporterMesh|InputEvent|InputEventAction|InputEventFromWindow|InputEventGesture|InputEventJoypadButton|InputEventJoypadMotion|InputEventKey|InputEventMagnifyGesture|InputEventMIDI|InputEventMouse|InputEventMouseButton|InputEventMouseMotion|InputEventPanGesture|InputEventScreenDrag|InputEventScreenTouch|InputEventShortcut|InputEventWithModifiers|JSON|LabelSettings|LightmapGIData|Material|Mesh|MeshLibrary|MeshTexture|MissingResource|MultiMesh|NavigationMesh|NavigationMeshSourceGeometryData3D|NavigationPolygon|Noise|NoiseTexture2D|NoiseTexture3D|Occluder3D|OccluderPolygon2D|OggPacketSequence|OpenXRAction|OpenXRActionMap|OpenXRActionSet|OpenXRInteractionProfile|OpenXRIPBinding|OptimizedTranslation|ORMMaterial3D|PackedDataContainer|PackedScene|PanoramaSkyMaterial|ParticleProcessMaterial|PhysicalSkyMaterial|PhysicsMaterial|PlaceholderCubemap|PlaceholderCubemapArray|PlaceholderMaterial|PlaceholderMesh|PlaceholderTexture2D|PlaceholderTexture2DArray|PlaceholderTexture3D|PlaceholderTextureLayered|PlaneMesh|PointMesh|PolygonOccluder3D|PolygonPathFinder|PortableCompressedTexture2D|PrimitiveMesh|PrismMesh|ProceduralSkyMaterial|QuadMesh|QuadOccluder3D|RDShaderFile|RDShaderSPIRV|RectangleShape2D|RibbonTrailMesh|RichTextEffect|SceneReplicationConfig|Script|ScriptExtension|SegmentShape2D|SeparationRayShape2D|SeparationRayShape3D|Shader|ShaderInclude|ShaderMaterial|Shape2D|Shape3D|Shortcut|SkeletonModification2D|SkeletonModification2DCCDIK|SkeletonModification2DFABRIK|SkeletonModification2DJiggle|SkeletonModification2DLookAt|SkeletonModification2DPhysicalBones|SkeletonModification2DStackHolder|SkeletonModification2DTwoBoneIK|SkeletonModificationStack2D|SkeletonProfile|SkeletonProfileHumanoid|Skin|Sky|SphereMesh|SphereOccluder3D|SphereShape3D|SpriteFrames|StandardMaterial3D|StyleBox|StyleBoxEmpty|StyleBoxFlat|StyleBoxLine|StyleBoxTexture|SyntaxHighlighter|SystemFont|TextMesh|Texture|Texture2D|Texture2DArray|Texture3D|TextureLayered|Theme|TileMapPattern|TileSet|TileSetAtlasSource|TileSetScenesCollectionSource|TileSetSource|TorusMesh|Translation|TubeTrailMesh|VideoStream|VideoStreamPlayback|VideoStreamTheora|ViewportTexture|VisualShader|VisualShaderNode|VisualShaderNodeBillboard|VisualShaderNodeBooleanConstant|VisualShaderNodeBooleanParameter|VisualShaderNodeClamp|VisualShaderNodeColorConstant|VisualShaderNodeColorFunc|VisualShaderNodeColorOp|VisualShaderNodeColorParameter|VisualShaderNodeComment|VisualShaderNodeCompare|VisualShaderNodeConstant|VisualShaderNodeCubemap|VisualShaderNodeCubemapParameter|VisualShaderNodeCurveTexture|VisualShaderNodeCurveXYZTexture|VisualShaderNodeCustom|VisualShaderNodeDerivativeFunc|VisualShaderNodeDeterminant|VisualShaderNodeDistanceFade|VisualShaderNodeDotProduct|VisualShaderNodeExpression|VisualShaderNodeFaceForward|VisualShaderNodeFloatConstant|VisualShaderNodeFloatFunc|VisualShaderNodeFloatOp|VisualShaderNodeFloatParameter|VisualShaderNodeFresnel|VisualShaderNodeGlobalExpression|VisualShaderNodeGroupBase|VisualShaderNodeIf|VisualShaderNodeInput|VisualShaderNodeIntConstant|VisualShaderNodeIntFunc|VisualShaderNodeIntOp|VisualShaderNodeIntParameter|VisualShaderNodeIs|VisualShaderNodeLinearSceneDepth|VisualShaderNodeMix|VisualShaderNodeMultiplyAdd|VisualShaderNodeOuterProduct|VisualShaderNodeOutput|VisualShaderNodeParameter|VisualShaderNodeParameterRef|VisualShaderNodeParticleAccelerator|VisualShaderNodeParticleBoxEmitter|VisualShaderNodeParticleConeVelocity|VisualShaderNodeParticleEmit|VisualShaderNodeParticleEmitter|VisualShaderNodeParticleMeshEmitter|VisualShaderNodeParticleMultiplyByAxisAngle|VisualShaderNodeParticleOutput|VisualShaderNodeParticleRandomness|VisualShaderNodeParticleRingEmitter|VisualShaderNodeParticleSphereEmitter|VisualShaderNodeProximityFade|VisualShaderNodeRandomRange|VisualShaderNodeRemap|VisualShaderNodeResizableBase|VisualShaderNodeSample3D|VisualShaderNodeScreenUVToSDF|VisualShaderNodeSDFRaymarch|VisualShaderNodeSDFToScreenUV|VisualShaderNodeSmoothStep|VisualShaderNodeStep|VisualShaderNodeSwitch|VisualShaderNodeTexture|VisualShaderNodeTexture2DArray|VisualShaderNodeTexture2DArrayParameter|VisualShaderNodeTexture2DParameter|VisualShaderNodeTexture3D|VisualShaderNodeTexture3DParameter|VisualShaderNodeTextureParameter|VisualShaderNodeTextureParameterTriplanar|VisualShaderNodeTextureSDF|VisualShaderNodeTextureSDFNormal|VisualShaderNodeTransformCompose|VisualShaderNodeTransformConstant|VisualShaderNodeTransformDecompose|VisualShaderNodeTransformFunc|VisualShaderNodeTransformOp|VisualShaderNodeTransformParameter|VisualShaderNodeTransformVecMult|VisualShaderNodeUIntConstant|VisualShaderNodeUIntFunc|VisualShaderNodeUIntOp|VisualShaderNodeUIntParameter|VisualShaderNodeUVFunc|VisualShaderNodeUVPolarCoord|VisualShaderNodeVarying|VisualShaderNodeVaryingGetter|VisualShaderNodeVaryingSetter|VisualShaderNodeVec2Constant|VisualShaderNodeVec2Parameter|VisualShaderNodeVec3Constant|VisualShaderNodeVec3Parameter|VisualShaderNodeVec4Constant|VisualShaderNodeVec4Parameter|VisualShaderNodeVectorBase|VisualShaderNodeVectorCompose|VisualShaderNodeVectorDecompose|VisualShaderNodeVectorDistance|VisualShaderNodeVectorFunc|VisualShaderNodeVectorLen|VisualShaderNodeVectorOp|VisualShaderNodeVectorRefract|VoxelGIData|World2D|World3D|WorldBoundaryShape2D|WorldBoundaryShape3D|X509Certificate)\b">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(Object|AESContext|AStar2D|AStar3D|AStarGrid2D|AudioEffectInstance|AudioEffectSpectrumAnalyzerInstance|AudioServer|AudioStreamGeneratorPlayback|AudioStreamPlayback|AudioStreamPlaybackOggVorbis|AudioStreamPlaybackPolyphonic|AudioStreamPlaybackResampled|CallbackTweener|CameraFeed|CameraServer|CharFXTransform|ClassDB|ConfigFile|Crypto|DirAccess|DisplayServer|DTLSServer|EditorDebuggerPlugin|EditorDebuggerSession|EditorExportPlatform|EditorExportPlatformAndroid|EditorExportPlatformIOS|EditorExportPlatformLinuxBSD|EditorExportPlatformMacOS|EditorExportPlatformPC|EditorExportPlatformWeb|EditorExportPlatformWindows|EditorExportPlugin|EditorFeatureProfile|EditorFileSystemDirectory|EditorFileSystemImportFormatSupportQuery|EditorImportPlugin|EditorInspectorPlugin|EditorInterface|EditorNode3DGizmo|EditorPaths|EditorResourceConversionPlugin|EditorResourcePreviewGenerator|EditorResourceTooltipPlugin|EditorSceneFormatImporter|EditorSceneFormatImporterBlend|EditorSceneFormatImporterFBX|EditorSceneFormatImporterGLTF|EditorScenePostImport|EditorScenePostImportPlugin|EditorScript|EditorSelection|EditorTranslationParserPlugin|EditorUndoRedoManager|EditorVCSInterface|EncodedObjectAsID|ENetConnection|ENetMultiplayerPeer|ENetPacketPeer|Engine|EngineDebugger|EngineProfiler|Expression|FileAccess|GDExtensionManager|Geometry2D|Geometry3D|GodotSharp|HashingContext|HMACContext|HTTPClient|ImageFormatLoader|ImageFormatLoaderExtension|Input|InputMap|IntervalTweener|IP|JavaClass|JavaClassWrapper|JavaScriptBridge|JavaScriptObject|JNISingleton|JSONRPC|KinematicCollision2D|KinematicCollision3D|Lightmapper|LightmapperRD|MainLoop|Marshalls|MeshConvexDecompositionSettings|MeshDataTool|MethodTweener|MobileVRInterface|MovieWriter|MultiplayerAPI|MultiplayerAPIExtension|MultiplayerPeer|MultiplayerPeerExtension|Mutex|NavigationMeshGenerator|NavigationPathQueryParameters2D|NavigationPathQueryParameters3D|NavigationPathQueryResult2D|NavigationPathQueryResult3D|NavigationServer2D|NavigationServer3D|Node|Node3DGizmo|OfflineMultiplayerPeer|OggPacketSequencePlayback|OpenXRInterface|OS|PackedDataContainerRef|PacketPeer|PacketPeerDTLS|PacketPeerExtension|PacketPeerStream|PacketPeerUDP|PCKPacker|Performance|PhysicsDirectBodyState2D|PhysicsDirectBodyState2DExtension|PhysicsDirectBodyState3D|PhysicsDirectBodyState3DExtension|PhysicsDirectSpaceState2D|PhysicsDirectSpaceState2DExtension|PhysicsDirectSpaceState3D|PhysicsDirectSpaceState3DExtension|PhysicsPointQueryParameters2D|PhysicsPointQueryParameters3D|PhysicsRayQueryParameters2D|PhysicsRayQueryParameters3D|PhysicsServer2D|PhysicsServer2DExtension|PhysicsServer2DManager|PhysicsServer3D|PhysicsServer3DExtension|PhysicsServer3DManager|PhysicsServer3DRenderingServerHandler|PhysicsShapeQueryParameters2D|PhysicsShapeQueryParameters3D|PhysicsTestMotionParameters2D|PhysicsTestMotionParameters3D|PhysicsTestMotionResult2D|PhysicsTestMotionResult3D|ProjectSettings|PropertyTweener|RandomNumberGenerator|RDAttachmentFormat|RDFramebufferPass|RDPipelineColorBlendState|RDPipelineColorBlendStateAttachment|RDPipelineDepthStencilState|RDPipelineMultisampleState|RDPipelineRasterizationState|RDPipelineSpecializationConstant|RDSamplerState|RDShaderSource|RDTextureFormat|RDTextureView|RDUniform|RDVertexAttribute|RefCounted|RegEx|RegExMatch|RenderingDevice|RenderingServer|Resource|ResourceFormatLoader|ResourceFormatSaver|ResourceImporter|ResourceLoader|ResourceSaver|ResourceUID|SceneMultiplayer|SceneState|SceneTree|SceneTreeTimer|ScriptLanguage|ScriptLanguageExtension|Semaphore|SkinReference|StreamPeer|StreamPeerBuffer|StreamPeerExtension|StreamPeerGZIP|StreamPeerTCP|StreamPeerTLS|SurfaceTool|TCPServer|TextLine|TextParagraph|TextServer|TextServerAdvanced|TextServerDummy|TextServerExtension|TextServerFallback|TextServerManager|ThemeDB|Thread|TileData|Time|TLSOptions|TranslationServer|TreeItem|TriangleMesh|Tween|Tweener|UDPServer|UndoRedo|UPNP|UPNPDevice|WeakRef|WebRTCDataChannel|WebRTCDataChannelExtension|WebRTCMultiplayerPeer|WebRTCPeerConnection|WebRTCPeerConnectionExtension|WebSocketMultiplayerPeer|WebSocketPeer|WebXRInterface|WorkerThreadPool|XMLParser|XRInterface|XRInterfaceExtension|XRPose|XRPositionalTracker|XRServer|ZIPPacker|ZIPReader)\b">
+        <token type="NameClass"/>
+      </rule>
+      <rule pattern="(?&lt;!\w)(EditorCommandPalette|EditorDebuggerPlugin|EditorDebuggerSession|EditorExportPlatform|EditorExportPlatformAndroid|EditorExportPlatformIOS|EditorExportPlatformLinuxBSD|EditorExportPlatformMacOS|EditorExportPlatformPC|EditorExportPlatformWeb|EditorExportPlatformWindows|EditorExportPlugin|EditorFeatureProfile|EditorFileDialog|EditorFileSystem|EditorFileSystemDirectory|EditorFileSystemImportFormatSupportQuery|EditorImportPlugin|EditorInspector|EditorInspectorPlugin|EditorInterface|EditorNode3DGizmo|EditorNode3DGizmoPlugin|EditorPaths|EditorPlugin|EditorProperty|EditorResourceConversionPlugin|EditorResourcePicker|EditorResourcePreview|EditorResourcePreviewGenerator|EditorResourceTooltipPlugin|EditorSceneFormatImporter|EditorSceneFormatImporterBlend|EditorSceneFormatImporterFBX|EditorSceneFormatImporterGLTF|EditorScenePostImport|EditorScenePostImportPlugin|EditorScript|EditorScriptPicker|EditorSelection|EditorSettings|EditorSpinSlider|EditorSyntaxHighlighter|EditorTranslationParserPlugin|EditorUndoRedoManager|EditorVCSInterface|FileSystemDock|ScriptCreateDialog|ScriptEditor|ScriptEditorBase)\b">
+        <token type="NameClass"/>
+      </rule>
+    </state>
+    <state name="strings_double">
+      <rule>
+        <include state="strings"/>
+      </rule>
+      <rule pattern="\{[^\\\&#34;\n]*\}">
+        <token type="LiteralStringInterpol"/>
+      </rule>
+      <rule pattern="[^\\\&#34;\{%]+">
+        <token type="LiteralStringDouble"/>
+      </rule>
+      <rule pattern="%">
+        <token type="LiteralStringDouble"/>
+      </rule>
+      <rule pattern="{">
         <token type="LiteralStringDouble"/>
       </rule>
     </state>
-    <state name="name">
-      <rule pattern="[a-zA-Z_]\w*">
-        <token type="Name"/>
+    <state name="strings">
+      <rule pattern="%(?:[+-]?[0-9*]*\.?[0-9*]*)?[scdoxXf]">
+        <token type="LiteralStringInterpol"/>
+      </rule>
+      <rule pattern="\\(U[0-9a-fA-F]{6}|u[0-9a-fA-F]{4}|[\n\\\&#39;\&#34;ntrabfv])">
+        <token type="LiteralStringEscape"/>
       </rule>
     </state>
     <state name="root">
       <rule pattern="\n">
         <token type="Text"/>
       </rule>
-      <rule pattern="^(\s*)([rRuUbB]{,2})(&#34;&#34;&#34;(?:.|\n)*?&#34;&#34;&#34;)">
-        <bygroups>
-          <token type="Text"/>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDoc"/>
-        </bygroups>
-      </rule>
-      <rule pattern="^(\s*)([rRuUbB]{,2})(&#39;&#39;&#39;(?:.|\n)*?&#39;&#39;&#39;)">
-        <bygroups>
-          <token type="Text"/>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDoc"/>
-        </bygroups>
-      </rule>
       <rule pattern="[^\S\n]+">
         <token type="Text"/>
       </rule>
       <rule pattern="#.*$">
         <token type="CommentSingle"/>
       </rule>
-      <rule pattern="[]{}:(),;[]">
-        <token type="Punctuation"/>
-      </rule>
       <rule pattern="\\\n">
         <token type="Text"/>
       </rule>
-      <rule pattern="\\">
-        <token type="Text"/>
+      <rule>
+        <include state="keywords"/>
       </rule>
-      <rule pattern="(in|and|or|not)\b">
-        <token type="OperatorWord"/>
+      <rule>
+        <include state="annotations"/>
       </rule>
-      <rule pattern="!=|==|&lt;&lt;|&gt;&gt;|&amp;&amp;|\+=|-=|\*=|/=|%=|&amp;=|\|=|\|\||[-~+/*%=&lt;&gt;&amp;^.!|$]">
+      <rule pattern="\*\*|[*\/~+-]|&lt;&lt;|&gt;&gt;|[&amp;^|]|==|!=|[&lt;&gt;]|&lt;=|&gt;=|!|&amp;&amp;|\|\||=|:=|\+=|-=|\*=|\/=|\*\*=|%=|&amp;=|\|=|\^=|&lt;&lt;=|&gt;&gt;=|-&gt;|\.">
         <token type="Operator"/>
       </rule>
-      <rule>
-        <include state="keywords"/>
+      <rule pattern="[]{}:(),;[]">
+        <token type="Punctuation"/>
       </rule>
-      <rule pattern="(def)((?:\s|\\\s)+)">
+      <rule pattern="(func)((?:\s|\\\s)+)">
         <bygroups>
-          <token type="Keyword"/>
+          <token type="KeywordDeclaration"/>
           <token type="Text"/>
         </bygroups>
         <push state="funcname"/>
       </rule>
-      <rule pattern="(class)((?:\s|\\\s)+)">
+      <rule pattern="(class|class_name|extends)((?:\s|\\\s)+)">
         <bygroups>
-          <token type="Keyword"/>
+          <token type="KeywordDeclaration"/>
           <token type="Text"/>
         </bygroups>
         <push state="classname"/>
       </rule>
-      <rule>
-        <include state="builtins"/>
-      </rule>
-      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#34;&#34;&#34;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDouble"/>
-        </bygroups>
-        <push state="tdqs"/>
-      </rule>
-      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#39;&#39;&#39;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringSingle"/>
-        </bygroups>
-        <push state="tsqs"/>
-      </rule>
-      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#34;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDouble"/>
-        </bygroups>
-        <push state="dqs"/>
-      </rule>
-      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#39;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringSingle"/>
-        </bygroups>
-        <push state="sqs"/>
+      <rule pattern="\$[a-zA-Z_][\w\/]*">
+        <token type="NameOther"/>
       </rule>
-      <rule pattern="([uUbB]?)(&#34;&#34;&#34;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDouble"/>
-        </bygroups>
-        <combined state="stringescape" state="tdqs"/>
+      <rule pattern="%[a-zA-Z_]\w*">
+        <token type="NameOther"/>
       </rule>
-      <rule pattern="([uUbB]?)(&#39;&#39;&#39;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringSingle"/>
-        </bygroups>
-        <combined state="stringescape" state="tsqs"/>
-      </rule>
-      <rule pattern="([uUbB]?)(&#34;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringDouble"/>
-        </bygroups>
-        <combined state="stringescape" state="dqs"/>
+      <rule pattern="%">
+        <token type="Operator"/>
       </rule>
-      <rule pattern="([uUbB]?)(&#39;)">
-        <bygroups>
-          <token type="LiteralStringAffix"/>
-          <token type="LiteralStringSingle"/>
-        </bygroups>
-        <combined state="stringescape" state="sqs"/>
+      <rule>
+        <include state="types"/>
       </rule>
       <rule>
-        <include state="name"/>
+        <include state="builtin_funcs"/>
       </rule>
       <rule>
         <include state="numbers"/>
       </rule>
-    </state>
-    <state name="keywords">
-      <rule pattern="(breakpoint|continue|onready|extends|signal|return|export|static|setget|switch|break|const|while|class|tool|pass|func|case|enum|else|elif|var|for|do|if)\b">
-        <token type="Keyword"/>
+      <rule pattern="(\b[a-zA-Z_]\w*)([(])">
+        <bygroups>
+          <token type="NameFunction"/>
+          <token type="Punctuation"/>
+        </bygroups>
+      </rule>
+      <rule pattern="&#39;">
+        <token type="LiteralStringSingle"/>
+        <push state="sqs"/>
       </rule>
-    </state>
-    <state name="dqs">
       <rule pattern="&#34;">
         <token type="LiteralStringDouble"/>
-        <pop depth="1"/>
-      </rule>
-      <rule pattern="\\\\|\\&#34;|\\\n">
-        <token type="LiteralStringEscape"/>
-      </rule>
-      <rule>
-        <include state="strings-double"/>
+        <push state="dqs"/>
       </rule>
-    </state>
-    <state name="tsqs">
       <rule pattern="&#39;&#39;&#39;">
         <token type="LiteralStringSingle"/>
-        <pop depth="1"/>
-      </rule>
-      <rule>
-        <include state="strings-single"/>
-      </rule>
-      <rule pattern="\n">
-        <token type="LiteralStringSingle"/>
-      </rule>
-    </state>
-    <state name="strings-double">
-      <rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsux%]">
-        <token type="LiteralStringInterpol"/>
-      </rule>
-      <rule pattern="[^\\\&#39;&#34;%\n]+">
-        <token type="LiteralStringDouble"/>
+        <push state="tsqs"/>
       </rule>
-      <rule pattern="[\&#39;&#34;\\]">
+      <rule pattern="&#34;&#34;&#34;">
         <token type="LiteralStringDouble"/>
+        <push state="tdqs"/>
       </rule>
-      <rule pattern="%">
-        <token type="LiteralStringDouble"/>
+      <rule pattern="[a-zA-Z_]\w*">
+        <token type="Name"/>
       </rule>
     </state>
   </rules>
-</lexer>
\ No newline at end of file
+</lexer>
diff --git a/lexers/embedded/gdscript3.xml b/lexers/embedded/gdscript3.xml
new file mode 100644
index 0000000..7045c54
--- /dev/null
+++ b/lexers/embedded/gdscript3.xml
@@ -0,0 +1,268 @@
+<lexer>
+  <config>
+    <name>GDScript3</name>
+    <alias>gdscript3</alias>
+    <alias>gd3</alias>
+    <filename>*.gd</filename>
+    <mime_type>text/x-gdscript</mime_type>
+    <mime_type>application/x-gdscript</mime_type>
+    <analyse single="true">
+      <regex pattern="^export" score="0.1"/>
+    </analyse>
+  </config>
+  <rules>
+    <state name="builtins">
+      <rule pattern="(?&lt;!\.)(instance_from_id|nearest_po2|print_stack|type_exist|rand_range|linear2db|var2bytes|dict2inst|randomize|bytes2var|rand_seed|db2linear|inst2dict|printerr|printraw|decimals|preload|deg2rad|str2var|stepify|var2str|convert|weakref|fposmod|funcref|rad2deg|dectime|printt|is_inf|is_nan|assert|Color8|typeof|ColorN|prints|floor|atan2|yield|randf|print|range|clamp|round|randi|sqrt|tanh|cosh|ceil|ease|acos|load|fmod|lerp|seed|sign|atan|sinh|hash|asin|sin|str|cos|tan|pow|exp|min|abs|log|max)\b">
+        <token type="NameBuiltin"/>
+      </rule>
+      <rule pattern="(?&lt;!\.)(self|false|true|PI|NAN|INF)\b">
+        <token type="NameBuiltinPseudo"/>
+      </rule>
+      <rule pattern="(?&lt;!\.)(Physics2DShapeQueryParameters|PhysicsShapeQueryParameters|Physics2DDirectBodyStateSW|NavigationPolygonInstance|ResourceInteractiveLoader|Physics2DDirectSpaceState|Physics2DShapeQueryResult|Physics2DTestMotionResult|InputEventJoystickButton|InputEventJoystickMotion|Physics2DDirectBodyState|PhysicsDirectBodyStateSW|PhysicsShapeQueryResult|PhysicsDirectSpaceState|SpatialSound2DServerSW|PackedDataContainerRef|NavigationMeshInstance|ResourceImportMetadata|PhysicsDirectBodyState|ConcavePolygonShape2D|CanvasItemShaderGraph|EditorScenePostImport|InputEventScreenTouch|InputEventMouseButton|InputEventMouseMotion|SpatialSound2DServer|AudioStreamOGGVorbis|VisibilityNotifier2D|InputEventScreenDrag|ConvexPolygonShape2D|SpatialSoundServerSW|ParticleAttractor2D|PackedDataContainer|SpatialStreamPlayer|RenderTargetTexture|AnimationTreePlayer|ConcavePolygonShape|InstancePlaceholder|MaterialShaderGraph|AudioStreamPlayback|VisibilityEnabler2D|SpatialSamplePlayer|DampedSpringJoint2D|InterpolatedCamera|ConvexPolygonShape|ConfirmationDialog|SpatialSoundServer|BakedLightInstance|ParallaxBackground|CollisionPolygon2D|CanvasItemMaterial|VisibilityNotifier|EditorImportPlugin|VideoStreamTheora|TouchScreenButton|ResourcePreloader|OccluderPolygon2D|BakedLightSampler|CollisionObject2D|RemoteTransform2D|PolygonPathFinder|StyleBoxImageMask|NavigationPolygon|TranslationServer|MultiMeshInstance|ImmediateGeometry|Physics2DServerSW|ColorPickerButton|VisibilityEnabler|PHashTranslation|RectangleShape2D|DirectionalLight|AnimatedSprite3D|WorldEnvironment|CollisionShape2D|EventStreamChibi|InputEventAction|CollisionPolygon|AudioStreamSpeex|EditorFileDialog|GeometryInstance|Generic6DOFJoint|PacketPeerStream|CanvasItemShader|KinematicBody2D|StyleBoxTexture|PhysicsServerSW|VSplitContainer|CenterContainer|GDFunctionState|AudioStreamOpus|TextureProgress|MarginContainer|CollisionObject|LightOccluder2D|AnimationPlayer|HSplitContainer|ScrollContainer|SoundRoomParams|Physics2DServer|MaterialShader|ShaderMaterial|ViewportSprite|SplitContainer|AudioStreamMPC|VisualInstance|PanelContainer|BackBufferCopy|SamplePlayer2D|CanvasModulate|ResourceLoader|CapsuleShape2D|ReferenceFrame|NavigationMesh|CollisionShape|ConeTwistJoint|ProximityGroup|AnimatedSprite|SegmentShape2D|BoneAttachment|RichTextLabel|CircleShape2D|VBoxContainer|PacketPeerUDP|SpatialPlayer|TextureButton|KinematicBody|SoundPlayer2D|PhysicsServer|ParallaxLayer|InputEventKey|GrooveJoint2D|PhysicsBody2D|FixedMaterial|GridContainer|HBoxContainer|StreamPeerSSL|StyleBoxEmpty|StreamPeerTCP|SampleLibrary|GDNativeClass|AudioServerSW|ResourceSaver|SpriteBase3D|StreamPlayer|AtlasTexture|VisualServer|SamplePlayer|StyleBoxFlat|StaticBody2D|SpriteFrames|MeshDataTool|MeshInstance|Vector3Array|BoxContainer|TabContainer|HButtonArray|LargeTexture|Navigation2D|WindowDialog|EditorScript|EditorPlugin|TextureFrame|AcceptDialog|ImageTexture|CapsuleShape|VehicleWheel|VButtonArray|Vector2Array|InputDefault|OptionButton|PathFollow2D|VehicleBody|ColorPicker|PopupDialog|ProgressBar|CanvasLayer|Translation|Environment|EventPlayer|VideoPlayer|EventStream|VideoStream|ButtonGroup|Particles2D|Patch9Frame|ButtonArray|SurfaceTool|MeshLibrary|PackedScene|PhysicsBody|AudioStream|Performance|StringArray|AudioServer|RigidBody2D|LineShape2D|SliderJoint|SphereShape|ShaderGraph|CheckButton|StreamPeer|FileDialog|PathFollow|SceneState|RoomBounds|Dictionary|VSeparator|PacketPeer|VScrollBar|MenuButton|HTTPClient|PinJoint2D|BakedLight|PlaneShape|InputEvent|BaseButton|HSeparator|HScrollBar|Navigation|PopupPanel|StaticBody|Position2D|Position3D|ToolButton|HingeJoint|CanvasItem|RayShape2D|ColorArray|ConfigFile|TCP_Server|RayCast2D|ColorRamp|SpotLight|RealArray|GraphNode|Container|Reference|PopupMenu|Separator|Polygon2D|MultiMesh|Semaphore|Transform|OmniLight|GraphEdit|Particles|Animation|Marshalls|SceneTree|RigidBody|XMLParser|PathRemap|ScrollBar|Directory|PCKPacker|RawArray|TextEdit|MainLoop|TreeItem|StyleBox|Material|Geometry|Matrix32|Resource|UndoRedo|RayShape|TestCube|ItemList|CheckBox|Camera2D|Skeleton|Sprite3D|Viewport|NodePath|IntArray|BoxShape|PinJoint|InputMap|LineEdit|GDScript|Vector3|TileMap|HSlider|Spatial|SpinBox|World2D|IP_Unix|Curve2D|Curve3D|WeakRef|GridMap|Matrix3|VSlider|CubeMap|Joint2D|Globals|Shape2D|Texture|Control|TileSet|Light2D|FuncRef|Vector2|RayCast|Script|Node2D|Button|BitMap|Sample|Object|String|Shader|Area2D|Slider|Sprite|Thread|Path2D|Camera|Portal|float|Theme|World|YSort|Shape|Joint|Mutex|Tween|RegEx|Label|Rect2|Array|Plane|Light|Range|Color|Input|Popup|Panel|Timer|Image|Area|Quad|bool|AABB|Quat|File|Tabs|Path|Font|Tree|Room|Mesh|Node|RID|int|Nil|IP|OS)\b">
+        <token type="NameException"/>
+      </rule>
+    </state>
+    <state name="sqs">
+      <rule pattern="&#39;">
+        <token type="LiteralStringSingle"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="\\\\|\\&#39;|\\\n">
+        <token type="LiteralStringEscape"/>
+      </rule>
+      <rule>
+        <include state="strings-single"/>
+      </rule>
+    </state>
+    <state name="stringescape">
+      <rule pattern="\\([\\abfnrtv&#34;\&#39;]|\n|N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})">
+        <token type="LiteralStringEscape"/>
+      </rule>
+    </state>
+    <state name="classname">
+      <rule pattern="[a-zA-Z_]\w*">
+        <token type="NameClass"/>
+        <pop depth="1"/>
+      </rule>
+    </state>
+    <state name="strings-single">
+      <rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsux%]">
+        <token type="LiteralStringInterpol"/>
+      </rule>
+      <rule pattern="[^\\\&#39;&#34;%\n]+">
+        <token type="LiteralStringSingle"/>
+      </rule>
+      <rule pattern="[\&#39;&#34;\\]">
+        <token type="LiteralStringSingle"/>
+      </rule>
+      <rule pattern="%">
+        <token type="LiteralStringSingle"/>
+      </rule>
+    </state>
+    <state name="funcname">
+      <rule pattern="[a-zA-Z_]\w*">
+        <token type="NameFunction"/>
+        <pop depth="1"/>
+      </rule>
+      <rule>
+        <pop depth="1"/>
+      </rule>
+    </state>
+    <state name="numbers">
+      <rule pattern="(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?">
+        <token type="LiteralNumberFloat"/>
+      </rule>
+      <rule pattern="\d+[eE][+-]?[0-9]+j?">
+        <token type="LiteralNumberFloat"/>
+      </rule>
+      <rule pattern="0[xX][a-fA-F0-9]+">
+        <token type="LiteralNumberHex"/>
+      </rule>
+      <rule pattern="\d+j?">
+        <token type="LiteralNumberInteger"/>
+      </rule>
+    </state>
+    <state name="tdqs">
+      <rule pattern="&#34;&#34;&#34;">
+        <token type="LiteralStringDouble"/>
+        <pop depth="1"/>
+      </rule>
+      <rule>
+        <include state="strings-double"/>
+      </rule>
+      <rule pattern="\n">
+        <token type="LiteralStringDouble"/>
+      </rule>
+    </state>
+    <state name="name">
+      <rule pattern="[a-zA-Z_]\w*">
+        <token type="Name"/>
+      </rule>
+    </state>
+    <state name="root">
+      <rule pattern="\n">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="^(\s*)([rRuUbB]{,2})(&#34;&#34;&#34;(?:.|\n)*?&#34;&#34;&#34;)">
+        <bygroups>
+          <token type="Text"/>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDoc"/>
+        </bygroups>
+      </rule>
+      <rule pattern="^(\s*)([rRuUbB]{,2})(&#39;&#39;&#39;(?:.|\n)*?&#39;&#39;&#39;)">
+        <bygroups>
+          <token type="Text"/>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDoc"/>
+        </bygroups>
+      </rule>
+      <rule pattern="[^\S\n]+">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="#.*$">
+        <token type="CommentSingle"/>
+      </rule>
+      <rule pattern="[]{}:(),;[]">
+        <token type="Punctuation"/>
+      </rule>
+      <rule pattern="\\\n">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="\\">
+        <token type="Text"/>
+      </rule>
+      <rule pattern="(in|and|or|not)\b">
+        <token type="OperatorWord"/>
+      </rule>
+      <rule pattern="!=|==|&lt;&lt;|&gt;&gt;|&amp;&amp;|\+=|-=|\*=|/=|%=|&amp;=|\|=|\|\||[-~+/*%=&lt;&gt;&amp;^.!|$]">
+        <token type="Operator"/>
+      </rule>
+      <rule>
+        <include state="keywords"/>
+      </rule>
+      <rule pattern="(def)((?:\s|\\\s)+)">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Text"/>
+        </bygroups>
+        <push state="funcname"/>
+      </rule>
+      <rule pattern="(class)((?:\s|\\\s)+)">
+        <bygroups>
+          <token type="Keyword"/>
+          <token type="Text"/>
+        </bygroups>
+        <push state="classname"/>
+      </rule>
+      <rule>
+        <include state="builtins"/>
+      </rule>
+      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#34;&#34;&#34;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDouble"/>
+        </bygroups>
+        <push state="tdqs"/>
+      </rule>
+      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#39;&#39;&#39;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringSingle"/>
+        </bygroups>
+        <push state="tsqs"/>
+      </rule>
+      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#34;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDouble"/>
+        </bygroups>
+        <push state="dqs"/>
+      </rule>
+      <rule pattern="([rR]|[uUbB][rR]|[rR][uUbB])(&#39;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringSingle"/>
+        </bygroups>
+        <push state="sqs"/>
+      </rule>
+      <rule pattern="([uUbB]?)(&#34;&#34;&#34;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDouble"/>
+        </bygroups>
+        <combined state="stringescape" state="tdqs"/>
+      </rule>
+      <rule pattern="([uUbB]?)(&#39;&#39;&#39;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringSingle"/>
+        </bygroups>
+        <combined state="stringescape" state="tsqs"/>
+      </rule>
+      <rule pattern="([uUbB]?)(&#34;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringDouble"/>
+        </bygroups>
+        <combined state="stringescape" state="dqs"/>
+      </rule>
+      <rule pattern="([uUbB]?)(&#39;)">
+        <bygroups>
+          <token type="LiteralStringAffix"/>
+          <token type="LiteralStringSingle"/>
+        </bygroups>
+        <combined state="stringescape" state="sqs"/>
+      </rule>
+      <rule>
+        <include state="name"/>
+      </rule>
+      <rule>
+        <include state="numbers"/>
+      </rule>
+    </state>
+    <state name="keywords">
+      <rule pattern="(breakpoint|continue|onready|extends|signal|return|export|static|setget|switch|break|const|while|class|tool|pass|func|case|enum|else|elif|var|for|do|if)\b">
+        <token type="Keyword"/>
+      </rule>
+    </state>
+    <state name="dqs">
+      <rule pattern="&#34;">
+        <token type="LiteralStringDouble"/>
+        <pop depth="1"/>
+      </rule>
+      <rule pattern="\\\\|\\&#34;|\\\n">
+        <token type="LiteralStringEscape"/>
+      </rule>
+      <rule>
+        <include state="strings-double"/>
+      </rule>
+    </state>
+    <state name="tsqs">
+      <rule pattern="&#39;&#39;&#39;">
+        <token type="LiteralStringSingle"/>
+        <pop depth="1"/>
+      </rule>
+      <rule>
+        <include state="strings-single"/>
+      </rule>
+      <rule pattern="\n">
+        <token type="LiteralStringSingle"/>
+      </rule>
+    </state>
+    <state name="strings-double">
+      <rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsux%]">
+        <token type="LiteralStringInterpol"/>
+      </rule>
+      <rule pattern="[^\\\&#39;&#34;%\n]+">
+        <token type="LiteralStringDouble"/>
+      </rule>
+      <rule pattern="[\&#39;&#34;\\]">
+        <token type="LiteralStringDouble"/>
+      </rule>
+      <rule pattern="%">
+        <token type="LiteralStringDouble"/>
+      </rule>
+    </state>
+  </rules>
+</lexer>
diff --git a/lexers/embedded/hlsl.xml b/lexers/embedded/hlsl.xml
index 774f53c..41ab323 100644
--- a/lexers/embedded/hlsl.xml
+++ b/lexers/embedded/hlsl.xml
@@ -4,6 +4,9 @@
     <alias>hlsl</alias>
     <filename>*.hlsl</filename>
     <filename>*.hlsli</filename>
+    <filename>*.cginc</filename>
+    <filename>*.fx</filename>
+    <filename>*.fxh</filename>
     <mime_type>text/x-hlsl</mime_type>
   </config>
   <rules>
@@ -104,4 +107,4 @@
       </rule>
     </state>
   </rules>
-</lexer>
\ No newline at end of file
+</lexer>
diff --git a/lexers/embedded/ini.xml b/lexers/embedded/ini.xml
index 13ef274..08f3870 100644
--- a/lexers/embedded/ini.xml
+++ b/lexers/embedded/ini.xml
@@ -15,6 +15,7 @@
     <filename>.pylintrc</filename>
     <mime_type>text/x-ini</mime_type>
     <mime_type>text/inf</mime_type>
+    <priority>0.1</priority> <!-- higher priority than Inform 6 -->
   </config>
   <rules>
     <state name="root">
diff --git a/lexers/embedded/mathematica.xml b/lexers/embedded/mathematica.xml
index 5f57470..0b8dfb6 100644
--- a/lexers/embedded/mathematica.xml
+++ b/lexers/embedded/mathematica.xml
@@ -4,10 +4,14 @@
     <alias>mathematica</alias>
     <alias>mma</alias>
     <alias>nb</alias>
-    <filename>*.nb</filename>
     <filename>*.cdf</filename>
-    <filename>*.nbp</filename>
+    <filename>*.m</filename>
     <filename>*.ma</filename>
+    <filename>*.mt</filename>
+    <filename>*.mx</filename>
+    <filename>*.nb</filename>
+    <filename>*.nbp</filename>
+    <filename>*.wl</filename>
     <mime_type>application/mathematica</mime_type>
     <mime_type>application/vnd.wolfram.mathematica</mime_type>
     <mime_type>application/vnd.wolfram.mathematica.package</mime_type>
diff --git a/lexers/embedded/nasm.xml b/lexers/embedded/nasm.xml
index a6107b5..defe65b 100644
--- a/lexers/embedded/nasm.xml
+++ b/lexers/embedded/nasm.xml
@@ -4,8 +4,10 @@
     <alias>nasm</alias>
     <filename>*.asm</filename>
     <filename>*.ASM</filename>
+    <filename>*.nasm</filename>
     <mime_type>text/x-nasm</mime_type>
     <case_insensitive>true</case_insensitive>
+    <priority>1.0</priority> <!-- TASM uses the same file endings, but TASM is not as common as NASM, so we prioritize NASM higher by default. -->
   </config>
   <rules>
     <state name="punctuation">
diff --git a/lexers/embedded/r.xml b/lexers/embedded/r.xml
index 6dbfcba..1e44ca4 100644
--- a/lexers/embedded/r.xml
+++ b/lexers/embedded/r.xml
@@ -17,6 +17,7 @@
     <mime_type>text/x-R</mime_type>
     <mime_type>text/x-r-history</mime_type>
     <mime_type>text/x-r-profile</mime_type>
+    <priority>0.1</priority> <!-- higher priority than Rebol -->
   </config>
   <rules>
     <state name="numbers">
diff --git a/lexers/embedded/twig.xml b/lexers/embedded/twig.xml
index 5b0496d..de95c5f 100644
--- a/lexers/embedded/twig.xml
+++ b/lexers/embedded/twig.xml
@@ -2,6 +2,7 @@
   <config>
     <name>Twig</name>
     <alias>twig</alias>
+    <filename>*.twig</filename>
     <mime_type>application/x-twig</mime_type>
     <dot_all>true</dot_all>
   </config>
diff --git a/lexers/go.go b/lexers/go.go
index 8a11ffc..77bc225 100644
--- a/lexers/go.go
+++ b/lexers/go.go
@@ -38,7 +38,7 @@ func goRules() Rules {
 			{`(var|func|struct|map|chan|type|interface|const)\b`, KeywordDeclaration, nil},
 			{Words(``, `\b`, `break`, `default`, `select`, `case`, `defer`, `go`, `else`, `goto`, `switch`, `fallthrough`, `if`, `range`, `continue`, `for`, `return`), Keyword, nil},
 			{`(true|false|iota|nil)\b`, KeywordConstant, nil},
-			{Words(``, `\b(\()`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `int`, `int8`, `int16`, `int32`, `int64`, `float`, `float32`, `float64`, `complex64`, `complex128`, `byte`, `rune`, `string`, `bool`, `error`, `uintptr`, `print`, `println`, `panic`, `recover`, `close`, `complex`, `real`, `imag`, `len`, `cap`, `append`, `copy`, `delete`, `new`, `make`), ByGroups(NameBuiltin, Punctuation), nil},
+			{Words(``, `\b(\()`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `int`, `int8`, `int16`, `int32`, `int64`, `float`, `float32`, `float64`, `complex64`, `complex128`, `byte`, `rune`, `string`, `bool`, `error`, `uintptr`, `print`, `println`, `panic`, `recover`, `close`, `complex`, `real`, `imag`, `len`, `cap`, `append`, `copy`, `delete`, `new`, `make`, `clear`, `min`, `max`), ByGroups(NameBuiltin, Punctuation), nil},
 			{Words(``, `\b`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `int`, `int8`, `int16`, `int32`, `int64`, `float`, `float32`, `float64`, `complex64`, `complex128`, `byte`, `rune`, `string`, `bool`, `error`, `uintptr`), KeywordType, nil},
 			{`\d+i`, LiteralNumber, nil},
 			{`\d+\.\d*([Ee][-+]\d+)?i`, LiteralNumber, nil},
diff --git a/lexers/vim.go b/lexers/vim.go
index b0059ea..5113062 100644
--- a/lexers/vim.go
+++ b/lexers/vim.go
@@ -30,9 +30,10 @@ func vimlRules() Rules {
 			{`#[0-9a-f]{6}`, LiteralNumberHex, nil},
 			{`^:`, Punctuation, nil},
 			{`[()<>+=!|,~-]`, Punctuation, nil},
-			{`\b(let|if|else|endif|elseif|fun|function|endfunction)\b`, Keyword, nil},
+			{`\b(let|if|else|endif|elseif|fun|function|endfunction|set|map|autocmd|filetype|hi(ghlight)?|execute|syntax|colorscheme)\b`, Keyword, nil},
 			{`\b(NONE|bold|italic|underline|dark|light)\b`, NameBuiltin, nil},
 			{`\b\w+\b`, NameOther, nil},
+			{`\n`, Text, nil},
 			{`.`, Text, nil},
 		},
 	}
diff --git a/regexp.go b/regexp.go
index 1794662..f49d5da 100644
--- a/regexp.go
+++ b/regexp.go
@@ -76,8 +76,8 @@ func (r Rules) Merge(rules Rules) Rules {
 }
 
 // MustNewLexer creates a new Lexer with deferred rules generation or panics.
-func MustNewLexer(config *Config, rulesFunc func() Rules) *RegexLexer {
-	lexer, err := NewLexer(config, rulesFunc)
+func MustNewLexer(config *Config, rules func() Rules) *RegexLexer {
+	lexer, err := NewLexer(config, rules)
 	if err != nil {
 		panic(err)
 	}
@@ -298,11 +298,12 @@ func (r *RegexLexer) SetAnalyser(analyser func(text string) float32) Lexer {
 	return r
 }
 
-func (r *RegexLexer) AnalyseText(text string) float32 { // nolint
+// AnalyseText scores how likely a fragment of text is to match this lexer, between 0.0 and 1.0.
+func (r *RegexLexer) AnalyseText(text string) float32 {
 	if r.analyser != nil {
 		return r.analyser(text)
 	}
-	return 0.0
+	return 0
 }
 
 // SetConfig replaces the Config for this Lexer.
@@ -311,7 +312,8 @@ func (r *RegexLexer) SetConfig(config *Config) *RegexLexer {
 	return r
 }
 
-func (r *RegexLexer) Config() *Config { // nolint
+// Config returns the Config for this Lexer.
+func (r *RegexLexer) Config() *Config {
 	return r.config
 }
 
@@ -406,7 +408,8 @@ func (r *RegexLexer) needRules() error {
 	return err
 }
 
-func (r *RegexLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) { // nolint
+// Tokenise text using lexer, returning an iterator.
+func (r *RegexLexer) Tokenise(options *TokeniseOptions, text string) (Iterator, error) {
 	err := r.needRules()
 	if err != nil {
 		return nil, err
diff --git a/registry.go b/registry.go
index b047dfc..55ed362 100644
--- a/registry.go
+++ b/registry.go
@@ -172,16 +172,37 @@ func (l *LexerRegistry) Analyse(text string) Lexer {
 	return picked
 }
 
-// Register a Lexer with the LexerRegistry.
+// Register a Lexer with the LexerRegistry. If the lexer is already registered
+// it will be replaced.
 func (l *LexerRegistry) Register(lexer Lexer) Lexer {
 	lexer.SetRegistry(l)
 	config := lexer.Config()
+
 	l.byName[config.Name] = lexer
 	l.byName[strings.ToLower(config.Name)] = lexer
+
 	for _, alias := range config.Aliases {
 		l.byAlias[alias] = lexer
 		l.byAlias[strings.ToLower(alias)] = lexer
 	}
-	l.Lexers = append(l.Lexers, lexer)
+
+	l.Lexers = add(l.Lexers, lexer)
+
 	return lexer
 }
+
+// add adds a lexer to a slice of lexers if it doesn't already exist, or if found will replace it.
+func add(lexers Lexers, lexer Lexer) Lexers {
+	for i, val := range lexers {
+		if val == nil {
+			continue
+		}
+
+		if val.Config().Name == lexer.Config().Name {
+			lexers[i] = lexer
+			return lexers
+		}
+	}
+
+	return append(lexers, lexer)
+}
diff --git a/serialise.go b/serialise.go
index 2b727db..f29dc5d 100644
--- a/serialise.go
+++ b/serialise.go
@@ -7,10 +7,13 @@ import (
 	"fmt"
 	"io"
 	"io/fs"
+	"math"
 	"path/filepath"
 	"reflect"
 	"regexp"
 	"strings"
+
+	"github.com/dlclark/regexp2"
 )
 
 // Serialisation of Chroma rules to XML. The format is:
@@ -107,7 +110,7 @@ func fastUnmarshalConfig(from fs.FS, path string) (*Config, error) {
 			var config Config
 			err = dec.DecodeElement(&config, &se)
 			if err != nil {
-				panic(err)
+				return nil, fmt.Errorf("%s: %w", path, err)
 			}
 			return &config, nil
 		}
@@ -129,14 +132,58 @@ func NewXMLLexer(from fs.FS, path string) (*RegexLexer, error) {
 	if err != nil {
 		return nil, err
 	}
+
 	for _, glob := range append(config.Filenames, config.AliasFilenames...) {
 		_, err := filepath.Match(glob, "")
 		if err != nil {
 			return nil, fmt.Errorf("%s: %q is not a valid glob: %w", config.Name, glob, err)
 		}
 	}
+
+	var analyserFn func(string) float32
+
+	if config.Analyse != nil {
+		type regexAnalyse struct {
+			re    *regexp2.Regexp
+			score float32
+		}
+
+		regexAnalysers := make([]regexAnalyse, 0, len(config.Analyse.Regexes))
+
+		for _, ra := range config.Analyse.Regexes {
+			re, err := regexp2.Compile(ra.Pattern, regexp2.None)
+			if err != nil {
+				return nil, fmt.Errorf("%s: %q is not a valid analyser regex: %w", config.Name, ra.Pattern, err)
+			}
+
+			regexAnalysers = append(regexAnalysers, regexAnalyse{re, ra.Score})
+		}
+
+		analyserFn = func(text string) float32 {
+			var score float32
+
+			for _, ra := range regexAnalysers {
+				ok, err := ra.re.MatchString(text)
+				if err != nil {
+					return 0
+				}
+
+				if ok && config.Analyse.Single {
+					return float32(math.Min(float64(ra.score), 1.0))
+				}
+
+				if ok {
+					score += ra.score
+				}
+			}
+
+			return float32(math.Min(float64(score), 1.0))
+		}
+	}
+
 	return &RegexLexer{
-		config: config,
+		config:   config,
+		analyser: analyserFn,
 		fetchRulesFunc: func() (Rules, error) {
 			var lexer struct {
 				Config
diff --git a/styles/onedark.xml b/styles/onedark.xml
index f5217b6..6921eb5 100644
--- a/styles/onedark.xml
+++ b/styles/onedark.xml
@@ -20,4 +20,6 @@
   <entry type="LiteralNumber"       style="#D19A66"/>
   <entry type="Operator"            style="#56B6C2"/>
   <entry type="Comment"             style="#7F848E"/>
+  <entry type="GenericDeleted"      style="#E06C75"/>
+  <entry type="GenericInserted"     style="bold #98C379"/>
 </style>


Test patch:
diff --git a/lexers/c_test.go b/lexers/c_test.go
deleted file mode 100644
index 4ef5b5d..0000000
--- a/lexers/c_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package lexers_test
-
-import (
-	"io/ioutil"
-	"testing"
-
-	"github.com/alecthomas/chroma/v2"
-	"github.com/alecthomas/chroma/v2/lexers"
-
-	"github.com/alecthomas/assert/v2"
-)
-
-func TestC_AnalyseText(t *testing.T) {
-	tests := map[string]struct {
-		Filepath string
-		Expected float32
-	}{
-		"include": {
-			Filepath: "testdata/c_include.c",
-			Expected: 0.1,
-		},
-		"ifdef": {
-			Filepath: "testdata/c_ifdef.c",
-			Expected: 0.1,
-		},
-		"ifndef": {
-			Filepath: "testdata/c_ifndef.c",
-			Expected: 0.1,
-		},
-	}
-
-	for name, test := range tests {
-		test := test
-		t.Run(name, func(t *testing.T) {
-			data, err := ioutil.ReadFile(test.Filepath)
-			assert.NoError(t, err)
-
-			analyser, ok := lexers.C.(chroma.Analyser)
-			assert.True(t, ok)
-
-			assert.Equal(t, test.Expected, analyser.AnalyseText(string(data)))
-		})
-	}
-}
diff --git a/lexers/cpp_test.go b/lexers/cpp_test.go
deleted file mode 100644
index ade2743..0000000
--- a/lexers/cpp_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package lexers_test
-
-import (
-	"os"
-	"testing"
-
-	"github.com/alecthomas/chroma/v2"
-	"github.com/alecthomas/chroma/v2/lexers"
-
-	"github.com/alecthomas/assert/v2"
-)
-
-func TestCpp_AnalyseText(t *testing.T) {
-	tests := map[string]struct {
-		Filepath string
-		Expected float32
-	}{
-		"include": {
-			Filepath: "testdata/cpp_include.cpp",
-			Expected: 0.2,
-		},
-		"namespace": {
-			Filepath: "testdata/cpp_namespace.cpp",
-			Expected: 0.4,
-		},
-	}
-
-	for name, test := range tests {
-		test := test
-		t.Run(name, func(t *testing.T) {
-			data, err := os.ReadFile(test.Filepath)
-			assert.NoError(t, err)
-
-			analyser, ok := lexers.CPP.(chroma.Analyser)
-			assert.True(t, ok)
-
-			assert.Equal(t, test.Expected, analyser.AnalyseText(string(data)))
-		})
-	}
-}
-
-func TestIssue290(t *testing.T) {
-	input := `// 64-bit floats have 53 digits of precision, including the whole-number-part.
-double a =     0011111110111001100110011001100110011001100110011001100110011010; // imperfect representation of 0.1
-double b =     0011111111001001100110011001100110011001100110011001100110011010; // imperfect representation of 0.2
-double c =     0011111111010011001100110011001100110011001100110011001100110011; // imperfect representation of 0.3
-double a + b = 0011111111010011001100110011001100110011001100110011001100110100; // Note that this is not quite equal to the "canonical" 0.3!a
-`
-	it, err := lexers.GlobalLexerRegistry.Get("C++").Tokenise(nil, input)
-	assert.NoError(t, err)
-	for {
-		token := it()
-		if token == chroma.EOF {
-			break
-		}
-	}
-}
diff --git a/lexers/lexers_test.go b/lexers/lexers_test.go
index f7f16dd..840d67e 100644
--- a/lexers/lexers_test.go
+++ b/lexers/lexers_test.go
@@ -9,7 +9,7 @@ import (
 	"strings"
 	"testing"
 
-	assert "github.com/alecthomas/assert/v2"
+	"github.com/alecthomas/assert/v2"
 	"github.com/alecthomas/repr"
 
 	"github.com/alecthomas/chroma/v2"
@@ -73,11 +73,16 @@ func FileTest(t *testing.T, lexer chroma.Lexer, actualFilename, expectedFilename
 		actual, err := chroma.Tokenise(lexer, nil, string(actualText))
 		assert.NoError(t, err)
 
-		if os.Getenv("RECORD") == "true" {
+		if os.Getenv("RECORD") != "" {
 			// Update the expected file with the generated output of this lexer
 			f, err := os.Create(expectedFilename)
 			defer f.Close() // nolint: gosec
 			assert.NoError(t, err)
+			for _, token := range actual {
+				if token.Type == chroma.Error {
+					t.Logf("Found Error token in lexer %s output: %s", lexer.Config().Name, repr.String(token))
+				}
+			}
 			assert.NoError(t, formatters.JSON.Format(f, nil, chroma.Literator(actual...)))
 		} else {
 			// Read expected JSON into token slice.
@@ -87,10 +92,14 @@ func FileTest(t *testing.T, lexer chroma.Lexer, actualFilename, expectedFilename
 			err = json.NewDecoder(r).Decode(&expected)
 			assert.NoError(t, err)
 
-			// Equal?
-			assert.Equal(t,
-				repr.String(expected, repr.Indent(" ")),
-				repr.String(actual, repr.Indent(" ")))
+			assert.Equal(t, expected, actual)
+
+			// Check for error tokens.
+			for _, token := range actual {
+				if token.Type == chroma.Error {
+					t.Logf("Found Error token in lexer %s output: %s", lexer.Config().Name, repr.String(token))
+				}
+			}
 		}
 	})
 }
diff --git a/lexers/testdata/c_ifdef.c b/lexers/testdata/analysis/c.ifdef.actual
similarity index 100%
rename from lexers/testdata/c_ifdef.c
rename to lexers/testdata/analysis/c.ifdef.actual
diff --git a/lexers/testdata/analysis/c.ifdef.expected b/lexers/testdata/analysis/c.ifdef.expected
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/lexers/testdata/analysis/c.ifdef.expected
@@ -0,0 +1,1 @@
+0.1
diff --git a/lexers/testdata/c_ifndef.c b/lexers/testdata/analysis/c.ifndef.actual
similarity index 100%
rename from lexers/testdata/c_ifndef.c
rename to lexers/testdata/analysis/c.ifndef.actual
diff --git a/lexers/testdata/analysis/c.ifndef.expected b/lexers/testdata/analysis/c.ifndef.expected
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/lexers/testdata/analysis/c.ifndef.expected
@@ -0,0 +1,1 @@
+0.1
diff --git a/lexers/testdata/c_include.c b/lexers/testdata/analysis/c.include.actual
similarity index 100%
rename from lexers/testdata/c_include.c
rename to lexers/testdata/analysis/c.include.actual
diff --git a/lexers/testdata/analysis/c.include.expected b/lexers/testdata/analysis/c.include.expected
new file mode 100644
index 0000000..49d5957
--- /dev/null
+++ b/lexers/testdata/analysis/c.include.expected
@@ -0,0 +1,1 @@
+0.1
diff --git a/lexers/testdata/cpp_include.cpp b/lexers/testdata/analysis/cpp.include.actual
similarity index 100%
rename from lexers/testdata/cpp_include.cpp
rename to lexers/testdata/analysis/cpp.include.actual
diff --git a/lexers/testdata/analysis/cpp.include.expected b/lexers/testdata/analysis/cpp.include.expected
new file mode 100644
index 0000000..3b04cfb
--- /dev/null
+++ b/lexers/testdata/analysis/cpp.include.expected
@@ -0,0 +1,1 @@
+0.2
diff --git a/lexers/testdata/cpp_namespace.cpp b/lexers/testdata/analysis/cpp.namespace.actual
similarity index 100%
rename from lexers/testdata/cpp_namespace.cpp
rename to lexers/testdata/analysis/cpp.namespace.actual
diff --git a/lexers/testdata/analysis/cpp.namespace.expected b/lexers/testdata/analysis/cpp.namespace.expected
new file mode 100644
index 0000000..bd73f47
--- /dev/null
+++ b/lexers/testdata/analysis/cpp.namespace.expected
@@ -0,0 +1,1 @@
+0.4
diff --git a/lexers/testdata/bashsession.actual b/lexers/testdata/bash-session.actual
similarity index 100%
rename from lexers/testdata/bashsession.actual
rename to lexers/testdata/bash-session.actual
diff --git a/lexers/testdata/bashsession.expected b/lexers/testdata/bash-session.expected
similarity index 100%
rename from lexers/testdata/bashsession.expected
rename to lexers/testdata/bash-session.expected
diff --git a/lexers/testdata/gdscript.actual b/lexers/testdata/gdscript.actual
index 64d8663..1615bb4 100644
--- a/lexers/testdata/gdscript.actual
+++ b/lexers/testdata/gdscript.actual
@@ -1,37 +1,48 @@
-# a file is a class!
+# Everything after "#" is a comment.
+# A file is a class!
 
-# inheritance
+# (optional) icon to show in the editor dialogs:
+@icon("res://path/to/optional/icon.svg")
 
+# (optional) class definition:
+class_name MyClass
+
+# Inheritance:
 extends BaseClass
 
-# member variables
 
+# Member variables.
 var a = 5
 var s = "Hello"
 var arr = [1, 2, 3]
-var dict = {"key": "value", 2:3}
-
-# constants
+var dict = {"key": "value", 2: 3}
+var other_dict = {key = "value", other_key = 2}
+var typed_var: int
+var inferred_type := "String"
 
-const answer = 42
-const thename = "Charly"
-
-# enums
+# Constants.
+const ANSWER = 42
+const THE_NAME = "Charly"
 
+# Enums.
 enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
 enum Named {THING_1, THING_2, ANOTHER_THING = -1}
 
-# function
+# Built-in vector types.
+var v2 = Vector2(1, 2)
+var v3 = Vector3(1, 2, 3)
+
 
-func some_function(param1, param2):
-    var local_var = 5
+# Functions.
+func some_function(param1, param2, param3):
+    const local_const = 5
 
-    if param1 < local_var:
+    if param1 < local_const:
         print(param1)
     elif param2 > 5:
         print(param2)
     else:
-        print("fail!")
+        print("Fail!")
 
     for i in range(20):
         print(i)
@@ -39,18 +50,34 @@ func some_function(param1, param2):
     while param2 != 0:
         param2 -= 1
 
-    var local_var2 = param1+3
-    return local_var2
+    match param3:
+        3:
+            print("param3 is 3!")
+        _:
+            print("param3 is not 3!")
+
+    var local_var = param1 + 3
+    return local_var
+
+
+# Functions override functions with the same name on the base/super class.
+# If you still want to call them, use "super":
+func something(p1, p2):
+    super(p1, p2)
+
 
+# It's also possible to call another function in the super class:
+func other_something(p1, p2):
+    super.something(p1, p2)
 
-# inner class
 
+# Inner class
 class Something:
     var a = 10
 
-# constructor
 
+# Constructor
 func _init():
-    print("constructed!")
+    print("Constructed!")
     var lv = Something.new()
-    print(lv.a)
\ No newline at end of file
+    print(lv.a)
diff --git a/lexers/testdata/gdscript.expected b/lexers/testdata/gdscript.expected
index f158383..308b74f 100644
--- a/lexers/testdata/gdscript.expected
+++ b/lexers/testdata/gdscript.expected
@@ -1,258 +1,414 @@
 [
-  {"type":"CommentSingle","value":"# a file is a class!"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# inheritance"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"extends"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"BaseClass"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# member variables"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"a"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"5"},
-  {"type":"Text","value":"\n"},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"s"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralStringDouble","value":"\"Hello\""},
-  {"type":"Text","value":"\n"},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"arr"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"Punctuation","value":"["},
-  {"type":"LiteralNumberInteger","value":"1"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"2"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"3"},
-  {"type":"Punctuation","value":"]"},
-  {"type":"Text","value":"\n"},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"dict"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"Punctuation","value":"{"},
-  {"type":"LiteralStringDouble","value":"\"key\""},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":" "},
-  {"type":"LiteralStringDouble","value":"\"value\""},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"2"},
-  {"type":"Punctuation","value":":"},
-  {"type":"LiteralNumberInteger","value":"3"},
-  {"type":"Punctuation","value":"}"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# constants"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"const"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"answer"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"42"},
-  {"type":"Text","value":"\n"},
-  {"type":"Keyword","value":"const"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"thename"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralStringDouble","value":"\"Charly\""},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# enums"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"enum"},
-  {"type":"Text","value":" "},
-  {"type":"Punctuation","value":"{"},
-  {"type":"Name","value":"UNIT_NEUTRAL"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"UNIT_ENEMY"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"UNIT_ALLY"},
-  {"type":"Punctuation","value":"}"},
-  {"type":"Text","value":"\n"},
-  {"type":"Keyword","value":"enum"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"Named"},
-  {"type":"Text","value":" "},
-  {"type":"Punctuation","value":"{"},
-  {"type":"Name","value":"THING_1"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"THING_2"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"ANOTHER_THING"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"-"},
-  {"type":"LiteralNumberInteger","value":"1"},
-  {"type":"Punctuation","value":"}"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# function"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"func"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"some_function"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"param1"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"param2"},
-  {"type":"Punctuation","value":"):"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"local_var"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"5"},
-  {"type":"Text","value":"\n\n    "},
-  {"type":"Keyword","value":"if"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"param1"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"\u003c"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"local_var"},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":"\n        "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"param1"},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"elif"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"param2"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"\u003e"},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"5"},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":"\n        "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"param2"},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"else"},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":"\n        "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"LiteralStringDouble","value":"\"fail!\""},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":"\n\n    "},
-  {"type":"Keyword","value":"for"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"i"},
-  {"type":"Text","value":" "},
-  {"type":"OperatorWord","value":"in"},
-  {"type":"Text","value":" "},
-  {"type":"NameBuiltin","value":"range"},
-  {"type":"Punctuation","value":"("},
-  {"type":"LiteralNumberInteger","value":"20"},
-  {"type":"Punctuation","value":"):"},
-  {"type":"Text","value":"\n        "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"i"},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":"\n\n    "},
-  {"type":"Keyword","value":"while"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"param2"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"!="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"0"},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":"\n        "},
-  {"type":"Name","value":"param2"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"-="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"1"},
-  {"type":"Text","value":"\n\n    "},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"local_var2"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"param1"},
-  {"type":"Operator","value":"+"},
-  {"type":"LiteralNumberInteger","value":"3"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"return"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"local_var2"},
-  {"type":"Text","value":"\n\n\n"},
-  {"type":"CommentSingle","value":"# inner class"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"class"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"Something"},
-  {"type":"Punctuation","value":":"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"a"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberInteger","value":"10"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"CommentSingle","value":"# constructor"},
-  {"type":"Text","value":"\n\n"},
-  {"type":"Keyword","value":"func"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"_init"},
-  {"type":"Punctuation","value":"():"},
-  {"type":"Text","value":"\n    "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"LiteralStringDouble","value":"\"constructed!\""},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"var"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"lv"},
-  {"type":"Text","value":" "},
-  {"type":"Operator","value":"="},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"Something"},
-  {"type":"Operator","value":"."},
-  {"type":"Name","value":"new"},
-  {"type":"Punctuation","value":"()"},
-  {"type":"Text","value":"\n    "},
-  {"type":"NameBuiltin","value":"print"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"lv"},
-  {"type":"Operator","value":"."},
-  {"type":"Name","value":"a"},
-  {"type":"Punctuation","value":")"}
+    {"type":"CommentSingle","value":"# Everything after \"#\" is a comment."},
+    {"type":"Text","value":"\n"},
+    {"type":"CommentSingle","value":"# A file is a class!"},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# (optional) icon to show in the editor dialogs:"},
+    {"type":"Text","value":"\n"},
+    {"type":"NameDecorator","value":"@icon"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralStringDouble","value":"\"res://path/to/optional/icon.svg\""},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# (optional) class definition:"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"class_name"},
+    {"type":"Text","value":" "},
+    {"type":"NameClass","value":"MyClass"},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# Inheritance:"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"extends"},
+    {"type":"Text","value":" "},
+    {"type":"NameClass","value":"BaseClass"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# Member variables."},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"a"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"5"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"s"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralStringDouble","value":"\"Hello\""},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"arr"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Punctuation","value":"["},
+    {"type":"LiteralNumberInteger","value":"1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"2"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"3"},
+    {"type":"Punctuation","value":"]"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"dict"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Punctuation","value":"{"},
+    {"type":"LiteralStringDouble","value":"\"key\""},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":" "},
+    {"type":"LiteralStringDouble","value":"\"value\""},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"2"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"3"},
+    {"type":"Punctuation","value":"}"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"other_dict"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Punctuation","value":"{"},
+    {"type":"Name","value":"key"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralStringDouble","value":"\"value\""},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"other_key"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"2"},
+    {"type":"Punctuation","value":"}"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"typed_var"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":" "},
+    {"type":"KeywordType","value":"int"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"inferred_type"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":":="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralStringDouble","value":"\"String\""},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# Constants."},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"const"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"ANSWER"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"42"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"const"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"THE_NAME"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralStringDouble","value":"\"Charly\""},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# Enums."},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"enum"},
+    {"type":"Text","value":" "},
+    {"type":"Punctuation","value":"{"},
+    {"type":"Name","value":"UNIT_NEUTRAL"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"UNIT_ENEMY"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"UNIT_ALLY"},
+    {"type":"Punctuation","value":"}"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"enum"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"Named"},
+    {"type":"Text","value":" "},
+    {"type":"Punctuation","value":"{"},
+    {"type":"Name","value":"THING_1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"THING_2"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"ANOTHER_THING"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"-"},
+    {"type":"LiteralNumberInteger","value":"1"},
+    {"type":"Punctuation","value":"}"},
+    {"type":"Text","value":"\n\n"},
+    {"type":"CommentSingle","value":"# Built-in vector types."},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"v2"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"NameClass","value":"Vector2"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralNumberInteger","value":"1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"2"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"v3"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"NameClass","value":"Vector3"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralNumberInteger","value":"1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"2"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"3"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# Functions."},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"func"},
+    {"type":"Text","value":" "},
+    {"type":"NameFunction","value":"some_function"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"param1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param2"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param3"},
+    {"type":"Punctuation","value":"):"},
+    {"type":"Text","value":"\n    "},
+    {"type":"KeywordDeclaration","value":"const"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"local_const"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"5"},
+    {"type":"Text","value":"\n\n    "},
+    {"type":"Keyword","value":"if"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param1"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"\u003c"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"local_const"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n        "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"param1"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n    "},
+    {"type":"Keyword","value":"elif"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param2"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"\u003e"},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"5"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n        "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"param2"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n    "},
+    {"type":"Keyword","value":"else"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n        "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralStringDouble","value":"\"Fail!\""},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n    "},
+    {"type":"Keyword","value":"for"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"i"},
+    {"type":"Text","value":" "},
+    {"type":"OperatorWord","value":"in"},
+    {"type":"Text","value":" "},
+    {"type":"NameBuiltin","value":"range"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralNumberInteger","value":"20"},
+    {"type":"Punctuation","value":"):"},
+    {"type":"Text","value":"\n        "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"i"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n    "},
+    {"type":"Keyword","value":"while"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param2"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"!="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"0"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n        "},
+    {"type":"Name","value":"param2"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"-="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"1"},
+    {"type":"Text","value":"\n\n    "},
+    {"type":"Keyword","value":"match"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param3"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n        "},
+    {"type":"LiteralNumberInteger","value":"3"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n            "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralStringDouble","value":"\"param3 is 3!\""},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n        "},
+    {"type":"Name","value":"_"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n            "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralStringDouble","value":"\"param3 is not 3!\""},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n    "},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"local_var"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"param1"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"+"},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"3"},
+    {"type":"Text","value":"\n    "},
+    {"type":"Keyword","value":"return"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"local_var"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# Functions override functions with the same name on the base/super class."},
+    {"type":"Text","value":"\n"},
+    {"type":"CommentSingle","value":"# If you still want to call them, use \"super\":"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"func"},
+    {"type":"Text","value":" "},
+    {"type":"NameFunction","value":"something"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"p1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"p2"},
+    {"type":"Punctuation","value":"):"},
+    {"type":"Text","value":"\n    "},
+    {"type":"Keyword","value":"super"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"p1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"p2"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# It's also possible to call another function in the super class:"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"func"},
+    {"type":"Text","value":" "},
+    {"type":"NameFunction","value":"other_something"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"p1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"p2"},
+    {"type":"Punctuation","value":"):"},
+    {"type":"Text","value":"\n    "},
+    {"type":"Keyword","value":"super"},
+    {"type":"Operator","value":"."},
+    {"type":"NameFunction","value":"something"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"p1"},
+    {"type":"Punctuation","value":","},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"p2"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# Inner class"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"class"},
+    {"type":"Text","value":" "},
+    {"type":"NameClass","value":"Something"},
+    {"type":"Punctuation","value":":"},
+    {"type":"Text","value":"\n    "},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"a"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"LiteralNumberInteger","value":"10"},
+    {"type":"Text","value":"\n\n\n"},
+    {"type":"CommentSingle","value":"# Constructor"},
+    {"type":"Text","value":"\n"},
+    {"type":"KeywordDeclaration","value":"func"},
+    {"type":"Text","value":" "},
+    {"type":"NameFunction","value":"_init"},
+    {"type":"Punctuation","value":"():"},
+    {"type":"Text","value":"\n    "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"LiteralStringDouble","value":"\"Constructed!\""},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n    "},
+    {"type":"KeywordDeclaration","value":"var"},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"lv"},
+    {"type":"Text","value":" "},
+    {"type":"Operator","value":"="},
+    {"type":"Text","value":" "},
+    {"type":"Name","value":"Something"},
+    {"type":"Operator","value":"."},
+    {"type":"NameFunction","value":"new"},
+    {"type":"Punctuation","value":"()"},
+    {"type":"Text","value":"\n    "},
+    {"type":"NameBuiltin","value":"print"},
+    {"type":"Punctuation","value":"("},
+    {"type":"Name","value":"lv"},
+    {"type":"Operator","value":"."},
+    {"type":"Name","value":"a"},
+    {"type":"Punctuation","value":")"},
+    {"type":"Text","value":"\n"}
 ]
diff --git a/lexers/testdata/gdscript3.actual b/lexers/testdata/gdscript3.actual
new file mode 100644
index 0000000..64d8663
--- /dev/null
+++ b/lexers/testdata/gdscript3.actual
@@ -0,0 +1,56 @@
+# a file is a class!
+
+# inheritance
+
+extends BaseClass
+
+# member variables
+
+var a = 5
+var s = "Hello"
+var arr = [1, 2, 3]
+var dict = {"key": "value", 2:3}
+
+# constants
+
+const answer = 42
+const thename = "Charly"
+
+# enums
+
+enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
+enum Named {THING_1, THING_2, ANOTHER_THING = -1}
+
+# function
+
+func some_function(param1, param2):
+    var local_var = 5
+
+    if param1 < local_var:
+        print(param1)
+    elif param2 > 5:
+        print(param2)
+    else:
+        print("fail!")
+
+    for i in range(20):
+        print(i)
+
+    while param2 != 0:
+        param2 -= 1
+
+    var local_var2 = param1+3
+    return local_var2
+
+
+# inner class
+
+class Something:
+    var a = 10
+
+# constructor
+
+func _init():
+    print("constructed!")
+    var lv = Something.new()
+    print(lv.a)
\ No newline at end of file
diff --git a/lexers/testdata/gdscript3.expected b/lexers/testdata/gdscript3.expected
new file mode 100644
index 0000000..f158383
--- /dev/null
+++ b/lexers/testdata/gdscript3.expected
@@ -0,0 +1,258 @@
+[
+  {"type":"CommentSingle","value":"# a file is a class!"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# inheritance"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"extends"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"BaseClass"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# member variables"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"a"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"5"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"s"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"Hello\""},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"arr"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"["},
+  {"type":"LiteralNumberInteger","value":"1"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"2"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"3"},
+  {"type":"Punctuation","value":"]"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"dict"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"LiteralStringDouble","value":"\"key\""},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"value\""},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"2"},
+  {"type":"Punctuation","value":":"},
+  {"type":"LiteralNumberInteger","value":"3"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# constants"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"const"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"answer"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"42"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"const"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"thename"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringDouble","value":"\"Charly\""},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# enums"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"enum"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Name","value":"UNIT_NEUTRAL"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"UNIT_ENEMY"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"UNIT_ALLY"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"enum"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Named"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Name","value":"THING_1"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"THING_2"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"ANOTHER_THING"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"-"},
+  {"type":"LiteralNumberInteger","value":"1"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# function"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"func"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"some_function"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"param1"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"param2"},
+  {"type":"Punctuation","value":"):"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"local_var"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"5"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"Keyword","value":"if"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"param1"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"\u003c"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"local_var"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"\n        "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"param1"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"elif"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"param2"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"5"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"\n        "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"param2"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"else"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"\n        "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralStringDouble","value":"\"fail!\""},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"Keyword","value":"for"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"i"},
+  {"type":"Text","value":" "},
+  {"type":"OperatorWord","value":"in"},
+  {"type":"Text","value":" "},
+  {"type":"NameBuiltin","value":"range"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralNumberInteger","value":"20"},
+  {"type":"Punctuation","value":"):"},
+  {"type":"Text","value":"\n        "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"i"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"Keyword","value":"while"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"param2"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"!="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"0"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"\n        "},
+  {"type":"Name","value":"param2"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"-="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"1"},
+  {"type":"Text","value":"\n\n    "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"local_var2"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"param1"},
+  {"type":"Operator","value":"+"},
+  {"type":"LiteralNumberInteger","value":"3"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"return"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"local_var2"},
+  {"type":"Text","value":"\n\n\n"},
+  {"type":"CommentSingle","value":"# inner class"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"class"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Something"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"a"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberInteger","value":"10"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"CommentSingle","value":"# constructor"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"func"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"_init"},
+  {"type":"Punctuation","value":"():"},
+  {"type":"Text","value":"\n    "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"LiteralStringDouble","value":"\"constructed!\""},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"var"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"lv"},
+  {"type":"Text","value":" "},
+  {"type":"Operator","value":"="},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"Something"},
+  {"type":"Operator","value":"."},
+  {"type":"Name","value":"new"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"Text","value":"\n    "},
+  {"type":"NameBuiltin","value":"print"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"lv"},
+  {"type":"Operator","value":"."},
+  {"type":"Name","value":"a"},
+  {"type":"Punctuation","value":")"}
+]
diff --git a/lexers/testdata/hlsl.expected b/lexers/testdata/hlsl.expected
index dcd0491..5a296ea 100644
--- a/lexers/testdata/hlsl.expected
+++ b/lexers/testdata/hlsl.expected
@@ -1,40 +1,40 @@
-[
-  {"type":"KeywordType","value":"float4"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"vertex"},
-  {"type":"Punctuation","value":"("},
-  {"type":"KeywordType","value":"float3"},
-  {"type":"Text","value":" "},
-  {"type":"Name","value":"position"},
-  {"type":"Punctuation","value":")"},
-  {"type":"Text","value":" "},
-  {"type":"Punctuation","value":"{"},
-  {"type":"Text","value":"\n    "},
-  {"type":"Keyword","value":"return"},
-  {"type":"Text","value":" "},
-  {"type":"NameBuiltin","value":"mul"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"projection"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"NameBuiltin","value":"mul"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"view"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"NameBuiltin","value":"mul"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"model"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"KeywordType","value":"float4"},
-  {"type":"Punctuation","value":"("},
-  {"type":"Name","value":"position"},
-  {"type":"Punctuation","value":","},
-  {"type":"Text","value":" "},
-  {"type":"LiteralNumberFloat","value":"1.0"},
-  {"type":"Punctuation","value":"))));"},
-  {"type":"Text","value":"\n"},
-  {"type":"Punctuation","value":"}"},
-  {"type":"Text","value":"\n"}
-]
\ No newline at end of file
+[
+  {"type":"KeywordType","value":"float4"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"vertex"},
+  {"type":"Punctuation","value":"("},
+  {"type":"KeywordType","value":"float3"},
+  {"type":"Text","value":" "},
+  {"type":"Name","value":"position"},
+  {"type":"Punctuation","value":")"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"Text","value":"\n    "},
+  {"type":"Keyword","value":"return"},
+  {"type":"Text","value":" "},
+  {"type":"NameBuiltin","value":"mul"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"projection"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"NameBuiltin","value":"mul"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"view"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"NameBuiltin","value":"mul"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"model"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"KeywordType","value":"float4"},
+  {"type":"Punctuation","value":"("},
+  {"type":"Name","value":"position"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":" "},
+  {"type":"LiteralNumberFloat","value":"1.0"},
+  {"type":"Punctuation","value":"))));"},
+  {"type":"Text","value":"\n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"Text","value":"\n"}
+]
diff --git a/lexers/testdata/natural.expected b/lexers/testdata/natural.expected
index 7f1bc80..0e88688 100644
--- a/lexers/testdata/natural.expected
+++ b/lexers/testdata/natural.expected
@@ -16,9 +16,9 @@
   {"type":"Other","value":"(A10)"},
   {"type":"Text","value":" "},
   {"type":"Keyword","value":"INIT"},
-  {"type":"Operator","value":"<"},
+  {"type":"Operator","value":"\u003c"},
   {"type":"LiteralStringSingle","value":"'Hello'"},
-  {"type":"Operator","value":">"},
+  {"type":"Operator","value":"\u003e"},
   {"type":"Text","value":"\n"},
   {"type":"LiteralNumberInteger","value":"1"},
   {"type":"Text","value":" "},
@@ -48,14 +48,12 @@
   {"type":"Text","value":" "},
   {"type":"NameVariable","value":"#VAR-NAME-1"},
   {"type":"Text","value":"\n\n"},
-
   {"type":"Keyword","value":"DEFINE"},
   {"type":"Text","value":" "},
   {"type":"Keyword","value":"SUBROUTINE"},
   {"type":"Text","value":" "},
   {"type":"NameFunction","value":"MY-SUBROUTINE"},
   {"type":"Text","value":"\n"},
-
   {"type":"Keyword","value":"FOR"},
   {"type":"Text","value":" "},
   {"type":"NameVariable","value":"#I"},
@@ -68,17 +66,13 @@
   {"type":"Text","value":" "},
   {"type":"LiteralNumberInteger","value":"10"},
   {"type":"Text","value":"\n"},
-
   {"type":"Keyword","value":"ESCAPE"},
   {"type":"Text","value":" "},
   {"type":"Keyword","value":"MODULE"},
   {"type":"Text","value":"\n"},
-
   {"type":"Keyword","value":"END-FOR"},
   {"type":"Text","value":"\n"},
-
   {"type":"Keyword","value":"END-SUBROUTINE"},
-
   {"type":"Text","value":"\n\n"},
   {"type":"Keyword","value":"END"},
   {"type":"Text","value":"\n\n"}
diff --git a/lexers/testdata/vhs.expected b/lexers/testdata/vhs.expected
index 3c305ef..b91cf58 100644
--- a/lexers/testdata/vhs.expected
+++ b/lexers/testdata/vhs.expected
@@ -1,54 +1,54 @@
 [
-	{"type":"Comment","value":"# Where should we write the GIF?"},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Output"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralString","value":"demo.gif"},
-	{"type":"TextWhitespace","value":"\n\n"},
-	{"type":"Comment","value":"# Set up a 1200x600 terminal with 46px font."},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Set"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"NameBuiltin","value":"FontSize"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralNumber","value":"46"},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Set"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"NameBuiltin","value":"Width"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralNumber","value":"1200"},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Set"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"NameBuiltin","value":"Height"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralNumber","value":"600"},
-	{"type":"TextWhitespace","value":"\n\n"},
-	{"type":"Comment","value":"# Type a command in the terminal."},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Type"},
-	{"type":"Punctuation", "value": "@"},
-	{"type":"LiteralNumber", "value": "100"},
-	{"type":"Text", "value": "ms"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralStringDouble","value":"\"echo 'Welcome to VHS!'\""},
-	{"type":"TextWhitespace","value":"\n\n"},
-	{"type":"Comment","value":"# Pause for dramatic effect..."},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Sleep"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralNumber","value":"500"},
-	{"type":"Text","value":"ms"},
-	{"type":"TextWhitespace","value":"\n\n"},
-	{"type":"Comment","value":"# Run the command by pressing enter."},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Enter"},
-	{"type":"TextWhitespace","value":"\n\n"},
-	{"type":"Comment","value":"# Admire the output for a bit."},
-	{"type":"TextWhitespace","value":"\n"},
-	{"type":"Keyword","value":"Sleep"},
-	{"type":"TextWhitespace","value":" "},
-	{"type":"LiteralNumber","value":"5"},
-	{"type":"Text","value":"s"}
+  {"type":"Comment","value":"# Where should we write the GIF?"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Output"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralString","value":"demo.gif"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Comment","value":"# Set up a 1200x600 terminal with 46px font."},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Set"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"FontSize"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumber","value":"46"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Set"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"Width"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumber","value":"1200"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Set"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameBuiltin","value":"Height"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumber","value":"600"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Comment","value":"# Type a command in the terminal."},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Type"},
+  {"type":"Punctuation","value":"@"},
+  {"type":"LiteralNumber","value":"100"},
+  {"type":"Text","value":"ms"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"echo 'Welcome to VHS!'\""},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Comment","value":"# Pause for dramatic effect..."},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Sleep"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumber","value":"500"},
+  {"type":"Text","value":"ms"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Comment","value":"# Run the command by pressing enter."},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Enter"},
+  {"type":"TextWhitespace","value":"\n\n"},
+  {"type":"Comment","value":"# Admire the output for a bit."},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Keyword","value":"Sleep"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumber","value":"5"},
+  {"type":"Text","value":"s"}
 ]
diff --git a/lexers/testdata/vim.actual b/lexers/testdata/vim.actual
new file mode 100644
index 0000000..eb7d152
--- /dev/null
+++ b/lexers/testdata/vim.actual
@@ -0,0 +1,88 @@
+execute pathogen#infect()
+
+syntax on
+colorscheme swapoff
+
+" Turn off status line.
+set laststatus=0
+
+" Turn off annoying beeps
+set vb
+set noeb
+set vb t_vb=
+
+set mouse=r
+set visualbell
+
+" Force latin1 terminal encoding?
+set fileencoding=utf-8
+set encoding=utf-8
+set termencoding=utf-8
+
+" Allows ~<motion>
+set tildeop
+
+" Stupid backspace
+set backspace=eol,indent,start
+
+" 99% of the time, wrap is shit
+set nowrap
+
+" Map U to 'redo', which I like better than U being 'undo changes to this line'
+map U <C-R>
+
+" Indentation defaults
+set ts=2 sts=2 sw=2 et
+
+" Abbreviate status messages
+set shortmess=aTI
+
+" No 'Press ENTER...' message when using man
+map K K<CR>
+
+" Filetypes that need real tabs
+autocmd FileType make :set ts=4 noet nolist
+
+" Set some formatoptions
+set formatoptions=tcrqn
+
+" Incremental search is good
+set incsearch
+set hlsearch
+hi MatchParen cterm=NONE ctermfg=LightGreen ctermbg=NONE
+
+" Disable highlighted search on redraw
+map <silent> <C-l> :nohlsearch<CR>:redraw!<CR>
+
+autocmd Syntax * syntax sync fromstart
+
+filetype plugin on
+filetype indent on
+
+" Always show cursor position
+set ruler
+
+" Fucking visual-select copying to clipboard! WTF!
+set clipboard=
+
+" C-d when file-completing
+set wildmenu
+
+highlight SpellBad cterm=NONE ctermfg=darkred ctermbg=none
+
+" Show trailing whitepace and spaces before a tab:
+highlight ExtraWhitespace cterm=NONE ctermbg=red guibg=red
+autocmd Syntax * syn match ExtraWhitespace /\s\+$\| \+\ze\t/
+
+" Round shifting to nearest shiftwidth
+set shiftround
+
+" Insert blanks according to shiftwidth
+set smarttab
+
+" Disable toolbar
+set go-=T
+
+set wildignore=*.o,*.a,*.so,*.pyc,*~,*.class,build/*,build-*,tags,cscope*,third_party/*,java/*,users/*,data/*,3rdparty/*,*.jar,target/*,dist/*
+
+autocmd BufRead,BufNewFile *.bk set filetype=python
diff --git a/lexers/testdata/vim.expected b/lexers/testdata/vim.expected
new file mode 100644
index 0000000..78b9255
--- /dev/null
+++ b/lexers/testdata/vim.expected
@@ -0,0 +1,384 @@
+[
+  {"type":"Keyword","value":"execute"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"pathogen"},
+  {"type":"Text","value":"#"},
+  {"type":"NameOther","value":"infect"},
+  {"type":"Punctuation","value":"()"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"syntax"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"on"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"colorscheme"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"swapoff"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Turn off status line."},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"laststatus"},
+  {"type":"Punctuation","value":"="},
+  {"type":"LiteralNumber","value":"0"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Turn off annoying beeps"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"vb"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"noeb"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"vb"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"t_vb"},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"mouse"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"r"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"visualbell"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Force latin1 terminal encoding?"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"fileencoding"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"utf"},
+  {"type":"LiteralNumber","value":"-8"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"encoding"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"utf"},
+  {"type":"LiteralNumber","value":"-8"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"termencoding"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"utf"},
+  {"type":"LiteralNumber","value":"-8"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Allows ~\u003cmotion\u003e"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"tildeop"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Stupid backspace"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"backspace"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"eol"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"indent"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"start"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" 99% of the time, wrap is shit"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"nowrap"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Map U to 'redo', which I like better than U being 'undo changes to this line'"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"map"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"U"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameOther","value":"C"},
+  {"type":"Punctuation","value":"-"},
+  {"type":"NameOther","value":"R"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Indentation defaults"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ts"},
+  {"type":"Punctuation","value":"="},
+  {"type":"LiteralNumber","value":"2"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"sts"},
+  {"type":"Punctuation","value":"="},
+  {"type":"LiteralNumber","value":"2"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"sw"},
+  {"type":"Punctuation","value":"="},
+  {"type":"LiteralNumber","value":"2"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"et"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Abbreviate status messages"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"shortmess"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"aTI"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" No 'Press ENTER...' message when using man"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"map"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"K"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"K"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameOther","value":"CR"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Filetypes that need real tabs"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"autocmd"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"FileType"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"make"},
+  {"type":"Text","value":" :"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ts"},
+  {"type":"Punctuation","value":"="},
+  {"type":"LiteralNumber","value":"4"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"noet"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"nolist"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Set some formatoptions"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"formatoptions"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"tcrqn"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Incremental search is good"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"incsearch"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"hlsearch"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"hi"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"MatchParen"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"cterm"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameBuiltin","value":"NONE"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ctermfg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"LightGreen"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ctermbg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameBuiltin","value":"NONE"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Disable highlighted search on redraw"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"map"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameOther","value":"silent"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":" "},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameOther","value":"C"},
+  {"type":"Punctuation","value":"-"},
+  {"type":"NameOther","value":"l"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":" :"},
+  {"type":"NameOther","value":"nohlsearch"},
+  {"type":"Punctuation","value":"\u003c"},
+  {"type":"NameOther","value":"CR"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":":"},
+  {"type":"NameOther","value":"redraw"},
+  {"type":"Punctuation","value":"!\u003c"},
+  {"type":"NameOther","value":"CR"},
+  {"type":"Punctuation","value":"\u003e"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"autocmd"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"Syntax"},
+  {"type":"Text","value":" * "},
+  {"type":"Keyword","value":"syntax"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"sync"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"fromstart"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"filetype"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"plugin"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"on"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"filetype"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"indent"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"on"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Always show cursor position"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ruler"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Fucking visual-select copying to clipboard! WTF!"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"clipboard"},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" C-d when file-completing"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"wildmenu"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"highlight"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"SpellBad"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"cterm"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameBuiltin","value":"NONE"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ctermfg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"darkred"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ctermbg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"none"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Show trailing whitepace and spaces before a tab:"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"highlight"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ExtraWhitespace"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"cterm"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameBuiltin","value":"NONE"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ctermbg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"red"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"guibg"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"red"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"autocmd"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"Syntax"},
+  {"type":"Text","value":" * "},
+  {"type":"NameOther","value":"syn"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"match"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"ExtraWhitespace"},
+  {"type":"Text","value":" "},
+  {"type":"LiteralStringRegex","value":"/\\s\\+$\\| \\+\\ze\\t/"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Round shifting to nearest shiftwidth"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"shiftround"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Insert blanks according to shiftwidth"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"smarttab"},
+  {"type":"Text","value":"\n"},
+  {"type":"Comment","value":"\n\" Disable toolbar"},
+  {"type":"Text","value":"\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"go"},
+  {"type":"Punctuation","value":"-="},
+  {"type":"NameOther","value":"T"},
+  {"type":"Text","value":"\n\n"},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"wildignore"},
+  {"type":"Punctuation","value":"="},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"o"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"a"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"so"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"pyc"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"*"},
+  {"type":"Punctuation","value":"~,"},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"class"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"build"},
+  {"type":"LiteralStringRegex","value":"/*,build-*,tags,cscope*,third_party/"},
+  {"type":"Text","value":"*"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"java"},
+  {"type":"LiteralStringRegex","value":"/*,users/"},
+  {"type":"Text","value":"*"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"data"},
+  {"type":"LiteralStringRegex","value":"/*,3rdparty/"},
+  {"type":"Text","value":"*"},
+  {"type":"Punctuation","value":","},
+  {"type":"Text","value":"*."},
+  {"type":"NameOther","value":"jar"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"target"},
+  {"type":"LiteralStringRegex","value":"/*,dist/"},
+  {"type":"Text","value":"*\n\n"},
+  {"type":"Keyword","value":"autocmd"},
+  {"type":"Text","value":" "},
+  {"type":"NameOther","value":"BufRead"},
+  {"type":"Punctuation","value":","},
+  {"type":"NameOther","value":"BufNewFile"},
+  {"type":"Text","value":" *."},
+  {"type":"NameOther","value":"bk"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"set"},
+  {"type":"Text","value":" "},
+  {"type":"Keyword","value":"filetype"},
+  {"type":"Punctuation","value":"="},
+  {"type":"NameOther","value":"python"},
+  {"type":"Text","value":"\n"}
+]