diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md
index 3c18956a..524c2adf 100644
--- a/book/src/generated/lang-support.md
+++ b/book/src/generated/lang-support.md
@@ -145,6 +145,7 @@
 | v | ✓ | ✓ | ✓ | `v` |
 | vala | ✓ |  |  | `vala-language-server` |
 | verilog | ✓ | ✓ |  | `svlangserver` |
+| vhdl | ✓ |  |  | `vhdl_ls` |
 | vhs | ✓ |  |  |  |
 | vue | ✓ |  |  | `vls` |
 | wast | ✓ |  |  |  |
diff --git a/languages.toml b/languages.toml
index a56de1f4..f6a54e87 100644
--- a/languages.toml
+++ b/languages.toml
@@ -2369,3 +2369,17 @@ language-server = { command = "cs", args = ["launch", "com.disneystreaming.smith
 [[grammar]]
 name = "smithy"
 source = { git = "https://github.com/indoorvivants/tree-sitter-smithy", rev = "cf8c7eb9faf7c7049839585eac19c94af231e6a0" }
+
+[[language]]
+name = "vhdl"
+scope = "source.vhdl"
+file-types = ["vhd", "vhdl"]
+roots = []
+comment-token = "--"
+language-server = { command = "vhdl_ls", args = [] }
+indent = { tab-width = 2, unit = "  " }
+injection-regex = "vhdl"
+
+[[grammar]]
+name = "vhdl"
+source = { git = "https://github.com/teburd/tree-sitter-vhdl", rev = "c57313adee2231100db0a7880033f6865deeadb2" }
diff --git a/runtime/queries/vhdl/highlights.scm b/runtime/queries/vhdl/highlights.scm
new file mode 100644
index 00000000..59cef41c
--- /dev/null
+++ b/runtime/queries/vhdl/highlights.scm
@@ -0,0 +1,338 @@
+(comment) @comment
+
+; Keywords
+[
+  ; vhdl 08
+  "abs"
+  "access"
+  "after"
+  "alias"
+  "all"
+  "and"
+  "architecture"
+  "array"
+  "assert"
+  "attribute"
+  "begin"
+  "block"
+  "body"
+  "buffer"
+  "bus"
+  "case"
+  "component"
+  "configuration"
+  "constant"
+  "disconnect"
+  "downto"
+  "else"
+  "elsif"
+  "end"
+  "entity"
+  "exit"
+  "file"
+  "for"
+  "function"
+  "generic"
+  "group"
+  "guarded"
+  "if"
+  "impure"
+  "in"
+  "inertial"
+  "inout"
+  "is"
+  "label"
+  "library"
+  "linkage"
+  "literal"
+  "loop"
+  "map"
+  "mod"
+  "nand"
+  "new"
+  "next"
+  "nor"
+  "not"
+  "null"
+  "of"
+  "on"
+  "open"
+  "or"
+  "others"
+  "out"
+  "package"
+  "port"
+  "postponed"
+  "procedure"
+  "process"
+  "protected"
+  "pure"
+  "range"
+  "record"
+  "register"
+  "reject"
+  "rem"
+  "report"
+  "return"
+  "rol"
+  "ror"
+  "select"
+  "severity"
+  "shared"
+  "signal"
+  "sla"
+  "sll"
+  "sra"
+  "srl"
+  "subtype"
+  "then"
+  "to"
+  "transport"
+  "type"
+  "unaffected"
+  "units"
+  "until"
+  "use"
+  "variable"
+  "wait"
+  "when"
+  "while"
+  "with"
+  "xnor"
+  "xor"
+  ; vhdl 08
+  "context"
+  "force"
+  "property"
+  "release"
+  "sequence"
+] @keyword
+
+[
+  ; vhdl 02
+  "boolean"
+  "bit"
+  "bit_vector"
+  ;"character"
+  ;"severity_level"
+  ;"integer"
+  ;"real"
+  ;"time"
+  ;"natural"
+  ;"positive"
+  "string"
+  ;"line"
+  ;"text"
+  ;"side"
+  ;"unsigned"
+  ;"signed"
+  ;"delay_length"
+  ;"file_open_kind"
+  ;"file_open_status"
+  ;"std_logic"
+  ;"std_logic_vector"
+  ;"std_ulogic"
+  ;"std_ulogic_vector"
+  ; vhdl 08
+  ;"boolean_vector"
+  ;"integer_vector"
+  ;"real_vector"
+  ;"time_vector"
+  ; math types
+  ;"complex"
+  ;"complex_polar"
+  ;"positive_real"
+  ;"principal_value"
+] @type.builtin
+
+[
+  ; vhdl 02
+  "base"
+  "left"
+  "right"
+  "high"
+  "low"
+  "pos"
+  "val"
+  "succ"
+  "pred"
+  "leftof"
+  "rightof"
+  "range"
+  "reverse_range"
+  "length"
+  "delayed"
+  "stable"
+  "quiet"
+  "transaction"
+  "event"
+  "active"
+  "last_event"
+  "last_active"
+  "last_value"
+  "driving"
+  "driving_value"
+  "ascending"
+  "value"
+  "image"
+  "simple_name"
+  "instance_name"
+  "path_name"
+  ;"foreign"
+  ; vhdl 08
+  "instance_name"
+  "path_name"
+] @attribute
+
+;[
+  ; vhdl 02
+  ;"now"
+  ;"resolved"
+  ;"rising_edge"
+  ;"falling_edge"
+  ;"read"
+  ;"readline"
+  ;"hread"
+  ;"oread"
+  ;"write"
+  ;"writeline"
+  ;"hwrite"
+  ;"owrite"
+  ;"endfile"
+  ;"resize"
+  ;"is_X"
+  ;"std_match"
+  ;"shift_left"
+  ;"shift_right"
+  ;"rotate_left"
+  ;"rotate_right"
+  ;"to_unsigned"
+  ;"to_signed"
+  ;"to_integer"
+  ;"to_stdLogicVector"
+  ;"to_stdULogic"
+  ;"to_stdULogicVector"
+  ;"to_bit"
+  ;"to_bitVector"
+  ;"to_X01"
+  ;"to_X01Z"
+  ;"to_UX01"
+  ;"to_01"
+  ;"conv_unsigned"
+  ;"conv_signed"
+  ;"conv_integer"
+  ;"conv_std_logic_vector"
+  ;"shl"
+  ;"shr"
+  ;"ext"
+  ;"sxt"
+  ;"deallocate"
+  ; vhdl 08
+  ;"finish"
+  ;"flush"
+  ;"justify"
+  ;"maximum"
+  ;"minimum"
+  ;"resolution_limit"
+  ;"stop"
+  ;"swrite"
+  ;"tee"
+  ;"to_binarystring"
+  ;"to_bstring"
+  ;"to_hexstring"
+  ;"to_hstring"
+  ;"to_octalstring"
+  ;"to_ostring"
+  ;"to_string"
+  ; vhdl math
+  ;"arccos"
+  ;"arccosh"
+  ;"arcsin"
+  ;"arcsinh"
+  ;"arctan"
+  ;"arctanh"
+  ;"arg"
+  ;"cbrt"
+  ;"ceil"
+  ;"cmplx"
+  ;"complex_to_polar"
+  ;"conj"
+  ;"cos"
+  ;"cosh"
+  ;"exp"
+  ;"floor"
+  ;"get_principal_value"
+  ;"log"
+  ;"log10"
+  ;"log2"
+  ;"polar_to_complex"
+  ;"realmax"
+  ;"realmin"
+  ;"round"
+  ;"sign"
+  ;"sin"
+  ;"sinh"
+  ;"sqrt"
+  ;"tan"
+  ;"tanh"
+  ;"trunc"
+  ;"uniform"
+;] @function.builtin
+
+; Operators
+[
+  "+"
+  "-"
+  "*"
+  "/"
+  "**"
+  "abs"
+  "not"
+  "mod"
+  "rem"
+  "&"
+  "sll"
+  "srl"
+  "sla"
+  "sra"
+  "rol"
+  "ror"
+  "="
+  "/="
+  "?="
+  "?/="
+  "?<"
+  "?<="
+  "?>"
+  "?>="
+  "<"
+  "<="
+  ">"
+  ">="
+  "and"
+  "or"
+  "nand"
+  "nor"
+  "xor"
+  "xnor"
+  ":="
+  "<="
+  "??"
+] @operator
+
+[
+  ";"
+  ","
+] @punctuation.delimiter
+
+[
+  "("
+  ")"
+  "'"
+] @punctuation.bracket
+
+(full_type_declaration "type" name: (identifier) @type)
+(signal_declaration "signal" (identifier_list) @variable)
+(variable_declaration "variable" (identifier_list) @variable)
+(constant_declaration "constant" (identifier_list) @variable)
+