From 188e607ec2792139052d45d8c24b0da194165764 Mon Sep 17 00:00:00 2001 From: xfy Date: Tue, 16 Jun 2026 14:17:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(highlight):=20=E8=A1=A5=E5=85=A8=20Swift=20?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E9=AB=98=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swift.sublime-syntax 之前是残缺定义,expression 上下文仅包含 空白/字符串/数字,导致关键字、类型、函数等全部无法高亮。 补全声明关键字(import/func/class/let 等)、控制流(if/return/ async/await)、标准库类型(Int/String/Array)、函数声明与调用、 属性(@objc)等上下文,并调整 include 顺序使函数声明名优先于 函数调用识别。 新增两个回归测试覆盖关键字/函数/类型/字符串高亮。 --- src/highlight.rs | 35 ++++++++++++++++ syntaxes/Swift.sublime-syntax | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/src/highlight.rs b/src/highlight.rs index dcc56c6..1bc2ca1 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -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 + ); + } } diff --git a/syntaxes/Swift.sublime-syntax b/syntaxes/Swift.sublime-syntax index 03eca97..84b708c 100644 --- a/syntaxes/Swift.sublime-syntax +++ b/syntaxes/Swift.sublime-syntax @@ -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 ( + 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 +