구문 강조 표시 가이드
구문 강조는 Visual Studio Code 편집기에 표시되는 소스 코드의 색상과 스타일을 결정합니다. JavaScript의 if 또는 for와 같은 키워드를 문자열, 주석 및 변수 이름과 다르게 색칠하는 역할을 합니다.
구문 강조에는 두 가지 구성 요소가 있습니다.
자세히 알아보기 전에, 스코프 검사기 도구를 사용하여 소스 파일에 어떤 토큰이 있는지, 그리고 어떤 테마 규칙과 일치하는지 탐색하는 것이 좋습니다. 의미론적 토큰과 구문 토큰을 모두 보려면 TypeScript 파일에 내장 테마(예: Dark+)를 사용하십시오.
토큰화
텍스트의 토큰화는 텍스트를 세그먼트로 분할하고 각 세그먼트를 토큰 유형으로 분류하는 것입니다.
VS Code의 토큰화 엔진은 TextMate 문법으로 구동됩니다. TextMate 문법은 정규 표현식의 구조화된 모음이며 plist(XML) 또는 JSON 파일로 작성됩니다. VS Code 확장은 grammars 기여 지점을 통해 문법을 제공할 수 있습니다.
TextMate 토큰화 엔진은 렌더러와 동일한 프로세스에서 실행되며, 사용자가 타이핑함에 따라 토큰이 업데이트됩니다. 토큰은 구문 강조에 사용될 뿐만 아니라 소스 코드를 주석, 문자열, 정규 표현식 영역으로 분류하는 데에도 사용됩니다.
1.43 릴리스부터 VS Code는 확장이 의미론적 토큰 제공자를 통해 토큰화를 제공할 수 있도록 허용합니다. 의미론적 제공자는 일반적으로 소스 파일을 더 깊이 이해하고 프로젝트 컨텍스트에서 기호를 확인할 수 있는 언어 서버에 의해 구현됩니다. 예를 들어, 상수 변수 이름은 선언된 위치뿐만 아니라 프로젝트 전체에서 상수 강조를 사용하여 렌더링될 수 있습니다.
의미론적 토큰을 기반으로 한 강조는 TextMate 기반 구문 강조에 대한 추가 기능으로 간주됩니다. 의미론적 강조는 구문 강조 위에 적용됩니다. 언어 서버가 로드되고 프로젝트를 분석하는 데 시간이 걸릴 수 있으므로 의미론적 토큰 강조는 짧은 지연 후에 나타날 수 있습니다.
이 문서는 TextMate 기반 토큰화에 중점을 둡니다. 의미론적 토큰화 및 테마 지정은 의미론적 강조 가이드에서 설명합니다.
TextMate 문법
VS Code는 TextMate 문법을 구문 토큰화 엔진으로 사용합니다. TextMate 편집기를 위해 발명되었으며, 오픈 소스 커뮤니티에서 생성 및 유지 관리하는 방대한 언어 번들 덕분에 다른 많은 편집기 및 IDE에서 채택되었습니다.
TextMate 문법은 Oniguruma 정규 표현식에 의존하며 일반적으로 plist 또는 JSON으로 작성됩니다. TextMate 문법에 대한 좋은 소개는 여기에서 찾을 수 있으며, 기존 TextMate 문법을 살펴보고 작동 방식을 더 자세히 배울 수 있습니다.
TextMate 토큰 및 스코프
토큰은 동일한 프로그램 요소의 일부인 하나 이상의 문자입니다. 예시 토큰으로는 + 및 *와 같은 연산자, myVar와 같은 변수 이름, "my string"과 같은 문자열이 있습니다.
각 토큰은 토큰의 컨텍스트를 정의하는 스코프와 연결됩니다. 스코프는 현재 토큰의 컨텍스트를 지정하는 식별자의 점으로 구분된 목록입니다. 예를 들어, JavaScript의 + 연산자는 keyword.operator.arithmetic.js 스코프를 가집니다.
테마는 스코프를 색상 및 스타일에 매핑하여 구문 강조를 제공합니다. TextMate는 많은 테마가 대상으로 하는 일반적인 스코프 목록을 제공합니다. 문법이 가능한 한 광범위하게 지원되도록 하려면 새 스코프를 정의하기보다는 기존 스코프를 기반으로 구축하십시오.
스코프는 중첩되므로 각 토큰은 부모 스코프 목록과도 연결됩니다. 아래 예시는 스코프 검사기를 사용하여 간단한 JavaScript 함수에서 + 연산자의 스코프 계층 구조를 보여줍니다. 가장 구체적인 스코프가 맨 위에 나열되고, 더 일반적인 부모 스코프가 아래에 나열됩니다.

