diff --git a/packages/app-web-docs/src/docs/contributing/MissingLanguageScopes.tsx b/packages/app-web-docs/src/docs/contributing/MissingLanguageScopes.tsx
index a27e5ac0dc..a8a1fb4249 100644
--- a/packages/app-web-docs/src/docs/contributing/MissingLanguageScopes.tsx
+++ b/packages/app-web-docs/src/docs/contributing/MissingLanguageScopes.tsx
@@ -1,16 +1,20 @@
import React, { useState } from "react";
-import type { ScopeSupportFacet } from "@cursorless/lib-common";
+import type {
+ LanguageScopeSupportId,
+ ScopeSupportFacet,
+} from "@cursorless/lib-common";
import {
languageScopeSupport,
scopeSupportFacetInfos,
ScopeSupportFacetLevel,
scopeSupportFacets,
serializeScopeType,
+ unsafeKeys,
} from "@cursorless/lib-common";
export function MissingLanguageScopes(): React.JSX.Element {
const [showPrivate, setShowPrivate] = useState(false);
- const languageIds = Object.keys(languageScopeSupport).toSorted();
+ const languageIds = unsafeKeys(languageScopeSupport).toSorted();
return (
<>
@@ -39,7 +43,7 @@ function Language({
languageId,
showPrivate,
}: {
- languageId: string;
+ languageId: LanguageScopeSupportId;
showPrivate: boolean;
}): React.JSX.Element | null {
const scopeSupport = languageScopeSupport[languageId] ?? {};
diff --git a/packages/app-web-docs/src/docs/contributing/private-scopes/disqualifyDelimiter.mdx b/packages/app-web-docs/src/docs/contributing/private-scopes/disqualifyDelimiter.mdx
index 149caa58bb..013a3e1143 100644
--- a/packages/app-web-docs/src/docs/contributing/private-scopes/disqualifyDelimiter.mdx
+++ b/packages/app-web-docs/src/docs/contributing/private-scopes/disqualifyDelimiter.mdx
@@ -72,7 +72,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Latex
+##### LaTeX
@@ -112,7 +112,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/contributing/private-scopes/interior.mdx b/packages/app-web-docs/src/docs/contributing/private-scopes/interior.mdx
index de18891a36..cf268fc930 100644
--- a/packages/app-web-docs/src/docs/contributing/private-scopes/interior.mdx
+++ b/packages/app-web-docs/src/docs/contributing/private-scopes/interior.mdx
@@ -200,7 +200,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/contributing/private-scopes/string.mdx b/packages/app-web-docs/src/docs/contributing/private-scopes/string.mdx
index 3f49351ca8..e90ff999d2 100644
--- a/packages/app-web-docs/src/docs/contributing/private-scopes/string.mdx
+++ b/packages/app-web-docs/src/docs/contributing/private-scopes/string.mdx
@@ -88,7 +88,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
@@ -172,11 +172,11 @@ The following are internal scopes. They are not intended for user interaction or
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
-##### Talon-list
+##### Talon list
@@ -190,7 +190,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/contributing/private-scopes/textFragment.mdx b/packages/app-web-docs/src/docs/contributing/private-scopes/textFragment.mdx
index 248a9fe480..08d663c38c 100644
--- a/packages/app-web-docs/src/docs/contributing/private-scopes/textFragment.mdx
+++ b/packages/app-web-docs/src/docs/contributing/private-scopes/textFragment.mdx
@@ -78,7 +78,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Latex
+##### LaTeX
@@ -150,7 +150,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Latex
+##### LaTeX
@@ -186,7 +186,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -194,7 +194,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Talon-list
+##### Talon list
@@ -202,7 +202,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
@@ -220,7 +220,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Latex
+##### LaTeX
@@ -288,7 +288,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
@@ -372,11 +372,11 @@ The following are internal scopes. They are not intended for user interaction or
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
-##### Talon-list
+##### Talon list
@@ -390,7 +390,7 @@ The following are internal scopes. They are not intended for user interaction or
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/languages/latex.mdx b/packages/app-web-docs/src/docs/user/languages/latex.mdx
index d356e7b6a8..1953217cfc 100644
--- a/packages/app-web-docs/src/docs/user/languages/latex.mdx
+++ b/packages/app-web-docs/src/docs/user/languages/latex.mdx
@@ -1,6 +1,6 @@
import { ScopeVisualizer, ScopeVisualizerOptions, ScopeVisualizerProvider } from "@site/src/docs/components/ScopeVisualizer";
-# Latex
+# LaTeX
diff --git a/packages/app-web-docs/src/docs/user/languages/scm.mdx b/packages/app-web-docs/src/docs/user/languages/scm.mdx
index 9ca439ba7c..f01745343a 100644
--- a/packages/app-web-docs/src/docs/user/languages/scm.mdx
+++ b/packages/app-web-docs/src/docs/user/languages/scm.mdx
@@ -1,6 +1,6 @@
import { ScopeVisualizer, ScopeVisualizerOptions, ScopeVisualizerProvider } from "@site/src/docs/components/ScopeVisualizer";
-# Tree sitter query (SCM)
+# Tree-sitter query (SCM)
diff --git a/packages/app-web-docs/src/docs/user/languages/talon-list.mdx b/packages/app-web-docs/src/docs/user/languages/talon-list.mdx
index a17cc2ae70..4ae28bf8cd 100644
--- a/packages/app-web-docs/src/docs/user/languages/talon-list.mdx
+++ b/packages/app-web-docs/src/docs/user/languages/talon-list.mdx
@@ -1,6 +1,6 @@
import { ScopeVisualizer, ScopeVisualizerOptions, ScopeVisualizerProvider } from "@site/src/docs/components/ScopeVisualizer";
-# Talon-list
+# Talon list
diff --git a/packages/app-web-docs/src/docs/user/languages/yaml.mdx b/packages/app-web-docs/src/docs/user/languages/yaml.mdx
index 5da8149c2f..00c0a9b95b 100644
--- a/packages/app-web-docs/src/docs/user/languages/yaml.mdx
+++ b/packages/app-web-docs/src/docs/user/languages/yaml.mdx
@@ -1,6 +1,6 @@
import { ScopeVisualizer, ScopeVisualizerOptions, ScopeVisualizerProvider } from "@site/src/docs/components/ScopeVisualizer";
-# Yaml
+# YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/argumentList.mdx b/packages/app-web-docs/src/docs/user/scopes/argumentList.mdx
index c09a210137..e86a84eb13 100644
--- a/packages/app-web-docs/src/docs/user/scopes/argumentList.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/argumentList.mdx
@@ -220,7 +220,7 @@ Default: `arg list`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -544,7 +544,7 @@ Default: `arg list`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -618,7 +618,7 @@ Default: `arg list`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
diff --git a/packages/app-web-docs/src/docs/user/scopes/argumentOrParameter.mdx b/packages/app-web-docs/src/docs/user/scopes/argumentOrParameter.mdx
index 2c4e72859d..acb18bee78 100644
--- a/packages/app-web-docs/src/docs/user/scopes/argumentOrParameter.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/argumentOrParameter.mdx
@@ -310,7 +310,7 @@ Default: `arg`
-##### Latex
+##### LaTeX
@@ -344,7 +344,7 @@ Default: `arg`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -400,7 +400,7 @@ Default: `arg`
-##### Latex
+##### LaTeX
@@ -436,7 +436,7 @@ Default: `arg`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -970,7 +970,7 @@ Default: `arg`
-##### Latex
+##### LaTeX
@@ -1004,7 +1004,7 @@ Default: `arg`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
diff --git a/packages/app-web-docs/src/docs/user/scopes/collectionItem.mdx b/packages/app-web-docs/src/docs/user/scopes/collectionItem.mdx
index aaa0f3ab30..827e75b537 100644
--- a/packages/app-web-docs/src/docs/user/scopes/collectionItem.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/collectionItem.mdx
@@ -100,7 +100,7 @@ Default: `item`
-##### Latex
+##### LaTeX
@@ -116,7 +116,7 @@ Default: `item`
-##### Yaml
+##### YAML
@@ -230,7 +230,7 @@ Default: `item`
-##### Latex
+##### LaTeX
@@ -256,7 +256,7 @@ Default: `item`
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/collectionKey.mdx b/packages/app-web-docs/src/docs/user/scopes/collectionKey.mdx
index 3aaa38b5e4..b539233a45 100644
--- a/packages/app-web-docs/src/docs/user/scopes/collectionKey.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/collectionKey.mdx
@@ -106,7 +106,7 @@ Default: `key`
-##### Talon-list
+##### Talon list
@@ -118,7 +118,7 @@ Default: `key`
-##### Yaml
+##### YAML
@@ -180,7 +180,7 @@ Default: `key`
-##### Talon-list
+##### Talon list
@@ -192,7 +192,7 @@ Default: `key`
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/comment.mdx b/packages/app-web-docs/src/docs/user/scopes/comment.mdx
index f55e59f99a..0e3497d376 100644
--- a/packages/app-web-docs/src/docs/user/scopes/comment.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/comment.mdx
@@ -76,7 +76,7 @@ Default: `comment`
-##### Latex
+##### LaTeX
@@ -148,7 +148,7 @@ Default: `comment`
-##### Latex
+##### LaTeX
@@ -186,7 +186,7 @@ Default: `comment`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -194,7 +194,7 @@ Default: `comment`
-##### Talon-list
+##### Talon list
@@ -202,7 +202,7 @@ Default: `comment`
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/environment.mdx b/packages/app-web-docs/src/docs/user/scopes/environment.mdx
index 4fa8b97823..abb61b37cb 100644
--- a/packages/app-web-docs/src/docs/user/scopes/environment.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/environment.mdx
@@ -30,7 +30,7 @@ Default: `environment`
An environment, eg in LaTeX
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/user/scopes/functionCall.mdx b/packages/app-web-docs/src/docs/user/scopes/functionCall.mdx
index 8df45ffeaa..48969a1dcb 100644
--- a/packages/app-web-docs/src/docs/user/scopes/functionCall.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/functionCall.mdx
@@ -66,7 +66,7 @@ Default: `call`
-##### Latex
+##### LaTeX
@@ -98,7 +98,7 @@ Default: `call`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
diff --git a/packages/app-web-docs/src/docs/user/scopes/functionCallee.mdx b/packages/app-web-docs/src/docs/user/scopes/functionCallee.mdx
index 9f1c5a355e..4431e5ceb1 100644
--- a/packages/app-web-docs/src/docs/user/scopes/functionCallee.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/functionCallee.mdx
@@ -66,7 +66,7 @@ Default: `callee`
-##### Latex
+##### LaTeX
@@ -98,7 +98,7 @@ Default: `callee`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
diff --git a/packages/app-web-docs/src/docs/user/scopes/list.mdx b/packages/app-web-docs/src/docs/user/scopes/list.mdx
index 7d3155c1c3..8ea0216b34 100644
--- a/packages/app-web-docs/src/docs/user/scopes/list.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/list.mdx
@@ -70,7 +70,7 @@ Default: `list`
-##### Latex
+##### LaTeX
@@ -116,11 +116,11 @@ Default: `list`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/map.mdx b/packages/app-web-docs/src/docs/user/scopes/map.mdx
index f7c92ac1ef..6884d940d6 100644
--- a/packages/app-web-docs/src/docs/user/scopes/map.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/map.mdx
@@ -92,7 +92,7 @@ Default: `map`
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/name.mdx b/packages/app-web-docs/src/docs/user/scopes/name.mdx
index 79ddaf5f52..b305b71e1a 100644
--- a/packages/app-web-docs/src/docs/user/scopes/name.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/name.mdx
@@ -1344,7 +1344,7 @@ Default: `name`
-##### Talon-list
+##### Talon list
@@ -1704,7 +1704,7 @@ Default: `name`
-##### Talon-list
+##### Talon list
diff --git a/packages/app-web-docs/src/docs/user/scopes/section.mdx b/packages/app-web-docs/src/docs/user/scopes/section.mdx
index 3631830481..e19aa90180 100644
--- a/packages/app-web-docs/src/docs/user/scopes/section.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/section.mdx
@@ -30,7 +30,7 @@ Default: `section`
A document section
-##### Latex
+##### LaTeX
@@ -42,7 +42,7 @@ Default: `section`
Iteration scope for sections: the entire document including leading and trailing empty lines.
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/user/scopes/statement.mdx b/packages/app-web-docs/src/docs/user/scopes/statement.mdx
index 59446d9574..da4484d6d9 100644
--- a/packages/app-web-docs/src/docs/user/scopes/statement.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/statement.mdx
@@ -832,7 +832,7 @@ Default: `state`
-##### Latex
+##### LaTeX
@@ -1140,7 +1140,7 @@ Default: `state`
-##### Tree sitter query (SCM)
+##### Tree-sitter query (SCM)
@@ -1632,7 +1632,7 @@ Default: `state`
-##### Talon-list
+##### Talon list
@@ -2052,7 +2052,7 @@ Default: `state`
-##### Talon-list
+##### Talon list
diff --git a/packages/app-web-docs/src/docs/user/scopes/value.mdx b/packages/app-web-docs/src/docs/user/scopes/value.mdx
index 3dc9d4fcd8..16f043c511 100644
--- a/packages/app-web-docs/src/docs/user/scopes/value.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/value.mdx
@@ -658,7 +658,7 @@ Default: `value`
-##### Talon-list
+##### Talon list
@@ -668,7 +668,7 @@ Default: `value`
-##### Yaml
+##### YAML
@@ -1032,7 +1032,7 @@ Default: `value`
-##### Talon-list
+##### Talon list
@@ -1370,7 +1370,7 @@ Default: `value`
-##### Talon-list
+##### Talon list
@@ -1658,7 +1658,7 @@ Default: `value`
-##### Talon-list
+##### Talon list
@@ -1670,7 +1670,7 @@ Default: `value`
-##### Yaml
+##### YAML
diff --git a/packages/app-web-docs/src/docs/user/scopes/xmlBothTags.mdx b/packages/app-web-docs/src/docs/user/scopes/xmlBothTags.mdx
index a56c94b494..bac0e77631 100644
--- a/packages/app-web-docs/src/docs/user/scopes/xmlBothTags.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/xmlBothTags.mdx
@@ -38,7 +38,7 @@ Default: `tags`
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/user/scopes/xmlElement.mdx b/packages/app-web-docs/src/docs/user/scopes/xmlElement.mdx
index 0ac60c978c..adef1c4f12 100644
--- a/packages/app-web-docs/src/docs/user/scopes/xmlElement.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/xmlElement.mdx
@@ -38,7 +38,7 @@ Default: `element`
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/user/scopes/xmlEndTag.mdx b/packages/app-web-docs/src/docs/user/scopes/xmlEndTag.mdx
index dce9ec14ec..e8b1a02096 100644
--- a/packages/app-web-docs/src/docs/user/scopes/xmlEndTag.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/xmlEndTag.mdx
@@ -38,7 +38,7 @@ Default: `end tag`
-##### Latex
+##### LaTeX
diff --git a/packages/app-web-docs/src/docs/user/scopes/xmlStartTag.mdx b/packages/app-web-docs/src/docs/user/scopes/xmlStartTag.mdx
index 9ab4ba95a7..3cbd6ca519 100644
--- a/packages/app-web-docs/src/docs/user/scopes/xmlStartTag.mdx
+++ b/packages/app-web-docs/src/docs/user/scopes/xmlStartTag.mdx
@@ -38,7 +38,7 @@ Default: `start tag`
-##### Latex
+##### LaTeX
diff --git a/packages/lib-common/src/index.ts b/packages/lib-common/src/index.ts
index a003910b68..ff0b3990aa 100644
--- a/packages/lib-common/src/index.ts
+++ b/packages/lib-common/src/index.ts
@@ -113,7 +113,6 @@ export * from "./util/itertools";
export * from "./util/Notifier";
export * from "./util/object";
export * from "./util/omitByDeep";
-export * from "./util/prettifyLanguageName";
export * from "./util/regex";
export * from "./util/selectionsEqual";
export * from "./util/serializedMarksToTokenHats";
diff --git a/packages/lib-common/src/references/index.ts b/packages/lib-common/src/references/index.ts
index f8874fde02..4ed6477b82 100644
--- a/packages/lib-common/src/references/index.ts
+++ b/packages/lib-common/src/references/index.ts
@@ -1,6 +1,7 @@
export * from "./actionReferenceGroups";
export * from "./actionReferences";
export * from "./hatStyleReferences";
+export * from "./languageReferences";
export * from "./modifierReferenceGroups";
export * from "./modifierReferences";
export * from "./pairedDelimiterReferences";
diff --git a/packages/lib-common/src/references/languageReferences.ts b/packages/lib-common/src/references/languageReferences.ts
new file mode 100644
index 0000000000..4d0b0d40bb
--- /dev/null
+++ b/packages/lib-common/src/references/languageReferences.ts
@@ -0,0 +1,121 @@
+interface LanguageReference {
+ name: string;
+}
+
+export const languageReferences = {
+ c: {
+ name: "C",
+ },
+ cpp: {
+ name: "C++",
+ },
+ csharp: {
+ name: "C#",
+ },
+ clojure: {
+ name: "Clojure",
+ },
+ css: {
+ name: "CSS",
+ },
+ dart: {
+ name: "Dart",
+ },
+ go: {
+ name: "Go",
+ },
+ html: {
+ name: "HTML",
+ },
+ java: {
+ name: "Java",
+ },
+ javascript: {
+ name: "JavaScript",
+ },
+ javascriptreact: {
+ name: "JavaScript React",
+ },
+ json: {
+ name: "JSON",
+ },
+ jsonc: {
+ name: "JSON with comments (JSONC)",
+ },
+ jsonl: {
+ name: "JSON lines (JSONL)",
+ },
+ kotlin: {
+ name: "Kotlin",
+ },
+ latex: {
+ name: "LaTeX",
+ },
+ lua: {
+ name: "Lua",
+ },
+ markdown: {
+ name: "Markdown",
+ },
+ php: {
+ name: "PHP",
+ },
+ plaintext: {
+ name: "Plaintext",
+ },
+ properties: {
+ name: "Properties",
+ },
+ python: {
+ name: "Python",
+ },
+ r: {
+ name: "R",
+ },
+ ruby: {
+ name: "Ruby",
+ },
+ rust: {
+ name: "Rust",
+ },
+ scala: {
+ name: "Scala",
+ },
+ scm: {
+ name: "Tree-sitter query (SCM)",
+ },
+ scss: {
+ name: "SCSS",
+ },
+ talon: {
+ name: "Talon",
+ },
+ "talon-list": {
+ name: "Talon list",
+ },
+ typescript: {
+ name: "TypeScript",
+ },
+ typescriptreact: {
+ name: "TypeScript React",
+ },
+ xml: {
+ name: "XML",
+ },
+ yaml: {
+ name: "YAML",
+ },
+} as const satisfies Record;
+
+export type LanguageId = keyof typeof languageReferences;
+
+export function isLanguageId(value: string): value is LanguageId {
+ return Object.hasOwn(languageReferences, value);
+}
+
+export function getLanguageId(value: string): LanguageId {
+ if (isLanguageId(value)) {
+ return value;
+ }
+ throw new Error(`Unknown language id: ${value}`);
+}
diff --git a/packages/lib-common/src/scopeSupportFacets/languageScopeSupport.ts b/packages/lib-common/src/scopeSupportFacets/languageScopeSupport.ts
index 39d5d106f7..1b8dad136b 100644
--- a/packages/lib-common/src/scopeSupportFacets/languageScopeSupport.ts
+++ b/packages/lib-common/src/scopeSupportFacets/languageScopeSupport.ts
@@ -1,4 +1,4 @@
-import type { StringRecord } from "../types/StringRecord";
+import type { LanguageId } from "../references/languageReferences";
import { cScopeSupport } from "./c";
import { clojureScopeSupport } from "./clojure";
import { cppScopeSupport } from "./cpp";
@@ -34,40 +34,59 @@ import { typescriptreactScopeSupport } from "./typescriptreact";
import { xmlScopeSupport } from "./xml";
import { yamlScopeSupport } from "./yaml";
-export const languageScopeSupport: StringRecord =
- {
- c: cScopeSupport,
- clojure: clojureScopeSupport,
- cpp: cppScopeSupport,
- csharp: csharpScopeSupport,
- css: cssScopeSupport,
- dart: dartScopeSupport,
- go: goScopeSupport,
- html: htmlScopeSupport,
- java: javaScopeSupport,
- // java-properties - handled by properties
- javascript: javascriptScopeSupport,
- javascriptreact: javascriptreactScopeSupport,
- json: jsonScopeSupport,
- jsonc: jsoncScopeSupport,
- jsonl: jsonlScopeSupport,
- kotlin: kotlinScopeSupport,
- latex: latexScopeSupport,
- lua: luaScopeSupport,
- markdown: markdownScopeSupport,
- php: phpScopeSupport,
- properties: propertiesScopeSupport,
- python: pythonScopeSupport,
- r: rScopeSupport,
- ruby: rubyScopeSupport,
- rust: rustScopeSupport,
- scala: scalaScopeSupport,
- scm: scmScopeSupport,
- scss: scssScopeSupport,
- "talon-list": talonListScopeSupport,
- talon: talonScopeSupport,
- typescript: typescriptScopeSupport,
- typescriptreact: typescriptreactScopeSupport,
- xml: xmlScopeSupport,
- yaml: yamlScopeSupport,
- };
+export type LanguageScopeSupportId = Exclude;
+
+export const languageScopeSupport: Record<
+ LanguageScopeSupportId,
+ LanguageScopeSupportFacetMap
+> = {
+ c: cScopeSupport,
+ clojure: clojureScopeSupport,
+ cpp: cppScopeSupport,
+ csharp: csharpScopeSupport,
+ css: cssScopeSupport,
+ dart: dartScopeSupport,
+ go: goScopeSupport,
+ html: htmlScopeSupport,
+ java: javaScopeSupport,
+ // java-properties - handled by properties
+ javascript: javascriptScopeSupport,
+ javascriptreact: javascriptreactScopeSupport,
+ json: jsonScopeSupport,
+ jsonc: jsoncScopeSupport,
+ jsonl: jsonlScopeSupport,
+ kotlin: kotlinScopeSupport,
+ latex: latexScopeSupport,
+ lua: luaScopeSupport,
+ markdown: markdownScopeSupport,
+ php: phpScopeSupport,
+ properties: propertiesScopeSupport,
+ python: pythonScopeSupport,
+ r: rScopeSupport,
+ ruby: rubyScopeSupport,
+ rust: rustScopeSupport,
+ scala: scalaScopeSupport,
+ scm: scmScopeSupport,
+ scss: scssScopeSupport,
+ "talon-list": talonListScopeSupport,
+ talon: talonScopeSupport,
+ typescript: typescriptScopeSupport,
+ typescriptreact: typescriptreactScopeSupport,
+ xml: xmlScopeSupport,
+ yaml: yamlScopeSupport,
+};
+
+export function isScopeSupportLanguageId(
+ value: string,
+): value is LanguageScopeSupportId {
+ return Object.hasOwn(languageScopeSupport, value);
+}
+
+export function getScopeSupportLanguageId(
+ value: string,
+): LanguageScopeSupportId {
+ if (isScopeSupportLanguageId(value)) {
+ return value;
+ }
+ throw new Error(`Unsupported language id: ${value}`);
+}
diff --git a/packages/lib-common/src/util/prettifyLanguageName.ts b/packages/lib-common/src/util/prettifyLanguageName.ts
deleted file mode 100644
index 43afc630e4..0000000000
--- a/packages/lib-common/src/util/prettifyLanguageName.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { capitalize } from "./stringUtils";
-
-export function prettifyLanguageName(name: string): string {
- switch (name) {
- case "cpp":
- return "C++";
- case "csharp":
- return "C#";
- case "javascript":
- return "JavaScript";
- case "typescript":
- return "TypeScript";
- case "javascriptreact":
- return "JavaScript React";
- case "typescriptreact":
- return "TypeScript React";
- case "jsonl":
- return "JSON lines (JSONL)";
- case "jsonc":
- return "JSON with comments (JSONC)";
- case "scm":
- return "Tree sitter query (SCM)";
- case "css":
- case "scss":
- case "json":
- case "php":
- case "html":
- case "xml":
- return name.toUpperCase();
- default:
- return capitalize(name);
- }
-}
diff --git a/packages/lib-engine/src/test/scopes.test.ts b/packages/lib-engine/src/test/scopes.test.ts
index e879045e34..ff19c03366 100644
--- a/packages/lib-engine/src/test/scopes.test.ts
+++ b/packages/lib-engine/src/test/scopes.test.ts
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
import { promises as fsp } from "node:fs";
import { groupBy, uniq } from "lodash-es";
import type {
+ LanguageId,
PlaintextScopeSupportFacet,
ScopeRangeConfig,
ScopeSupportFacet,
@@ -9,6 +10,7 @@ import type {
} from "@cursorless/lib-common";
import {
asyncSafety,
+ getLanguageId,
languageScopeSupport,
plaintextScopeSupportFacetInfos,
scopeSupportFacetInfos,
@@ -47,7 +49,7 @@ suite("Scope test cases", () => {
const tests = languages[languageId];
test(`${languageId} facet coverage`, () =>
testLanguageSupport(
- languageId,
+ getLanguageId(languageId),
tests.map((test) => test.facet),
));
}
@@ -67,7 +69,7 @@ suite("Scope test cases", () => {
* @param languageId The language to test
* @param testedFacets The facets for {@link languageId} that are tested
*/
-function testLanguageSupport(languageId: string, testedFacets: string[]) {
+function testLanguageSupport(languageId: LanguageId, testedFacets: string[]) {
const supportedFacets = (() => {
if (languageId === "plaintext") {
return Object.keys(plaintextScopeSupportFacetInfos);
diff --git a/packages/lib-test-case-recorder/src/ScopeTestRecorder.ts b/packages/lib-test-case-recorder/src/ScopeTestRecorder.ts
index 1021b71e7c..a3f6131760 100644
--- a/packages/lib-test-case-recorder/src/ScopeTestRecorder.ts
+++ b/packages/lib-test-case-recorder/src/ScopeTestRecorder.ts
@@ -1,14 +1,20 @@
import fs from "node:fs";
import fsPromises from "node:fs/promises";
import path from "node:path";
+import type {
+ IDE,
+ LanguageId,
+ LanguageScopeSupportId,
+ ScopeSupportFacet,
+} from "@cursorless/lib-common";
import {
ScopeSupportFacetLevel,
+ getScopeSupportLanguageId,
groupBy,
languageScopeSupport,
scopeSupportFacetInfos,
showInfo,
} from "@cursorless/lib-common";
-import type { IDE, ScopeSupportFacet } from "@cursorless/lib-common";
import {
getScopeTestPathsRecursively,
getScopeTestsDirPath,
@@ -21,12 +27,13 @@ export class ScopeTestRecorder {
}
async showUnimplementedFacets() {
- const languageId = await this.languageSelection();
+ const languageSelection = await this.languageSelection();
- if (languageId == null) {
+ if (languageSelection == null) {
return;
}
+ const languageId = getScopeSupportLanguageId(languageSelection);
const supportedScopeFacets = getSupportedScopeFacets(languageId);
const existingScopeTestFacets = getExistingScopeFacetTest(languageId);
@@ -39,7 +46,7 @@ export class ScopeTestRecorder {
(facet) =>
`[${facet}] - ${scopeSupportFacetInfos[facet].description}\n$${currentSnippetPlaceholder++}\n---\n`,
);
- const header = `[[${languageId}]]\n\n`;
+ const header = `[[${languageSelection}]]\n\n`;
const snippetText = `${header}${missingScopeFacetRows.join("\n")}`;
const editor = await this.ide.openUntitledTextDocument({
@@ -122,7 +129,9 @@ export class ScopeTestRecorder {
}
}
-function getSupportedScopeFacets(languageId: string): ScopeSupportFacet[] {
+function getSupportedScopeFacets(
+ languageId: LanguageScopeSupportId,
+): ScopeSupportFacet[] {
const scopeSupport = languageScopeSupport[languageId];
if (scopeSupport == null) {
@@ -136,7 +145,7 @@ function getSupportedScopeFacets(languageId: string): ScopeSupportFacet[] {
);
}
-function getExistingScopeFacetTest(languageId: string): Set {
+function getExistingScopeFacetTest(languageId: LanguageId): Set {
const testPaths = getScopeTestPathsRecursively();
const languages = groupBy(testPaths, (test) => test.languageId);
const testPathsForLanguage = languages.get(languageId) ?? [];
diff --git a/packages/tool-meta-updater/src/metaUpdater.ts b/packages/tool-meta-updater/src/metaUpdater.ts
index 58b3eb37dd..bfd22d6d9c 100644
--- a/packages/tool-meta-updater/src/metaUpdater.ts
+++ b/packages/tool-meta-updater/src/metaUpdater.ts
@@ -9,12 +9,13 @@ import type { ScopeTypeType } from "@cursorless/lib-common";
import {
actionReferenceGroups,
actionReferences,
- languageScopeSupport,
+ languageReferences,
modifierReferenceGroups,
modifierReferences,
pairedDelimiterReferences,
scopeReferenceGroups,
scopeReferences,
+ unsafeKeys,
} from "@cursorless/lib-common";
import type { Context } from "./Context";
import { createScopeFixtureGroups } from "./scopeFixtureGroups";
@@ -47,7 +48,7 @@ export const updater = async (workspaceDir: string) => {
const userDir = "src/docs/user";
const contributingDir = "src/docs/contributing";
const scopeFixtureGroups = createScopeFixtureGroups(workspaceDir);
- const languageIds = [...Object.keys(languageScopeSupport), "plaintext"];
+ const languageIds = unsafeKeys(languageReferences);
return createUpdateOptions({
files: {
diff --git a/packages/tool-meta-updater/src/renderScopeVisualizerMdx.ts b/packages/tool-meta-updater/src/renderScopeVisualizerMdx.ts
index 433222dded..8d86caf647 100644
--- a/packages/tool-meta-updater/src/renderScopeVisualizerMdx.ts
+++ b/packages/tool-meta-updater/src/renderScopeVisualizerMdx.ts
@@ -1,4 +1,4 @@
-import { prettifyLanguageName } from "@cursorless/lib-common";
+import { languageReferences } from "@cursorless/lib-common";
import type {
ScopeFixtureFacet,
ScopeFixtureGroup,
@@ -117,7 +117,7 @@ function renderFacets(
fixture.languageId !== previousLanguageId
) {
previousLanguageId = fixture.languageId;
- lines.push(`##### ${prettifyLanguageName(fixture.languageId)}`, "");
+ lines.push(`##### ${languageReferences[fixture.languageId].name}`, "");
}
const languageProp =
diff --git a/packages/tool-meta-updater/src/scopeFixtureGroups.ts b/packages/tool-meta-updater/src/scopeFixtureGroups.ts
index 402e7f069c..52b120c69b 100644
--- a/packages/tool-meta-updater/src/scopeFixtureGroups.ts
+++ b/packages/tool-meta-updater/src/scopeFixtureGroups.ts
@@ -1,6 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import type {
+ LanguageId,
PlaintextScopeSupportFacet,
ScopeSupportFacet,
ScopeSupportFacetInfo,
@@ -9,6 +10,7 @@ import type {
import {
camelCaseToAllDown,
capitalize,
+ getLanguageId,
plaintextScopeSupportFacetInfos,
prettifyScopeType,
scopeReferences,
@@ -30,7 +32,7 @@ interface FixtureMetadata {
}
export interface ScopeFixture {
- languageId: string;
+ languageId: LanguageId;
name: string;
}
@@ -269,7 +271,7 @@ function nameComparator(a: { name: string }, b: { name: string }): number {
return a.name.localeCompare(b.name, undefined, { numeric: true });
}
-function normalizeLanguageId(languageId: string): string {
+function normalizeLanguageId(languageId: string): LanguageId {
switch (languageId) {
case "javascript.core":
return "javascript";
@@ -278,6 +280,6 @@ function normalizeLanguageId(languageId: string): string {
case "javascript.jsx":
return "javascriptreact";
default:
- return languageId;
+ return getLanguageId(languageId);
}
}
diff --git a/packages/tool-meta-updater/src/updateLanguageMdx.ts b/packages/tool-meta-updater/src/updateLanguageMdx.ts
index 67dac4480a..a1fc0a3e1d 100644
--- a/packages/tool-meta-updater/src/updateLanguageMdx.ts
+++ b/packages/tool-meta-updater/src/updateLanguageMdx.ts
@@ -1,5 +1,6 @@
import type { FormatPluginFnOptions } from "@pnpm/meta-updater";
-import { prettifyLanguageName } from "@cursorless/lib-common";
+import type { LanguageId } from "@cursorless/lib-common";
+import { languageReferences } from "@cursorless/lib-common";
import {
renderLanguageScopeVisualizer,
scopeVisualizerImport,
@@ -7,7 +8,7 @@ import {
import type { ScopeFixtureGroup } from "./scopeFixtureGroups";
export function updateLanguageMdx(
- languageId: string,
+ languageId: LanguageId,
scopeFixtureGroups: ScopeFixtureGroup[],
actual: string | null,
options: FormatPluginFnOptions,
@@ -19,7 +20,7 @@ export function updateLanguageMdx(
const expected = [
scopeVisualizerImport,
"",
- `# ${prettifyLanguageName(languageId)}`,
+ `# ${languageReferences[languageId].name}`,
"",
renderLanguageScopeVisualizer(languageId, scopeFixtureGroups),
"",