fix(highlight): 补全 Swift 语法高亮

Swift.sublime-syntax 之前是残缺定义,expression 上下文仅包含
空白/字符串/数字,导致关键字、类型、函数等全部无法高亮。

补全声明关键字(import/func/class/let 等)、控制流(if/return/
async/await)、标准库类型(Int/String/Array)、函数声明与调用、
属性(@objc)等上下文,并调整 include 顺序使函数声明名优先于
函数调用识别。

新增两个回归测试覆盖关键字/函数/类型/字符串高亮。
This commit is contained in:
xfy 2026-06-16 14:17:17 +08:00
parent 6986a62bb5
commit 188e607ec2
2 changed files with 113 additions and 0 deletions

View File

@ -221,4 +221,39 @@ mod tests {
2
);
}
#[test]
fn highlight_code_swift_keyword_and_func() {
// Swift 关键字 func/import/let 应生成 declaration/keyword span而不是纯文本。
let code = "import Foundation\nfunc greet(person: String) -> String {\n return \"Hi\"\n}";
let result = highlight_code(code, Some("swift"));
assert!(
result.contains("keyword"),
"Swift 输出缺少关键字高亮: {}",
result
);
// 函数名应被识别为函数(声明名 entity name function 或调用 variable function
assert!(
result.contains("name function") || result.contains("variable function"),
"Swift func 名缺少函数高亮: {}",
result
);
}
#[test]
fn highlight_code_swift_types_and_strings() {
// Swift 标准库类型与字符串字面量都应被识别。
let code = "let count: Int = 42\nlet name = \"hello\"";
let result = highlight_code(code, Some("swift"));
assert!(
result.contains("support type") || result.contains("entity name type"),
"Swift Int 类型未被识别为类型: {}",
result
);
assert!(
result.contains("string"),
"Swift 字符串未被识别: {}",
result
);
}
}

View File

@ -194,6 +194,84 @@ contexts:
expression:
- include: whitespace
- include: comments
- include: attribute
- include: string-literal
- include: floating-point-literal
- include: integer-literal
- include: function-declaration
- include: declaration-keywords
- include: control-keywords
- include: modifiers
- include: types
- include: constants
- include: function-calls
- include: types-and-identifiers
comments:
- include: comment
- include: multiline-comment
# 属性:@MainActor、@objc、@available(iOS 14, *)
attribute:
- match: '@\b{{identifier_head}}{{identifier_character}}*'
scope: meta.attribute.swift entity.other.attribute-name.swift
# 声明类关键字
declaration-keywords:
- match: '\b(?:import|func|class|struct|enum|protocol|extension|let|var|typealias|init|deinit|subscript|operator|precedencegroup|actor|macro)\b'
scope: keyword.declaration.swift
- match: '\b(?:associatedtype|fileprivate|internal|private|public|open|static|final|lazy|weak|unowned|dynamic|inout|mutating|nonmutating|convenience|required|optional|override|indirect|borrowing|consuming|distributed|nonisolated|isolated)\b'
scope: storage.modifier.swift
# 控制流关键字
control-keywords:
- match: '\b(?:if|else|guard|switch|case|default|for|in|while|repeat|do|where|fallthrough|break|continue|return|throw|throws|rethrows|try|catch|defer|as|is|async|await|yield|some|any|each)\b'
scope: keyword.control.swift
- match: '\b(?:true|false|nil|self|Self|super)\b'
scope: constant.language.swift
# try?/try!/as?/as!
- match: '\b(?:try|as)([?!])'
captures:
1: keyword.control.swift
# 单独列出的修饰符(已在 declaration-keywords 内,此处保留占位以便扩展)
modifiers: []
# 内置/标准库常用类型
types:
- match: '\b(?:Int|UInt|Int8|Int16|Int32|Int64|UInt8|UInt16|UInt32|UInt64|Float|Double|Bool|String|Character|Void|Optional|Array|Dictionary|Set|Range|ClosedRange|Any|Never|Result)\b'
scope: support.type.swift
# 常量与全局函数
constants:
- match: '\b(?:print|println|debugPrint|fatalError|assert|assertionFailure|precondition|preconditionFailure|min|max|abs|count|append|contains|map|filter|reduce|compactMap|flatMap|sorted|first|last|isEmpty)\b'
scope: support.function.swift
# 函数声明func name(...) 与 init/subscript
function-declaration:
- match: '\b(func)\s+({{identifier_head}}{{identifier_character}}*|`[^`]+`|operator)'
captures:
1: keyword.declaration.swift
2: entity.name.function.swift
- match: '\b(init)\b'
scope: keyword.declaration.swift entity.name.function.swift
- match: '\b(deinit)\b'
scope: keyword.declaration.swift
- match: '\b(subscript)\b'
scope: keyword.declaration.swift
# 函数调用name( 或 name <Generic>(
function-calls:
- match: '\b{{identifier_head}}{{identifier_character}}*(?=\s*(?:<[^(){}\n]*>)?\s*\()'
scope: variable.function.swift
- match: '\b{{identifier_head}}{{identifier_character}}*(?=\s*\{)'
scope: variable.function.swift
# 普通标识符(大写识别为类型风格,小写为变量)
types-and-identifiers:
- match: '\b[A-Z]{{identifier_character}}*\b'
scope: entity.name.type.swift
- match: '\b{{identifier_head}}{{identifier_character}}*\b'
scope: variable.swift