부모 스코프 정보는 테마 지정에도 사용됩니다. 테마가 스코프를 대상으로 할 때, 해당 부모 스코프를 가진 모든 토큰은 테마가 개별 스코프에 대해 더 구체적인 색상을 제공하지 않는 한 색상이 지정됩니다.
기본 문법 기여
VS Code는 JSON TextMate 문법을 지원합니다. 이는 grammars 기여 지점을 통해 제공됩니다.
각 문법 기여는 다음을 지정합니다. 문법이 적용되는 언어의 식별자, 문법 토큰의 최상위 스코프 이름, 문법 파일의 상대 경로. 아래 예시는 가상의 abc 언어에 대한 문법 기여를 보여줍니다.
{
"contributes": {
"languages": [
{
"id": "abc",
"extensions": [".abc"]
}
],
"grammars": [
{
"language": "abc",
"scopeName": "source.abc",
"path": "./syntaxes/abc.tmGrammar.json"
}
]
}
}
문법 파일 자체는 최상위 규칙으로 구성됩니다. 일반적으로 프로그램의 최상위 요소를 나열하는 patterns 섹션과 각 요소를 정의하는 repository로 분할됩니다. 문법의 다른 규칙은 { "include": "#id" }를 사용하여 repository의 요소를 참조할 수 있습니다.
예시 abc 문법은 a, b, c 문자를 키워드로 표시하고, 괄호의 중첩을 표현식으로 표시합니다.
{
"scopeName": "source.abc",
"patterns": [{ "include": "#expression" }],
"repository": {
"expression": {
"patterns": [{ "include": "#letter" }, { "include": "#paren-expression" }]
},
"letter": {
"match": "a|b|c",
"name": "keyword.letter"
},
"paren-expression": {
"begin": "\\(",
"end": "\\)",
"beginCaptures": {
"0": { "name": "punctuation.paren.open" }
},
"endCaptures": {
"0": { "name": "punctuation.paren.close" }
},
"name": "expression.group",
"patterns": [{ "include": "#expression" }]
}
}
}
문법 엔진은 expression 규칙을 문서의 모든 텍스트에 순차적으로 적용하려고 시도합니다. 다음의 간단한 프로그램의 경우
a
(
b
)
x
(
(
c
xyz
)
)
(
a
예시 문법은 다음 스코프를 생성합니다 (가장 구체적인 스코프에서 가장 덜 구체적인 스코프로 왼쪽에서 오른쪽으로 나열됨).
a keyword.letter, source.abc
( punctuation.paren.open, expression.group, source.abc
b keyword.letter, expression.group, source.abc
) punctuation.paren.close, expression.group, source.abc
x source.abc
( punctuation.paren.open, expression.group, source.abc
( punctuation.paren.open, expression.group, expression.group, source.abc
c keyword.letter, expression.group, expression.group, source.abc
xyz expression.group, expression.group, source.abc
) punctuation.paren.close, expression.group, expression.group, source.abc
) punctuation.paren.close, expression.group, source.abc
( punctuation.paren.open, expression.group, source.abc
a keyword.letter, expression.group, source.abc
xyz 문자열과 같이 규칙 중 하나와 일치하지 않는 텍스트는 현재 스코프에 포함된다는 점에 유의하십시오. 파일 끝의 마지막 괄호는 end 규칙이 일치하지 않더라도 end-of-document가 end 규칙 전에 발견되었기 때문에 expression.group의 일부입니다.
포함된 언어
문법에 HTML의 CSS 스타일 블록과 같이 부모 언어 내에 포함된 언어가 포함된 경우, embeddedLanguages 기여 지점을 사용하여 VS Code가 포함된 언어를 부모 언어와 다르게 취급하도록 할 수 있습니다. 이를 통해 포함된 언어에서 괄호 일치, 주석 처리 및 기타 기본 언어 기능이 예상대로 작동합니다.
embeddedLanguages 기여 지점은 포함된 언어의 스코프를 최상위 언어 스코프에 매핑합니다. 아래 예시에서 meta.embedded.block.javascript 스코프의 모든 토큰은 JavaScript 콘텐츠로 취급됩니다.
{
"contributes": {
"grammars": [
{
"path": "./syntaxes/abc.tmLanguage.json",
"scopeName": "source.abc",
"embeddedLanguages": {
"meta.embedded.block.javascript": "javascript"
}
}
]
}
}
이제 meta.embedded.block.javascript로 표시된 토큰 세트 내에서 코드에 주석을 달거나 스니펫을 트리거하면 올바른 // JavaScript 스타일 주석과 올바른 JavaScript 스니펫이 제공됩니다.
새 문법 확장 개발
새로운 문법 확장을 빠르게 생성하려면 VS Code의 Yeoman 템플릿을 사용하여 yo code를 실행하고 New Language 옵션을 선택하십시오.

Yeoman은 새 확장을 스캐폴딩하기 위한 몇 가지 기본 질문을 안내합니다. 새 문법을 만드는 데 중요한 질문은 다음과 같습니다.
Language id- 언어의 고유 식별자입니다.Language name- 언어의 사람이 읽을 수 있는 이름입니다.Scope names- 문법의 루트 TextMate 스코프 이름입니다.

생성기는 새로운 언어와 해당 언어에 대한 새로운 문법을 정의한다고 가정합니다. 기존 언어에 대한 문법을 만드는 경우, 대상 언어 정보로 이 필드를 채우고 생성된 package.json에서 languages 기여 지점을 삭제하십시오.
모든 질문에 답하면 Yeoman은 다음과 같은 구조로 새 확장을 생성합니다.

VS Code가 이미 알고 있는 언어에 대한 문법을 제공하는 경우, 생성된 package.json에서 languages 기여 지점을 삭제해야 합니다.
기존 TextMate 문법 변환
yo code는 기존 TextMate 문법을 VS Code 확장으로 변환하는 데도 도움이 됩니다. 다시 yo code를 실행하고 Language extension을 선택합니다. 기존 문법 파일에 대한 질문을 받으면 .tmLanguage 또는 .json TextMate 문법 파일의 전체 경로를 제공하십시오.

YAML을 사용하여 문법 작성
문법이 복잡해질수록 JSON으로 이해하고 유지 관리하기 어려워질 수 있습니다. 복잡한 정규 표현식을 작성하거나 문법의 일부를 설명하기 위해 주석을 추가해야 하는 경우 대신 YAML을 사용하여 문법을 정의하는 것을 고려하십시오.
YAML 문법은 JSON 기반 문법과 동일한 구조를 가지지만, YAML의 더 간결한 구문과 여러 줄 문자열 및 주석과 같은 기능을 사용할 수 있습니다.

VS Code는 JSON 문법만 로드할 수 있으므로 YAML 기반 문법은 JSON으로 변환해야 합니다. js-yaml 패키지 및 명령줄 도구를 사용하면 이를 쉽게 할 수 있습니다.
# Install js-yaml as a development only dependency in your extension
$ npm install js-yaml --save-dev
# Use the command-line tool to convert the yaml grammar to json
$ npx js-yaml syntaxes/abc.tmLanguage.yaml > syntaxes/abc.tmLanguage.json
주입 문법
주입 문법을 사용하면 기존 문법을 확장할 수 있습니다. 주입 문법은 특정 스코프 내의 기존 문법에 주입되는 일반 TextMate 문법입니다. 주입 문법의 예시 응용 프로그램
- 주석 내에서
TODO와 같은 키워드 강조. - 기존 문법에 더 구체적인 스코프 정보 추가.
- Markdown으로 구분된 코드 블록에 새 언어에 대한 강조 추가.
기본 주입 문법 생성
주입 문법은 일반 문법과 마찬가지로 package.json을 통해 제공됩니다. 그러나 language를 지정하는 대신, 주입 문법은 injectTo를 사용하여 문법을 주입할 대상 언어 스코프 목록을 지정합니다.
이 예시에서는 JavaScript 주석에서 TODO를 키워드로 강조하는 간단한 주입 문법을 만듭니다. JavaScript 파일에 주입 문법을 적용하기 위해 injectTo에서 source.js 대상 언어 스코프를 사용합니다.
{
"contributes": {
"grammars": [
{
"path": "./syntaxes/injection.json",
"scopeName": "todo-comment.injection",
"injectTo": ["source.js"]
}
]
}
}
문법 자체는 최상위 injectionSelector 항목을 제외하고 표준 TextMate 문법입니다. injectionSelector는 주입된 문법이 적용되어야 하는 스코프를 지정하는 스코프 선택기입니다. 이 예시에서는 모든 // 주석에서 TODO 단어를 강조하고 싶습니다. 스코프 검사기를 사용하여 JavaScript의 이중 슬래시 주석이 comment.line.double-slash 스코프를 가진다는 것을 알았으므로, 주입 선택기는 L:comment.line.double-slash입니다.
{
"scopeName": "todo-comment.injection",
"injectionSelector": "L:comment.line.double-slash",
"patterns": [
{
"include": "#todo-keyword"
}
],
"repository": {
"todo-keyword": {
"match": "TODO",
"name": "keyword.todo"
}
}
}
주입 선택기에서 L:는 주입이 기존 문법 규칙의 왼쪽에 추가됨을 의미합니다. 이는 기본적으로 주입된 문법의 규칙이 기존 문법 규칙보다 먼저 적용됨을 의미합니다.
포함된 언어
주입 문법은 부모 문법에 포함된 언어도 제공할 수 있습니다. 일반 문법과 마찬가지로 주입 문법은 embeddedLanguages를 사용하여 포함된 언어의 스코프를 최상위 언어 스코프에 매핑할 수 있습니다.
예를 들어, JavaScript 문자열 내의 SQL 쿼리를 강조하는 확장은 embeddedLanguages를 사용하여 meta.embedded.inline.sql로 표시된 문자열 안의 모든 토큰이 괄호 일치 및 스니펫 선택과 같은 기본 언어 기능에 대해 SQL로 취급되도록 할 수 있습니다.
{
"contributes": {
"grammars": [
{
"path": "./syntaxes/injection.json",
"scopeName": "sql-string.injection",
"injectTo": ["source.js"],
"embeddedLanguages": {
"meta.embedded.inline.sql": "sql"
}
}
]
}
}
토큰 유형 및 포함된 언어
주입 언어 및 포함된 언어에 대한 한 가지 추가 복잡성이 있습니다. 기본적으로 VS Code는 문자열 내의 모든 토큰을 문자열 콘텐츠로, 주석이 있는 모든 토큰을 토큰 콘텐츠로 취급합니다. 괄호 일치 및 자동 닫기 쌍과 같은 기능은 문자열 및 주석 내에서 비활성화되므로, 포함된 언어가 문자열 또는 주석 내에 나타나는 경우 이 기능도 포함된 언어에서 비활성화됩니다.
이 동작을 재정의하려면 meta.embedded.* 스코프를 사용하여 VS Code가 토큰을 문자열 또는 주석 콘텐츠로 표시하는 것을 재설정할 수 있습니다. 포함된 언어가 VS Code에서 제대로 취급되도록 하려면 항상 포함된 언어를 meta.embedded.* 스코프로 래핑하는 것이 좋습니다.
문법에 meta.embedded.* 스코프를 추가할 수 없는 경우, 대신 문법의 기여 지점에 있는 tokenTypes를 사용하여 특정 스코프를 콘텐츠 모드로 매핑할 수 있습니다. 아래의 tokenTypes 섹션은 my.sql.template.string 스코프의 모든 콘텐츠가 소스 코드로 취급되도록 합니다.
{
"contributes": {
"grammars": [
{
"path": "./syntaxes/injection.json",
"scopeName": "sql-string.injection",
"injectTo": ["source.js"],
"embeddedLanguages": {
"my.sql.template.string": "sql"
},
"tokenTypes": {
"my.sql.template.string": "other"
}
}
]
}
}
테마
테마 지정은 토큰에 색상 및 스타일을 할당하는 것입니다. 테마 지정 규칙은 색상 테마에 지정되지만, 사용자는 사용자 설정에서 테마 지정 규칙을 사용자 정의할 수 있습니다.
TextMate 테마 규칙은 tokenColors에 정의되며 일반 TextMate 테마와 동일한 구문을 가집니다. 각 규칙은 TextMate 스코프 선택기와 결과 색상 및 스타일을 정의합니다.
토큰의 색상 및 스타일을 평가할 때, 현재 토큰의 스코프는 규칙 선택기와 일치하여 각 스타일 속성(전경, 굵게, 기울임꼴, 밑줄)에 대한 가장 구체적인 규칙을 찾습니다.
색상 테마 가이드에서는 색상 테마를 만드는 방법을 설명합니다. 의미론적 토큰에 대한 테마 지정은 의미론적 강조 가이드에서 설명합니다.
스코프 검사기
VS Code의 내장 스코프 검사기 도구는 문법 및 의미론적 토큰을 디버깅하는 데 도움이 됩니다. 파일의 현재 위치에 있는 토큰 및 의미론적 토큰의 스코프와 해당 토큰에 적용되는 테마 규칙에 대한 메타데이터를 표시합니다.
명령 팔레트에서 Developer: Inspect Editor Tokens and Scopes 명령을 실행하거나 키 바인딩을 만들어 스코프 검사기를 트리거하십시오.
{
"key": "cmd+alt+shift+i",
"command": "editor.action.inspectTMScopes"
}

스코프 검사기는 다음 정보를 표시합니다.
- 현재 토큰.
- 토큰에 대한 메타데이터 및 계산된 모양에 대한 정보. 포함된 언어를 작업하는 경우, 여기서 중요한 항목은
language및token type입니다. - 의미론적 토큰 섹션은 현재 언어에 대한 의미론적 토큰 공급자가 있고 현재 테마가 의미론적 강조를 지원하는 경우에 표시됩니다. 현재 의미론적 토큰 유형 및 수정자와 의미론적 토큰 유형 및 수정자와 일치하는 테마 규칙을 표시합니다.
- TextMate 섹션은 현재 TextMate 토큰의 스코프 목록을 표시하며, 가장 구체적인 스코프가 맨 위에 있습니다. 또한 스코프와 일치하는 가장 구체적인 테마 규칙도 표시합니다. 이는 토큰의 현재 스타일에 책임이 있는 테마 규칙만 표시하며, 재정의된 규칙은 표시하지 않습니다. 의미론적 토큰이 있는 경우, 테마 규칙은 의미론적 토큰과 일치하는 규칙과 다른 경우에만 표시됩니다.