branch: elpa/swift-mode commit 030b1b8db8ffd3cb6d0b79b95e8b1561b6a0fe77 Author: taku0 <mxxouy6x3m_git...@tatapa.org> Commit: taku0 <mxxouy6x3m_git...@tatapa.org>
Update documentations and wordings --- CONTRIBUTING.md | 2 +- README.md | 22 +- doc/string.png | Bin 0 -> 19233 bytes doc/string.svg | 237 ++++++++++++++++++ doc/string_properties.png | Bin 0 -> 39997 bytes doc/string_properties.svg | 617 ++++++++++++++++++++++++++++++++++++++++++++++ swift-mode-indent.el | 57 ++--- swift-mode-lexer.el | 92 +++++-- 8 files changed, 965 insertions(+), 62 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47a4cc0..7a633b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ repository. Follow the guidelines below to make sure everything goes smoothly. - Follow the coding conventions already in use - Verify Emacs Lisp code with `checkdoc` - Add unit tests whenever possible -- Run `make check` and ensure no errors other than known-bugs. +- Run `make test` and ensure no errors other than known-bugs. - Open a [pull request](https://help.github.com/articles/using-pull-requests) relating to a single issue. diff --git a/README.md b/README.md index 74b1ab2..675b284 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Major-mode for Apple's [Swift programming language](https://developer.apple.com/ Install `swift-mode` package from MELPA. -To install without MELPA, download [latest release](https://github.com/swift-emacs/swift-mode/releases) and execute `M-x package-install-file`. +To install without MELPA, download [latest release](https://github.com/swift-emacs/swift-mode/releases) and execute `M-x package-install-file` for the .tar archive. ## Features @@ -91,7 +91,7 @@ Some syntax constructs removed from Swift 3.0 are not supported: } ``` -Indentation may not accurate. For example, `foo(Bar < A, B > (c))` is indented like either +Indentation may not accurate. For example, `foo(Bar < A, B > (c))` can be indented like either ```swift foo(Bar < A, B > (c)) // Passing two Boolean arguments to foo @@ -99,11 +99,11 @@ foo(Bar < A, or ```swift foo(Bar < A, - B > (c)) // constructing Bar with two type arguments and a value + B > (c)) // Passing a new Bar with two type arguments and a value ``` The Swift compiler disambiguates this case using tokens after `>`, but those tokens may not available at editing time. We use some heuristic for this. -Another example is difficulty of handling of colons. We have to pair all `?` and `:` of conditional operators to decide indentation. This is a future work. +Another example is difficulty of handling of colons. We have to pair all `?` and `:` of conditional operators to decide indentation of the below snippet. This is a future work. ```swift switch foo { @@ -128,7 +128,7 @@ var x = foo } ``` -while we also want to indent if body like this: +while we also want to indent the body of `if` like this: ```swift if anotherVeryLongVariableName @@ -137,7 +137,9 @@ if anotherVeryLongVariableName } ``` -Then, how should we indent this when the cursor is before `@`? +That is, we have to indent the closing brace with offset if it is a part of expressions while it should be aligned with the beginning of the statement/declaration if it is a part of a statement/declaration. + +Then, how should we indent the following code when the cursor is before `@`? ```swift var x = foo @@ -153,6 +155,7 @@ var x = foo aaa } } +// property declaration ``` or ```swift @@ -161,6 +164,7 @@ var x = foo @abc var x = 1 x } +// property initialization ``` Both are syntactically correct code. We cannot handle this case properly. This is also a future work. @@ -177,9 +181,9 @@ For other commands, run `make help`. ## Related projects -- [Official swift-mode.el by Apple](https://github.com/apple/swift/blob/master/utils/swift-mode.el) Seems still in very early stage for now. We cannot contribute to it due to the license incompatibility. -- [company-sourcekit](https://github.com/nathankot/company-sourcekit) Completion for Swift projects via SourceKit with the help of SourceKitten. -- [flycheck-swift](https://github.com/swift-emacs/flycheck-swift) Flycheck extensions for Swift. +- [Official swift-mode.el by Apple](https://github.com/apple/swift/blob/master/utils/swift-mode.el): Seems still in very early stage for now. We cannot contribute to it due to the license incompatibility. +- [company-sourcekit](https://github.com/nathankot/company-sourcekit): Completion for Swift projects via SourceKit with the help of SourceKitten. +- [flycheck-swift](https://github.com/swift-emacs/flycheck-swift): Flycheck extensions for Swift. ## Contributing diff --git a/doc/string.png b/doc/string.png new file mode 100644 index 0000000..8da630f Binary files /dev/null and b/doc/string.png differ diff --git a/doc/string.svg b/doc/string.svg new file mode 100644 index 0000000..3810366 --- /dev/null +++ b/doc/string.svg @@ -0,0 +1,237 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="584" + height="144" + viewBox="0 0 584 144.00001" + version="1.1" + id="svg8" + inkscape:version="0.92.0 r15299" + sodipodi:docname="string.svg" + inkscape:export-filename="string.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + <defs + id="defs2"> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="marker6705" + style="overflow:visible" + inkscape:isstock="true"> + <path + inkscape:connector-curvature="0" + id="path6703" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.4,0,0,-0.4,-4,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker13385" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path13383" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="marker5763" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path5761" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.4,0,0,-0.4,-4,0)" + inkscape:connector-curvature="0" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1" + inkscape:cx="538.71168" + inkscape:cy="40.729919" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:window-width="2152" + inkscape:window-height="1924" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true"> + <inkscape:grid + type="xygrid" + id="grid4485" + empspacing="8" + empcolor="#0000ff" + empopacity="0.1254902" + color="#0000ff" + opacity="0.0627451" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="レイヤー 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-978.51965)"> + <rect + style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="rect13915" + width="584" + height="144" + x="0" + y="978.51965" /> + <text + id="text4606" + y="1075.9337" + x="19.000004" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;str [...] + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4604" + y="1075.9337" + x="19.000004" + sodipodi:role="line">"The quick brown \(<tspan + id="tspan4628" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000">fox()<tspan + id="tspan4594" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1">) jumps over the lazy \(</tspan>dog()</tspan>)"</tspan></text> + <path + sodipodi:nodetypes="cccccccc" + inkscape:connector-curvature="0" + d="m 200,1084.5197 c 0,4.4183 -3.58172,8 -8,8 h -80.00005 c -4.41828,0 -7.99995,3.5817 -7.99995,8 m -88.00005,-16 c 0,4.4183 3.581754,8 8.000054,8 H 96 c 4.4182,0 8,3.5817 8,8" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="path4633" /> + <text + id="text4637" + y="1116.4796" + x="70.353432" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1116.4796" + x="70.353432" + id="tspan4635" + sodipodi:role="line">string chunk</tspan></text> + <path + id="path4639" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + d="m 248,1056.3897 c 0,-4.4183 -3.58172,-8 -8,-8 h -8.00005 c -4.41828,0 -7.99995,-3.5818 -7.99995,-8 m -24.00005,16 c 0,-4.4183 3.58175,-8 8.00005,-8 h 8 c 4.4182,0 8,-3.5818 8,-8" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="168.87584" + y="1032.2296" + id="text4643"><tspan + sodipodi:role="line" + id="tspan4641" + x="168.87584" + y="1032.2296">interpolated expression</tspan></text> + <path + id="path4645" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + d="m 480,1084.5197 c 0,4.4183 -3.58172,8 -8,8 h -96.00005 c -4.41828,0 -7.99995,3.5817 -7.99995,8 m -120.00005,-16 c 0,4.4183 3.58175,8 8.00005,8 h 104 c 4.4182,0 8,3.5817 8,8" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> + <path + sodipodi:nodetypes="cccccccc" + inkscape:connector-curvature="0" + d="m 528,1056.3897 c 0,-4.4183 -3.58172,-8 -8,-8 h -8.00005 c -4.41828,0 -7.99995,-3.5818 -7.99995,-8 m -24,16 c 0,-4.4183 3.58175,-8 8.00005,-8 h 6.00005 c 4.4182,0 9.9999,-3.5818 9.9999,-8" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="path4647" /> + <path + sodipodi:nodetypes="ccccccc" + inkscape:connector-curvature="0" + d="m 559.99995,1084.5197 c 0,4.4183 -3.58172,8 -8,8 v 0 c -4.41828,0 -7.99995,3.5817 -7.99995,8 m -14.00005,-16 c 0,4.4183 3.58175,8 8,8 4.41825,0 6.00005,3.5817 6.00005,8" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="path4649" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="335.02167" + y="1116.4796" + id="text4653"><tspan + sodipodi:role="line" + id="tspan4651" + x="335.02167" + y="1116.4796">string chunk</tspan></text> + <text + id="text4657" + y="1114.0197" + x="516.02167" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1114.0197" + x="516.02167" + id="tspan4655" + sodipodi:role="line">string chunk</tspan></text> + <text + id="text4661" + y="1032.2296" + x="449.87582" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1032.2296" + x="449.87582" + id="tspan4659" + sodipodi:role="line">interpolated expression</tspan></text> + <path + id="path9031" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + d="m 560,1021.3897 c 0,-4.4183 -3.58172,-8 -8,-8 H 295.99995 c -4.41828,0 -7.99995,-3.5818 -7.99995,-8 m -272.00005,16 c 0,-4.4183 3.581754,-8 8.000054,-8 H 280 c 4.4182,0 8,-3.5818 8,-8" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> + <text + id="text9035" + y="997.76978" + x="224.0453" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="997.76978" + x="224.0453" + id="tspan9033" + sodipodi:role="line">interpolated string</tspan></text> + </g> +</svg> diff --git a/doc/string_properties.png b/doc/string_properties.png new file mode 100644 index 0000000..e0faf35 Binary files /dev/null and b/doc/string_properties.png differ diff --git a/doc/string_properties.svg b/doc/string_properties.svg new file mode 100644 index 0000000..ea77c63 --- /dev/null +++ b/doc/string_properties.svg @@ -0,0 +1,617 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="510" + height="320" + viewBox="0 0 510 320.00002" + version="1.1" + id="svg8" + inkscape:version="0.92.0 r15299" + sodipodi:docname="string_properties.svg" + inkscape:export-filename="string_properties.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + <defs + id="defs2"> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker5494" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path5492" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker4802" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path4800" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="marker4730" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + inkscape:connector-curvature="0" + id="path4728" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.4,0,0,-0.4,-4,0)" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker13385" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:collect="always"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path13383" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:isstock="true" + style="overflow:visible" + id="marker11187" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path11185" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="marker8131" + style="overflow:visible" + inkscape:isstock="true" + inkscape:collect="always"> + <path + id="path8129" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#ff8000;fill-opacity:1;fill-rule:evenodd;stroke:#ff8000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.4,0,0,-0.4,-4,0)" + inkscape:connector-curvature="0" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="marker5763" + style="overflow:visible" + inkscape:isstock="true"> + <path + id="path5761" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.4,0,0,-0.4,-4,0)" + inkscape:connector-curvature="0" /> + </marker> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2" + inkscape:cx="247.2539" + inkscape:cy="118.79165" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:window-width="2152" + inkscape:window-height="1924" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:snap-bbox="true" + inkscape:bbox-paths="true" + inkscape:bbox-nodes="true"> + <inkscape:grid + type="xygrid" + id="grid4485" + empspacing="8" + empcolor="#0000ff" + empopacity="0.1254902" + color="#0000ff" + opacity="0.0627451" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="レイヤー 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-802.51965)"> + <rect + style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="rect13915" + width="510" + height="320" + x="0" + y="802.51965" /> + <text + id="text4606" + y="1216.7039" + x="83.000053" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;str [...] + xml:space="preserve"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4604" + y="1216.7039" + x="83.000053" + sodipodi:role="line">"The quick brown \(<tspan + id="tspan4628" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000">fox()<tspan + id="tspan4594" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1">) jumps over the lazy \(</tspan>dog()</tspan>)"</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 88.000054,1253.0397 v -40" + id="path4663" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="9.9245806" + y="1261.2197" + id="text5333"><tspan + sodipodi:role="line" + id="tspan5331" + x="9.9245806" + y="1261.2197">property: syntax-table (15) (generic string delimiters)</tspan></text> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path5335" + d="m 232.00005,1253.0397 83,-32" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 216.00005,1253.0397 43,-32" + id="path5759" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 552.00005,1253.0397 -10,-32" + id="path6347" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path7013" + d="m 598.00005,1253.0397 v -32" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 608.00005,1253.0397 v -40" + id="path8127" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <text + id="text9029" + y="1261.2197" + x="543.08002" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1261.2197" + x="543.08002" + id="tspan9027" + sodipodi:role="line">property: syntax-table (15) (generic string delimiters)</tspan></text> + <path + id="path9031" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + d="m 616,1194.6866 c 0,-4.4182 -3.58172,-8 -8,-8 H 362.82843 c -4.41828,0 -7.99995,-3.5817 -7.99995,-8 m -272.000053,16 c 0,-4.4182 3.581754,-8 8.000054,-8 H 346.82848 c 4.4182,0 8,-3.5817 8,-8" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cccccccc" /> + <text + id="text9035" + y="1171.0667" + x="290.87378" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1171.0667" + x="290.87378" + id="tspan9033" + sodipodi:role="line">property: syntax-multiline t</tspan></text> + <text + id="text10047" + y="1282.5398" + x="293.1058" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1282.5398" + x="293.1058" + sodipodi:role="line" + id="tspan10169">property: swift-mode:matching-parenthesis</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8131)" + d="m 317.00005,1221.0397 c -29,53 -62,0 -62,0" + id="path10173" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path11183" + d="m 264.00005,1221.0397 c 24,32 51,0 51,0" + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11187)" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path13379" + d="m 598.00005,1221.0397 c -29,53 -62,0 -62,0" + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker13385)" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker11187)" + d="m 545.00005,1221.0397 c 24,32 51,0 51,0" + id="path13381" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 295.00005,1234.0397 25,35" + id="path13903" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 288.00005,1245.0397 24,24" + id="path13905" + inkscape:connector-curvature="0" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path13907" + d="m 560.00005,1234.0397 -72,35" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + <path + inkscape:connector-curvature="0" + id="path13909" + d="m 541.00005,1229.0397 -61,40" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="172.75865" + y="1314.6997" + id="text13913"><tspan + sodipodi:role="line" + id="tspan13911" + x="172.75865" + y="1314.6997">Those properties are put by syntax-propertize-function (swift-mode:syntax-propertize).</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;str [...] + x="197" + y="846.76184" + id="text4615"><tspan + sodipodi:role="line" + x="197" + y="846.76184" + id="tspan4613" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1">"""</tspan><tspan + sodipodi:role="line" + x="197" + y="870.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4617"> The quick brown</tspan><tspan + sodipodi:role="line" + x="197" + y="894.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4621"> \(<tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4611"></tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="918.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4625"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4627"> fox()<tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4609"></tspan></tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="942.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4630"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4632"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4634"> ) </tspan></tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="966.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4636"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4638"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4640"> jumps over the lazy</tspan></tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="990.76184" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4642"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4644"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4646"> \(</tspan></tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="1014.7618" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4648"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000" + id="tspan4650"> dog()</tspan></tspan><tspan + sodipodi:role="line" + x="197" + y="1038.7618" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4652"> )</tspan><tspan + sodipodi:role="line" + x="197" + y="1062.7618" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:24px;font-family:'DejaVu Sans Mono';-inkscape-font-specification:'DejaVu Sans Mono, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#8b2252;fill-opacity:1" + id="tspan4654"> """</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="420.69" + y="946.47968" + id="text4658"><tspan + sodipodi:role="line" + id="tspan4656" + x="420.69" + y="946.47968">syntax-multiline t</tspan></text> + <text + id="text4662" + y="816.01965" + x="132.69" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="816.01965" + x="132.69" + id="tspan4660" + sodipodi:role="line">syntax-table (15) (generic string delimiters)</tspan></text> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4664" + d="m 202,834.51965 v -16" + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="200.85812" + y="1082.6997" + id="text4668"><tspan + sodipodi:role="line" + id="tspan4666" + x="200.85812" + y="1082.6997">syntax-table (15)</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 240,1074.5197 v -16" + id="path4670" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="256.85812" + y="890.69965" + id="text4674"><tspan + sodipodi:role="line" + id="tspan4672" + x="256.85812" + y="890.69965">syntax-table (15)</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 232,890.51965 h 21" + id="path4676" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4678" + d="m 223,938.51965 h 30.00001" + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 232,986.51965 h 21" + id="path4680" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-curvature="0" + id="path4682" + d="m 223,1034.5197 h 30.00001" + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + id="text4686" + y="938.69965" + x="256.85812" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="938.69965" + x="256.85812" + id="tspan4684" + sodipodi:role="line">syntax-table (15)</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="256.85812" + y="986.69965" + id="text4690"><tspan + sodipodi:role="line" + id="tspan4688" + x="256.85812" + y="986.69965">syntax-table (15)</tspan></text> + <text + id="text4694" + y="1034.6997" + x="256.85812" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1034.6997" + x="256.85812" + id="tspan4692" + sodipodi:role="line">syntax-table (15)</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4730)" + d="m 230,994.51965 -8,28.99995" + id="path4696" + inkscape:connector-curvature="0" /> + <path + inkscape:connector-curvature="0" + id="path4798" + d="m 220,1024.0608 0.22166,-30.08235" + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4802)" /> + <path + inkscape:connector-curvature="0" + id="path5488" + d="m 230,899.51965 -8,29" + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5494)" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#ff8000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4802)" + d="m 220,929.06085 0.22166,-30.0824" + id="path5490" + inkscape:connector-curvature="0" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:12px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + x="12.760468" + y="996.01965" + id="text5990"><tspan + id="tspan5988" + sodipodi:role="line" + x="12.760468" + y="996.01965" + style="line-height:12px;fill:#0080ff;fill-opacity:1">swift-mode:matching-parenthesis</tspan><tspan + sodipodi:role="line" + x="12.760468" + y="1008.0197" + id="tspan6000" + style="line-height:12px;fill:#0080ff;fill-opacity:1">(location of the matching parenthesis)</tspan></text> + <path + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 189,1002.5196 31,1" + id="path5996" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 189,1002.5196 37,6" + id="path5998" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <text + id="text6016" + y="900.01965" + x="12.760468" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:12px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#0080ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + style="line-height:12px;fill:#0080ff;fill-opacity:1" + y="900.01965" + x="12.760468" + sodipodi:role="line" + id="tspan6012">swift-mode:matching-parenthesis</tspan><tspan + style="line-height:12px;fill:#0080ff;fill-opacity:1" + id="tspan6014" + y="912.01965" + x="12.760468" + sodipodi:role="line">(location of the matching parenthesis)</tspan></text> + <path + inkscape:connector-curvature="0" + id="path6018" + d="m 189,906.51965 31,0.99997" + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + <path + inkscape:connector-curvature="0" + id="path6020" + d="m 189,906.51965 37,5.99997" + style="fill:none;fill-rule:evenodd;stroke:#0080ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cccccccc" + inkscape:connector-curvature="0" + d="m 397,834.51965 c 4.41828,0 8,3.58172 8,8 v 96.00005 c 0,4.41828 3.58173,7.99995 8,7.99995 m -16,112.00005 c 4.41828,0 8,-3.5817 8,-8 v -96.00005 c 0,-4.4182 3.58173,-8 8,-8" + style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#0080ff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" + id="path6022" /> + <text + id="text6026" + y="1114.6997" + x="68.690002" + style="font-style:normal;font-weight:normal;font-size:10px;line-height:25px;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve"><tspan + y="1114.6997" + x="68.690002" + id="tspan6024" + sodipodi:role="line">Those properties are put by syntax-propertize-function (swift-mode:syntax-propertize).</tspan></text> + </g> +</svg> diff --git a/swift-mode-indent.el b/swift-mode-indent.el index 937e10e..0a50bc7 100644 --- a/swift-mode-indent.el +++ b/swift-mode-indent.el @@ -103,7 +103,7 @@ Intended for debugging." (defconst swift-mode:expression-parent-tokens (append swift-mode:statement-parent-tokens '(\, < supertype-: "where" "if" "guard" "while" "for" "catch" - string-chunk-before-interpolation)) + string-chunk-before-interpolated-expression)) "Parent tokens for expressions.") (defvar-local swift-mode:anchor-overlay nil) @@ -201,7 +201,7 @@ declaration and its offset is `swift-mode:basic-offset'." swift-mode:multiline-statement-offset)) (forward-line 0) (backward-char) - (swift-mode:goto-non-string-interpolation-bol) + (swift-mode:goto-non-interpolated-expression-bol) (back-to-indentation) (if (<= (point) string-beginning-position) ;; The cursor was on the 2nd line of the comment, so aligns with @@ -217,8 +217,8 @@ declaration and its offset is `swift-mode:basic-offset'." (swift-mode:calculate-indent-of-multiline-string) (swift-mode:indentation (point) 0)))))) -(defun swift-mode:goto-non-string-interpolation-bol () - "Back to the beginning of line that is not inside a string interpolation." +(defun swift-mode:goto-non-interpolated-expression-bol () + "Back to the beginning of line that is not inside a interpolated expression." (let ((string-beginning-position (nth 8 (syntax-ppss))) (matching-parenthesis t)) (while (and matching-parenthesis @@ -240,37 +240,37 @@ declaration and its offset is `swift-mode:basic-offset'." (next-token (save-excursion (swift-mode:forward-token))) (next-type (swift-mode:token:type next-token)) (next-text (swift-mode:token:text next-token)) - (next-is-on-same-line + (next-is-on-current-line (<= (swift-mode:token:start next-token) (line-end-position)))) (cond ;; Beginning of the buffer ((eq previous-type 'outside-of-buffer) (swift-mode:indentation (point-min) 0)) - ;; Before } on the same line - ((and next-is-on-same-line (eq next-type '})) + ;; Before } on the current line + ((and next-is-on-current-line (eq next-type '})) (goto-char (swift-mode:token:end next-token)) (backward-list) (swift-mode:calculate-indent-after-open-curly-brace 0)) - ;; Before ) or ] on the same line - ((and next-is-on-same-line (memq next-type '(\) \]))) + ;; Before ) or ] on the current line + ((and next-is-on-current-line (memq next-type '(\) \]))) (goto-char (swift-mode:token:end next-token)) (backward-list) (swift-mode:calculate-indent-of-expression 0)) - ;; Before end of a string interpolation on the same line - ((and next-is-on-same-line - (eq next-type 'string-chunk-after-interpolation)) + ;; Before end of a interpolated expression on the current line + ((and next-is-on-current-line + (eq next-type 'string-chunk-after-interpolated-expression)) (goto-char (get-text-property (swift-mode:token:start next-token) 'swift-mode:matching-parenthesis)) (forward-char 2) (swift-mode:backward-string-chunk) - (swift-mode:calculate-indent-after-beginning-of-string-interpolation 0)) + (swift-mode:calculate-indent-after-beginning-of-interpolated-expression 0)) - ;; Before , on the same line - ((and next-is-on-same-line (eq next-type '\,)) + ;; Before , on the current line + ((and next-is-on-current-line (eq next-type '\,)) (swift-mode:calculate-indent-of-prefix-comma)) ;; After , @@ -278,9 +278,9 @@ declaration and its offset is `swift-mode:basic-offset'." (goto-char (swift-mode:token:start previous-token)) (swift-mode:calculate-indent-after-comma)) - ;; Before "case" or "default" on the same line, for switch statement + ;; Before "case" or "default" on the current line, for switch statement ((and - next-is-on-same-line + next-is-on-current-line (member next-text '("case" "default")) (save-excursion (let ((head @@ -374,14 +374,14 @@ declaration and its offset is `swift-mode:basic-offset'." swift-mode:parenthesized-expression-offset swift-mode:parenthesized-expression-offset)) - ;; After beginning of a string interpolation - ((eq previous-type 'string-chunk-before-interpolation) + ;; After beginning of a interpolated expression + ((eq previous-type 'string-chunk-before-interpolated-expression) (goto-char (swift-mode:token:start previous-token)) - (swift-mode:calculate-indent-after-beginning-of-string-interpolation + (swift-mode:calculate-indent-after-beginning-of-interpolated-expression swift-mode:parenthesized-expression-offset)) - ;; Before "in" on the same line - ((and next-is-on-same-line (equal next-text "in")) + ;; Before "in" on the current line + ((and next-is-on-current-line (equal next-text "in")) ;; When it is for-in statement, align with the token after "for": ;; ;; for @@ -420,8 +420,8 @@ declaration and its offset is `swift-mode:basic-offset'." ;; } (swift-mode:find-and-align-with-parents '("for" {))) - ;; Before "where" on the same line - ((and next-is-on-same-line (equal next-text "where")) + ;; Before "where" on the current line + ((and next-is-on-current-line (equal next-text "where")) ;; switch { ;; case let P(x) ;; where // Aligns with the pattern. @@ -625,8 +625,8 @@ declaration and its offset is `swift-mode:basic-offset'." swift-mode:statement-parent-tokens (- swift-mode:basic-offset swift-mode:switch-case-offset))) - ;; Before ; on the same line - ((and next-is-on-same-line (eq next-type '\;)) + ;; Before ; on the current line + ((and next-is-on-current-line (eq next-type '\;)) (swift-mode:find-and-align-with-parents (remove '\; (remove 'implicit-\; swift-mode:statement-parent-tokens)) 0 @@ -1185,9 +1185,10 @@ comma at eol." (t parent)))) -(defun swift-mode:calculate-indent-after-beginning-of-string-interpolation +(defun swift-mode:calculate-indent-after-beginning-of-interpolated-expression (offset) - "Return indentation with OFFSET after the beginning of a string interpolation. + "Return indentation after the beginning of a interpolated expression. +It has offset specified with OFFSET. Assuming the cursor is before the string chunk." (let ((pos (point))) diff --git a/swift-mode-lexer.el b/swift-mode-lexer.el index a3b0369..845efef 100644 --- a/swift-mode-lexer.el +++ b/swift-mode-lexer.el @@ -39,6 +39,29 @@ ;;; Code: +;; Terminology: +;; (See also docs/string.png) +;; +;; Interpolated string: +;; A string containing expressions to be evaluated and inserted into the +;; string at run time. +;; Example: "1 + 1 = \(1 + 1)" is evaluated to "1 + 1 = 2" at run time. +;; https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html +;; https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html +;; +;; Interpolated expression: +;; An expression between \( and ) inside a string. +;; Suppose a string "aaa\( foo() )bbb\( bar() )ccc", +;; `foo()' and `bar()' are interpolated expression. +;; https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html +;; Why not interpolating expression? +;; +;; String chunk: +;; A part of single-line/multiline string delimited with quotation marks +;; or interpolated expressions. +;; Suppose a string "aaa\( foo() )bbb\( bar() )ccc", +;; "aaa\(, )bbb\(, and )ccc" are string chunks. + (declare-function swift-mode:backward-sexps-until "swift-mode-indent.el" (token-types &optional @@ -92,8 +115,8 @@ END is the point after the token." ;; - case-: (colon for case or default label) ;; - : (part of conditional operator, key-value separator, label-statement separator) ;; - anonymous-function-parameter-in ("in" after anonymous function parameter) -;; - string-chunk-after-interpolation (part of a string ending with ")") -;; - string-chunk-before-interpolation (part of a string ending with "\\(") +;; - string-chunk-after-interpolated-expression (part of a string ending with ")") +;; - string-chunk-before-interpolated-expression (part of a string ending with "\\(") ;; - outside-of-buffer ;; ;; Additionaly, `swift-mode:backward-token-or-list' may return a parenthesized @@ -154,17 +177,37 @@ END is the point after the token." table)) +;;; Text properties + +;; (See also docs/string_properties.png) +;; +;; Some properties are put by `syntax-propertize-function', that is +;; `swift-mode:syntax-propertize'. +;; +;; The beginning of and end of strings are marked with text property +;; '(syntax-table (15)), which indicates generic string delimiters. Both +;; single-line strings and multiline strings are marked with it. The +;; parentheses surrounding interpolated expressions are also marked with +;; '(syntax-table (15)). The property helps font-lock and the tokenizer to +;; recognize strings. +;; +;; The entire string, including interpolated expressions, are marked with text +;; property '(syntax-multiline t). The property is used by +;; `swift-mode:syntax-propertize-extend-region' to avoid scanning from the +;; middle of strings. +;; +;; The parentheses surrounding interpolated expressions have text property +;; '(swift-mode:matching-parenthesis POS), where POS is the position of the +;; matching parenthesis. Strictly speaking, the POS on the closing parenthesis +;; refers to the backslash before the opening parenthesis. The property speeds +;; up the indentation logic. + (defun swift-mode:syntax-propertize-extend-region (start end) "Return region to be propertized. The returned region contains the region (START . END). If the region is not modified, return nil. Intended for `syntax-propertize-extend-region-functions'." - (when (get-text-property (max (point-min) (1- start)) 'swift-mode:string) - (cons (or (previous-single-property-change - (max (point-min) (1- start)) - 'swift-mode:string) - (point-min)) - end))) + (syntax-propertize-multiline start end)) (defun swift-mode:syntax-propertize (start end) "Update text properties for strings. @@ -174,7 +217,7 @@ Intended for `syntax-propertize-function'." (remove-text-properties start end '(syntax-table nil - swift-mode:string + syntax-multiline nil swift-mode:matching-parenthesis nil)) @@ -215,7 +258,7 @@ stops where the level becomes zero." (string-to-syntax "|")) (let ((start (match-beginning 0))) (swift-mode:syntax-propertize:end-of-multiline-string end) - (put-text-property start (point) 'swift-mode:string t))) + (put-text-property start (point) 'syntax-multiline t))) ((equal "\"" (match-string-no-properties 0)) (put-text-property (match-beginning 0) (1+ (match-beginning 0)) @@ -223,7 +266,7 @@ stops where the level becomes zero." (string-to-syntax "|")) (let ((start (match-beginning 0))) (swift-mode:syntax-propertize:end-of-single-line-string end) - (put-text-property start (point) 'swift-mode:string t))) + (put-text-property start (point) 'syntax-multiline t))) ((equal "//" (match-string-no-properties 0)) (goto-char (match-beginning 0)) @@ -273,7 +316,7 @@ The string should be terminated with QUOTATION." (string-to-syntax "|"))) ((and (equal "(" (match-string-no-properties 0)) (swift-mode:escaped-p (match-beginning 0))) - ;; Found string interpolation. Skips the expression. + ;; Found an interpolated expression. Skips the expression. ;; We cannot use `scan-sexps' because multiline strings are not yet ;; propertized. (let ((start (- (point) 2))) @@ -284,7 +327,7 @@ The string should be terminated with QUOTATION." 'syntax-table (string-to-syntax "|")) (when (swift-mode:syntax-propertize:scan end 1) - ;; Found matching parenthesis. Going further. + ;; Found the matching parenthesis. Going further. (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax "|")) @@ -536,10 +579,10 @@ Return nil otherwise." ;; ) ((eq (swift-mode:token:type next-token) '\() t) - ;; Suppress implicit semicolon after the beginning of a string - ;; interpolation. + ;; Suppress implicit semicolon after the beginning of an interpolated + ;; expression. ((eq (swift-mode:token:type previous-token) - 'string-chunk-before-interpolation) + 'string-chunk-before-interpolated-expression) nil) ;; Otherwise, inserts implicit semicolon. @@ -603,10 +646,11 @@ Return nil otherwise." ;; switch foo { ;; case let x where x is Foo ? ;; a : // This function should return nil but it - ;; // actually retuns t. + ;; // actually retuns t. ;; b: // This function should return t but it ;; // actually return nil. - ;; let y = a ? b : c // This function returns nil correctly for this. + ;; let y = a ? b : c // This function returns nil correctly for + ;; // this. ;; } ;; FIXME: mutual dependency @@ -750,14 +794,14 @@ This function does not return `implicit-;' or `type-:'." ((eobp) (swift-mode:token 'outside-of-buffer "" (point) (point))) - ;; End of string interpolation + ;; End of interpolated expression ((and (eq (char-after) ?\)) (equal (get-text-property (point) 'syntax-table) (string-to-syntax "|"))) (let ((pos-after-comment (point))) (swift-mode:forward-string-chunk) (swift-mode:token - 'string-chunk-after-interpolation + 'string-chunk-after-interpolated-expression (buffer-substring-no-properties pos-after-comment (point)) pos-after-comment (point)))) @@ -961,14 +1005,14 @@ This function does not return `implicit-;' or `type-:'." ((bobp) (swift-mode:token 'outside-of-buffer "" (point) (point))) - ;; Beginning of string interpolation + ;; Beginning of interpolated expression ((and (eq (char-before) ?\() (equal (get-text-property (1- (point)) 'syntax-table) (string-to-syntax "|"))) (let ((pos-before-comment (point))) (swift-mode:backward-string-chunk) (swift-mode:token - 'string-chunk-before-interpolation + 'string-chunk-before-interpolated-expression (buffer-substring-no-properties (point) pos-before-comment) (point) pos-before-comment))) @@ -1130,7 +1174,7 @@ This function does not return `implicit-;' or `type-:'." (defun swift-mode:forward-string-chunk () "Skip forward a string chunk. A string chunk is a part of single-line/multiline string delimited with -quotation marks or string interpolations." +quotation marks or interpolated expressions." (condition-case nil (goto-char (scan-sexps (point) 1)) (scan-error (goto-char (point-max))))) @@ -1138,7 +1182,7 @@ quotation marks or string interpolations." (defun swift-mode:backward-string-chunk () "Skip backward a string chunk. A string chunk is a part of single-line/multiline string delimited with -quotation marks or string interpolations." +quotation marks or interpolated expressions." (condition-case nil (goto-char (scan-sexps (point) -1)) (scan-error (goto-char (point-min)))))