Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Language improvements:
- New grammar for attributes
- Added support for quoted identifiers, implicit parameters, and property wrapper projections
- Support for more complex expressions in string interpolation
- enh(swift) Improved highlighting for types and generic arguments (#2920) [Steven Van Impe][]
- fix(http) avoid recursive sublanguage and tighten rules (#2893) [Josh Goebel][]
- fix(asciidoc): Handle section titles level 5 (#2868) [Vaibhav Chanana][]

Expand Down
3 changes: 3 additions & 0 deletions src/languages/lib/kws_swift.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ export const identifierCharacter = either(
// Valid identifier.
export const identifier = concat(identifierHead, identifierCharacter, '*');

// Valid type identifier.
export const typeIdentifier = concat(/[A-Z]/, identifierCharacter, '*');

// Built-in attributes, which are highlighted as keywords.
// @available is handled separately.
export const keywordAttributes = [
Expand Down
77 changes: 58 additions & 19 deletions src/languages/swift.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ import {

/** @type LanguageFn */
export default function(hljs) {
// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID411
const BLOCK_COMMENT = hljs.COMMENT(
'/\\*',
'\\*/',
{
contains: [ 'self' ]
}
);

// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID413
// https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html
const DOT_KEYWORD = {
Expand Down Expand Up @@ -77,6 +86,11 @@ export default function(hljs) {
];

// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
const OPERATOR_GUARD = {
// Prevent -> from being highlighting as an operator.
begin: /->/,
relevance: 0
};
const OPERATOR = {
className: 'operator',
relevance: 0,
Expand All @@ -92,6 +106,10 @@ export default function(hljs) {
}
]
};
const OPERATORS = [
OPERATOR_GUARD,
OPERATOR
];

// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_numeric-literal
// TODO: Update for leading `-` after lookbehind is supported everywhere
Expand Down Expand Up @@ -205,7 +223,7 @@ export default function(hljs) {
.join(' ')
},
contains: [
OPERATOR,
...OPERATORS,
NUMBER,
STRING
]
Expand All @@ -224,24 +242,46 @@ export default function(hljs) {
USER_DEFINED_ATTRIBUTE
];

// https://docs.swift.org/swift-book/ReferenceManual/Types.html
const TYPE = {
className: 'type',
begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*',
relevance: 0
begin: lookahead(/\b[A-Z]/),
relevance: 0,
contains: [
{ // Common Apple frameworks, for relevance boost
className: 'type',
begin: concat(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/, Swift.identifierCharacter, '+')
},
{ // Type identifier
className: 'type',
begin: Swift.typeIdentifier,
relevance: 0
},
{ // Optional type
begin: /[?!]+/,
relevance: 0
},
{ // Variadic parameter
begin: /\.\.\./,
relevance: 0
},
{ // Protocol composition
begin: concat(/\s+&\s+/, lookahead(Swift.typeIdentifier)),
relevance: 0
}
]
};
// slightly more special to swift
const OPTIONAL_USING_TYPE = {
className: 'type',
begin: '\\b[A-Z][\\w\u00C0-\u02B8\']*[!?]',
relevance: 0
const GENERIC_ARGUMENTS = {
begin: /</,
end: />/,
keywords: KEYWORDS,
contains: [
...KEYWORD_MODES,
...ATTRIBUTES,
OPERATOR_GUARD,
TYPE
]
};
const BLOCK_COMMENT = hljs.COMMENT(
'/\\*',
'\\*/',
{
contains: [ 'self' ]
}
);
TYPE.contains.push(GENERIC_ARGUMENTS);

// Add supported submodes to string interpolation.
for (const variant of STRING.variants) {
Expand All @@ -251,7 +291,7 @@ export default function(hljs) {
const submodes = [
...KEYWORD_MODES,
...BUILT_INS,
OPERATOR,
...OPERATORS,
NUMBER,
STRING,
...IDENTIFIERS
Expand Down Expand Up @@ -333,12 +373,11 @@ export default function(hljs) {
},
...KEYWORD_MODES,
...BUILT_INS,
OPERATOR,
...OPERATORS,
NUMBER,
STRING,
...IDENTIFIERS,
...ATTRIBUTES,
OPTIONAL_USING_TYPE,
TYPE
]
};
Expand Down
43 changes: 43 additions & 0 deletions test/markup/swift/types.expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<span class="hljs-comment">// Simple identifier</span>
<span class="hljs-type">Int</span>

<span class="hljs-comment">// Types from Apple frameworks</span>
<span class="hljs-type">CALayer</span>
<span class="hljs-type">CGRect</span>
<span class="hljs-type">MKMapView</span>
<span class="hljs-type">NSView</span>
<span class="hljs-type">UIView</span>
<span class="hljs-type">XCTest</span>

<span class="hljs-comment">// ?, !, ..., and &amp; should not be highlighted as operators</span>
<span class="hljs-type">Int</span>?
<span class="hljs-type">Int</span>!
<span class="hljs-type">Int</span>?!
<span class="hljs-type">String</span>...
<span class="hljs-type">SomeClass</span> &amp; <span class="hljs-type">SomeProtocol</span>

<span class="hljs-comment">// Arrays, dictionaries, and nested types</span>
[<span class="hljs-type">String</span>]
<span class="hljs-type">Array</span>&lt;<span class="hljs-type">String</span>&gt;
[[<span class="hljs-type">Int</span>?]]
<span class="hljs-type">Array</span>&lt;<span class="hljs-type">Array</span>&lt;<span class="hljs-type">Int</span>?&gt;&gt;
[<span class="hljs-type">String</span>: <span class="hljs-type">Int</span>]
<span class="hljs-type">Dictionary</span>&lt;<span class="hljs-type">String</span>, <span class="hljs-type">Int</span>&gt;
<span class="hljs-type">Swift</span>.<span class="hljs-type">Array</span>&lt;<span class="hljs-type">Int</span>&gt;.<span class="hljs-type">Element</span>

<span class="hljs-comment">// Tuples</span>
()
(<span class="hljs-type">Double</span>, <span class="hljs-type">Double</span>)
(x: <span class="hljs-type">Double</span>, y: <span class="hljs-type">Double</span>)

<span class="hljs-comment">// Functions</span>
(<span class="hljs-keyword">@escaping</span> (<span class="hljs-type">String</span>) -&gt; <span class="hljs-type">Void</span>, <span class="hljs-keyword">@autoclosure</span> () -&gt; <span class="hljs-type">String</span>) -&gt; <span class="hljs-type">String</span>
(<span class="hljs-type">Int</span>, <span class="hljs-type">String</span>...) -&gt; <span class="hljs-keyword">some</span> <span class="hljs-type">Collection</span>
() <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-keyword">Self</span>

<span class="hljs-comment">// Generic arguments</span>
<span class="hljs-type">Array</span>&lt;<span class="hljs-type">String</span>.<span class="hljs-keyword">Type</span>&gt;
<span class="hljs-type">Array</span>&lt;<span class="hljs-type">Sequence</span>.<span class="hljs-keyword">Protocol</span>&gt;
<span class="hljs-type">Dictionary</span>&lt;<span class="hljs-type">String</span>, <span class="hljs-keyword">Any</span>&gt;
<span class="hljs-type">Dictionary</span>&lt;<span class="hljs-type">String</span>, <span class="hljs-type">Array</span>&lt;<span class="hljs-type">Int</span>&gt;&gt;
<span class="hljs-type">Array</span>&lt;(<span class="hljs-keyword">@autoclosure</span> () -&gt; <span class="hljs-type">String</span>) <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-type">String</span>?&gt;
43 changes: 43 additions & 0 deletions test/markup/swift/types.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Simple identifier
Int

// Types from Apple frameworks
CALayer
CGRect
MKMapView
NSView
UIView
XCTest

// ?, !, ..., and & should not be highlighted as operators
Int?
Int!
Int?!
String...
SomeClass & SomeProtocol

// Arrays, dictionaries, and nested types
[String]
Array<String>
[[Int?]]
Array<Array<Int?>>
[String: Int]
Dictionary<String, Int>
Swift.Array<Int>.Element

// Tuples
()
(Double, Double)
(x: Double, y: Double)

// Functions
(@escaping (String) -> Void, @autoclosure () -> String) -> String
(Int, String...) -> some Collection
() throws -> Self

// Generic arguments
Array<String.Type>
Array<Sequence.Protocol>
Dictionary<String, Any>
Dictionary<String, Array<Int>>
Array<(@autoclosure () -> String) throws -> String?>