[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/swift-mode 9471669 304/496: Merge taku0/swift3-mode
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/swift-mode 9471669 304/496: Merge taku0/swift3-mode |
Date: |
Sun, 29 Aug 2021 11:33:56 -0400 (EDT) |
branch: elpa/swift-mode
commit 9471669b0bc5a72236b434f66a4c6782d807afea
Author: taku0 <mxxouy6x3m_github@tatapa.org>
Commit: taku0 <mxxouy6x3m_github@tatapa.org>
Merge taku0/swift3-mode
---
.gitignore | 4 +-
Cask | 10 +-
Makefile | 102 +-
README.md | 238 ++--
swift-mode-beginning-of-defun.el | 152 +++
swift-mode-font-lock.el | 232 ++++
swift-mode-indent.el | 1475 ++++++++++++++++++++++
swift-mode-lexer.el | 883 ++++++++++++++
swift-mode-repl.el | 108 ++
swift-mode.el | 860 ++-----------
test/font-lock-tests.el | 212 ----
test/indentation-tests.el | 2280 -----------------------------------
test/swift-files/comment.swift | 35 +
test/swift-files/declarations.swift | 376 ++++++
test/swift-files/expressions.swift | 571 +++++++++
test/swift-files/identifiers.swift | 40 +
test/swift-files/operators.swift | 70 ++
test/swift-files/statements.swift | 805 +++++++++++++
test/swift-files/types.swift | 274 +++++
test/swift-mode-test-indent.el | 164 +++
20 files changed, 5492 insertions(+), 3399 deletions(-)
diff --git a/.gitignore b/.gitignore
index bf0d9e6..f613485 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
+*~
/.cask/
*.elc
-/swift-mode.elc
/dist/
+swift-mode-autoloads.el
+swift-mode-pkg.el
diff --git a/Cask b/Cask
index 01fa162..9960ec2 100644
--- a/Cask
+++ b/Cask
@@ -1,12 +1,4 @@
-(source melpa)
(source gnu)
-(source org)
+(source melpa)
(package-file "swift-mode.el")
-
-(development
- (depends-on "s")
- (depends-on "dash")
- (depends-on "cl-lib")
- (depends-on "flycheck")
- (depends-on "flycheck-cask"))
diff --git a/Makefile b/Makefile
index c0c02fb..9086362 100644
--- a/Makefile
+++ b/Makefile
@@ -1,56 +1,56 @@
-CWD = $(shell pwd)
-DIST = $(CWD)/dist
-CASK ?= cask
-EMACS ?= emacs
-EMACSFLAGS = --batch -Q
-VERSION := $(shell EMACS=$(EMACS) $(CASK) version)
-PKG_DIR := $(shell EMACS=$(EMACS) $(CASK) package-directory)
-USER_EMACS_D = ~/.emacs.d
-USER_ELPA_D = $(USER_EMACS_D)/elpa
-
-SRCS = $(filter-out %-pkg.el, $(wildcard *.el))
-TESTS = $(filter-out %-pkg.el, $(wildcard test/*.el))
-EL = $(DIST)/swift-mode-$(VERSION).el
-
-.PHONY: all
-all : deps $(DIST)
-
-.PHONY: deps
-deps : $(PKG_DIR)
-$(PKG_DIR) :
+CASK ?= cask
+EMACS ?= emacs
+VERSION := $(shell EMACS=$(EMACS) $(CASK) version)
+PKG_DIR := $(shell EMACS=$(EMACS) $(CASK) package-directory)
+
+SRC = $(wildcard *.el)
+PACKAGE = dist/swift-mode-$(VERSION).tar
+
+.PHONY: help all deps package install test clean
+
+help:
+## Shows this message.
+# Process this Makefile with following filters
+#
+# - Remove empty line.
+# - Remove lien containing ## no-doc.
+# - Remove after colon if the line is not a comment line.
+# - Replace /^## / to " ".
+# - Remove other comment lines.
+# - Insert newline before rules.
+ @sed -e '/^\s*$$/d; /^[ .A-Z]/d; /## no-doc/d; s/^\([^#][^:]*\):.*/\1/;
s/^## / /; /^#/d; s/^[^ ]/\n&/' Makefile
+
+all: package
+## Builds the package.
+
+$(PKG_DIR): ## no-doc
$(CASK) install
-.PHONY: check
-check : deps
- $(CASK) exec $(EMACS) $(EMACSFLAGS) \
- $(patsubst %,-l % , $(SRCS))\
- $(patsubst %,-l % , $(TESTS))\
- -f ert-run-tests-batch-and-exit
+deps: $(PKG_DIR)
+## Installs the dependencies.
-.PHONY: install
-install : $(DIST) $(USER_ELPA_D)
- $(EMACS) $(EMACSFLAGS) -l package \
- -f package-initialize --eval '(package-install-file "$(EL)")'
-
-.PHONY: uninstall
-uninstall :
- rm -rf $(USER_ELPA_D)/swift-mode-*
-
-.PHONY: reinstall
-reinstall : clean uninstall install
-
-.PHONY: clean-all
-clean-all : clean
- rm -rf $(PKG_DIR)
-
-.PHONY: clean
-clean :
- $(CASK) clean-elc
- rm -f *.elc
- rm -rf $(DIST)
-
-$(DIST) :
+$(PACKAGE): $(SRC) deps ## no-doc
+ rm -rf dist
$(CASK) package
-$(USER_ELPA_D) :
- mkdir -p $(USER_ELPA_D)
+package: $(PACKAGE)
+## Builds the package.
+
+install: package
+## Installs the package.
+ $(CASK) exec $(EMACS) --batch \
+ -l package \
+ -f package-initialize \
+ --eval '(package-install-file "$(PACKAGE)")'
+
+clean:
+## Cleans the dist directory.
+ rm -rf dist
+
+check: deps
+## Tests the package.
+ $(CASK) exec $(EMACS) --batch -q \
+ --eval "(add-to-list 'load-path \""$(shell realpath .)"\")" \
+ -l swift-mode.el \
+ -l test/swift-mode-test-indent.el \
+ -f swift-mode:run-test:indent
diff --git a/README.md b/README.md
index a195d73..aadda12 100644
--- a/README.md
+++ b/README.md
@@ -1,107 +1,193 @@
[![License GPL 3][badge-license]][copying]
[![Build Status][badge-travis]][travis]
[![MELPA](https://melpa.org/packages/swift-mode-badge.svg)](https://melpa.org/#/swift-mode)
-[![MELPA
stable](https://stable.melpa.org/packages/swift-mode-badge.svg)](https://stable.melpa.org/#/swift-mode)
+[![MELPA](https://stable.melpa.org/packages/swift-mode-badge.svg)](https://melpa.org/#/swift-mode)
# swift-mode
-## Summary
-
-Major-mode for Apple's [Swift programming language][swift]. Provides:
-
-- syntax highlighting
-- indentation
-- code navigation with [imenu][]
-- automatic syntax checking with [flycheck][] (disabled by default)
-
-This is currently at an early stage of development and there's plenty of work
to
-do. Check the issue tracker.
-
-A new [swift3-mode](https://github.com/taku0/swift3-mode) is
-under development. It will be merged into `swift-mode` in the near future.
-
-Requires Emacs 24.4 or later.
-
-## Installing
-
-`swift-mode` can be installed using Emacs' built-in package manager or from
-source. You can also install [flycheck][] if you want syntax checking.
-
-### package.el
-
-#### MELPA
+Major-mode for Apple's [Swift programming
language](https://developer.apple.com/swift/).
+
+## Installation
+
+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`.
+
+## Features
+
+- Font Lock
+- Indentation
+
+ ```swift
+ switch foo {
+ case let .P1(x)
+ where
+ x > 0,
+ let .P2(x)
+ where
+ x > 0:
+ bar()
+ .then { x in
+ return baz(x)
+ }
+ .then {(
+ x,
+ y
+ ) in
+ return moo(x + y)
+ }
+ }
+
+ // Hanging brace
+ let x = [
+ 1,
+ 2,
+ 3
+ ]
+
+ // Brace on its own line
+ let y =
+ [
+ 1,
+ 2,
+ 3
+ ]
+
+ // Utrecht style
+ let z =
+ [ 1
+ , 2
+ , 3
+ ]
+ ```
+- `forward-sexp`
+- `beginning-of-defun` and `end-of-defun`
+- `indent-new-comment-line`
+- [Imenu](https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html)
+- Running Swift REPL in a buffer (`M-x run-swift`)
+
+This package does not provide flycheck. See
[flycheck-swift](https://github.com/swift-emacs/flycheck-swift).
+
+## Limitations
+
+Some syntax constructs removed from Swift 3.0 are not supported:
+
+- C-style for-loop: `for var i = 1; i < 10; i++ { }`
+- Multiple assignments in single `if let`:
+ ```swift
+ if let x = x,
+ y = y {
+ }
+ ```
+
+ Use multiple `let` instead:
+ ```swift
+ if let x = x,
+ let y = y {
+ }
+ ```
+
+Indentation may not accurate. For example, `foo(Bar < A, B > (c))` is
ambiguous. It is indented like either
+```swift
+foo(Bar < A,
+ B > (c)) // Passing two Boolean arguments to foo
+```
+or
+```swift
+foo(Bar < A,
+ B > (c)) // constructing Bar with two type arguments and a value
+```
+The Swift compiler disambiguates this case using tokens after `>`, but those
tokens may not available in editing time. We use some heuristic for this.
-You can install a snapshot version of `swift-mode` from the [MELPA][]
-repository. The version of `swift-mode` there will always be up-to-date, but it
-might be unstable (albeit rarely).
+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.
-You can add MELPA to the list of `package.el` repositories like this:
+```swift
+switch foo {
+ case let P(x) where x is Foo? ? a ? b : c ?? d : e ? f : g :
+ h ? i?.j() : k()
+}
-```el
-(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
+switch foo {
+ case let P(x) where (x is Foo?) ? (a ? b : c ?? d) : (e ? f : g) :
+ h ? i?.j() : k()
+}
```
-#### MELPA Stable
-
-You can install the last stable version of `swift-mode` from the
-[MELPA Stable][] repository.
+Yet another difficult case is consistency of blocks. We want to indent method
chains like this:
+```swift
+var x = foo
+ .then { x in
+ aaa
+ }
+ .then { x in
+ aaa
+ }
+```
-You can add MELPA Stable to the list of `package.el` repositories like this:
+while we also want to indent if body like this:
-```el
-(add-to-list 'package-archives '("melpa-stable" .
"https://stable.melpa.org/packages/"))
+```swift
+if anotherVeryLongVariableName
+ .veryLongPropertyName {
+ aaa
+}
```
-***
-
-The package installation is as easy as:
+Then, how should we indent this when the cursor is before `@`?
+```swift
+var x = foo
+ .bar {
+ @
```
-M-x package-install swift-mode
-```
-
-If you'd like to get on-the-fly syntax checking you should install
-[flycheck][] as well:
+This could be
+```swift
+var x = foo
+ .bar {
+ @abc willSet {
+ aaa
+ }
+}
```
-M-x package-install flycheck
+or
+```swift
+var x = foo
+ .bar {
+ @abc var x = 1
+ x
+ }
```
-And enable `flycheck` checker for `swift`:
+Both are syntactically correct code. We cannot handle this case properly. This
is also a future work.
-```
-(add-to-list 'flycheck-checkers 'swift)
-```
+## Hacking
-### Manual
+To build the package locally, run `make package`. You need
[Cask](https://github.com/cask/cask).
-You will need `make` and [Cask][] to build the project.
+To install the built package, run `make install`.
-```
-cd swift-mode
-make && make install
-```
+To run tests, run `make check`.
-This will install `swift-mode` via `package.el` locally.
+For other commands, run `make help`.
-You can also install `swift-mode` the old-school way by simply dropping it
-somewhere on your `load-path`.
+## Related projects
-```el
-(add-to-list 'load-path "~/emacs.d/vendor")
-(require 'swift-mode)
-```
+- [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
-Yes, please do! See [CONTRIBUTING][] for guidelines.
+Yes, please do! See [CONTRIBUTING](./CONTRIBUTING.md) for guidelines.
## Acknowledgements
-The REPL code is based on [js-comint][].
+The REPL code is based on [js-comint](http://js-comint-el.sourceforge.net/).
-Thanks to the following users for their contributions:
+Thanks to the following original developer and users for their contributions:
+- [@chrisbarrett](https://github.com/chrisbarrett) (Chris Barrett)
- [@ap4y](https://github.com/ap4y) (Arthur Evstifeev)
- [@bbatsov](https://github.com/bbatsov) (Bozhidar Batsov)
- [@ckruse](https://github.com/ckruse) (Christian Kruse)
@@ -110,20 +196,12 @@ Thanks to the following users for their contributions:
You can find a [full list of those people
here](https://github.com/swift-emacs/swift-mode/graphs/contributors).
+Thanks to [@purcell](https://github.com/purcell) (Steve Purcell) for advices
on the code and arrangement for merging `swift3-mode` and `swift-mode`.
+
## License
-See [COPYING][]. Copyright (c) 2014-2016 Chris Barrett, Bozhidar Batsov,
Arthur Evstifeev.
+GPLv3. See [COPYING][] for details. Copyright (C) 2014-2016 taku0, Chris
Barrett, Bozhidar Batsov, Arthur Evstifeev.
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
-[badge-travis]: https://travis-ci.org/swift-emacs/swift-mode.png?branch=master
[travis]: https://travis-ci.org/swift-emacs/swift-mode
-[COPYING]: https://github.com/swift-emacs/swift-mode/blob/master/COPYING
-[CONTRIBUTING]:
https://github.com/swift-emacs/swift-mode/blob/master/CONTRIBUTING.md
-[swift]: https://developer.apple.com/swift/
-[cask]: https://github.com/cask/cask
-[rust-mode]: https://github.com/mozilla/rust/tree/master/src/etc/emacs
-[melpa]: https://melpa.org
-[melpa stable]: https://stable.melpa.org
-[imenu]: http://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html
-[flycheck]: http://flycheck.readthedocs.org/en/latest/
-[js-comint]: http://js-comint-el.sourceforge.net/
+[COPYING]: ./COPYING
diff --git a/swift-mode-beginning-of-defun.el b/swift-mode-beginning-of-defun.el
new file mode 100644
index 0000000..c884361
--- /dev/null
+++ b/swift-mode-beginning-of-defun.el
@@ -0,0 +1,152 @@
+;;; swift-mode-beginning-of-defun.el --- Major-mode for Apple's Swift
programming language, beginning/end-of-defun. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 taku0
+
+;; Authors: taku0 (http://github.com/taku0)
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; beginning-of-defun and end-of-defun
+
+;;; Code:
+
+(require 'swift-mode-lexer)
+(require 'swift-mode-indent)
+
+(defun swift-mode:beginning-of-defun (&optional arg)
+ "Move backward to the beginning of a defun."
+ (interactive)
+ (setq arg (or arg 1))
+ (let (result
+ pos)
+ (if (<= 0 arg)
+ (while (< 0 arg)
+ (setq result (swift-mode:beginning-of-defun-1
+ #'swift-mode:backward-token-or-list))
+ (setq arg (1- arg)))
+ (while (< arg 0)
+ (setq pos (point))
+
+ (swift-mode:beginning-of-statement)
+
+ (when (<= (point) pos)
+ (while (not
+ (memq
+ (swift-mode:token:type (swift-mode:forward-token-or-list))
+ '({} outside-of-buffer)))))
+
+ (setq result (swift-mode:beginning-of-defun-1
+ (lambda ()
+ (prog1 (swift-mode:forward-token-or-list)
+ (forward-comment (point-max))))))
+ (setq arg (1+ arg))))
+ result))
+
+(defun swift-mode:beginning-of-defun-1 (next-token-function)
+ (catch 'swift-mode:found-defun
+ (while (not (eq (swift-mode:token:type (funcall next-token-function))
+ 'outside-of-buffer))
+ (when (save-excursion (swift-mode:is-point-before-body-of-defun))
+ (swift-mode:beginning-of-statement)
+ (throw 'swift-mode:found-defun t)))
+ nil))
+
+
+(defun swift-mode:is-point-before-body-of-defun ()
+ (and
+ (= (char-after) ?{)
+ (progn
+ ;; Skips implicit ;
+ (forward-comment (- (point)))
+ (let* ((defun-keywords '("class" "struct" "protocol" "enum" "extension"
+ "func" "operator" "var" "get" "set" "willSet"
+ "didSet" "deinit" "subscript"))
+ (previous-token (swift-mode:backward-token-or-list))
+ (previous-type (swift-mode:token:type previous-token))
+ (previous-text (swift-mode:token:text previous-token)))
+ (while (and
+ (not (eq previous-type 'outside-of-buffer))
+ (not (memq previous-type swift-mode:statement-parent-tokens))
+ (not (member previous-text swift-mode:statement-parent-tokens))
+ (not (member previous-text defun-keywords))
+ (not (and (equal previous-text "init")
+ (save-excursion
+ ;; Excludes self.init() {}
+ (not
+ (equal
+ (swift-mode:token:text
(swift-mode:backward-token))
+ "."))))))
+ (setq previous-token (swift-mode:backward-token-or-list))
+ (setq previous-type (swift-mode:token:type previous-token))
+ (setq previous-text (swift-mode:token:text previous-token)))
+ (unless (bobp)
+ (swift-mode:forward-token-simple))
+ (or (equal previous-text "init")
+ (member previous-text defun-keywords))))))
+
+(defun swift-mode:beginning-of-statement ()
+ "Move backward to the beginning of a statement or some kind of expression.
+
+Intended for internal use."
+ (let ((parent (swift-mode:backward-sexps-until
+ swift-mode:statement-parent-tokens)))
+ (forward-comment (point-max))
+ (swift-mode:goto-non-comment-bol)
+ (when (< (point) (swift-mode:token:end parent))
+ (goto-char (swift-mode:token:end parent)))
+ (swift-mode:skip-whitespaces)))
+
+
+(defun swift-mode:end-of-defun (&optional arg)
+ "Move forward to the end of a defun."
+ (interactive)
+ (setq arg (or arg 1))
+ (let (result)
+ (if (<= 0 arg)
+ (while (< 0 arg)
+ (setq result (swift-mode:end-of-defun-1
+ #'swift-mode:forward-token-or-list
+ ))
+ (setq arg (1- arg)))
+ (while (< arg 0)
+ (setq result (swift-mode:end-of-defun-1
+ (lambda ()
+ (prog1 (swift-mode:backward-token-or-list)
+ (forward-comment (- (point)))))))
+ (setq arg (1+ arg))))
+ result))
+
+(defun swift-mode:end-of-defun-1 (next-token-function)
+ (catch 'swift-mode:found-defun
+ (while (not (eq (swift-mode:token:type (funcall next-token-function))
+ 'outside-of-buffer))
+ (when (and (= (char-before) ?})
+ (save-excursion
+ (backward-list)
+ (swift-mode:is-point-before-body-of-defun)))
+ (throw 'swift-mode:found-defun t)))
+ nil))
+
+
+(provide 'swift-mode-beginning-of-defun)
+
+;;; swift-mode-beginning-of-defun.el ends here
diff --git a/swift-mode-font-lock.el b/swift-mode-font-lock.el
new file mode 100644
index 0000000..dfa9a2a
--- /dev/null
+++ b/swift-mode-font-lock.el
@@ -0,0 +1,232 @@
+;;; swift-mode-font-lock.el --- Major-mode for Apple's Swift programming
language, Font Locks. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 taku0, Chris Barrett, Bozhidar Batsov, Arthur
Evstifeev
+
+;; Authors: taku0 (http://github.com/taku0)
+;; Chris Barrett <chris.d.barrett@me.com>
+;; Bozhidar Batsov <bozhidar@batsov.com>
+;; Arthur Evstifeev <lod@pisem.net>
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Routines for Font Locks
+
+;;; Code:
+
+(defun swift-mode:function-name-pos-p (pos)
+ "Return t if POS is at just before function name."
+ (save-excursion
+ (save-match-data
+ (goto-char pos)
+ (forward-comment (- (point)))
+ (skip-syntax-backward "w_")
+ (looking-at
"\\<\\(func\\|enum\\|struct\\|class\\|protocol\\|extension\\)\\>"))))
+
+(defun swift-mode:font-lock-match-function-names (limit)
+ "Move the cursor just after a function name or others.
+
+Others includes enum, struct, class, protocol name.
+Set `match-data', and return t if a function name found before position LIMIT.
+Return nil otherwise."
+ (and
+ (re-search-forward "\\<\\(\\sw\\|\\s_\\)+\\>" limit t)
+ (or
+ (swift-mode:function-name-pos-p (match-beginning 0))
+ (swift-mode:font-lock-match-function-names limit))))
+
+(defconst swift-mode:font-lock-keywords
+ '(
+ ;; Attributes
+ "@\\(\\sw\\|\\s_\\)*"
+
+ ;; Constants
+ ("\\<true\\>" . font-lock-constant-face)
+ ("\\<false\\>" . font-lock-constant-face)
+ ("\\<nil\\>" . font-lock-constant-face)
+
+ ;; Keywords
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410
+
+ ;; Keywords that begin with a number sign (#)
+ ("#available\\>" . font-lock-preprocessor-face)
+ ("#column\\>" . font-lock-preprocessor-face)
+ ("#elseif\\>" . font-lock-preprocessor-face)
+ ("#else\\>" . font-lock-preprocessor-face)
+ ("#endif\\>" . font-lock-preprocessor-face)
+ ("#file\\>" . font-lock-preprocessor-face)
+ ("#function\\>" . font-lock-preprocessor-face)
+ ("#if\\>" . font-lock-preprocessor-face)
+ ("#line\\>" . font-lock-preprocessor-face)
+ ("#selector\\>" . font-lock-preprocessor-face)
+
+ ;; Keywords used in declarations
+ "\\<associatedtype\\>"
+ "\\<class\\>"
+ "\\<deinit\\>"
+ "\\<enum\\>"
+ "\\<extension\\>"
+ "\\<fileprivate\\>"
+ "\\<func\\>"
+ "\\<import\\>"
+ "\\<init\\>"
+ "\\<inout\\>"
+ "\\<internal\\>"
+ "\\<let\\>"
+ "\\<open\\>"
+ "\\<operator\\>"
+ "\\<private\\>"
+ "\\<protocol\\>"
+ "\\<public\\>"
+ "\\<static\\>"
+ "\\<struct\\>"
+ "\\<subscript\\>"
+ "\\<typealias\\>"
+ "\\<var\\>"
+
+ ;; Keywords used in statements
+ "\\<break\\>"
+ "\\<case\\>"
+ "\\<continue\\>"
+ "\\<default\\>"
+ "\\<defer\\>"
+ "\\<do\\>"
+ "\\<else\\>"
+ "\\<fallthrough\\>"
+ "\\<for\\>"
+ "\\<guard\\>"
+ "\\<if\\>"
+ "\\<in\\>"
+ "\\<repeat\\>"
+ "\\<return\\>"
+ "\\<switch\\>"
+ "\\<where\\>"
+ "\\<while\\>"
+
+ ;; Keywords used in expressions and types (without true, false, and
keywords begin with a number sign)
+ "\\<as\\>"
+ "\\<catch\\>"
+ "\\<dynamicType\\>"
+ "\\<is\\>"
+ "\\<nil\\>"
+ "\\<rethrows\\>"
+ "\\<super\\>"
+ "\\<self\\>"
+ "\\<Self\\>"
+ "\\<throws\\>"
+ "\\<throw\\>"
+ "\\<try\\>"
+
+ ;; Keywords reserved in particular contexts
+ "\\<Protocol\\>"
+ "\\<Type\\>"
+ "\\<and\\>"
+ "\\<assignment\\>"
+ "\\<associativity\\>"
+ "\\<convenience\\>"
+ "\\<didSet\\>"
+ "\\<dynamic\\>"
+ "\\<final\\>"
+ "\\<get\\>"
+ "\\<higherThan\\>"
+ "\\<indirect\\>"
+ "\\<infix\\>"
+ "\\<lazy\\>"
+ "\\<left\\>"
+ "\\<lowerThan\\>"
+ "\\<mutating\\>"
+ "\\<none\\>"
+ "\\<nonmutating\\>"
+ "\\<optional\\>"
+ "\\<override\\>"
+ "\\<postfix\\>"
+ "\\<precedence\\>"
+ "\\<precedencegroup\\>"
+ "\\<prefix\\>"
+ "\\<required\\>"
+ "\\<right\\>"
+ "\\<set\\>"
+ "\\<unowned\\>"
+ "\\<weak\\>"
+ "\\<willSet\\>"
+
+ ;; Standard library functions
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/doc/uid/TP40016052
+ ("\\<abs\\>" . font-lock-builtin-face)
+ ("\\<alignof\\>" . font-lock-builtin-face)
+ ("\\<alignofValue\\>" . font-lock-builtin-face)
+ ("\\<anyGenerator\\>" . font-lock-builtin-face)
+ ("\\<assert\\>" . font-lock-builtin-face)
+ ("\\<assertionFailure\\>" . font-lock-builtin-face)
+ ("\\<debugPrint\\>" . font-lock-builtin-face)
+ ("\\<dump\\>" . font-lock-builtin-face)
+ ("\\<fatalError\\>" . font-lock-builtin-face)
+ ("\\<getVaList\\>" . font-lock-builtin-face)
+ ("\\<isUniquelyReferenced\\>" . font-lock-builtin-face)
+ ("\\<isUniquelyReferencedNonObjC\\>" . font-lock-builtin-face)
+ ("\\<max\\>" . font-lock-builtin-face)
+ ("\\<min\\>" . font-lock-builtin-face)
+ ("\\<numericCast\\>" . font-lock-builtin-face)
+ ("\\<precondition\\>" . font-lock-builtin-face)
+ ("\\<preconditionFailure\\>" . font-lock-builtin-face)
+ ("\\<print\\>" . font-lock-builtin-face)
+ ("\\<readLine\\>" . font-lock-builtin-face)
+ ("\\<sizeof\\>" . font-lock-builtin-face)
+ ("\\<sizeofValue\\>" . font-lock-builtin-face)
+ ("\\<strideof\\>" . font-lock-builtin-face)
+ ("\\<strideofValue\\>" . font-lock-builtin-face)
+ ("\\<swap\\>" . font-lock-builtin-face)
+ ("\\<transcode\\>" . font-lock-builtin-face)
+ ("\\<unsafeAddressOf\\>" . font-lock-builtin-face)
+ ("\\<unsafeBitCast\\>" . font-lock-builtin-face)
+ ("\\<unsafeDowncast\\>" . font-lock-builtin-face)
+ ("\\<unsafeUnwrap\\>" . font-lock-builtin-face)
+ ("\\<withExtendedLifetime\\>" . font-lock-builtin-face)
+ ("\\<withUnsafeMutablePointer\\>" . font-lock-builtin-face)
+ ("\\<withUnsafeMutablePointers\\>" . font-lock-builtin-face)
+ ("\\<withUnsafePointer\\>" . font-lock-builtin-face)
+ ("\\<withUnsafePointers\\>" . font-lock-builtin-face)
+ ("\\<withVaList\\>" . font-lock-builtin-face)
+ ("\\<zip\\>" . font-lock-builtin-face)
+
+ ;; keywords for build configuration statements
+ ("\\<os\\>" . font-lock-builtin-face)
+ ("\\<arch\\>" . font-lock-builtin-face)
+ ("\\<swift\\>" . font-lock-builtin-face)
+ ("\\<OSX\\>" . font-lock-builtin-face)
+ ("\\<iOS\\>" . font-lock-builtin-face)
+ ("\\<watchOS\\>" . font-lock-builtin-face)
+ ("\\<tvOS\\>" . font-lock-builtin-face)
+ ("\\<i386\\>" . font-lock-builtin-face)
+ ("\\<x86_64\\>" . font-lock-builtin-face)
+ ("\\<arm\\>" . font-lock-builtin-face)
+ ("\\<arm64\\>" . font-lock-builtin-face)
+ ("\\<iOSApplicationExtension\\>" . font-lock-builtin-face)
+ ("\\<OSXApplicationExtension\\>" . font-lock-builtin-face)
+
+ (swift-mode:font-lock-match-function-names . font-lock-function-name-face)
+ )
+ "Swift mode keywords for Font Lock.")
+
+
+(provide 'swift-mode-font-lock)
+
+;;; swift-mode-font-lock.el ends here
diff --git a/swift-mode-indent.el b/swift-mode-indent.el
new file mode 100644
index 0000000..0a69525
--- /dev/null
+++ b/swift-mode-indent.el
@@ -0,0 +1,1475 @@
+;;; swift-mode-indent.el --- Major-mode for Apple's Swift programming
language, indentation. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 taku0, Chris Barrett, Bozhidar Batsov, Arthur
Evstifeev
+
+;; Authors: taku0 (http://github.com/taku0)
+;; Chris Barrett <chris.d.barrett@me.com>
+;; Bozhidar Batsov <bozhidar@batsov.com>
+;; Arthur Evstifeev <lod@pisem.net>
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Routines for Indentation
+
+;;; Code:
+
+(require 'swift-mode-lexer)
+
+;;;###autoload
+(defcustom swift-mode:basic-offset 4
+ "Amount of indentation for block contents."
+ :type 'integer
+ :group 'swift
+ :safe 'integerp)
+
+;;;###autoload
+(defcustom swift-mode:parenthesized-expression-offset 2
+ "Amount of indentation inside parentheses and square brackets."
+ :type 'integer
+ :group 'swift
+ :safe 'integerp)
+
+;;;###autoload
+(defcustom swift-mode:multiline-statement-offset 2
+ "Amount of indentation for continuations of expressions."
+ :type 'integer
+ :group 'swift
+ :safe 'integerp)
+
+;;;###autoload
+(defcustom swift-mode:switch-case-offset 0
+ "Amount of indentation for case labels in switch statements."
+ :type 'integer
+ :group 'swift
+ :safe 'integerp)
+
+;;;###autoload
+(defcustom swift-mode:insert-space-after-asterisk-in-comment t
+ "Automatically insert a space after asterisk in comment if non-nil."
+ :type 'boolean
+ :group 'swift
+ :safe 'booleanp)
+
+;;;###autoload
+(defcustom swift-mode:auto-close-multiline-comment t
+ "If non-nil, `indent-new-comment-line' automatically close multiline
comment."
+ :type 'boolean
+ :group 'swift
+ :safe 'booleanp)
+
+;;;###autoload
+(defcustom swift-mode:fix-comment-close t
+ "Fix \"* /\" in incomplete multiline comment to \"*/\" if non-nil."
+ :type 'boolean
+ :group 'swift
+ :safe 'booleanp)
+
+(defconst swift-mode:statement-parent-tokens
+ '(implicit-\; \; case-: { \( \[ anonymous-function-parameter-in)
+ "Parent tokens for statements.")
+
+(defconst swift-mode:expression-parent-tokens
+ (append swift-mode:statement-parent-tokens
+ '(\, < "where" "if" "guard" "while"))
+ "Parent tokens for expressions.")
+
+(defun swift-mode:indent-line ()
+ (let ((indent (save-excursion (swift-mode:calculate-indent)))
+ (current-indent
+ (save-excursion (back-to-indentation) (current-column))))
+ (if (<= (current-column) current-indent)
+ ;; The cursor is on the left margin. Moving to the new indent.
+ (indent-line-to indent)
+ ;; Keeps current relative position.
+ (save-excursion (indent-line-to indent)))))
+
+(defun swift-mode:calculate-indent ()
+ (back-to-indentation)
+
+ (if (nth 4 (syntax-ppss))
+ ;; If the 4th element of `(syntax-ppss)' is non-nil, the cursor is on
+ ;; the 2nd or following lines of a multiline comment, because:
+ ;;
+ ;; - The 4th element of `(syntax-ppss)' is nil on the comment starter.
+ ;; - We have called `back-to-indentation`.
+ (swift-mode:calculate-indent-of-multiline-comment)
+ (swift-mode:calculate-indent-of-code)))
+
+(defun swift-mode:calculate-indent-of-multiline-comment ()
+ (back-to-indentation)
+ (let ((comment-beginning-position (nth 8 (syntax-ppss))))
+ (forward-line -1)
+ (back-to-indentation)
+ (if (<= (point) comment-beginning-position)
+ ;; The cursor was on the 2nd line of the comment, so aligns with
+ ;; the asterisk of the comment starter.
+ (progn
+ (goto-char comment-beginning-position)
+ (forward-char)
+ (current-column))
+ ;; The cursor was on the 3rd or following lines of the comment, so aligns
+ ;; with a non-empty preceding line.
+ (if (eolp)
+ ;; The cursor is on an empty line, so seeks a non-empty-line.
+ (swift-mode:calculate-indent-of-multiline-comment)
+ (current-column)))))
+
+(defun swift-mode:calculate-indent-of-code ()
+ (back-to-indentation)
+ (let* ((previous-token (save-excursion (swift-mode:backward-token)))
+ (previous-type (swift-mode:token:type previous-token))
+ (previous-text (swift-mode:token:text previous-token))
+ (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
+ (<= (swift-mode:token:end next-token) (line-end-position))))
+ (cond
+ ;; Beginning of the buffer
+ ((eq previous-type 'outside-of-buffer)
+ 0)
+
+ ;; Before } on the same line
+ ((and next-is-on-same-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 '(\) \])))
+ (goto-char (swift-mode:token:end next-token))
+ (backward-list)
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:expression-parent-tokens
+ 0
+ ;; Stops scanning at BOL:
+ ;;
+ ;; foo
+ ;; .bar(
+ ;; 1
+ ;; )
+ ;;
+ ;; rather than
+ ;;
+ ;; foo
+ ;; .bar(
+ ;; 1
+ ;; )
+ 'any))
+
+ ;; Before , on the same line
+ ((and next-is-on-same-line (eq next-type '\,))
+ (swift-mode:calculate-indent-of-prefix-comma))
+
+ ;; After ,
+ ((eq previous-type '\,)
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:calculate-indent-after-comma))
+
+ ;; Before "in" on the same line
+ ((and next-is-on-same-line (equal next-text "in"))
+ ;; When it is for-in statement, align with the token after "for":
+ ;;
+ ;; for
+ ;; x
+ ;; in
+ ;; foo
+ ;;
+ ;; for x
+ ;; in
+ ;; foo
+ ;;
+ ;; When it is anonymous function, align with the token after {:
+ ;;
+ ;; foo {
+ ;; x
+ ;; in
+ ;; ...
+ ;; }
+ ;;
+ ;;
+ ;; foo { x
+ ;; in
+ ;; ...
+ ;; }
+ ;;
+ ;; foo { [
+ ;; weak self
+ ;; ]
+ ;; (
+ ;; x,
+ ;; y
+ ;; )
+ ;; -> Void
+ ;; in
+ ;; a
+ ;; }
+ (swift-mode:calculate-indent-of-expression '("for" {)))
+
+ ;; Before "case" or "default" on the same line, for switch statement
+ ((and
+ next-is-on-same-line
+ (member next-text '("case" "default"))
+ (save-excursion
+ (equal (swift-mode:token:text
+ (swift-mode:backward-sexps-until
+ '("switch" "enum" "for" "while" "if" "guard")))
+ "switch")))
+ ;; "case" is used for "switch", "enum", "for", "while", "if", and
"guard".
+ ;; Only switch statement has special indentation rule.
+ ;;
+ ;; switch foo {
+ ;; default:
+ ;; aaa
+ ;; case A:
+ ;; aaa
+ ;; case B, C, D:
+ ;; aaa
+ ;; case E(1, 2, 3, (4, 5)) where aaa,
+ ;; F(1, 2, 3, (4, 5)) where aaa:
+ ;; aaa
+ ;; case G: print(1); case H: print(2)
+ ;; case I:
+ ;; ...
+ ;; }
+ ;;
+ ;; enum Foo {
+ ;; case A
+ ;; case B, C, D
+ ;; indirect
+ ;; case E(x: Int, y: Int)
+ ;; }
+ ;;
+ ;; enum Foo: Int, A, B {
+ ;; case A = 1, B = 2
+ ;; case C = 3
+ ;; }
+ ;;
+ ;; for
+ ;; case let (x, y) in tuples {
+ ;; }
+ ;; if
+ ;; case let (x, y) = tuple {
+ ;; }
+ ;; while
+ ;; case let (x, y) = tuple {
+ ;; }
+ ;;
+ ;; Searches sibling "case" at the beginning of a line. If found, aligns
+ ;; with it.
+ ;;
+ ;; Otherwise, searches "switch" and aligh with it with offset.
+ (let ((parent (swift-mode:backward-sexps-until
+ '("switch") nil '("case" "default"))))
+ (if (equal (swift-mode:token:text parent) "switch")
+ ;; Inside a switch-statement. Aligns with the "switch"
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:statement-parent-tokens
+ swift-mode:switch-case-offset)
+ ;; Other cases. Aligns with the previous case.
+ (swift-mode:align-with-current-line))))
+
+ ;; Before "where" on the same line
+ ((and next-is-on-same-line (equal next-text "where"))
+ ;; switch {
+ ;; case let P(x)
+ ;; where
+ ;; a,
+ ;; let Q(x)
+ ;; where
+ ;; a:
+ ;; aaa
+ ;; }
+ ;;
+ ;; for case (x, y) in xys
+ ;; where
+ ;; aaa {
+ ;; }
+ ;;
+ ;; do {
+ ;; } catch let P(x)
+ ;; where
+ ;; aaa
+ ;;
+ ;; func foo<A: AAA,
+ ;; B: BBB
+ ;; where
+ ;; ABC>() {
+ ;; }
+ ;;
+ ;; class Foo<A,
+ ;; B,
+ ;; C>: AAA,
+ ;; BBB,
+ ;; CCC
+ ;; where
+ ;; ABC {
+ ;; }
+ (let ((parent (save-excursion (swift-mode:backward-sexps-until
+ (append swift-mode:statement-parent-tokens
+ '("case"))))))
+ (swift-mode:calculate-indent-of-expression
+ (append swift-mode:statement-parent-tokens
+ '(< "case" "catch" "for")
+ (if (equal (swift-mode:token:text parent) "case") '(\,) '()))
+ swift-mode:multiline-statement-offset)))
+
+ ;; After {
+ ((eq previous-type '{)
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:calculate-indent-after-open-curly-brace
+ swift-mode:basic-offset))
+
+ ;; After ( or [
+ ((memq previous-type '(\( \[))
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:expression-parent-tokens
+ swift-mode:parenthesized-expression-offset
+ ;; Stops scanning at BOL:
+ ;;
+ ;; foo
+ ;; .bar(
+ ;; 1
+ ;; )
+ ;;
+ ;; rather than
+ ;;
+ ;; foo
+ ;; .bar(
+ ;; 1
+ ;; )
+ 'any
+ nil
+ swift-mode:parenthesized-expression-offset))
+
+ ;; After "where"
+ ((equal previous-text "where")
+ ;; switch {
+ ;; case let P(x) where
+ ;; A,
+ ;; let Q(x) where
+ ;; A:
+ ;; aaa
+ ;; case let P(x)
+ ;; where
+ ;; a,
+ ;; let Q(x)
+ ;; where
+ ;; a:
+ ;; aaa
+ ;; case let P(x), let Q(x) where
+ ;; a
+ ;; }
+ ;;
+ ;; for case let (x, y) in xys where
+ ;; aaa {
+ ;; }
+ ;;
+ ;; for case let (x, y) in xys
+ ;; where
+ ;; aaa {
+ ;; }
+ ;;
+ ;; do {
+ ;; } catch let P(x) where
+ ;; aaa
+ ;; do {
+ ;; } catch let P(x)
+ ;; where
+ ;; aaa
+ ;;
+ ;;
+ ;;
+ ;; func foo<A: AAA,
+ ;; B: BBB where
+ ;; ABC>() {
+ ;; }
+ ;;
+ ;; func foo<A: AAA,
+ ;; B: BBB
+ ;; where
+ ;; ABC>() {
+ ;; }
+ ;;
+ ;; class Foo<A,
+ ;; B,
+ ;; C> A,
+ ;; B,
+ ;; C where
+ ;; ABC {
+ ;; }
+ ;;
+ ;; class Foo<A,
+ ;; B,
+ ;; C>: A,
+ ;; B,
+ ;; C
+ ;; where
+ ;; ABC {
+ ;; }
+ (goto-char (swift-mode:token:start previous-token))
+ (if (swift-mode:bol-other-than-comments-p)
+ (swift-mode:align-with-current-line
+ swift-mode:multiline-statement-offset)
+ (let ((parent (save-excursion
+ (swift-mode:backward-sexps-until
+ (append swift-mode:statement-parent-tokens
+ '("case"))))))
+ (swift-mode:calculate-indent-of-expression
+ (append swift-mode:statement-parent-tokens
+ '(< "case" "catch" "for")
+ (if (equal (swift-mode:token:text parent) "case") '(\,)
'()))
+ swift-mode:multiline-statement-offset))))
+
+ ;; After implicit-\; or ;
+ ((memq previous-type '(implicit-\; \;))
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:calculate-indent-of-expression
+ (remove '\; (remove 'implicit-\; swift-mode:statement-parent-tokens))
+ 0
+ '(implicit-\; \;)))
+
+ ;; After "in" for anonymous function parameters
+ ((eq previous-type 'anonymous-function-parameter-in)
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:backward-sexps-until '({))
+ (swift-mode:calculate-indent-after-open-curly-brace
+ swift-mode:basic-offset))
+
+ ;; After "in" for "for" statements
+ ((equal previous-text "in")
+ ;; Aligns with "in" if it is at the start of the line:
+ ;;
+ ;; for
+ ;; x
+ ;; in
+ ;; foo
+ ;;
+ ;; for x
+ ;; in
+ ;; foo
+ ;;
+ ;; Otherwise, aligns with the next token of the "for".
+ ;;
+ ;; for x in
+ ;; foo
+ ;;
+ ;; for
+ ;; x in
+ ;; foo
+ (goto-char (swift-mode:token:start previous-token))
+ (if (swift-mode:bol-other-than-comments-p)
+ (swift-mode:align-with-current-line)
+ (let ((parent (swift-mode:backward-sexps-until '("for" {))))
+ (swift-mode:align-with-next-token parent))))
+
+ ;; After case ... : or default:
+ ((eq previous-type 'case-:)
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:statement-parent-tokens
+ swift-mode:basic-offset))
+
+ ;; Before ; on the same line
+ ((and next-is-on-same-line (eq next-type '\;))
+ (swift-mode:calculate-indent-of-expression
+ (remove '\; (remove 'implicit-\; swift-mode:statement-parent-tokens))
+ 0
+ '(implicit-\; \;)))
+
+ ;; After if, guard, while
+ ((member previous-text '("if" "guard" "while"))
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:statement-parent-tokens
+ swift-mode:multiline-statement-offset))
+
+ ;; After attributes at the beginning of a statement, without arguments
+ ((and
+ (string-prefix-p "@" previous-text)
+ (memq (save-excursion
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:token:type (swift-mode:backward-token)))
+ swift-mode:statement-parent-tokens))
+ ;; Aligns with the attribute.
+ (goto-char (swift-mode:token:start previous-token))
+ (swift-mode:align-with-next-token (swift-mode:backward-token)))
+
+ ;; After attributes at the beginning of a statement, with arguments
+ ((and
+ (eq previous-type '\))
+ (save-excursion
+ (backward-list)
+ (and
+ (string-prefix-p
+ "@"
+ (swift-mode:token:text (swift-mode:backward-token)))
+ (memq (swift-mode:token:type (swift-mode:backward-token))
+ swift-mode:statement-parent-tokens))))
+ (backward-list)
+ (swift-mode:backward-token)
+ (swift-mode:align-with-next-token (swift-mode:backward-token)))
+
+ ;; Otherwise, it is continuation of the previous line
+ (t
+ (goto-char (swift-mode:token:end previous-token))
+ (swift-mode:backward-token-or-list)
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:expression-parent-tokens
+ swift-mode:multiline-statement-offset
+ 'any)))))
+
+(defun swift-mode:calculate-indent-of-expression
+ (parents
+ &optional
+ offset
+ stop-at-eol-token-types
+ stop-at-bol-token-types
+ bol-offset)
+ "Return start column of the current expressions or statement plus OFFSET.
+
+If OFFSET is omitted, it is assumed to be 0.
+PARENTS is a list of token types that precedes an expression or a statement.
+See `swift-mode:backward-sexps-until' for the details of
+STOP-AT-EOL-TOKEN-TYPES and STOP-AT-BOL-TOKEN-TYPES.
+If scanning stops at STOP-AT-EOL-TOKEN-TYPES, align with the next token with
+BOL-OFFSET.
+If scanning stops at STOP-AT-BOL-TOKEN-TYPES, align with that token with
+BOL-OFFSET.
+If STOP-AT-BOL-TOKEN-TYPES is the symbol `any', the cursor is assumed to be
+on the previous line."
+ (save-excursion
+ (let* ((parent (swift-mode:backward-sexps-until
+ parents
+ stop-at-eol-token-types
+ stop-at-bol-token-types))
+ (parent-end (swift-mode:token:end parent))
+ (stopped-at-parent
+ (or (memq (swift-mode:token:type parent) parents)
+ (member (swift-mode:token:text parent) parents)
+ (eq (swift-mode:token:type parent) 'outside-of-buffer)))
+ (stopped-at-eol
+ (and
+ (not stopped-at-parent)
+ stop-at-eol-token-types
+ (or
+ (eq stop-at-eol-token-types 'any)
+ (memq (swift-mode:token:type parent)
+ stop-at-eol-token-types)
+ (member (swift-mode:token:text parent)
+ stop-at-eol-token-types)))))
+ (when (or stopped-at-parent stopped-at-eol)
+ (goto-char parent-end)
+ (forward-comment (point-max)))
+ ;; Now, the cursor is at the first token of the expression.
+
+ (if stopped-at-parent
+ ;; The cursor is at the start of the entire expression.
+ ;; Aligns with the start of the expression with offset.
+ (swift-mode:align-with-next-token parent offset)
+ ;; The cursor is at the middle of the expression.
+ ;; Aligns with this line with bol-offset.
+ (swift-mode:align-with-current-line bol-offset)))))
+
+(defun swift-mode:calculate-indent-after-open-curly-brace (offset)
+ "Return indentation after open curly braces.
+
+Assuming the cursor is on the open parenthesis.
+OFFSET is the offset of the contents.
+This function is also used for close-curly-brace."
+ ;; If the statement is multiline expression, aligns with the start of
+ ;; the line on which the open brace is:
+ ;;
+ ;; foo()
+ ;; .then { x in
+ ;; foo()
+ ;; foo()
+ ;; }
+ ;; .then { x in
+ ;; foo()
+ ;; foo()
+ ;; }
+ ;;
+ ;; rather than
+ ;;
+ ;; foo()
+ ;; .then { x in
+ ;; foo()
+ ;; foo()
+ ;; }
+ ;; .then { x in
+ ;; foo()
+ ;; foo()
+ ;; }
+ ;;
+ ;; Otherwise, aligns with the start of the whole statement:
+ ;;
+ ;; for x in
+ ;; xs
+ ;; .foo() {
+ ;; }
+ ;;
+ ;; rather than
+ ;;
+ ;; for x in
+ ;; xs
+ ;; .foo() {
+ ;; }
+ ;;
+ ;; Note that curly brace after binary operator is a part of
+ ;; a multiline expression:
+ ;;
+ ;; for x in
+ ;; xs
+ ;; +++ { x in
+ ;; // this is not the body of the for-statement.
+ ;; } {
+ ;; // The body of the for-statement.
+ ;; }
+ (let ((pos (point))
+ next-token
+ is-declaration-or-control-statement-body)
+ (if (save-excursion
+ (eq (swift-mode:token:type (swift-mode:backward-token))
+ 'binary-operator))
+ ;; for x in
+ ;; xs
+ ;; +++ { x in
+ ;; // this is not the body of the for statement.
+ ;; } {
+ ;; ...
+ ;; }
+ (setq is-declaration-or-control-statement-body nil)
+ (save-excursion
+ (swift-mode:backward-sexps-until swift-mode:statement-parent-tokens)
+ (swift-mode:forward-token)
+ (setq next-token (swift-mode:forward-token-or-list))
+ (while (<= (point) pos)
+ (cond
+ ((member
+ (swift-mode:token:text next-token)
+ '("for" "while" "repeat" "if" "else" "defer" "do" "catch"
+ "get" "set" "willSet" "didSet" "func" "init" "subscript"
+ "enum" "struct" "class" "extension" "prefix" "postfix" "infix"
+ "precedencegroup"))
+ (setq is-declaration-or-control-statement-body t)
+ (goto-char (1+ pos)))
+
+ ((and
+ (equal (swift-mode:token:text next-token) "protocol")
+ (not (equal (swift-mode:token:text
+ (save-excursion (swift-mode:forward-token)))
+ "<")))
+ (setq is-declaration-or-control-statement-body t)
+ (goto-char (1+ pos)))
+
+ ((equal (swift-mode:token:text next-token) "var")
+ ;; There are several cases:
+ ;;
+ ;; var foo = bar
+ ;; .then { x in
+ ;; x
+ ;; }
+ ;; .then { x in
+ ;; x
+ ;; }
+ ;;
+ ;; var foo = bar
+ ;; .baz {
+ ;; willSet {
+ ;; ...
+ ;; }
+ ;; }
+ ;;
+ ;; var foo {
+ ;; get {
+ ;; ...
+ ;; }
+ ;; }
+ ;;
+ ;; Note that the 1st and the 2nd cases cannot be distinguished
+ ;; without inspecting the contents of the block.
+ ;; We indent the 2nd case like the 1st case for now.
+ ;; Future implementation may use more sophisticated logic.
+ (goto-char pos)
+ (setq is-declaration-or-control-statement-body
+ (equal (swift-mode:token:text
+ (swift-mode:backward-sexps-until '("var" "=")))
+ "var"))
+ (goto-char (1+ pos)))
+
+ (t
+ ;; Suppose indenting the A token below.
+ ;;
+ ;; foo {
+ ;; A
+ ;;
+ ;; This function is called on the open curly brace.
+ ;; If the close curly brace doesn't exist,
+ ;; swift-mode:forward-token-or-list results in
+ ;; "Unbalanced parentheses" error.
+ ;; So if the point is just before the open curly brace,
+ ;; exits immediately.
+ (forward-comment (point-max))
+ (if (< (point) pos)
+ (setq next-token (swift-mode:forward-token-or-list))
+ (goto-char (1+ pos))))))))
+ (swift-mode:calculate-indent-of-expression
+ swift-mode:statement-parent-tokens
+ offset
+ (if is-declaration-or-control-statement-body nil 'any)
+ nil
+ offset)))
+
+(defun swift-mode:calculate-indent-of-prefix-comma ()
+ "Return indentation for prefix comma.
+
+Example:
+
+let x = [ 1
+ , 2
+ , 3
+]
+
+class Foo: A
+ , B
+ , C
+
+case A
+ , B
+ , C
+ :
+
+var x = 1
+ , y = 2
+ , z = 3
+
+This is also known as Utrecht-style in the Haskell community."
+ (let* ((comma-type-and-statement-parent (swift-mode:detect-type-of-comma))
+ (comma-type (nth 0 comma-type-and-statement-parent))
+ (statement-parent (nth 1 comma-type-and-statement-parent)))
+ (if (eq comma-type 'condition-list)
+ (swift-mode:calculate-indent-of-prefix-comma-of-condition-list
+ statement-parent)
+ (let* ((parents (swift-mode:parents-of-comma comma-type))
+ (parent (swift-mode:backward-sexps-until parents
+ nil
+ '(\,)))
+ (parent-end (swift-mode:token:end parent))
+ (stopped-at-parent
+ (or (memq (swift-mode:token:type parent) parents)
+ (member (swift-mode:token:text parent) parents)
+ (eq (swift-mode:token:type parent) 'outside-of-buffer))))
+ (if stopped-at-parent
+ (progn
+ ;; Aligns with the end of the parent.
+ (goto-char parent-end)
+ (backward-char)
+ (current-column))
+ ;; Aligns with the previous comma.
+ (swift-mode:align-with-current-line))))))
+
+(defun swift-mode:calculate-indent-of-prefix-comma-of-condition-list
+ (statement-parent)
+ ;; The comma is in a condition-list but not in an enum-case-pattern-list.
+ ;;
+ ;; Example:
+ ;;
+ ;; if case let P(x)
+ ;; , let Q(x) // comma for enum-case-pattern-list
+ ;; , let R(x) = a // comma for enum-case-pattern-list
+ ;; , let x = x // comma for condition-list
+ ;; , foo == bar // comma for condition-list
+ ;;
+ ;; We scan from beginning of the statement and remembers last anchor token,
+ ;; i.e. "if", "guard", "while", or comma at the beginning of the line.
+ (let ((pos (point))
+ next-token
+ (anchor statement-parent)
+ in-case-pattern-list)
+ (goto-char (swift-mode:token:end statement-parent))
+ (setq next-token (swift-mode:forward-token-or-list))
+ (while (< (point) pos)
+ (cond
+ ((equal (swift-mode:token:text next-token) "case")
+ (setq in-case-pattern-list t))
+
+ ((equal (swift-mode:token:text next-token) "=")
+ (setq in-case-pattern-list nil))
+
+ ((member (swift-mode:token:text next-token) '("if" "guard" "while"))
+ (setq anchor next-token))
+
+ ((and (not in-case-pattern-list)
+ (eq (swift-mode:token:type next-token) '\,)
+ (save-excursion
+ (goto-char (swift-mode:token:start next-token))
+ (swift-mode:bol-other-than-comments-p)))
+ (setq anchor next-token)))
+ (setq next-token (swift-mode:forward-token-or-list)))
+ (if (eq (swift-mode:token:type anchor) '\,)
+ ;; Aligns with the previous comma.
+ (progn
+ (goto-char (swift-mode:token:start anchor))
+ (swift-mode:align-with-current-line))
+ ;; Aligns with the end of the anchor
+ (goto-char (swift-mode:token:end anchor))
+ (backward-char)
+ (current-column))))
+
+(defun swift-mode:calculate-indent-after-comma ()
+ "Return indentation after comma.
+
+Assuming the cursor is on the comma."
+ (let* ((comma-type-and-statement-parent (swift-mode:detect-type-of-comma))
+ (comma-type (nth 0 comma-type-and-statement-parent))
+ (statement-parent (nth 1 comma-type-and-statement-parent)))
+ (if (eq comma-type 'condition-list)
+ (swift-mode:calculate-indent-after-comma-of-condition-list
+ statement-parent)
+ (swift-mode:align-with-next-token
+ (swift-mode:backward-sexps-until
+ (swift-mode:parents-of-comma comma-type)
+ '(\,))))))
+
+(defun swift-mode:calculate-indent-after-comma-of-condition-list
+ (statement-parent)
+ ;; The comma is in a condition-list but not in an enum-case-pattern-list.
+ ;;
+ ;; Example:
+ ;;
+ ;; if
+ ;; case let P(x), // comma for enum-case-pattern-list
+ ;; let Q(x), // comma for enum-case-pattern-list
+ ;; let R(x) = a, // comma for condition-list
+ ;; let x = x, // comma for condition-list
+ ;; foo == bar
+ ;;
+ ;; We scan from beginning of the statement and remembers last parent token,
+ ;; i.e. "if", "guard", "while", or comma at the end of the line.
+ (let ((pos (point))
+ next-token
+ (parent statement-parent)
+ in-case-pattern-list)
+ (goto-char (swift-mode:token:end statement-parent))
+ (setq next-token (swift-mode:forward-token-or-list))
+ (while (< (point) pos)
+ (cond
+ ((equal (swift-mode:token:text next-token) "case")
+ (setq in-case-pattern-list t))
+
+ ((equal (swift-mode:token:text next-token) "=")
+ (setq in-case-pattern-list nil))
+
+ ((member (swift-mode:token:text next-token) '("if" "guard" "while"))
+ (setq parent next-token))
+
+ ((and (not in-case-pattern-list)
+ (eq (swift-mode:token:type next-token) '\,)
+ (swift-mode:eol-other-than-comments-p))
+ (setq parent next-token)))
+ (setq next-token (swift-mode:forward-token-or-list)))
+ (swift-mode:align-with-next-token parent)))
+
+(defun swift-mode:detect-type-of-comma ()
+ "Return type of comma token under the cursor.
+
+Comma type is a list where:
+0th element is one of the following:
+
+- tuple-or-array (inside () or [])
+- type-parameters-or-requirements (inside <>)
+- enum-case-pattern-list (e.g. if case P, Q, R = x)
+- condition-list (e.g. if let x = x, let y = y)
+- variable-declarations (e.g. let x = 1, y = 2)
+- switch-case-or-enum-case-item-list (e.g. switch {case P, Q, R: a} or
+ enum {case A, B, C})
+- class-like-declarations (supertypes of class, or where clause after
+ super types)
+
+1st element is the token before the beginning of the statement.
+"
+ ;; Various examples:
+ ;;
+ ;; let x = ( // simple case
+ ;; 1,
+ ;; 2,
+ ;; 3
+ ;; )
+ ;;
+ ;; let x = [ // simple case
+ ;; 1,
+ ;; 2,
+ ;; 3
+ ;; ]
+ ;;
+ ;; let x: Foo<A, B> = a, // "let" is not a part of elements
+ ;; y: Foo<A, B> = b,
+ ;; z: Foo<A, B> = c
+ ;;
+ ;; switch foo {
+ ;; case (let x, // "let" is a part of an element
+ ;; Y,
+ ;; Z):
+ ;; aaa
+ ;; }
+ ;;
+ ;; class Foo<A where A: B, // "where" is not a part of elements
+ ;; A: C,
+ ;; A: D> {
+ ;; }
+ ;;
+ ;; switch foo {
+ ;; case A(x) where p(x), // "case" is not a part of elements
+ ;; B(x) where p(x), // "where" is a part of an element
+ ;; C(x) where p(x):
+ ;; aaa
+ ;; }
+ ;;
+ ;; if // or guard or while
+ ;; let x = x, // "let" is a part of an element
+ ;; let y = y,
+ ;; let z = z,
+ ;; case P(a, b, c), // "case" is a part of an element of condition-list
+ ;; Q(a, b, c) = abc, // "case" is not a part of elements of
+ ;; // enum-case-pattern-list
+ ;; case (a, b, c) = abc,
+ ;; aaa {
+ ;;
+ ;; bbb
+ ;; }
+ ;;
+ ;; See also SE-0099 and SE-0043:
+ ;;
https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md
+ ;;
https://github.com/apple/swift-evolution/blob/master/proposals/0043-declare-variables-in-case-labels-with-multiple-patterns.md
+ ;;
+ ;; class Foo<T>: A,
+ ;; B,
+ ;; C
+ ;; where
+ ;; T: A,
+ ;; T: B,
+ ;; T: C {
+ ;; }
+ ;;
+ ;; extension _ArrayType
+ ;; where
+ ;; Generator.Element: A,
+ ;; Generator.Element: B,
+ ;; Generator.Element: C {
+ ;; }
+ ;;
+ ;; func foo<T> -> Int
+ ;; where
+ ;; T: A,
+ ;; T: B,
+ ;; T: C {
+ ;; }
+ ;;
+ ;; enum Foo {
+ ;; case A(x: Int),
+ ;; B(y: Int),
+ ;; C(z: Int)
+ ;; case D(x: Int)
+ ;; , E(y: Int)
+ ;; , F(z: Int)
+ ;; }
+ ;;
+ ;; enum Foo: Int {
+ ;; case A,
+ ;; B,
+ ;; C = 2
+ ;; case D = 3
+ ;; , E
+ ;; , F
+ ;; }
+ (save-excursion
+ (let ((pos (point))
+ (parent (swift-mode:backward-sexps-until
+ (cons '< swift-mode:statement-parent-tokens))))
+ (cond
+ ((memq (swift-mode:token:type parent) '(\( \[))
+ (list 'tuple-or-array parent))
+
+ ((eq (swift-mode:token:type parent) '<)
+ (list 'type-parameters-or-requirements parent))
+
+ (t
+ (goto-char (swift-mode:token:end parent))
+ (let ((next-token (swift-mode:forward-token-or-list))
+ result)
+ (while (and (<= (point) pos) (not result))
+ (cond
+ ((member (swift-mode:token:text next-token)
+ '("if" "guard" "while"))
+ ;; Conditions
+ ;;
+ ;; Distinguishes condition-list and enum-case-pattern-list:
+ ;;
+ ;; if
+ ;; let x = x,
+ ;; case P(a, b, c),
+ ;; Q(a, b, c),
+ ;; R(a, b, c) = abc,
+ ;; let x = x,
+ ;; foo == bar,
+ ;; case (a, b, c) = abc {
+ ;; }
+ (goto-char pos)
+ (if (equal
+ (swift-mode:token:text (swift-mode:backward-sexps-until
+ '("if" "guard" "while" "case" "=")))
+ "case")
+ (setq result 'enum-case-pattern-list)
+ (setq result 'condition-list)))
+
+ ((member (swift-mode:token:text next-token)
+ '("let" "var"))
+ (setq result 'variable-declarations))
+
+ ((equal (swift-mode:token:text next-token)
+ "case")
+ (setq result 'switch-case-or-enum-case-item-list))
+
+ ((equal (swift-mode:token:text next-token)
+ "where")
+ (setq result 'type-parameters-or-requirements))
+
+ ((eq (swift-mode:token:type next-token) 'typing-:)
+ (setq result 'class-like-declarations)))
+
+ (setq next-token (swift-mode:forward-token-or-list)))
+ (if (and (> (point) pos) (eq (swift-mode:token:type next-token) '<>))
+ ;; The comma was inside <> but scanner misunderstand < as
+ ;; a binary-operator.
+ (list 'type-parameters-or-requirements parent)
+ (list result parent))))))))
+
+(defun swift-mode:parents-of-comma (comma-type)
+ "Return parent token types of comma token Ffrom COMMA-TYPE."
+ (append
+ swift-mode:statement-parent-tokens
+ (cond
+ ((eq comma-type 'tuple-or-array)
+ '(\( \[))
+
+ ((eq comma-type 'type-parameters-or-requirements)
+ '(< "where"))
+
+ ((eq comma-type 'enum-case-pattern-list)
+ '("case"))
+
+ ((eq comma-type 'variable-declarations)
+ '("let" "var"))
+
+ ((eq comma-type 'switch-case-or-enum-case-item-list)
+ '("case"))
+
+ ((eq comma-type 'class-like-declarations)
+ '(typing-: "where")))))
+
+(defun swift-mode:backward-sexps-until (token-types
+ &optional
+ stop-at-eol-token-types
+ stop-at-bol-token-types)
+ "Backward sexps until a token with one of given token types appears.
+Return the token.
+When this function returns, the cursor is at the start of the token.
+
+TOKEN-TYPES is a list of guard token typess. This function backs to a token
+with one of those token types.
+STOP-AT-EOL-TOKEN-TYPES is a list of token types that if we skipped the end of
+a line just after a token with one of given toke typen, the function returns.
+Typically, this is a list of token types that separates list elements
+\(e.g. ',', ';'). If STOP-AT-EOL-TOKEN-TYPES is the symbol `any', it matches
+all tokens.
+STOP-AT-BOL-TOKEN-TYPES is a list of token types that if we hit
+the beginning of a line just before a token with one of given token types,
+the function returns. Typically, this is a list of token types that starts
+list element (e.g. 'case' of switch statement body). If STOP-AT-BOL-TOKEN-TYPES
+is the symbol `any', it matches all tokens."
+ (let*
+ ((parent (swift-mode:backward-token-or-list))
+ (type (swift-mode:token:type parent))
+ (text (swift-mode:token:text parent)))
+ (while (not
+ ;; Stops loop when...
+ (or
+ ;; Hits a guard token.
+ (member type token-types)
+ (member text token-types)
+
+ ;; Beginning of the buffer.
+ (eq type 'outside-of-buffer)
+
+ ;; When this function is called on "," token before position (1),
+ ;; this function stops just before the "," token after "Foo".
+ ;;
+ ;; case Foo,
+ ;; Bar, Baz, // (1)
+ ;; AAA
+ (and stop-at-eol-token-types
+ (save-excursion
+ (swift-mode:forward-token-or-list)
+ (forward-comment (- (point)))
+ (swift-mode:eol-other-than-comments-p))
+ (or (eq stop-at-eol-token-types 'any)
+ (member type stop-at-eol-token-types)
+ (member text stop-at-eol-token-types)))
+
+ ;; When this function is called on "case" token before position
+ ;; (1), this function stops just before "case Bar".
+ ;;
+ ;; switch foo {
+ ;; case Foo:
+ ;; ...
+ ;; case Bar: case Baz:
+ ;; ...
+ ;; case AAA: // (1)
+ ;; }
+ (and stop-at-bol-token-types
+ (and
+ (or
+ (eq stop-at-bol-token-types 'any)
+ (member type stop-at-bol-token-types)
+ (member text stop-at-bol-token-types))
+ (swift-mode:bol-other-than-comments-p)))))
+ (setq parent (swift-mode:backward-token-or-list))
+ (setq type (swift-mode:token:type parent))
+ (setq text (swift-mode:token:text parent)))
+ parent))
+
+(defun swift-mode:align-with-next-token (parent &optional offset)
+ (let ((parent-end (swift-mode:token:end parent)))
+ (goto-char parent-end)
+ (forward-comment (point-max))
+ (swift-mode:goto-non-comment-bol)
+ (when (< (point) parent-end)
+ (goto-char parent-end))
+ (swift-mode:skip-whitespaces)
+ (+ (or offset 0) (current-column))))
+
+(defun swift-mode:align-with-current-line (&optional offset)
+ (swift-mode:goto-non-comment-bol)
+ (swift-mode:skip-whitespaces)
+ (+ (or offset 0) (current-column)))
+
+(defun swift-mode:backward-token-or-list ()
+ "Move point to the start position of the previous token or list.
+Return the token skipped."
+ (let* ((previous-token (swift-mode:backward-token))
+ (previous-type (swift-mode:token:type previous-token))
+ (previous-text (swift-mode:token:text previous-token))
+ (previous-start (swift-mode:token:start previous-token))
+ (previous-end (swift-mode:token:end previous-token)))
+ (cond
+ ;; List
+ ((memq previous-type '(} \) \]))
+ (goto-char previous-end)
+ (backward-list)
+ (swift-mode:token
+ (cdr (assoc previous-type '((} . {})
+ (\) . \(\))
+ (\] . \[\]))))
+ (buffer-substring-no-properties (point) previous-end)
+ (point)
+ previous-end))
+
+ ;; Generic parameter list
+ ((equal previous-text ">")
+ (swift-mode:try-backward-generic-parameters)
+ (if (= (point) previous-start)
+ previous-token
+ (swift-mode:token
+ '<>
+ (buffer-substring-no-properties (point) previous-end)
+ (point)
+ previous-end)))
+
+ ;; Other token
+ (t previous-token))))
+
+(defun swift-mode:forward-token-or-list ()
+ "Move point to the end position of the next token or list.
+Return the token skipped."
+ (let* ((next-token (swift-mode:forward-token))
+ (next-type (swift-mode:token:type next-token))
+ (next-text (swift-mode:token:text next-token))
+ (next-start (swift-mode:token:start next-token))
+ (next-end (swift-mode:token:end next-token)))
+ (cond
+ ;; List
+ ((memq next-type '({ \( \[))
+ (goto-char next-start)
+ (forward-list)
+ (swift-mode:token
+ (cdr (assoc next-type '(({ . {})
+ (\( . \(\))
+ (\[ . \[\]))))
+ (buffer-substring-no-properties next-start (point))
+ next-start
+ (point)))
+
+ ;; Generic parameter list
+ ((equal next-text "<")
+ (swift-mode:try-forward-generic-parameters)
+ (if (= (point) next-end)
+ next-token
+ (swift-mode:token
+ '<>
+ (buffer-substring-no-properties next-start (point))
+ next-start
+ (point))))
+
+ ;; Other token
+ (t next-token))))
+
+(defun swift-mode:try-backward-generic-parameters ()
+ "Move point to the start of the generic parameter list.
+
+Keep position if the cursor is not at the end of a generic parameter list.
+
+Assuming the cursor is on the close angle bracket.
+
+It is a Generic parameter list if:
+- it has matching angle brackets, and
+- it does not have tokens that cannot appears in a generic parameter list."
+ (swift-mode:try-skip-generic-parameters
+ #'swift-mode:backward-token-or-list
+ "<" ">"))
+
+(defun swift-mode:try-forward-generic-parameters ()
+ "Move point to the end of the generic parameter list.
+
+Keep position if the cursor is not at the start of a generic parameter list.
+
+Assuming the cursor is after the open angle bracket.
+
+It is a Generic parameter list if:
+- it has matching angle brackets, and
+- it does not have tokens that cannot appears in a generic parameter list."
+ (swift-mode:try-skip-generic-parameters
+ #'swift-mode:forward-token-or-list
+ ">" "<"))
+
+(defconst siwft-mode:tokens-not-in-generic-parameter-list
+ ;; Whitelisting tend to be fragile. So we list tokens that are
+ ;; unlikely to appear in generic parameter lists in the current
+ ;; version and future ones.
+ ;;
+ ;; Example of complex generic parameters:
+ ;; <
+ ;; A: B,
+ ;; C: protocol<X, Y>
+ ;; where
+ ;; A: @aaa(1 + 2 + 3) D<Int>!,
+ ;; C == (@aaa(1) inout [E.F]?, G...) throws -> [Int:Int]
+ ;; >
+ ;;
+ ;; We don't need to consider the contents of inner brackets because they are
+ ;; skipped by `swift-mode:backward-token-or-list'.
+ ;;
+ ;; String literals, implicit parameter names, and numbers are also excluded
+ ;; by `swift-mode:try-skip-generic-parameters'.
+ '(outside-of-buffer
+ \;
+ { } \( \) \[ \]
+ "true" "false"
+ "class" "struct" "enum" "extension" "func" "operator"
+ "try" "try?" "try!"
+ "as" "as?" "as!"
+ "is"
+ "in"
+ "init" "deinit" "get" "set" "willSet" "didSet" "subscript"
+ "for" "case" "default" "while" "let" "var" "repeat" "if" "else"
+ "guard" "break" "continue" "fallthrough" "return" "throw" "defer"
+ "do" "catch" "import" "typealias" "associatedtype"))
+
+(defun swift-mode:try-skip-generic-parameters
+ (skip-token-or-list-function matching-bracket-text unmatching-bracket-text)
+ (let ((pos (point))
+ (prohibited-tokens (append
+ unmatching-bracket-text
+ siwft-mode:tokens-not-in-generic-parameter-list))
+ (next-token (funcall skip-token-or-list-function)))
+ (while
+ (cond
+ ((or (memq (swift-mode:token:type next-token) prohibited-tokens)
+ (member (swift-mode:token:text next-token) prohibited-tokens)
+ (string-match-p "^[\"$0-9]"
+ (swift-mode:token:text next-token)))
+ ;; Not a generic parameter list. Returns to the initial position and
+ ;; stops the loop.
+ (goto-char pos)
+ nil)
+
+ ((equal (swift-mode:token:text next-token) matching-bracket-text)
+ ;; Found the matching open angle bracket. Stops the loop.
+ nil)
+
+ ;; Otherwise, keep scanning
+ (t t))
+ (setq next-token (funcall skip-token-or-list-function)))
+ next-token))
+
+(defun swift-mode:bol-other-than-comments-p ()
+ "Return t if there is nothing other than comments in the front of this line.
+
+Return nil otherwise.
+Newlines inside comments are ignored."
+ ;; Foo // ← bol
+ ;; /* */ Foo // ← bol
+ ;; X /* */ Foo // ← not bol
+ ;;
+ ;; /*
+ ;; */ /* */ /*
+ ;; */ Foo // ← bol
+ ;;
+ ;; X /*
+ ;; */ /* */ /*
+ ;; */ Foo // ← not bol
+ ;;
+ ;; X
+ ;; /* */ /*
+ ;; */ Foo // ← bol
+ (save-excursion
+ (let ((pos (point)))
+ (swift-mode:goto-non-comment-bol)
+ (forward-comment (point-max))
+ (<= pos (point)))))
+
+(defun swift-mode:eol-other-than-comments-p ()
+ "Return t if there is nothing other than comments until the end of this line.
+
+Return nil otherwise.
+Newlines inside comments are ignored."
+ (save-excursion
+ (let ((pos (point)))
+ (swift-mode:goto-non-comment-eol)
+ (forward-comment (- (point)))
+ (<= (point) pos))))
+
+(defun swift-mode:bolp ()
+ "Return t if there is nothing in the front of this line.
+
+Return nil otherwise."
+ (save-excursion
+ (skip-syntax-backward " ")
+ (bolp)))
+
+(defun swift-mode:skip-whitespaces ()
+ "Skips forward whitespaces and newlines."
+ (skip-syntax-forward " >"))
+
+(defun swift-mode:incomplete-comment-p ()
+ (and (nth 4 (syntax-ppss))
+ (save-excursion
+ (goto-char (nth 8 (syntax-ppss)))
+ (not (forward-comment 1)))))
+
+(defun swift-mode:indent-new-comment-line (&optional soft)
+ "Break the line at the point and indent the new line.
+
+If the point is inside a comment, continue the comment. If the comment is a
+multiline comment, close the previous comment and start new one if
+`comment-multi-line' is nil."
+ (interactive)
+ (let* ((parser-state (syntax-ppss))
+ (is-inside-comment (nth 4 parser-state))
+ (is-single-line-comment (eq (nth 7 parser-state) 1))
+ (comment-beginning-position (nth 8 parser-state))
+ (space-after-asterisk
+ (if swift-mode:insert-space-after-asterisk-in-comment " " "")))
+ (delete-horizontal-space)
+ (if soft (insert-and-inherit ?\n) (newline 1))
+ (delete-horizontal-space)
+
+ (when is-inside-comment
+ (insert-before-markers-and-inherit
+ (cond
+ (is-single-line-comment
+ "// ")
+
+ (comment-multi-line
+ (save-excursion
+ (beginning-of-line)
+ (forward-char -1)
+ (beginning-of-line)
+ (if (<= (point) comment-beginning-position)
+ ;; The cursor was on the 2nd line of the comment.
+ ;; Uses default prefix.
+ (concat "*" space-after-asterisk)
+ ;; The cursor was on the 3nd or following lines of
+ ;; the comment.
+ ;; Use the prefix of the previous line.
+ (back-to-indentation)
+ (if (looking-at "\\*+")
+ (concat (match-string-no-properties 0) space-after-asterisk)
+ ""))))
+
+ (t
+ (backward-char)
+ (insert-before-markers-and-inherit " */")
+ (forward-char)
+ (save-excursion
+ (goto-char comment-beginning-position)
+ (looking-at "/\\*+")
+ (concat (match-string-no-properties 0) space-after-asterisk))))))
+ (indent-according-to-mode)
+
+ ;; Closes incomplete multiline comment.
+ (when (and swift-mode:auto-close-multiline-comment
+ (not is-single-line-comment)
+ (swift-mode:incomplete-comment-p))
+ (save-excursion
+ (end-of-line)
+ (if soft (insert-and-inherit ?\n) (newline 1))
+ (insert-before-markers-and-inherit "*/")
+ (indent-according-to-mode)))))
+
+(defun swift-mode:post-self-insert ()
+ (cond
+ ((and
+ (= last-command-event ?*)
+ (nth 4 (syntax-ppss))
+ (save-excursion (backward-char) (skip-syntax-backward " ") (bolp)))
+ (when swift-mode:insert-space-after-asterisk-in-comment
+ (insert-before-markers-and-inherit " "))
+ (indent-according-to-mode))
+ ((and
+ (= last-command-event ?/)
+ swift-mode:fix-comment-close
+ (nth 4 (syntax-ppss))
+ (save-excursion
+ (let ((pos (point)))
+ (beginning-of-line)
+ (and
+ (looking-at "^[ ]*\\*[ ]+/")
+ (eq (match-end 0) pos)
+ (swift-mode:incomplete-comment-p)))))
+ (backward-char)
+ (delete-horizontal-space)
+ (forward-char))))
+
+(provide 'swift-mode-indent)
+
+;;; swift-mode-indent.el ends here
diff --git a/swift-mode-lexer.el b/swift-mode-lexer.el
new file mode 100644
index 0000000..d5c1ed8
--- /dev/null
+++ b/swift-mode-lexer.el
@@ -0,0 +1,883 @@
+;;; swift-mode-lexer.el --- Major-mode for Apple's Swift programming language,
lexer. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 taku0, Chris Barrett, Bozhidar Batsov, Arthur
Evstifeev
+
+;; Authors: taku0 (http://github.com/taku0)
+;; Chris Barrett <chris.d.barrett@me.com>
+;; Bozhidar Batsov <bozhidar@batsov.com>
+;; Arthur Evstifeev <lod@pisem.net>
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Routines for Swift tokens
+
+;; Token is a tuple consists of:
+;;
+;; - Token type
+;; - Token text
+;; - Start position (inclusive)
+;; - End position (exclusive)
+
+;;; Code:
+
+(declare-function swift-mode:backward-sexps-until "swift-mode-indent.el"
+ (token-types
+ &optional
+ stop-at-eol-token-types
+ stop-at-bol-token-types))
+
+(defun swift-mode:token (type text start end)
+ "Construct and returns a token."
+ (list type text start end))
+
+(defun swift-mode:token:type (token)
+ "Return the type of TOKEN."
+ (nth 0 token))
+
+(defun swift-mode:token:text (token)
+ "Return the text of TOKEN."
+ (nth 1 token))
+
+(defun swift-mode:token:start (token)
+ "Return the start position of TOKEN."
+ (nth 2 token))
+
+(defun swift-mode:token:end (token)
+ "Return the end position of TOKEN."
+ (nth 3 token))
+
+;; Token types is one of the follwing symbols:
+;;
+;; - prefix-operator (including try, try?, and try!)
+;; - postfix-operator
+;; - binary-operator (including as, as?, as!, is, =, ., and ->)
+;; - identifier (including keywords, numbers, implicit parameters, and unknown
tokens)
+;; - [
+;; - ]
+;; - {
+;; - }
+;; - (
+;; - )
+;; - ,
+;; - ;
+;; - implicit-;
+;; - < (as an angle bracket)
+;; - > (as an angle bracket)
+;; - typing-: (colon for supertype declaration or type declaration of let or
var)
+;; - 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)
+;; - outside-of-buffer
+;;
+;; Additionaly, `swift-mode:backward-token-or-list' may return a parenthesized
+;; expression as a token with one of the following types:
+;; - ()
+;; - []
+;; - {}
+;; - <>
+
+;;; Syntax table
+
+(defconst swift-mode:syntax-table
+ (let ((table (make-syntax-table)))
+ ;; Whitespace characters
+ ;; Word constituents
+
+ ;; Symbol constituents
+ (modify-syntax-entry ?_ "_" table)
+ (modify-syntax-entry ?$ "_" table)
+ (modify-syntax-entry ?@ "_" table)
+ (modify-syntax-entry ?# "_" table)
+
+ ;; Punctuation characters
+ ;;
+ ;; Operators
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410
+ ;; TODO Unicode operators
+ ;;
+ ;; / and * will be overridden below as comment delimiters
+ (mapc (lambda (c) (modify-syntax-entry c "." table)) "/=-+!*%<>&|^~?.")
+ ;; Separators
+ (mapc (lambda (c) (modify-syntax-entry c "." table)) ",;")
+
+ ;; Parenthesis characters
+ (modify-syntax-entry ?\( "()" table)
+ (modify-syntax-entry ?\) ")(" table)
+ (modify-syntax-entry ?\[ "(]" table)
+ (modify-syntax-entry ?\] ")[" table)
+ (modify-syntax-entry ?{ "(}" table)
+ (modify-syntax-entry ?} "){" table)
+
+ ;; String quotes
+ (modify-syntax-entry ?\" "\"" table)
+ (modify-syntax-entry ?` "\"" table)
+
+ ;; Escape-syntax characters
+ (modify-syntax-entry ?\\ "\\" table)
+
+ ;; Character quotes
+ ;; Paired delimiters
+ ;; Expression prefixes
+
+ ;; Comments
+ (modify-syntax-entry ?/ ". 124b" table)
+ (modify-syntax-entry ?* ". 23n" table)
+ (modify-syntax-entry ?\n "> b" table)
+ (modify-syntax-entry ?\r "> b" table)
+
+ table))
+
+
+;;; Lexers
+
+(defun swift-mode:implicit-semi-p ()
+ "Return t if the cursor is after the end of a statement."
+ (let
+ ((previous-token (save-excursion
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:backward-token-simple))))
+ (next-token (save-excursion
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:forward-token-simple)))))
+ ;; If the cursor is on the empty line, pretend an identifier is the line.
+ (when (and
+ (< (swift-mode:token:end previous-token) (line-beginning-position))
+ (< (line-end-position) (swift-mode:token:start next-token)))
+ (setq next-token (swift-mode:token 'identifier "" (point) (point))))
+ (cond
+ ((or
+ ;; Supresses implicit semicolon around binary operators and separators.
+ (memq (swift-mode:token:type previous-token)
+ '(binary-operator \; \, :))
+ (memq (swift-mode:token:type next-token)
+ '(binary-operator \; \, :))
+
+ ;; Supresses implicit semicolon after try, try?, and try!.
+ (member (swift-mode:token:text previous-token)
+ '("try" "try?" "try!"))
+
+ ;; Suppress implicit semicolon after open brackets or before close
+ ;; brackets.
+ (memq (swift-mode:token:type previous-token) '({ \( \[))
+ (memq (swift-mode:token:type next-token) '(} \) \]))
+
+ ;; Suppress implicit semicolon around keywords that cannot start or end
+ ;; statements.
+ (member (swift-mode:token:text previous-token)
+ '("inout" "throws" "rethrows" "in" "where"))
+ (member (swift-mode:token:text next-token)
+ '("inout" "throws" "rethrows" "in" "where")))
+ nil)
+
+ ;; Inserts implicit semicolon around #... directives.
+ ;;
+ ;; Note that we cannot split #if line; the following code is not allowed.
+ ;;
+ ;; #if
+ ;; true
+ ;; #end if
+ ((and
+ (or
+ (string-prefix-p "#" (swift-mode:token:text previous-token))
+ (string-prefix-p "#" (swift-mode:token:text next-token)))
+ (not (member (swift-mode:token:text previous-token)
+ '("#file" "#line" "column" "#function")))
+ (not (member (swift-mode:token:text next-token)
+ '("#file" "#line" "column" "#function"))))
+ t)
+
+ ;; Suppress implicit semicolon after modifiers.
+ ((member (swift-mode:token:text previous-token)
+ '("indirect" "convenience" "dynamic" "final" "infix" "lazy"
+ "mutating" "nonmutating" "optional" "override" "postfix"
+ "prefix" "required" "static" "unowned" "weak" "internal"
+ "private" "public" "open" "fileprivate"))
+ nil)
+
+ ;; internal(set) private(set) public(set) open(set) fileprivate(set)
+ ;; unowned(safe) unowned(unsafe)
+ ((and
+ (eq (swift-mode:token:type previous-token) '\))
+ (save-excursion
+ (and
+ (eq (swift-mode:token:type (swift-mode:backward-token-simple)) '\))
+ (member (swift-mode:token:text (swift-mode:backward-token-simple))
+ '("set" "safe" "unsafe"))
+ (eq (swift-mode:token:type (swift-mode:backward-token-simple)) '\()
+ (member (swift-mode:token:text
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:backward-token-simple)))
+ '("unowned" "internal" "private" "public" "open"
+ "fileprivate")))))
+ nil)
+
+ ;; Insert implicit semicolon before modifiers.
+ ;;
+ ;; Preceding mofidiers takes precedence over this.
+ ((member (swift-mode:token:text next-token)
+ '("indirect" "convenience" "dynamic" "final" "infix" "lazy"
+ "mutating" "nonmutating" "optional" "override" "postfix"
+ "prefix" "required" "static" "unowned" "weak" "internal"
+ "private" "public" "open" "fileprivate"))
+ t)
+
+ ;; Inserts implicit semicolon around keywords that forms single keyword
+ ;; statements.
+ ((or
+ (member (swift-mode:token:text previous-token)
+ '("break" "continue" "fallthrough"))
+ (member (swift-mode:token:text next-token)
+ '("break" "continue" "fallthrough")))
+ t)
+
+ ;; Suppress implicit semicolon after keywords that cannot end statements.
+ ((member (swift-mode:token:text previous-token)
+ '("while" "for" "switch" "case" "default" "catch" "if" "guard"
+ "let" "var" "throw" "import" "return"))
+ nil)
+
+ ;; Inserts implicit semicolon before keywords that starts a new
+ ;; statement.
+ ((member (swift-mode:token:text next-token)
+ '("for" "repeat" "switch" "case" "default" "defer" "do" "if"
+ "guard" "let" "var" "throw" "import" "return"))
+ t)
+
+ ;; Inserts implicit semicolon before `while' unless it is part of
+ ;; `repeat...while'.
+ ((equal (swift-mode:token:text next-token) "while")
+ (save-excursion
+ (not
+ (and
+ (eq (swift-mode:token:type previous-token) '\})
+ (progn
+ (backward-list)
+ (equal (swift-mode:token:text
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:backward-token-simple)))
+ "repeat"))))))
+
+ ;; Inserts implicit around else
+ ((or
+ (equal (swift-mode:token:text previous-token) "else")
+ (equal (swift-mode:token:text next-token) "else"))
+ t)
+
+ ;; Supress implicit semicolon after attributes.
+ ((string-prefix-p "@" (swift-mode:token:text previous-token)) nil)
+
+ ;; Inserts implicit semicolon before keywords that behave like method
+ ;; names.
+ ((member (swift-mode:token:text next-token)
+ '("get" "set" "willSet" "didSet" "subscript" "init" "deinit"))
+ t)
+
+ ;; Suppress implicit semicolon after keywords that behave like method
+ ;; names.
+ ;;
+ ;; Note that binary operators take precedence over this:
+ ;;
+ ;; self . // not insert semicolon here
+ ;; init
+ ((member (swift-mode:token:text previous-token)
+ '("set" "willSet" "didSet" "subscript" "init" "deinit"))
+ nil)
+
+ ;; Suppress implicit semicolon after declaration starters.
+ ((member (swift-mode:token:text previous-token)
+ '("class" "struct" "protocol" "enum" "extension" "func"
+ "typealias""associatedtype" "precedencegroup" "operator"))
+ nil)
+
+ ;; Inserts implicit semicolon before declaration starters.
+ ;; Modifiers take precedence over this.
+ ;;
+ ;; Notes that class-requirement is handled by the `:' rule above:
+ ;;
+ ;; protocol Foo: // not insert semicolon here
+ ;; class
+ ;;
+ ;; `protocol' is handled by the next rule
+ ((member (swift-mode:token:text next-token)
+ '("class" "struct" "enum" "extension" "func" "typealias"
+ "associatedtype" "precedencegroup"))
+ t)
+
+ ;; Inserts implicit semicolon before protocol unless it is followed by <.
+ ((equal "protocol" (swift-mode:token:text next-token))
+ (not (equal (swift-mode:token:text
+ (save-excursion
+ (swift-mode:forward-token-simple)
+ (swift-mode:forward-token-simple)))
+ "<")))
+
+ ;; Inserts implicit semicolon before attributes unless other condtions
+ ;; met.
+ ((string-prefix-p "@" (swift-mode:token:text previous-token)) t)
+
+ ;; Inserts implicit semicolon before open square bracket.
+ ;;
+ ;; Open square bracket for array indexing cannot appear at the start of a
+ ;; line.
+ ;;
https://github.com/apple/swift/blob/8d4b1cc3c47c7624d57f188d5b227152ccb03163/lib/Parse/ParseExpr.cpp#L1525
+ ;;
+ ;; Note that the following pattern (i.e. after binary-operator) is handled
+ ;; by above case.
+ ;;
+ ;; let x =
+ ;; [
+ ;; 1
+ ;; ]
+ ((eq (swift-mode:token:type next-token) '\[) t)
+
+ ;; Inserts implicit semicolon before open parenthesis.
+ ;;
+ ;; Open parenthesis for function arguments cannot appear at the start of a
+ ;; line.
+ ;;
https://github.com/apple/swift/blob/8d4b1cc3c47c7624d57f188d5b227152ccb03163/lib/Parse/ParseExpr.cpp#L1251
+ ;;
+ ;; Note that the following pattern (i.e. after binary-operator) is handled
+ ;; by above case.
+ ;;
+ ;; let x =
+ ;; (
+ ;; 1
+ ;; )
+ ((eq (swift-mode:token:type next-token) '\() t)
+
+ ;; Inserts semicolon before open curly bracket.
+ ;;
+ ;; Open curly bracket may continue the previous line, but we do not indent
+ ;; there. For example, the code below is parsed as `(foo() { x in ... })'
+ ;; by the Swift compiler, but we indent it like `foo(); { x in ... }'.
+ ;;
+ ;; foo()
+ ;; { // does not indent here
+ ;; x in
+ ;; ...
+ ;; }
+ ((eq (swift-mode:token:type next-token) '\{) t)
+
+ ;; Otherwise, inserts implicit semicolon.
+ (t t))))
+
+(defun swift-mode:type-colon-p ()
+ "Return t if a colon at the cursor is the colon for type annotation.
+
+That is supertype declaration or type declaration of let or var."
+ (save-excursion
+ (let ((previous-token (swift-mode:backward-token-simple)))
+ ;; class Foo<T>: Bar ← type colon
+ ;; class Foo<T> : Bar ← type colon
+ ;; class Foo<T where T: Bar<[(Int, String)]>> : Bar ← type colon
+ ;; case Foo: ← not a type colon
+ ;; case Foo where foo: ← not a type colon
+ ;; default: ← not a type colon
+ ;; foo ? bar : baz ← not a type colon
+ ;; [
+ ;; foo: ← not a type colon
+ ;; bar
+ ;; ]
+ ;; foo(bar, baz: baz) ← not a type colon
+ (or
+ (eq (swift-mode:token:type previous-token) '>)
+ ;; class Foo: ← type colon
+ ;; extension Foo: ← type colon
+ ;; let foo: ← type colon
+ ;; var foo: ← type colon
+ ;; protocol Foo {
+ ;; typealias Bar: Baz ← type colon
+ ;; }
+ (member (swift-mode:token:text
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:backward-token-simple)))
+ '("class" "extension" "enum" "struct" "protocol" "typealias"
+ "associatedtype" "let" "var"))))))
+
+(defun swift-mode:case-colon-p ()
+ "Return t if a colon at the cursor is the colon for case or default label."
+ (save-excursion
+ (member
+ ;; This function can be confused by conditional operator.
+ ;;
+ ;;
+ ;; switch foo {
+ ;; case let x where x is Foo ?
+ ;; a : // This function should return nil but it
+ ;; // 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.
+ ;; }
+
+ ;; FIXME: mutual dependency
+ (swift-mode:token:text
+ (swift-mode:backward-sexps-until
+ '(implicit-\; \; { \( \[ "case" "default" 'case-:)))
+ '("case" "default"))))
+
+(defun swift-mode:anonyous-parameter-in-p ()
+ "Return t if a 'in' token at the cursor is for anonymous function
parameters."
+ (save-excursion
+ (eq
+ ;; FIXME: mutual dependency
+ (swift-mode:token:type (swift-mode:backward-sexps-until
+ '(\; { \( \[ "for")))
+ '{)))
+
+(defun swift-mode:fix-operator-type (token)
+ "Return new operator token with proper token type."
+ ;; Operator type (i.e. prefix, postfix, infix) is decided from spaces or
+ ;; comments around the operator.
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410
+ ;;
https://github.com/apple/swift-evolution/blob/master/proposals/0037-clarify-comments-and-operators.md
+ (let*
+ ((text (swift-mode:token:text token))
+ (start (swift-mode:token:start token))
+ (end (swift-mode:token:end token))
+ (has-preceding-space (or
+ (= start (point-min))
+ (memq (char-syntax (char-before start)) '(? ?>))
+ (nth 4 (save-excursion
+ (syntax-ppss (1- start))))))
+ (has-following-space (or
+ (= end (point-max))
+ (memq (char-syntax (char-after end)) '(? ?<))
+ (save-excursion (goto-char end)
+ (looking-at "/\\*\\|//"))
+ (= (char-after end) ?\C-j)))
+ (has-following-dot (eq (char-after end) ?.))
+ (is-declaration (save-excursion
+ ;; i.e.
+ ;; func +++(x1: X, x2: X)
+ ;; or operator declarations.
+ (goto-char start)
+ (member
+ (swift-mode:token:text
+ (swift-mode:backquote-identifier-if-after-dot
+ (swift-mode:backward-token-simple)))
+ '("func" "operator"))))
+ (type
+ (cond
+ (is-declaration 'identifier)
+ ((member text '("try" "try?" "try!")) 'prefix-operator)
+ ((equal text ".") 'binary-operator)
+ ((and has-preceding-space has-following-space) 'binary-operator)
+ (has-preceding-space 'prefix-operator)
+ ((or has-following-space has-following-dot) 'postfix-operator)
+ (t 'binary-operator))))
+ (swift-mode:token type text start end)))
+
+(defun swift-mode:backquote-identifier-if-after-dot (token)
+ "Backquote identifiers including keywords if it is after dot.
+
+See SE-0071:
+https://github.com/apple/swift-evolution/blob/master/proposals/0071-member-keywords.md"
+ (if (and (string-match "^[a-z]" (swift-mode:token:text token))
+ (save-excursion
+ (goto-char (swift-mode:token:start token))
+ (equal (swift-mode:token:text (swift-mode:backward-token-simple))
+ ".")))
+ (swift-mode:token
+ 'identifier
+ (concat "`" (swift-mode:token:text token) "`")
+ (swift-mode:token:start token)
+ (swift-mode:token:end token))
+ token))
+
+(defun swift-mode:forward-token ()
+ "Move point forward to the next position of the end of a token.
+
+Return the token object. If no more tokens available, return a token with
+type `out-of-buffer'"
+
+ (let ((pos (point)))
+ (forward-comment (point-max))
+ (cond
+ ;; Outside of buffer
+ ((eobp)
+ (swift-mode:token 'outside-of-buffer "" (point) (point)))
+
+ ;; Implicit semicolon
+ ((and (< pos
+ (save-excursion
+ (swift-mode:goto-non-comment-bol)
+ (point)))
+ (save-excursion (goto-char pos) (swift-mode:implicit-semi-p)))
+
+ (swift-mode:token 'implicit-\;
+ (buffer-substring-no-properties pos (point))
+ pos
+ (point)))
+
+ ;; Colon
+ ((eq (char-after) ?:)
+ (swift-mode:token (cond
+ ((swift-mode:type-colon-p) 'typing-:)
+ ((swift-mode:case-colon-p) 'case-:)
+ (t ':))
+ ":"
+ (progn (forward-char) (1- (point)))
+ (point)))
+
+ (t
+ (let ((token (swift-mode:forward-token-simple)))
+ (setq token (swift-mode:backquote-identifier-if-after-dot token))
+
+ (when (and (equal (swift-mode:token:text token) "in")
+ (save-excursion
+ (goto-char (swift-mode:token:start token))
+ (swift-mode:anonyous-parameter-in-p)))
+ (setq token
+ (swift-mode:token
+ 'anonymous-function-parameter-in
+ "in"
+ (swift-mode:token:start token)
+ (swift-mode:token:end token))))
+
+ token)))))
+
+(defun swift-mode:forward-token-simple ()
+ "Like `swift-mode:forward-token' without recursion, and never produces
+`implicit-;' or `type-:'."
+ (forward-comment (point-max))
+ (cond
+ ;; Outside of buffer
+ ((eobp)
+ (swift-mode:token 'outside-of-buffer "" (point) (point)))
+
+ ;; Separators and parentheses
+ ((memq (char-after) '(?, ?\; ?\{ ?\} ?\[ ?\] ?\( ?\) ?:))
+ (forward-char)
+ (swift-mode:token (intern (string (char-before)))
+ (string (char-before))
+ (1- (point))
+ (point)))
+
+ ;; Open angle bracket for type parameters
+ ;;
+ ;; We use a heuristic: spaces are inserted around inequality sign, but not
+ ;; for angle bracket, and a type paramer starts with an upper case
+ ;; character, a square bracket, a parenthesis, or keyword 'protocol'.
+ ((and (eq (char-after) ?<)
+ (looking-at "<\\([[:upper:]\\[[(]\\|protocol\\)"))
+ (forward-char)
+ (swift-mode:token '< "<" (1- (point)) (point)))
+
+ ;; Close angle bracket for type parameters
+ ;;
+ ;; Close angle bracket follows identifier, a square bracket, a parenthesis,
+ ;; or another another bracket (e.g. Foo<Bar<[(Int, String)]>>)
+ ((and (eq (char-after) ?>)
+ (save-excursion
+ ;; You know that regular language can be reversed. Thus you may
+ ;; think that `looking-back' reverse the given regexp and scan
+ ;; chars backwards. Nevertheless, `looking' function does not
+ ;; do that. It just repeats `looking-at' with decrementing start
+ ;; position until it succeeds. The document says that it is not
+ ;; recommended to use. So using `skip-chars-backward',
+ ;; `skip-syntax-backward', and `looking-at' here.
+ (skip-chars-backward "])>")
+ (skip-syntax-backward "w_")
+ (looking-at "[[:upper:]_]")))
+ (forward-char)
+ (swift-mode:token '> ">" (1- (point)) (point)))
+
+ ;; Operator (other than as, try, or is)
+ ;;
+ ;; Operators starts with a dot can contains dots. Other operators cannot
+ ;; contain dots.
+ ;;
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/dot-operator-head
+ ((looking-at "[-/=+!*%<>&|^~?]+\\|[.][-./=+!*%<>&|^~?]*")
+ (let*
+ ((text (match-string-no-properties 0))
+ (start (match-beginning 0))
+ (end (match-end 0)))
+ (when (string-match ".*/\\*\\|.*//" text)
+ ;; e.g. +++/* */ or +++//
+ (setq end
+ (- end
+ (- (length text) (- (match-end 0) 2))))
+ (setq text (substring text 0 (- (match-end 0) 2))))
+ (goto-char end)
+ (swift-mode:fix-operator-type
+ (swift-mode:token nil text start end))))
+
+ ;; String and backquoted identifer
+ ((memq (char-after) '(?\" ?`))
+ (let ((pos-after-comment (point)))
+ (goto-char (scan-sexps (point) 1))
+ (swift-mode:token
+ 'identifier
+ (buffer-substring-no-properties pos-after-comment (point))
+ pos-after-comment
+ (point))))
+
+ ;; Other tokens including identifers, implicit parameters, keywords, and
+ ;; numbers
+ (t
+ (let*
+ ((pos-after-comment (point))
+ (text
+ (cond
+ ;; Identifers, implicit parameters, keywords, numbers
+ ;;
+ ;; Note: syntax class _ includes #, @, and $.
+ ((memq (char-syntax (char-after)) '(?w ?_))
+ (progn (forward-symbol 1)
+ (buffer-substring-no-properties pos-after-comment
+ (point))))
+ ;; Unknown character type. Treats as a single-letter token.
+ (t (forward-char) (string (char-before))))))
+ (cond
+ ((member text '("as" "try"))
+ ;; as?, as!, try?, or try!
+ (when (member (char-after) '(?? ?!))
+ (forward-char)
+ (setq text (concat text (list (char-before)))))
+ (swift-mode:token (if (member text '("as" "as?" "as!"))
+ 'binary-operator
+ 'prefix-operator)
+ text
+ (- (point) (length text))
+ (point)))
+ ((equal text "is")
+ (swift-mode:token 'binary-operator
+ text
+ (- (point) (length text))
+ (point)))
+ (t
+ (swift-mode:token 'identifer
+ text
+ (- (point) (length text))
+ (point))))))))
+
+(defun swift-mode:backward-token ()
+ "Move point backward to the previous position of the end of a token.
+
+Return the token object. If no more tokens available, return a token with
+type `out-of-buffer'."
+
+ (let ((pos (point)))
+ (forward-comment (- (point)))
+ (cond
+ ;; Outside of buffer
+ ((bobp)
+ (swift-mode:token 'outside-of-buffer "" (point) (point)))
+
+ ;; Implicit semicolon
+ ((and (< (save-excursion
+ (swift-mode:goto-non-comment-eol)
+ (point))
+ pos)
+ (save-excursion (goto-char pos) (swift-mode:implicit-semi-p)))
+ (swift-mode:token 'implicit-\;
+ (buffer-substring-no-properties (point) pos)
+ (point)
+ pos))
+
+ ;; Colon
+ ((eq (char-before) ?:)
+ (backward-char)
+ (swift-mode:token (cond
+ ((swift-mode:type-colon-p) 'typing-:)
+ ((swift-mode:case-colon-p) 'case-:)
+ (t ':))
+ ":"
+ (point)
+ (1+ (point))))
+
+ (t
+ (let ((token (swift-mode:backward-token-simple)))
+ (setq token (swift-mode:backquote-identifier-if-after-dot token))
+
+ (when (and (equal (swift-mode:token:text token) "in")
+ (save-excursion
+ (goto-char (swift-mode:token:start token))
+ (swift-mode:anonyous-parameter-in-p)))
+ (setq token
+ (swift-mode:token
+ 'anonymous-function-parameter-in
+ "in"
+ (swift-mode:token:start token)
+ (swift-mode:token:end token))))
+ token)))))
+
+(defun swift-mode:backward-token-simple ()
+ "Like `swift-mode:backward-token' without recursion, and never produces
+`implicit-;' or `type-:'."
+ (forward-comment (- (point)))
+ (cond
+ ;; Outside of buffer
+ ((bobp)
+ (swift-mode:token 'outside-of-buffer "" (point) (point)))
+
+ ;; Separators and parentheses
+ ((memq (char-before) '(?, ?\; ?\{ ?\} ?\[ ?\] ?\( ?\) ?:))
+ (backward-char)
+ (swift-mode:token (intern (string (char-after)))
+ (string (char-after))
+ (point)
+ (1+ (point))))
+
+ ;; >! or >?
+ ((and (memq (char-before) '(?! ??))
+ (eq (char-before (1- (point))) ?>)
+ (save-excursion
+ (backward-char)
+ (eq (swift-mode:token:type (swift-mode:backward-token-simple))
+ '>)))
+ (backward-char)
+ (swift-mode:token (intern (string (char-after)))
+ (string (char-after))
+ (point)
+ (1+ (point))))
+
+ ;; Open angle bracket for type parameters
+ ;;
+ ;; We use a heuristic: spaces are inserted around inequality sign, but not
+ ;; for angle bracket, and a type paramer starts with an upper case
+ ;; character, a square bracket, a parenthesis, or keyword `protocol'.
+ ((and (eq (char-before) ?<)
+ (looking-at "\\([[:upper:]\\[[(]\\|protocol\\)"))
+ (backward-char)
+ (swift-mode:token '< "<" (point) (1+ (point))))
+
+ ;; Close angle bracket for type parameters
+ ;;
+ ;; Close angle bracket follows identifier, a square bracket, a parenthesis,
+ ;; or another another bracket (e.g. Foo<Bar<[(Int, String)]>>)
+ ((and (eq (char-before) ?>)
+ (save-excursion
+ (skip-chars-backward "])>")
+ (skip-syntax-backward "w_")
+ (looking-at "[[:upper:]_]")))
+ (backward-char)
+ (swift-mode:token '> ">" (point) (1+ (point))))
+
+ ;; Operator (other than as, try, or is)
+ ;;
+ ;; Operators which starts with a dot can contain other dots. Other
+ ;; operators cannot contain dots.
+ ;;
+ ;;
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/dot-operator-head
+ ((memq (char-before) '(?. ?- ?/ ?= ?+ ?! ?* ?% ?< ?> ?& ?| ?^ ?~ ??))
+ (let ((point-before-comments (point)))
+ (skip-chars-backward "-./=+!*%<>&|^~?")
+ (cond
+ ((save-excursion
+ (forward-symbol -1)
+ (and (looking-at "\\(as\\|try\\)[?!]")
+ (= point-before-comments (match-end 0))))
+ ;; as?, as!, try?, try!
+ t)
+ ((looking-at "[.][-./=+!*%<>&|^~?]*")
+ ;; e.g. 1 .++++.++++...+. 1
+ t)
+ ((and (looking-at "[-/=+!*%<>&|^~?]+")
+ (<= point-before-comments (match-end 0)))
+ ;; e.g. 1 +++++++++ 1
+ t)
+ (t
+ ;; e.g. 1+++++...++++1, that is (1+++++) ...++++ 1
+ (skip-chars-forward "-/=+!*%<>&|^~?")
+ (looking-at "[.][-./=+!*%<>&|^~?]*")))
+ (let*
+ ((start (match-beginning 0))
+ (end (min point-before-comments (match-end 0)))
+ (text (substring (match-string-no-properties 0) 0 (- end start))))
+ (goto-char start)
+ (swift-mode:fix-operator-type
+ (swift-mode:token nil text start end)))))
+
+ ;; String and backquoted identifer
+ ((memq (char-before) '(?\" ?`))
+ (let ((pos-before-comment (point)))
+ (goto-char (scan-sexps (point) -1))
+ (swift-mode:token
+ 'identifier
+ (buffer-substring-no-properties (point) pos-before-comment)
+ (point)
+ pos-before-comment)))
+
+ ;; Other tokens including identifers, implicit parameters, keywords, and
+ ;; numbers
+ (t
+ (let*
+ ((pos-before-comment (point))
+ (text
+ (cond
+ ;; Identifers, implicit parameters, keywords, numbers
+ ;;
+ ;; Note: syntax class _ includes #, @, and $.
+ ((memq (char-syntax (char-before)) '(?w ?_))
+ (progn (forward-symbol -1)
+ (buffer-substring-no-properties (point)
+ pos-before-comment)))
+ ;; Unknown character type. Treats as a single-letter token.
+ (t (backward-char) (string (char-after))))))
+ (cond
+ ((member text '("is" "as"))
+ (swift-mode:token 'binary-operator
+ text
+ (point)
+ (+ (point) (length text))))
+ ((equal text "try")
+ (swift-mode:token 'prefix-operator
+ text
+ (point)
+ (+ (point) (length text))))
+ (t
+ (swift-mode:token 'identifier
+ text
+ (point)
+ (+ (point) (length text)))))))))
+
+(defun swift-mode:goto-non-comment-bol ()
+ "Back to the beginning of line that is not inside a comment."
+ (beginning-of-line)
+ (while (nth 4 (syntax-ppss))
+ ;; The cursor is in a comment. Backs to the beginning of the comment.
+ (goto-char (nth 8 (syntax-ppss)))
+ (beginning-of-line)))
+
+(defun swift-mode:goto-non-comment-eol ()
+ "Proceed to the end of line that is not inside a comment.
+
+If this line ends with a single-line comment, goto just before the comment."
+ (end-of-line)
+ (while (nth 4 (syntax-ppss))
+ ;; The cursor is in a comment.
+ (if (eq (nth 4 (syntax-ppss)) t)
+ ;; This ia a single-line comment
+ ;; Back to the beginning of the comment.
+ (goto-char (nth 8 (syntax-ppss)))
+ ;; This is a multiline comment
+ ;; Proceed to the end of the comment.
+ (goto-char (nth 8 (syntax-ppss)))
+ (forward-comment 1)
+ (end-of-line))))
+
+(provide 'swift-mode-lexer)
+
+;;; swift-mode-lexer.el ends here
diff --git a/swift-mode-repl.el b/swift-mode-repl.el
new file mode 100644
index 0000000..e4198d8
--- /dev/null
+++ b/swift-mode-repl.el
@@ -0,0 +1,108 @@
+;;; swift-mode-repl.el --- Run Apple's Swift processes in Emacs buffers -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 taku0, Chris Barrett, Bozhidar Batsov, Arthur
Evstifeev
+
+;; Authors: taku0 (http://github.com/taku0)
+;; Chris Barrett <chris.d.barrett@me.com>
+;; Bozhidar Batsov <bozhidar@batsov.com>
+;; Arthur Evstifeev <lod@pisem.net>
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Run Apple's Swift processes in Emacs buffers.
+
+;;; Code:
+
+(require 'comint)
+
+(defcustom swift-mode:repl-executable
+ "xcrun swift"
+ "Path to the Swift CLI."
+ :type 'string
+ :group 'swift
+ :safe 'stringp)
+
+(defvar swift-mode:repl-buffer nil
+ "Stores the name of the current swift REPL buffer, or nil.")
+
+;;;###autoload
+(defun swift-mode:run-repl (cmd &optional dont-switch)
+ "Run a Swift REPL process.
+It input and output via buffer `*CMD*' where CMD is replaced with the CMD
given.
+If there is a process already running in `*CMD*', switch to that buffer.
+With argument CMD allows you to edit the command line (default is value
+of `swift-mode:repl-executable'). This function updates the buffer local
+variable `swift-mode:repl-executable' with the given CMD, so it will be used
+as the default value for the next invocatoin in the current buffer.
+With DONT-SWITCH cursor will stay in current buffer.
+Runs the hook `swift-repl-mode-hook' \(after the `comint-mode-hook' is run).
+\(Type \\[describe-mode] in the process buffer for a list of commands.)"
+
+ (interactive
+ (list (if current-prefix-arg
+ (read-string "Run swift REPL: " swift-mode:repl-executable)
+ swift-mode:repl-executable)))
+ (unless (comint-check-proc (concat "*" cmd "*"))
+ (save-excursion
+ (let ((cmdlist (split-string cmd)))
+ (set-buffer
+ (apply 'make-comint cmd (car cmdlist) nil (cdr cmdlist)))
+ (swift-repl-mode))))
+ (setq-local swift-mode:repl-executable cmd)
+ (setq-local swift-mode:repl-buffer (concat "*" cmd "*"))
+ (setq-default swift-mode:repl-buffer swift-mode:repl-buffer)
+ (unless dont-switch
+ (pop-to-buffer swift-mode:repl-buffer)))
+
+;;;###autoload
+(defalias 'run-swift 'swift-mode:run-repl)
+
+;;;###autoload
+(defun swift-mode:send-region (start end)
+ "Send the current region to the inferior swift process.
+START and END define region within current buffer"
+ (interactive "r")
+ (swift-mode:run-repl swift-mode:repl-executable t)
+ (comint-send-region swift-mode:repl-buffer start end)
+ (comint-send-string swift-mode:repl-buffer "\n"))
+
+;;;###autoload
+(defun swift-mode:send-buffer ()
+ "Send the buffer to the Swift REPL process."
+ (interactive)
+ (swift-mode:send-region (point-min) (point-max)))
+
+(define-derived-mode swift-repl-mode comint-mode "Swift REPL"
+ "Major mode for interacting with Swift REPL.
+
+A REPL can be fired up with M-x swift-mode:run-repl or M-x run-swift.
+
+Customization: Entry to this mode runs the hooks on comint-mode-hook and
+swift-repl-mode-hook (in that order).
+
+You can send text to the REPL process from other buffers containing source.
+ swift-mode:send-region sends the current region to the REPL process,
+ swift-mode:send-buffer sends the current buffer to the REPL process.")
+
+(provide 'swift-mode-repl)
+
+;;; swift-mode-repl.el ends here
diff --git a/swift-mode.el b/swift-mode.el
index 206a8e2..0c02e9b 100644
--- a/swift-mode.el
+++ b/swift-mode.el
@@ -1,13 +1,16 @@
;;; swift-mode.el --- Major-mode for Apple's Swift programming language. -*-
lexical-binding: t -*-
-;; Copyright (C) 2014-2016 Chris Barrett, Bozhidar Batsov, Arthur Evstifeev
+;; Copyright (C) 2014-2016 taku0, Chris Barrett, Bozhidar Batsov, Arthur
Evstifeev
-;; Authors: Chris Barrett <chris.d.barrett@me.com>
+;; Authors: taku0 (http://github.com/taku0)
+;; Chris Barrett <chris.d.barrett@me.com>
;; Bozhidar Batsov <bozhidar@batsov.com>
;; Arthur Evstifeev <lod@pisem.net>
-;; Version: 0.5.0-snapshot
+;;
+;; Version: 2.1
;; Package-Requires: ((emacs "24.4"))
;; Keywords: languages swift
+;; URL: https://github.com/swift-emacs/swift-mode
;; This file is not part of GNU Emacs.
@@ -30,763 +33,28 @@
;;; Code:
-(require 'rx)
-(require 'comint)
-(require 'cl-lib)
+(require 'swift-mode-lexer)
+(require 'swift-mode-indent)
+(require 'swift-mode-font-lock)
+(require 'swift-mode-beginning-of-defun)
+(require 'swift-mode-repl)
+;;;###autoload
(defgroup swift nil
- "Configuration for swift-mode."
+ "Major-mode for Apple's Swift programming language."
:group 'languages
- :prefix "swift-")
-
-(defcustom swift-indent-offset 4
- "Defines the indentation offset for Swift code."
- :group 'swift
- :type 'integer)
-
-(defcustom swift-indent-switch-case-offset 0
- "Defines the indentation offset for cases in a switch statement."
- :group 'swift
- :type 'integer)
-
-(defcustom swift-indent-multiline-statement-offset 2
- "Defines the indentation offset for multiline statements."
- :group 'swift
- :type 'integer
- :package-version '(swift-mode "0.3.0"))
-
-(defcustom swift-indent-hanging-comma-offset nil
- "Defines the indentation offset for hanging comma."
- :group 'swift
- :type '(choice (const :tag "Use default relative formatting" nil)
- (integer :tag "Custom offset"))
- :package-version '(swift-mode "0.4.0"))
-
-(defcustom swift-repl-executable
- "xcrun swift"
- "Path to the Swift CLI."
- :group 'swift)
-
-;;; Indentation
-
-(require 'smie)
-
-(defconst swift-smie-grammar
- (smie-prec2->grammar
- (smie-merge-prec2s
- (smie-bnf->prec2
- '((id)
- (type (type) (type "<T" types "T>") ("[" type "]"))
- (types (type) (type "," type))
-
- (class-decl-exp (id) (id ":" types))
- (decl-exp (id) (id ":" type))
- (decl-exps (decl-exp) (decl-exp "," decl-exp))
-
- (assign-exp (decl-exp) (id "=" exp))
-
- (decl (decl ";" decl))
- (decl (let-decl) (var-decl))
- (let-decl
- ("let" decl-exp)
- ("let" decl-exp "=" exp))
- (var-decl
- ("var" decl-exp)
- ("var" decl-exp "=" exp))
-
- (top-level-sts (top-level-st) (top-level-st ";" top-level-st))
- (top-level-st
- ("import" type)
- (decl)
- ("ACCESSMOD" "class" class-decl-exp "{" class-level-sts "}")
- ("ACCESSMOD" "protocol" class-decl-exp "{" protocol-level-sts "}")
- )
-
- (class-level-sts (class-level-st) (class-level-st ";" class-level-st))
- (class-level-st
- (decl)
- (func))
-
- (protocol-level-sts (protocol-level-st) (protocol-level-st ";"
protocol-level-st))
- (protocol-level-st
- (decl)
- (func-decl))
-
- (func-body (insts) ("return" exp))
- (func (func-decl "{" func-body "}"))
- (func-decl ("DECSPEC" "func" func-header)
- (func-decl "->" type))
- (func-header (id "(" func-params ")"))
- (func-param (decl-exp) (decl-exp "=" id) ("..."))
- (func-params (func-param "," func-param))
-
- (insts (inst) (insts ";" insts))
- (inst (decl)
- (exp "=" exp)
- (in-exp)
- (dot-exp)
- (dot-exp "{" closure "}")
- (method-call)
- (method-call "{" closure "}")
- ("enum" decl-exp "{" enum-body "}")
- ("switch" exp "{" switch-body "}")
- (if-clause)
- (guard-statement)
- ("for" for-head "{" insts "}")
- ("while" exp "{" insts "}"))
-
- (dot-exp (id "." id))
-
- (method-call (dot-exp "(" method-args ")"))
- (method-args (method-arg) (method-args "," method-args))
- (method-arg (id "{" closure "}") (exp))
-
- (exp ("[" decl-exps "]"))
- (in-exp (id "in" exp))
- (guard-exp (exp "where" exp))
-
- (enum-case ("ecase" assign-exp)
- ("ecase" "(" type ")"))
- (enum-cases (enum-case) (enum-case ";" enum-case))
- (enum-body (enum-cases) (insts))
-
- (case-exps (exp)
- (guard-exp)
- (case-exps "," case-exps))
- (case (case-exps "case-:" insts))
- (switch-body (case) (case "case" case))
-
- (for-head (in-exp) (op-exp) (for-head ";" for-head))
-
- (guard-conditional (exp) (let-decl) (var-decl))
- (guard-statement ("guard" guard-conditional "elseguard" "{" insts "}"))
-
- (if-conditional (exp) (let-decl))
- (if-body ("if" if-conditional "{" insts "}"))
- (if-clause (if-body)
- (if-body "elseif" if-conditional "{" insts "}")
- (if-body "else" "{" insts "}"))
-
- (closure (insts) (exp "in" insts) (exp "->" id "in" insts)))
- ;; Conflicts
- '((nonassoc "{") (assoc "in") (assoc ",") (assoc ";") (right "=") (right
":"))
- '((assoc "in") (assoc "where"))
- '((assoc ";") (assoc "ecase"))
- '((assoc "case")))
-
- (smie-precs->prec2
- '(
- (right "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" "&="
- "^=" "|=" "&&=" "||=" "=") ;; Assignment
(Right associative, precedence level 90)
- (right "?" ":") ;; Ternary
Conditional (Right associative, precedence level 100)
- (left "||") ;; Disjunctive
(Left associative, precedence level 110)
- (left "&&") ;; Conjunctive
(Left associative, precedence level 120)
- (right "??") ;; Nil
Coalescing (Right associativity, precedence level 120)
- (nonassoc "<" "<=" ">" ">=" "==" "!=" "===" "!==" "~=") ;; Comparative
(No associativity, precedence level 130)
- (nonassoc "is" "as" "as!" "as?") ;; Cast (No
associativity, precedence level 132)
- (nonassoc "..<" "...") ;; Range (No
associativity, precedence level 135)
- (left "+" "-" "&+" "&-" "|" "^") ;; Additive
(Left associative, precedence level 140)
- (left "*" "/" "%" "&*" "&/" "&%" "&") ;;
Multiplicative (Left associative, precedence level 150)
- (nonassoc "<<" ">>") ;;
Exponentiative (No associativity, precedence level 160)
- ))
- )))
-
-(defun verbose-swift-smie-rules (kind token)
- (let ((value (swift-smie-rules kind token)))
- (message "%s '%s'; sibling-p:%s parent:%s hanging:%s == %s" kind token
- (ignore-errors (smie-rule-sibling-p))
- (ignore-errors smie--parent)
- (ignore-errors (smie-rule-hanging-p))
- value)
- value))
-
-(defvar swift-smie--operators
- '("*=" "/=" "%=" "+=" "-=" "<<=" ">>=" "&=" "^=" "|=" "&&=" "||="
- "<" "<=" ">" ">=" "==" "!=" "===" "!==" "~=" "||" "&&"
- "is" "as" "as!" "as?" "..<" "..."
- "+" "-" "&+" "&-" "|" "^"
- "*" "/" "%" "&*" "&/" "&%" "&"
- "<<" ">>" "??"))
-
-(defvar swift-smie--operators-regexp
- (regexp-opt swift-smie--operators))
-
-(defvar swift-smie--decl-specifier-regexp
- "\\(?1:mutating\\|override\\|static\\|unowned\\|weak\\)")
-
-(defvar swift-smie--access-modifier-regexp
- (regexp-opt '("private" "public" "internal")))
-
-(defun swift-smie--implicit-semi-p ()
- (save-excursion
- (not (or (memq (char-before) '(?\{ ?\[ ?, ?. ?: ?= ?\())
- ;; Checking for operators form for "?" and "!",
- ;; they can be a part of the type.
- ;; Special case: is? and as? are operators.
- (looking-back "[[:space:]][?!]" (- (point) 2) t)
- ;; ??, is? and as? are operators
- (looking-back "[?][?]\\|as[?]\\|is[?]" (- (point) 3) t)
- ;; "in" operator in closure
- (looking-back "\\bin" (- (point) 3) t)
- ;; Characters placed on the second line in multi-line expression
- (save-excursion
- (forward-comment (buffer-size))
- (looking-at "[.?:]"))
- ;; Operators placed on the second line in multi-line expression
- ;; Should respect here possible comments strict before the
linebreak
- (save-excursion
- (forward-comment (buffer-size))
- (looking-at swift-smie--operators-regexp))
-
- (and (looking-back swift-smie--operators-regexp (- (point) 3) t)
- ;; Not a generic type
- (not (looking-back "[[:upper:]]>" (- (point) 2) t)))
- ))))
-
-(defun swift-smie--forward-token-debug ()
- (let ((token (swift-smie--forward-token)))
- (unless (equal token "")
- (cl-assert (equal token
- (save-excursion (swift-smie--backward-token))) t))
- token
- ))
-
-(defun swift-smie--backward-token-debug ()
- (let ((token (swift-smie--backward-token)))
- (unless (equal token "")
- (cl-assert (equal token
- (save-excursion (swift-smie--forward-token))) t))
- token
- ))
-
-(defconst swift-smie--lookback-max-lines -2
- "Max number of lines 'looking-back' allowed to scan.
-In some cases we can't avoid reverse lookup and this operation can be slow.
-We try to constraint those lookups by reasonable number of lines.")
-
-(defun swift-smie--forward-token ()
- (skip-chars-forward " \t")
- (cond
- ((and (looking-at "\n\\|\/\/") (swift-smie--implicit-semi-p))
- (if (eolp) (forward-char 1) (forward-comment 1))
- ";")
- (t
- (forward-comment (point))
- (cond
- ((looking-at "{") (forward-char 1) "{")
- ((looking-at "}") (forward-char 1) "}")
-
- ((looking-at ",") (forward-char 1) ",")
- ((looking-at ":") (forward-char 1)
- ;; look-back until "case", "default", ":", "{", ";"
- (if (looking-back "\\(case[\n\t ][^:{;]+\\|default[\n\t ]*\\):")
- "case-:"
- ":"))
-
- ((looking-at "->") (forward-char 2) "->")
-
- ((looking-at "<") (forward-char 1)
- (if (looking-at "[[:upper:]]") "<T" "<"))
-
- ((looking-at ">[?!]?")
- (goto-char (match-end 0))
- (if (looking-back "[[:space:]]>" 2 t) ">" "T>"))
-
- ((looking-at swift-smie--decl-specifier-regexp)
- (goto-char (match-end 1)) "DECSPEC")
-
- ((looking-at swift-smie--access-modifier-regexp)
- (goto-char (match-end 0)) "ACCESSMOD")
-
- ((looking-at "\\<default\\>")
- (goto-char (match-end 0)) "case")
-
- ((looking-at "else if")
- (goto-char (match-end 0)) "elseif")
-
- (t (let ((tok (smie-default-forward-token)))
- (cond
- ((equal tok "case")
- (if (looking-at "\\([\n\t ]\\|.\\)+?\\(where.*[,]\\|:\\)")
- "case"
- "ecase"))
- ((equal tok "else")
- (if (looking-back "\\(guard.*\\)" (line-beginning-position) t)
- "elseguard"
- "else"))
- (t tok))))
- ))
- ))
-
-(defun swift-smie--backward-token ()
- (let ((pos (point)))
- (forward-comment (- (point)))
- (cond
- ((and (> pos (line-end-position))
- (swift-smie--implicit-semi-p))
- ";")
-
- ((eq (char-before) ?\{) (backward-char 1) "{")
- ((eq (char-before) ?\}) (backward-char 1) "}")
-
- ((eq (char-before) ?,) (backward-char 1) ",")
- ((eq (char-before) ?:) (backward-char 1)
- ;; look-back until "case", "default", ":", "{", ";"
- (if (looking-back "\\(case[\n\t ][^:{;]+\\|default[\n\t ]*\\)")
- "case-:"
- ":"))
-
- ((looking-back "->" (- (point) 2) t)
- (goto-char (match-beginning 0)) "->")
-
- ((eq (char-before) ?<) (backward-char 1)
- (if (looking-at "<[[:upper:]]") "<T" "<"))
- ((looking-back ">[?!]?" (- (point) 2) t)
- (goto-char (match-beginning 0))
- (if (looking-back "[[:space:]]" 1 t) ">" "T>"))
-
- ((looking-back (regexp-opt swift-mode--type-decl-keywords) (- (point) 9)
t)
- (goto-char (match-beginning 0))
- (match-string-no-properties 0))
-
- ((looking-back swift-smie--decl-specifier-regexp (- (point) 8) t)
- (goto-char (match-beginning 1)) "DECSPEC")
-
- ((looking-back swift-smie--access-modifier-regexp (- (point) 8) t)
- (goto-char (match-beginning 0)) "ACCESSMOD")
-
- ((looking-back "\\<default\\>" (- (point) 9) t)
- (goto-char (match-beginning 0)) "case")
-
- ((looking-back "else if" (- (point) 7) t)
- (goto-char (match-beginning 0)) "elseif")
-
- (t (let ((tok (smie-default-backward-token)))
- (cond
- ((equal tok "case")
- (if (looking-at "\\([\n\t ]\\|.\\)+?\\(where.*[,]\\|:\\)")
- "case"
- "ecase"))
- ((equal tok "else")
- (if (looking-back "\\(guard.*\\)" (line-beginning-position) t)
- "elseguard"
- "else"))
- (t tok))))
- )))
-
-(defun swift-smie-rules (kind token)
- (pcase (cons kind token)
- (`(:elem . basic) swift-indent-offset)
-
- (`(:after . ":") 0)
- (`(:before . ":")
- (cond
- ;; Rule for ternary operator in
- ;; assignment expression.
- ((and (smie-rule-parent-p "?") (smie-rule-bolp)) 0)
- ((smie-rule-parent-p ",") (smie-rule-parent swift-indent-offset))
- ;; Rule for the class definition.
- ((smie-rule-parent-p "class") (smie-rule-parent swift-indent-offset))))
-
- ;; Indentation rules for switch statements
- (`(:before . "case")
- (if (smie-rule-parent-p "{")
- (smie-rule-parent swift-indent-switch-case-offset)))
- (`(:before . "case-:") (smie-rule-parent swift-indent-offset))
-
- ;; Apply swift-indent-multiline-statement-offset only if
- ;; - if is a first token on the line
- (`(:before . ".")
- (when (smie-rule-bolp)
- (if (smie-rule-parent-p "{")
- (+ swift-indent-offset swift-indent-multiline-statement-offset)
- swift-indent-multiline-statement-offset)))
-
- ;; Apply swift-indent-multiline-statement-offset if
- ;; operator is the last symbol on the line
- (`(:after . ,(pred (lambda (token)
- (member token swift-smie--operators))))
- (when (and (smie-rule-hanging-p)
- (not (apply 'smie-rule-parent-p
- (append swift-smie--operators '("?" ":" "=")))))
- swift-indent-multiline-statement-offset
- ))
-
- (`(:before . ",")
- (if (and swift-indent-hanging-comma-offset (smie-rule-parent-p "class"
"case"))
- (smie-rule-parent swift-indent-hanging-comma-offset)))
-
- ;; Disable unnecessary default indentation for
- ;; "func" and "class" keywords
- (`(:after . ,(or `"func" `"class")) (smie-rule-parent))
+ :prefix "swift-mode:")
- ;; "in" token in closure
- (`(:after . "in")
- (if (smie-rule-parent-p "{")
- (smie-rule-parent swift-indent-offset)
- (smie-rule-parent 0)))
-
- (`(:after . "(")
- (cond
- ((smie-rule-parent-p "(") 0)
- ((and (smie-rule-parent-p "." "func")
- (not (smie-rule-hanging-p))) 1)
- (t (smie-rule-parent swift-indent-offset))))
-
- (`(:before . "(")
- (cond
- ((smie-rule-next-p "[") (smie-rule-parent))
- ;; Custom indentation for method arguments
- ((smie-rule-parent-p "." "func") (smie-rule-parent))))
-
- (`(:before . "[")
- (cond
- ((smie-rule-prev-p "->") swift-indent-offset)
- ((smie-rule-parent-p "[") (smie-rule-parent swift-indent-offset))
- ((smie-rule-parent-p "{") nil)
- ((smie-rule-parent-p "class-{") nil)
- (t (smie-rule-parent))))
- (`(:after . "->") (smie-rule-parent swift-indent-offset))
- ))
-
-;;; Font lock
-
-(defvar swift-mode--type-decl-keywords
- '("class" "enum" "protocol" "struct" "typealias"))
-
-(defvar swift-mode--val-decl-keywords
- '("let" "var"))
-
-(defvar swift-mode--context-variables-keywords
- '("self" "super"))
-
-(defvar swift-mode--fn-decl-keywords
- '("deinit" "func" "init"))
-
-(defvar swift-mode--misc-keywords
- '("import" "static" "subscript" "extension"))
-
-(defvar swift-mode--statement-keywords
- '("break" "case" "continue" "default" "do" "else" "fallthrough"
- "if" "in" "for" "return" "switch" "where" "while" "guard"))
-
-(defvar swift-mode--contextual-keywords
- '("associativity" "didSet" "get" "infix" "inout" "left" "mutating" "none"
- "nonmutating" "operator" "override" "postfix" "precedence" "prefix" "right"
- "set" "unowned" "unowned(safe)" "unowned(unsafe)" "weak" "willSet"
"convenience"
- "required" "dynamic" "final" "lazy" "optional" "private" "public"
"internal"))
-
-(defvar swift-mode--attribute-keywords
- '("class_protocol" "exported" "noreturn"
- "NSCopying" "NSManaged" "objc" "autoclosure"
- "available" "noescape" "nonobjc" "NSApplicationMain" "testable"
"UIApplicationMain" "warn_unused_result" "convention"
- "IBAction" "IBDesignable" "IBInspectable" "IBOutlet"))
-
-(defvar swift-mode--keywords
- (append swift-mode--type-decl-keywords
- swift-mode--val-decl-keywords
- swift-mode--context-variables-keywords
- swift-mode--fn-decl-keywords
- swift-mode--misc-keywords
- swift-mode--statement-keywords
- swift-mode--contextual-keywords)
- "Keywords used in the Swift language.")
-
-(defvar swift-mode--constants
- '("true" "false" "nil"))
-
-(defvar swift-font-lock-keywords
- `(
- ;; Keywords
- ;;
- ;; Swift allows reserved words to be used as identifiers when enclosed
- ;; with backticks, in which case they should be highlighted as
- ;; identifiers, not keywords.
- (,(rx-to-string
- `(and (or bol (not (any "`"))) bow
- (group (or ,@swift-mode--keywords))
- eow)
- t)
- 1 font-lock-keyword-face)
-
- ;; Attributes
- ;;
- ;; Highlight attributes with keyword face
- (,(rx-to-string
- `(and "@" bow (or ,@swift-mode--attribute-keywords) eow)
- t)
- 0 font-lock-keyword-face)
-
- ;; Types
- ;;
- ;; Any token beginning with an uppercase character is highlighted as a
- ;; type.
- (,(rx bow upper (* word) eow)
- 0 font-lock-type-face)
-
- ;; Function names
- ;;
- ;; Any token beginning after `func' is highlighted as a function name.
- (,(rx bow "func" eow (+ space) (group bow (+ word) eow))
- 1 font-lock-function-name-face)
-
- ;; Value bindings
- ;;
- ;; Any token beginning after `let' or `var' is highlighted as an
- ;; identifier.
- (,(rx-to-string `(and bow
- (or ,@swift-mode--val-decl-keywords)
- eow
- (+ space)
- (? "(")
- (group (+ (or (+ (? ?`) word (? ?`)) ?, space)))
- (? ")"))
- t)
- 1 font-lock-variable-name-face)
-
- ;; Use high-visibility face for pattern match wildcards.
- (,(rx (not (any word digit)) (group "_") (or eol (not (any word digit))))
- 1 font-lock-negation-char-face)
-
- ;; Constants
- ;;
- ;; Highlight nil and boolean literals.
- (,(rx-to-string `(and bow (or ,@swift-mode--constants) eow))
- 0 font-lock-constant-face)
-
- ;; Attributes
- ;;
- ;; Use string face for attribute name.
- (,(rx (or bol space)(group "@" (+ word)) eow)
- 1 font-lock-string-face)
-
- ;; Imported modules
- ;;
- ;; Highlight the names of imported modules. Use `font-lock-string-face' for
- ;; consistency with C modes.
- (,(rx bow "import" eow (+ space) (group (+ word)))
- 1 font-lock-string-face)
-
- ;; String interpolation
- ;;
- ;; Highlight interpolation expression as identifier.
- (swift-match-interpolation 0 font-lock-variable-name-face t)
- ))
-
-(defun swift-syntax-propertize-function (start end)
- "Syntactic keywords for Swift mode."
- (let (case-fold-search)
- (goto-char start)
- (remove-text-properties start end '(swift-interpolation-match-data))
- (funcall
- (syntax-propertize-rules
- ((rx (group "\\(" (* (any alnum " ()+-._/*[]!?<>&~!:|^%")) ")"))
- (0 (ignore (swift-syntax-propertize-interpolation)))))
- start end)))
-
-(defun swift-syntax-propertize-interpolation ()
- (let* ((beg (match-beginning 0))
- (context (save-excursion (save-match-data (syntax-ppss beg)))))
- (put-text-property beg (1+ beg) 'swift-interpolation-match-data
- (cons (nth 3 context) (match-data)))))
-
-(defun swift-match-interpolation (limit)
- (let ((pos (next-single-char-property-change (point)
'swift-interpolation-match-data
- nil limit)))
- (when (and pos (> pos (point)))
- (goto-char pos)
- (let ((value (get-text-property pos 'swift-interpolation-match-data)))
- (if (eq (car value) ?\")
- (progn
- (set-match-data (cdr value))
- t)
- (swift-match-interpolation limit))))))
-
-;;; Imenu
-
-(defun swift-mode--mk-regex-for-def (keyword)
- "Make a regex matching the identifier introduced by KEYWORD."
- (let ((ident (rx (any word nonascii "_") (* (any word nonascii digit "_")))))
- (rx-to-string `(and bow ,keyword eow (+ space) (group (regexp ,ident)))
- t)))
-
-(defvar swift-mode--imenu-generic-expression
- (list
- (list "Functions" (swift-mode--mk-regex-for-def "func") 1)
- (list "Classes" (swift-mode--mk-regex-for-def "class") 1)
- (list "Enums" (swift-mode--mk-regex-for-def "enum") 1)
- (list "Protocols" (swift-mode--mk-regex-for-def "protocol") 1)
- (list "Structs" (swift-mode--mk-regex-for-def "struct") 1)
- (list "Constants" (swift-mode--mk-regex-for-def "let") 1)
- (list "Variables" (swift-mode--mk-regex-for-def "var") 1))
- "Value for `imenu-generic-expression' in swift-mode.")
-
-;;; Flycheck
-
-(with-eval-after-load 'flycheck
- (flycheck-def-option-var flycheck-swift-sdk-path nil swift
- "A path to the targeted SDK"
- :type '(choice (const :tag "Don't link against sdk" nil)
- (string :tag "Targeted SDK path"))
- :safe #'stringp)
-
- (flycheck-def-option-var flycheck-swift-linked-sources nil swift
- "Source files path to link against. Can be glob, i.e. *.swift"
- :type '(choice (const :tag "Don't use linked sources" nil)
- (string :tag "Linked Sources"))
- :safe #'stringp)
-
- (flycheck-def-option-var flycheck-swift-framework-search-paths nil swift
- "A list of framework search paths"
- :type '(repeat (directory :tag "Include directory"))
- :safe #'flycheck-string-list-p)
-
- (flycheck-def-option-var flycheck-swift-cc-include-search-paths nil swift
- "A list of include file search paths to pass to the Objective C compiler"
- :type '(repeat (directory :tag "Include directory"))
- :safe #'flycheck-string-list-p)
-
- (flycheck-def-option-var flycheck-swift-target "i386-apple-ios8.1" swift
- "Target used by swift compiler"
- :type '(choice (const :tag "Don't specify target" nil)
- (string :tag "Build target"))
- :safe #'stringp)
-
- (flycheck-def-option-var flycheck-swift-import-objc-header nil swift
- "Objective C header file to import, if any"
- :type '(choice (const :tag "Don't specify objective C bridging header"
nil)
- (string :tag "Objective C bridging header path"))
- :safe #'stringp)
-
- (flycheck-define-checker swift
- "Flycheck plugin for for Apple's Swift programming language."
- :command ("swift"
- "-frontend" "-parse"
- (option "-sdk" flycheck-swift-sdk-path)
- (option-list "-F" flycheck-swift-framework-search-paths)
- ;; Swift compiler will complain about redeclaration
- ;; if we will include original file along with
- ;; temporary source file created by flycheck.
- ;; We also don't want a hidden emacs interlock files.
- (eval
- (let (source file)
- (when flycheck-swift-linked-sources
- (setq source (car (flycheck-substitute-argument 'source
'swift)))
- (setq file (file-name-nondirectory source))
- (cl-remove-if-not
- #'(lambda (path)
- (and
- (eq (string-match ".#" path) nil)
- (eq (string-match file path) nil)))
- (file-expand-wildcards flycheck-swift-linked-sources)))))
- (option "-target" flycheck-swift-target)
- (option "-import-objc-header" flycheck-swift-import-objc-header)
- (eval
- (cl-mapcan
- #'(lambda (path) (list "-Xcc" (concat "-I" path)))
- flycheck-swift-cc-include-search-paths))
- "-primary-file" source)
- :error-patterns
- ((error line-start (file-name) ":" line ":" column ": "
- "error: " (message) line-end)
- (warning line-start (file-name) ":" line ":" column ": "
- "warning: " (message) line-end))
- :modes swift-mode))
-
-;;; REPL
-
-(defvar swift-repl-buffer nil
- "Stores the name of the current swift REPL buffer, or nil.")
-
-;;;###autoload
-(defun swift-mode-run-repl (cmd &optional dont-switch-p)
- "Run a REPL process, input and output via buffer `*swift-repl*'.
-If there is a process already running in `*swift-repl*', switch to that buffer.
-With argument CMD allows you to edit the command line (default is value
-of `swift-repl-executable').
-With DONT-SWITCH-P cursor will stay in current buffer.
-Runs the hook `swift-repl-mode-hook' \(after the `comint-mode-hook'
-is run).
-\(Type \\[describe-mode] in the process buffer for a list of commands.)"
-
- (interactive (list (if current-prefix-arg
- (read-string "Run swift REPL: " swift-repl-executable)
- swift-repl-executable)))
- (unless (comint-check-proc "*swift-repl*")
- (save-excursion (let ((cmdlist (split-string cmd)))
- (set-buffer (apply 'make-comint "swift-repl" (car
cmdlist)
- nil (cdr cmdlist)))
- (swift-repl-mode))))
- (setq swift-repl-executable cmd)
- (setq swift-repl-buffer "*swift-repl*")
- (unless dont-switch-p
- (pop-to-buffer "*swift-repl*")))
-
-(defun swift-mode-send-region (start end)
- "Send the current region to the inferior swift process.
-START and END define region within current buffer"
- (interactive "r")
- (swift-mode-run-repl swift-repl-executable t)
- (comint-send-region swift-repl-buffer start end)
- (comint-send-string swift-repl-buffer "\n"))
-
-(defun swift-mode-send-buffer ()
- "Send the buffer to the Swift REPL process."
- (interactive)
- (swift-mode-send-region (point-min) (point-max)))
-
-(define-derived-mode swift-repl-mode comint-mode "Swift REPL"
- "Major mode for interacting with Swift REPL.
-
-A REPL can be fired up with M-x swift-mode-run-repl.
-
-Customization: Entry to this mode runs the hooks on comint-mode-hook and
-swift-repl-mode-hook (in that order).
-
-You can send text to the REPL process from other buffers containing source.
- swift-mode-send-region sends the current region to the REPL process,
- swift-mode-send-buffer sends the current buffer to the REPL process.
-")
-
-;;; Mode definition
-
-(defvar swift-mode-syntax-table
- (let ((table (make-syntax-table)))
-
- ;; Operators
- (dolist (i '(?+ ?- ?* ?/ ?& ?| ?^ ?< ?> ?~))
- (modify-syntax-entry i "." table))
-
- ;; Strings
- (modify-syntax-entry ?\" "\"" table)
- (modify-syntax-entry ?\\ "\\" table)
-
- ;; Additional symbols
- (modify-syntax-entry ?_ "w" table)
- (modify-syntax-entry ?? "_" table)
- (modify-syntax-entry ?! "_" table)
- (modify-syntax-entry ?: "." table)
-
- ;; Comments
- (modify-syntax-entry ?/ ". 124b" table)
- (modify-syntax-entry ?* ". 23n" table)
- (modify-syntax-entry ?\n "> b" table)
-
- ;; Parenthesis, braces and brackets
- (modify-syntax-entry ?\( "()" table)
- (modify-syntax-entry ?\) ")(" table)
- (modify-syntax-entry ?\[ "(]" table)
- (modify-syntax-entry ?\] ")[" table)
- (modify-syntax-entry ?\{ "(}" table)
- (modify-syntax-entry ?\} "){" table)
-
- table))
+;;; Keymap
(defvar swift-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-c C-z") 'swift-mode-run-repl)
- (define-key map (kbd "C-c C-f") 'swift-mode-send-buffer)
- (define-key map (kbd "C-c C-r") 'swift-mode-send-region)
+ (set-keymap-parent map prog-mode-map)
+ (define-key map (kbd "M-j") #'swift-mode:indent-new-comment-line)
+ (define-key map (kbd "C-M-j") #'swift-mode:indent-new-comment-line)
+ (define-key map (kbd "C-c C-z") 'swift-mode:run-repl)
+ (define-key map (kbd "C-c C-f") 'swift-mode:send-buffer)
+ (define-key map (kbd "C-c C-r") 'swift-mode:send-region)
(easy-menu-define swift-menu map "Swift Mode menu"
`("Swift"
:help "Swift-specific Features"
@@ -797,31 +65,91 @@ You can send text to the REPL process from other buffers
containing source.
["Send region to REPL" swift-mode-send-region
:help "Send currently selected region to the REPL"]))
map)
- "Key map for swift mode.")
+ "Swift mode key map.")
+
+;;; `foward-sexp-function'
+
+(defun swift-mode:forward-sexp (&optional arg)
+ (setq arg (or arg 1))
+ (if (< 0 arg)
+ (while (< 0 arg)
+ (while (eq
+ (swift-mode:token:type (swift-mode:forward-token-or-list))
+ 'implicit-\;))
+ (setq arg (1- arg))))
+ (while (< arg 0)
+ (while (eq
+ (swift-mode:token:type (swift-mode:backward-token-or-list))
+ 'implicit-\;))
+ (setq arg (1+ arg))))
+
+;; Imenu
+
+(defun swift-mode:mk-regex-for-def (keyword)
+ "Make a regex matching the identifier introduced by KEYWORD."
+ (concat "\\<" (regexp-quote keyword) "\\>"
+ "\\s *"
+ "\\("
+ "\\(?:" "\\sw" "\\|" "\\s_" "\\)" "+"
+ "\\)"))
+
+(defconst swift-mode:imenu-generic-expression
+ (list
+ (list "Functions" (swift-mode:mk-regex-for-def "func") 1)
+ (list "Classes" (swift-mode:mk-regex-for-def "class") 1)
+ (list "Enums" (swift-mode:mk-regex-for-def "enum") 1)
+ (list "Protocols" (swift-mode:mk-regex-for-def "protocol") 1)
+ (list "Structs" (swift-mode:mk-regex-for-def "struct") 1)
+ (list "Extensions" (swift-mode:mk-regex-for-def "extension") 1)
+ (list "Constants" (swift-mode:mk-regex-for-def "let") 1)
+ (list "Variables" (swift-mode:mk-regex-for-def "var") 1))
+ "Value for `imenu-generic-expression' in `swift-mode'.")
;;;###autoload
(define-derived-mode swift-mode prog-mode "Swift"
- "Major mode for Apple's Swift programming language.
+ "Major mode for editing Swift code.
-\\<swift-mode-map>"
+\\{swift-mode-map}"
+ :syntax-table swift-mode:syntax-table
:group 'swift
- :syntax-table swift-mode-syntax-table
- (setq font-lock-defaults '((swift-font-lock-keywords) nil nil))
- (setq-local syntax-propertize-function #'swift-syntax-propertize-function)
- (setq-local imenu-generic-expression swift-mode--imenu-generic-expression)
+ (setq font-lock-defaults '(swift-mode:font-lock-keywords))
(setq-local comment-start "// ")
(setq-local comment-end "")
+ ;; ":" is for Playground Rich Comments Markup Syntax:
+ ;;
https://developer.apple.com/library/prerelease/ios/documentation/Xcode/Reference/xcode_markup_formatting_ref/PlaygroundRichComments.html
+ (setq-local comment-start-skip
+ (concat
+ "\\s *"
+ "\\(?:"
+ ;; Single-line comment
+ "//+" ":?" "\\|"
+ ;; Multi-line comment
+ "/\\*+" ":?" "\\|"
+ ;; Middle of multi-line-comment
+ "\\*+ "
+ "\\)"
+ "\\s *"))
+ (setq-local adaptive-fill-regexp comment-start-skip)
+ (setq-local comment-multi-line t)
+
(setq-local indent-tabs-mode nil)
+ (setq-local indent-line-function #'swift-mode:indent-line)
+
+ (setq-local forward-sexp-function #'swift-mode:forward-sexp)
+
(setq-local electric-indent-chars
- (append '(?. ?, ?: ?\) ?\] ?\}) electric-indent-chars))
- (smie-setup swift-smie-grammar 'swift-smie-rules ;; 'verbose-swift-smie-rules
- :forward-token 'swift-smie--forward-token
- :backward-token 'swift-smie--backward-token))
+ (append "{}()[]:;,." electric-indent-chars))
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.swift\\'" . swift-mode))
+ (add-hook 'post-self-insert-hook #'swift-mode:post-self-insert nil t)
+
+ (setq-local imenu-generic-expression swift-mode:imenu-generic-expression)
+
+ (setq-local beginning-of-defun-function #'swift-mode:beginning-of-defun)
+ (setq-local end-of-defun-function #'swift-mode:end-of-defun))
+
+;;;###autoload (add-to-list 'auto-mode-alist '("\\.swift\\'" . swift-mode))
(provide 'swift-mode)
diff --git a/test/font-lock-tests.el b/test/font-lock-tests.el
deleted file mode 100644
index eff40e3..0000000
--- a/test/font-lock-tests.el
+++ /dev/null
@@ -1,212 +0,0 @@
-;;; font-lock-tests.el --- Tests for font-lock behaviours in swift-mode. -*-
lexical-binding: t; -*-
-
-;; Copyright (C) 2014-2016 Chris Barrett
-
-;; Author: Chris Barrett <chris.d.barrett@me.com>
-;; Version: 0.1
-
-;; This file is not part of GNU Emacs.
-
-;; This program is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Tests for font-lock behaviours in swift-mode.
-;;
-;; Uses puppet-mode tests as a reference:
-;;
https://github.com/lunaryorn/puppet-mode/blob/master/test/puppet-mode-test.el
-
-;;; Code:
-
-
-(require 'swift-mode)
-(require 'ert)
-(require 'cl-lib)
-(require 's nil t)
-(require 'dash nil t)
-
-;;; Test utilities
-
-(defun swift-test--moustache-substring (str)
- "Propertise STR and extract the portion between moustaches.
-Returns the substring with properties."
- (with-temp-buffer
- (insert str)
- (goto-char (point-min))
- (let (start end)
- ;; Remove open-moustache chars and save position.
- (search-forward "{{")
- (delete-char -2)
- (setq start (point))
- ;; Remove end-moustache chars and save position.
- (search-forward-regexp (rx (>= 2 "}")))
- (delete-char -2)
- (setq end (point))
- ;; Propertise buffer.
- (swift-mode)
- (font-lock-fontify-buffer)
- (buffer-substring start end))))
-
-(defun swift-test--whole-string-has-face? (str face)
- "Non-nil if all of STR is propertised with FACE."
- (with-temp-buffer
- (insert str)
- (goto-char (point-min))
- (let ((points
- ;; Walk over the string and get the faces at each position.
- (cl-loop while (not (eobp))
- collecting (get-text-property (point) 'face)
- do (forward-char 1))))
-
- (--all? (cond ((null it) (null face))
- ((listp it) (member face it))
- (t (equal face it)))
- points))))
-
-(defmacro check-face (description face str)
- "Declare an ert test for font-lock behaviour.
-The test will check that a portion of the buffer is propertised with the
-given face.
-
-DESCRIPTION is a symbol describing the test.
-
-FACE is the face name as an unquoted symbol. It can also be nil, which
-means the string should not have any face.
-
-STR is the string to test for face propertisation. The portion of the
-string to be checked is surrounded with moustaches ('{{' and '}}'), as
-below:
-
- let {{foo}} = y
-
-The whole substring between moustaches must be propertised with FACE or the
-test will fail."
- (declare (indent 2))
- (cl-assert (symbolp description))
- (cl-assert (or (facep face) (null face)))
- (cl-assert (stringp str))
- (cl-assert (s-contains? "{{" str))
- (cl-assert (s-contains? "}}" str))
- (cl-assert (<= 1 (length (swift-test--moustache-substring str))))
-
- (let ((test-name (intern (format "font-lock/%s" description))))
- `(ert-deftest ,test-name ()
- (let ((substr (swift-test--moustache-substring ,str)))
- (should (swift-test--whole-string-has-face? substr ,face))))))
-
-;; Provide font locking for easier test editing.
-
-(font-lock-add-keywords
- 'emacs-lisp-mode
- `((,(rx "(" (group "check-face" eow))
- (1 font-lock-keyword-face))
- (,(rx "("
- (group "check-face") (+ space)
- (group bow (+ (not space)) eow)
- )
- (1 font-lock-keyword-face)
- (2 font-lock-function-name-face))))
-
-;;; Tests
-
-(check-face let/has-keyword-face/1 font-lock-keyword-face "{{let}}")
-(check-face let/has-keyword-face/2 font-lock-keyword-face " {{let}}")
-(check-face let/has-keyword-face/3 font-lock-keyword-face "{{let}} x = y")
-(check-face let-bind/has-variable-face/1 font-lock-variable-name-face "let
{{x}} = y")
-(check-face let-bind/has-variable-face/2 font-lock-variable-name-face "let
{{foo}} = y")
-(check-face let-bind/has-variable-face/3 font-lock-variable-name-face "let
{{x}}: T = y")
-(check-face let-bind/has-variable-face/4 font-lock-variable-name-face "let
({{foo}}, bar) = y")
-(check-face let-bind/has-variable-face/5 font-lock-variable-name-face "let
(foo, {{bar}}) = y")
-(check-face let-bind-type-ann/has-type-face/1 font-lock-type-face "let x:
{{T}} = y")
-(check-face let-bind-type-ann/has-type-face/2 font-lock-type-face "let x:
{{Type}} = y")
-
-(check-face var/has-keyword-face/1 font-lock-keyword-face "{{var}}")
-(check-face var/has-keyword-face/2 font-lock-keyword-face " {{var}}")
-(check-face var/has-keyword-face/3 font-lock-keyword-face "{{var}} x = y")
-(check-face var-bind/has-variable-face/1 font-lock-variable-name-face "var
{{x}} = y")
-(check-face var-bind/has-variable-face/2 font-lock-variable-name-face "var
{{foo}} = y")
-(check-face var-bind/has-variable-face/3 font-lock-variable-name-face "var
{{x}}: T = y")
-(check-face var-bind-type-ann/has-type-face/1 font-lock-type-face "var x:
{{T}} = y")
-(check-face var-bind-type-ann/has-type-face/2 font-lock-type-face "var x:
{{Type}} = y")
-
-(check-face func/has-keyword-face/1 font-lock-keyword-face "{{func}}")
-(check-face func/has-keyword-face/2 font-lock-keyword-face "{{func}} x() {})")
-(check-face func-name/has-function-name-face/1 font-lock-function-name-face
"func {{x}}")
-(check-face func-name/has-function-name-face/2 font-lock-function-name-face
"func {{foo}}")
-(check-face func-name/has-function-name-face/3 font-lock-function-name-face
"func {{foo}}()")
-(check-face func-name/has-function-name-face/4 font-lock-function-name-face
"func {{foo}}<T>")
-(check-face func-name/has-function-name-face/6 font-lock-function-name-face
- "func {{foo}}<T>(param: T) -> U {}")
-(check-face func-access-control/has-keyword-face/1 font-lock-keyword-face
"{{private}} func foo() {}")
-(check-face func-access-control/has-keyword-face/2 font-lock-keyword-face
"{{public}} func foo() {}")
-(check-face func-access-control/has-keyword-face/3 font-lock-keyword-face
"{{internal}} func foo() {}")
-
-(check-face func-return-type/has-type-face/1 font-lock-type-face "func foo()
-> {{U}} {}")
-(check-face func-return-type/arrow-has-default-face/1 nil "func foo() {{->}} U
{}")
-
-(check-face enum/has-keyword-face/1 font-lock-keyword-face "{{enum}} T")
-(check-face enum/has-keyword-face/2 font-lock-keyword-face "{{enum}} T")
-(check-face enum/type-has-type-face/1 font-lock-type-face "enum {{T}}")
-(check-face enum/type-has-type-face/2 font-lock-type-face "enum {{Type}}")
-(check-face enum/type-has-type-face/3 font-lock-type-face "enum {{T}} {}")
-(check-face enum/type-has-type-face/4 font-lock-type-face "enum {{T}} {\n}")
-(check-face enum/generic-parameter/has-type-face/1 font-lock-type-face "enum
N<{{T}}>")
-(check-face enum/generic-parameter/has-type-face/2 font-lock-type-face "enum
Name<{{T}}> {}")
-(check-face enum/generic-parameter/has-type-face/3 font-lock-type-face "enum
Name <{{T}}> {}")
-(check-face enum/generic-parameter/brackets-have-default-face/1 nil "enum
N{{<}}T>")
-(check-face enum/generic-parameter/brackets-have-default-face/2 nil "enum
N<T{{>}}")
-
-(check-face class/has-keyword-face/1 font-lock-keyword-face "{{class}} T")
-(check-face class/has-keyword-face/2 font-lock-keyword-face "{{class}} T")
-(check-face class/type-has-type-face/1 font-lock-type-face "class {{T}}")
-(check-face class/type-has-type-face/2 font-lock-type-face "class {{Type}}")
-(check-face class/type-has-type-face/3 font-lock-type-face "class {{T}} {}")
-(check-face class/type-has-type-face/4 font-lock-type-face "class {{T}} {\n}")
-(check-face class/type-has-type-face/5 font-lock-type-face "class {{T}}: Base")
-
-(check-face class/body-brackets-have-default-face nil "class T {{{}}}")
-
-(check-face class/generic-parameter/has-type-face/1 font-lock-type-face "class
N<{{T}}>")
-(check-face class/generic-parameter/has-type-face/2 font-lock-type-face "class
Name<{{T}}> {}")
-(check-face class/generic-parameter/has-type-face/3 font-lock-type-face "class
Name <{{T}}> {}")
-(check-face class/generic-parameter/brackets-have-default-face/1 nil "class
N{{<}}T>")
-(check-face class/generic-parameter/brackets-have-default-face/2 nil "class
N<T{{>}}")
-
-(check-face class/base-type-has-type-face/1 font-lock-type-face "class
T:{{Base}}")
-(check-face class/base-type-has-type-face/2 font-lock-type-face "class T:
{{Base}}")
-(check-face class/base-type-has-type-face/3 font-lock-type-face "class T :
{{Base}}")
-(check-face class/base-type-has-type-face/4 font-lock-type-face "class T<U> :
{{Base}}")
-(check-face class/base-type-colon-has-default-face/1 nil "class T {{:}} Base")
-
-(check-face string-interpolation/has-variable-face/1
font-lock-variable-name-face "\"foo {{\\\(bar)}}\"")
-(check-face string-interpolation/has-variable-face/2
font-lock-variable-name-face "\"{{\\\(bar)}}\"")
-(check-face string-interpolation/has-variable-face/3
font-lock-variable-name-face "\"\\\(bar\(1\){{\)}}\"")
-(check-face string-interpolation/has-variable-face/4
font-lock-variable-name-face "\"\\\(bar\(1\){{ + baz\(2\)\)}}\"")
-(check-face string-interpolation/has-variable-face/5
font-lock-variable-name-face "\"foo {{\\\(bar_baz)}}\"")
-(check-face string-interpolation/has-variable-face/6
font-lock-variable-name-face "\"foo {{\\\(bar.baz)}}\"")
-(check-face string-interpolation/has-variable-face/7
font-lock-variable-name-face "\"foo {{\\\(bar[0])}}\"")
-(check-face string-interpolation/has-variable-face/8
font-lock-variable-name-face "\"foo {{\\\(bar!.baz)}}\"")
-(check-face string-interpolation/has-variable-face/9
font-lock-variable-name-face "\"foo {{\\\(bar?.baz)}}\"")
-(check-face string-interpolation/after-has-string-face/2 font-lock-string-face
"\"(foo \\\(bar){{baz}}\")")
-
-(check-face self/has-keyword-face/1 font-lock-keyword-face "{{self}}.foo")
-(check-face super/has-keyword-face/1 font-lock-keyword-face "{{super}}.foo")
-
-(check-face attributes/has-keyword-face/1 font-lock-keyword-face
"{{@IBAction}} func")
-
-(check-face comments/nested-multiline-comments-has-comments-face/1
font-lock-comment-face "/*/* text */{{*/}}")
-
-(provide 'font-lock-tests)
-
-;;; font-lock-tests.el ends here
diff --git a/test/indentation-tests.el b/test/indentation-tests.el
deleted file mode 100644
index 6a4c295..0000000
--- a/test/indentation-tests.el
+++ /dev/null
@@ -1,2280 +0,0 @@
-;;; indentation-tests.el --- Test swift-mode indentation behaviour
-
-;; Copyright (C) 2014-2016 Chris Barrett
-
-;; Author: Chris Barrett <chris.d.barrett@me.com>
-;; Version: 0.1
-
-;; This file is not part of GNU Emacs.
-
-;; This program is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Test swift-mode indentation behaviour
-
-;;; Code:
-
-(require 'ert)
-(require 'swift-mode)
-(require 's)
-
-;;; Test utilities
-
-(defmacro check-indentation (description before after &optional var-bindings)
- "Declare an ert test for indentation behaviour.
-The test will check that the swift indentation command changes the buffer
-from one state to another. It will also test that point is moved to an
-expected position.
-
-DESCRIPTION is a symbol describing the test.
-
-BEFORE is the buffer string before indenting, where a pipe (|) represents
-point.
-
-AFTER is the expected buffer string after indenting, where a pipe (|)
-represents the expected position of point.
-
-VAR-BINDINGS is an optional let-bindings list. It can be used to set the
-values of customisable variables."
- (declare (indent 1))
- (let ((fname (intern (format "indentation/%s" description))))
- `(ert-deftest ,fname ()
- (let* ((after ,after)
- (expected-cursor-pos (1+ (s-index-of "|" after)))
- (expected-state (delete ?| after))
-
- ;; Bind customisable vars to default values for tests.
- (swift-indent-offset 4)
- (swift-indent-switch-case-offset 0)
- (swift-indent-multiline-statement-offset 2)
- (swift-indent-hanging-comma-offset nil)
- ,@var-bindings)
- (with-temp-buffer
- (insert ,before)
- (goto-char (point-min))
- (search-forward "|")
- (delete-char -1)
- (swift-mode)
- (setq smie-forward-token-function 'swift-smie--forward-token-debug)
- (setq smie-backward-token-function
'swift-smie--backward-token-debug)
- (indent-according-to-mode)
-
- (should (equal expected-state (buffer-string)))
- (should (equal expected-cursor-pos (point)))
-
- (goto-char (point-min))
- (forward-sexp 10)
- (should (equal (point-max) (point)))
- (forward-sexp -10)
- (should (equal (point-min) (point)))
-
- (goto-char (point-min))
- (forward-list 10)
- (should (equal (point-max) (point)))
- (forward-list -10)
- (should (equal (point-min) (point)))
- )))))
-
-;; Provide font locking for easier test editing.
-
-(font-lock-add-keywords
- 'emacs-lisp-mode
- `((,(rx "(" (group "check-indentation") eow)
- (1 font-lock-keyword-face))
- (,(rx "("
- (group "check-indentation") (+ space)
- (group bow (+ (not space)) eow)
- )
- (1 font-lock-keyword-face)
- (2 font-lock-function-name-face))))
-
-
-;;; Tests
-
-
-(check-indentation no-indentation-at-top-level
- "|x"
- "|x")
-
-(check-indentation toplevel-exprs-indented-to-same-level/1
- "
-x
-|y
-" "
-x
-|y
-")
-
-(check-indentation toplevel-exprs-indented-to-same-level/2
- "
-x
- |y
-" "
-x
-|y
-")
-
-(check-indentation nested-exprs-indented-to-same-level/1
- "
-{
- x
- |y
-}
-" "
-{
- x
- |y
-}
-")
-
-(check-indentation nested-exprs-indented-to-same-level/2
- "
-{
- x
- |y
-}
-" "
-{
- x
- |y
-}
-")
-
-(check-indentation nested-exprs-indented-to-same-level/3
- "
-{
- x
-|y
-}
-" "
-{
- x
- |y
-}
-")
-
-(check-indentation indent-if-body
- "
-if true {
-|x
-}
-" "
-if true {
- |x
-}
-")
-
-(check-indentation indent-if-else
- "
-if true {
-} else {
-|foo
-}
-" "
-if true {
-} else {
- |foo
-}
-")
-
-(check-indentation indent-if-else-if
- "
-if true {
-} else if false {
-|foo
-}
-" "
-if true {
-} else if false {
- |foo
-}
-")
-
-(check-indentation indent-if-body--no-effect-if-already-indented
- "
-if true {
- |x
-}
-""
-if true {
- |x
-}
-")
-
-(check-indentation indent-if-body-nested
- "
-if foo {
- if true {
-|foo
- }
-}
-" "
-if foo {
- if true {
- |foo
- }
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/1
- "
-switch true {
- |case foo:
-}
-" "
-switch true {
-|case foo:
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/2
- "
-switch true {
- |case foo:
-}
-" "
-switch true {
-|case foo:
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/3
- "
-{
- switch true {
-|case foo:
- }
-}
-" "
-{
- switch true {
- |case foo:
- }
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/4
- "
-{
- switch true {
- |case foo:
- }
-}
-" "
-{
- switch true {
- |case foo:
- }
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/5
- "
-switch {
- |case foo,
- bar, buz:
- foo
-}
-" "
-switch {
-|case foo,
- bar, buz:
- foo
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/6
- "
-switch {
- |case
- foo, bar, buz:
- foo
-}
-" "
-switch {
-|case
- foo, bar, buz:
- foo
-}
-")
-
-(check-indentation indents-case-statements-to-same-level-as-enclosing-switch/7
- "
-switch {
-case foo:
- foo
- bar
- |case baz:
-}
-" "
-switch {
-case foo:
- foo
- bar
-|case baz:
-}
-")
-
-(check-indentation indents-case-statement-bodies/1
-"
-switch x {
-case y:
-|return z
-}
-" "
-switch x {
-case y:
- |return z
-}
-")
-
-(check-indentation indents-case-statement-bodies/2
-"
-switch x {
-case y:
- |return z
-}
-" "
-switch x {
-case y:
- |return z
-}
-")
-
-(check-indentation indents-case-statement-bodies/3
-"
-switch x {
-case y:
- |return z
-}
-" "
-switch x {
-case y:
- |return z
-}
-")
-
-(check-indentation indents-case-statement-bodies/4
-"
-switch x {
-case y:
- x
- |return z
-}
-" "
-switch x {
-case y:
- x
- |return z
-}
-")
-
-(check-indentation indents-case-statement-bodies/5
-"
-switch x {
-case y:
- x
-|return z
-}
-" "
-switch x {
-case y:
- x
- |return z
-}
-")
-
-(check-indentation indents-case-statement-bodies/6
-"
-switch x {
-case y:
- x
- |return z
-}
-" "
-switch x {
-case y:
- x
- |return z
-}
-")
-
-
-(check-indentation
indents-default-statements-to-same-level-as-enclosing-switch/1
- "
-{
- switch true {
- case y:
- x
-|default:
- }
-}
-" "
-{
- switch true {
- case y:
- x
- |default:
- }
-}
-")
-
-(check-indentation
indents-default-statements-to-same-level-as-enclosing-switch/2
- "
-{
- switch true {
- case y:
- x
- |default:
- }
-}
-" "
-{
- switch true {
- case y:
- x
- |default:
- }
-}
-")
-
-(check-indentation
indents-default-statements-to-same-level-as-enclosing-switch/3
- "
-{
- switch true {
- case y:
- x
- default:
- foo
- |}
-}
-" "
-{
- switch true {
- case y:
- x
- default:
- foo
- |}
-}
-")
-
-(check-indentation indents-statements-under-default-case/1
- "
-{
- switch true {
- case y:
- x
- default:
- |z
- }
-}
-" "
-{
- switch true {
- case y:
- x
- default:
- |z
- }
-}
-")
-
-(check-indentation indents-case-statements-with-destucturing/1
- "
-switch true {
-case let(x, y) where x < y:
-|foo
-}
-" "
-switch true {
-case let(x, y) where x < y:
- |foo
-}
-")
-
-(check-indentation indents-case-statements-with-destucturing/2
- "
-switch true {
-case let .Foo(x) where x > 0:
-|foo
-}
-" "
-switch true {
-case let .Foo(x) where x > 0:
- |foo
-}
-")
-
-(check-indentation indents-case-statements-with-guard
- "
-switch true {
-case foo where bar:
-|foo
-}
-" "
-switch true {
-case foo where bar:
- |foo
-}
-")
-
-(check-indentation indents-case-statements-with-multiline-guard/1
- "
-switch true {
-case foo where bar,
-|bar where baz:
-}
-" "
-switch true {
-case foo where bar,
- |bar where baz:
-}
-")
-
-(check-indentation indents-case-statements-with-multiline-guard-custom-offset/1
- "
-switch true {
-case foo where bar,
-|bar where baz:
-}
-" "
-switch true {
-case foo where bar,
- |bar where baz:
-}
-"
-((swift-indent-hanging-comma-offset 3)))
-
-(check-indentation indents-case-statements-with-multiline-guard/2
- "
-switch true {
-case foo where bar,
- bar where baz:
-|foo
-}
-" "
-switch true {
-case foo where bar,
- bar where baz:
- |foo
-}
-")
-
-
-(check-indentation indents-case-statements-to-user-defined-offset/1
- "
-switch true {
- |case foo:
-}
-" "
-switch true {
- |case foo:
-}
-"
-((swift-indent-switch-case-offset 2)))
-
-(check-indentation indents-case-statements-to-user-defined-offset/2
- "
-switch true {
- |default:
-}
-" "
-switch true {
- |default:
-}
-"
-((swift-indent-switch-case-offset 2)))
-
-
-(check-indentation indents-case-statements-in-enum/1
- "
-enum T {
-|case
-}
-" "
-enum T {
- |case
-}
-")
-
-(check-indentation indents-case-statements-in-enum/2
- "
-enum T {
- |case
-}
-" "
-enum T {
- |case
-}
-")
-
-(check-indentation indents-case-statements-in-enum/3
- "
-enum Foo: Bar {
- |case
-}
-" "
-enum Foo: Bar {
- |case
-}
-")
-
-(check-indentation indents-declaration-statements-in-enum/1
- "
-enum Foo: Bar {
- case foo
- case bar
- |var foo
-}
-" "
-enum Foo: Bar {
- case foo
- case bar
- |var foo
-}
-")
-
-(check-indentation indents-for-statements/1
- "
-for index in 1..5 {
-|foo
-}
-" "
-for index in 1..5 {
- |foo
-}
-")
-
-(check-indentation indents-for-statements/2
- "
-for (key, value) in dict {
-|foo
-}
-" "
-for (key, value) in dict {
- |foo
-}
-")
-
-(check-indentation indents-for-statements/3
- "
-for var index = 0; index < 3; ++index {
-|foo
-}
-" "
-for var index = 0; index < 3; ++index {
- |foo
-}
-")
-
-(check-indentation indents-while-statements
- "
-while foo < bar{
-|foo
-}
-" "
-while foo < bar{
- |foo
-}
-")
-
-(check-indentation indents-import-statements/1
- "
-import Foo
- |import Bar
-" "
-import Foo
-|import Bar
-")
-
-(check-indentation indents-import-statements/2
- "
-import Darwin
- |class Test {
-}
-" "
-import Darwin
-|class Test {
-}
-")
-
-(check-indentation indents-class-declaration/1
- "
-class Foo {
- |foo
-}
-" "
-class Foo {
- |foo
-}
-")
-
-(check-indentation indents-class-declaration/2
- "
-class Foo: Bar {
- |foo
-}
-" "
-class Foo: Bar {
- |foo
-}
-")
-
-(check-indentation indents-class-declaration/3
- "
-class Foo: Foo, Bar, Baz {
- |foo
-}
-" "
-class Foo: Foo, Bar, Baz {
- |foo
-}
-")
-
-(check-indentation indents-class-declaration/4
- "
-class Foo: Bar {
-|class Baz: Bar {
- }
-}
-" "
-class Foo: Bar {
- |class Baz: Bar {
- }
-}
-")
-
-(check-indentation indents-class-declaration/5
- "
-class Foo: Foo, Bar,
-|Baz {
-}
-" "
-class Foo: Foo, Bar,
- |Baz {
-}
-")
-
-(check-indentation indents-class-declaration-custom-offset/1
- "
-class Foo: Foo, Bar,
-|Baz {
-}
-" "
-class Foo: Foo, Bar,
- |Baz {
-}
-"
-((swift-indent-hanging-comma-offset 3)))
-
-(check-indentation indents-class-declaration/6
- "
-class Foo:
-|Foo, Bar, Baz {
-}
-" "
-class Foo:
- |Foo, Bar, Baz {
-}
-")
-
-(check-indentation indents-class-declaration/7
- "
-class Foo: Bar<A, B,
-|C>
-" "
-class Foo: Bar<A, B,
- |C>
-")
-
-(check-indentation indents-class-declaration/8
- "
-class Foo<A: B<C>>:
- |Bar
-" "
-class Foo<A: B<C>>:
- |Bar
-")
-
-(check-indentation indents-class-declaration/9
- "
-class Foo: Foo,
- Bar,
- Bar2,
- |Baz {
-}
-" "
-class Foo: Foo,
- Bar,
- Bar2,
- |Baz {
-}
-")
-
-(check-indentation indents-class-declaration/10
- "
-class Foo: Foo,
- Bar,
- Bar2,
- Baz {
- |}
-" "
-class Foo: Foo,
- Bar,
- Bar2,
- Baz {
-|}
-")
-
-(check-indentation indents-public-class-declaration/1
- "
-public class Foo: Foo, Bar,
-|Baz {
-}
-" "
-public class Foo: Foo, Bar,
- |Baz {
-}
-")
-
-(check-indentation indents-public-class-declaration-custom-offset/1
- "
-public class Foo: Foo, Bar,
-|Baz {
-}
-" "
-public class Foo: Foo, Bar,
- |Baz {
-}
-"
-((swift-indent-hanging-comma-offset 3)))
-
-(check-indentation indents-public-class-declaration/2
- "
-public class Foo {
- |foo
-}
-" "
-public class Foo {
- |foo
-}
-")
-
-(check-indentation indents-public-class-declaration/3
- "
-public class Foo: Foo, Bar,
- Baz {
- |}
-" "
-public class Foo: Foo, Bar,
- Baz {
-|}
-")
-
-(check-indentation indents-public-class-declaration/4
- "
-public class Foo: Foo, Bar,
- Baz {
-|foo
-}
-" "
-public class Foo: Foo, Bar,
- Baz {
- |foo
-}
-")
-
-(check-indentation indents-func-declaration/1
- "
-func Foo(a: String) {
-|foo
-}
-" "
-func Foo(a: String) {
- |foo
-}
-")
-
-(check-indentation indents-func-declaration/2
- "
-override func Foo() {
-|foo
-}
-" "
-override func Foo() {
- |foo
-}
-")
-
-(check-indentation indents-func-declaration/3
- "
-func Foo(b: Double...) -> Bool {
-|foo
-}
-" "
-func Foo(b: Double...) -> Bool {
- |foo
-}
-")
-
-(check-indentation indents-func-declaration/4
- "
-class Foo {
- override func Foo(b: Double...) -> Bool {
-|foo
- }
-}
-" "
-class Foo {
- override func Foo(b: Double...) -> Bool {
- |foo
- }
-}
-")
-
-(check-indentation indents-func-declaration/5
- "
-class func Foo() {
-|foo
-}
-" "
-class func Foo() {
- |foo
-}
-")
-
-(check-indentation indents-func-declaration/6
- "
-func Foo(aaaaaaaaa:
- |AAAAAAAAA) {
-}
-" "
-func Foo(aaaaaaaaa:
- |AAAAAAAAA) {
-}
-")
-
-(check-indentation indents-func-declaration/7
- "
-func foo() ->
-|Foo
-" "
-func foo() ->
- |Foo
-")
-
-(check-indentation indents-func-declaration/8
- "
-func foo() ->
-|(A, B) {}
-" "
-func foo() ->
- |(A, B) {}
-")
-
-(check-indentation indents-func-declaration/9
- "
-func foo() ->
-|[A] {}
-" "
-func foo() ->
- |[A] {}
-")
-
-(check-indentation indents-func-declaration/10
- "
-func a(a: NSString = 1,
- |b: NSString = 2) {}
-" "
-func a(a: NSString = 1,
- |b: NSString = 2) {}
-")
-
-(check-indentation indents-func-declaration/11
- "
-class Foo: Bar {
- func Foo() {
-|foo
- }
-}
-" "
-class Foo: Bar {
- func Foo() {
- |foo
- }
-}
-")
-
-(check-indentation indents-func-declaration/12
- "
-class Foo: Bar {
- override func Foo() {
-|foo
- }
-}
-" "
-class Foo: Bar {
- override func Foo() {
- |foo
- }
-}
-")
-
-(check-indentation indents-protocol-declaration/1
- "
-protocol Foo {
- func foo()
-|func bar()
-}
-" "
-protocol Foo {
- func foo()
- |func bar()
-}
-")
-
-(check-indentation indents-protocol-declaration/2
- "
-protocol Foo {
- func foo() -> Foo
-|func bar() -> Bar
-}
-" "
-protocol Foo {
- func foo() -> Foo
- |func bar() -> Bar
-}
-")
-
-(check-indentation indents-protocol-declaration/3
- "
-protocol Foo {
- func foo() -> Foo<A>
-|func bar() -> Bar<A>
-}
-" "
-protocol Foo {
- func foo() -> Foo<A>
- |func bar() -> Bar<A>
-}
-")
-
-(check-indentation indents-protocol-declaration/4
- "
-protocol Foo {
- func foo() -> [A]
-|func bar() -> [A]
-}
-" "
-protocol Foo {
- func foo() -> [A]
- |func bar() -> [A]
-}
-")
-
-(check-indentation indents-declaration/1
- "
-var foo = bar + baz
- |
-" "
-var foo = bar + baz
-|
-")
-
-(check-indentation indents-declaration/2
- "
-let foo = bar +
-|baz
-" "
-let foo = bar +
- |baz
-")
-
-(check-indentation indents-declaration/3
- "
-let foo = [foo: bar, bar: baz]
- |
-" "
-let foo = [foo: bar, bar: baz]
-|
-")
-
-(check-indentation indents-declaration/4
- "
-let foo = [
-|bar: baz
-]
-" "
-let foo = [
- |bar: baz
-]
-")
-
-(check-indentation indents-declaration/5
- "
-let foo = [foo, bar]
- |
-" "
-let foo = [foo, bar]
-|
-")
-
-(check-indentation indents-declaration/6
- "
-let foo = [
-|bar
-]
-" "
-let foo = [
- |bar
-]
-")
-
-(check-indentation indents-declaration/7
- "
-var result = Dictionary<String, V>()
- |foo
-" "
-var result = Dictionary<String, V>()
-|foo
-")
-(check-indentation indents-declaration/8
- "
-let foo =
-|bar
-" "
-let foo =
- |bar
-")
-
-(check-indentation indents-declaration/9
- "
-let foo: Foo? =
-|bar
-" "
-let foo: Foo? =
- |bar
-")
-
-(check-indentation indents-declaration/10
- "
-let foo: Foo<A> =
-|bar
-" "
-let foo: Foo<A> =
- |bar
-")
-
-(check-indentation indents-declaration/11
- "
-let foo = [
- foo:
-|bar
-]
-" "
-let foo = [
- foo:
- |bar
-]
-")
-
-(check-indentation indents-declaration/12
- "
-let foo = [
-|[]]
-" "
-let foo = [
- |[]]
-")
-
-(check-indentation indents-declaration/13
- "
-let foo = [
-|[
- bar: baz
- ]
-]
-" "
-let foo = [
- |[
- bar: baz
- ]
-]
-")
-
-(check-indentation indents-declaration/14
- "
-let foo = [
- [
- |bar: baz
- ]
-]
-" "
-let foo = [
- [
- |bar: baz
- ]
-]
-")
-
-(check-indentation indents-declaration/15
- "
-let foo = [
- [
- bar: baz
-|]
-]
-" "
-let foo = [
- [
- bar: baz
- |]
-]
-")
-
-(check-indentation indents-expressions/1
- "
-class Foo {
- func a() {
- |[a]
- }
-}
-" "
-class Foo {
- func a() {
- |[a]
- }
-}
-")
-
-(check-indentation indents-expressions/2
- "
-class Foo {
- func a() {
- a
- |[a]
- }
-}
-" "
-class Foo {
- func a() {
- a
- |[a]
- }
-}
-")
-
-(check-indentation indents-multiline-expressions/1
-"
-Foo.bar([foo: bar,
-|bar: baz
-])
-" "
-Foo.bar([foo: bar,
- |bar: baz
-])
-")
-
-(check-indentation indents-multiline-expressions/2
- "
-Foo.bar(bar!,
-|baz)
-" "
-Foo.bar(bar!,
- |baz)
-")
-
-(check-indentation indents-multiline-expressions/3
- "
-Foo.bar(bar?,
-|baz)
-" "
-Foo.bar(bar?,
- |baz)
-")
-
-(check-indentation indents-multiline-expressions/4
- "
-let json_ary = NSJSONSerialization.
-|JSONObjectWithData(data, options: nil, error: &json_err) as NSArray
-" "
-let json_ary = NSJSONSerialization.
- |JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-")
-
-(check-indentation indents-multiline-expressions/5
- "
-let json_ary = NSJSONSerialization
-|.JSONObjectWithData(data, options: nil, error: &json_err) as NSArray
-" "
-let json_ary = NSJSONSerialization
- |.JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-")
-
-(check-indentation indents-multiline-expressions/6
- "
-let json_ary = NSJSONSerialization.
- |JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-" "
-let json_ary = NSJSONSerialization.
- |JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-")
-
-(check-indentation indents-multiline-expressions/7
- "
-let json_ary = NSJSONSerialization
- |.JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-" "
-let json_ary = NSJSONSerialization
- |.JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-")
-
-(check-indentation indents-multiline-expressions/8
- "
-let options = NSRegularExpressionOptions.CaseInsensitive &
-|NSRegularExpressionOptions.DotMatchesLineSeparators
-" "
-let options = NSRegularExpressionOptions.CaseInsensitive &
- |NSRegularExpressionOptions.DotMatchesLineSeparators
-")
-
-(check-indentation indents-multiline-expressions/9
- "
-foo?[bar] +
- |a
-" "
-foo?[bar] +
- |a
-")
-
-(check-indentation indents-multiline-expressions/10
- "
-foo?(bar) +
- |a
-" "
-foo?(bar) +
- |a
-")
-
-(check-indentation indents-multiline-expressions/11
- "
-func a () {
- a +
-|a
-}
-" "
-func a () {
- a +
- |a
-}
-")
-
-(check-indentation indents-multiline-expressions/12
- "
-func a () {
- a
-|.a()
-}
-" "
-func a () {
- a
- |.a()
-}
-")
-
-(check-indentation indents-multiline-expressions/13
- "
-if (a
-|.b){}
-" "
-if (a
- |.b){}
-")
-
-(check-indentation indents-multiline-expressions/14
- "
-a ??
-|b
-" "
-a ??
- |b
-")
-
-(check-indentation indents-multiline-expressions/15
- "
-a as
-|b
-" "
-a as
- |b
-")
-
-(check-indentation indents-multiline-expressions/16
- "
-a as?
-|b
-" "
-a as?
- |b
-")
-
-(check-indentation indents-multiline-expressions/17
- "
-a is
-|b
-" "
-a is
- |b
-")
-
-(check-indentation indents-multiline-expressions/18
- "
-CGPoint(x: aaaaaaaaaaaaaaa.x +
-|bbbbbbbbbbbbbbbb,
- y: aaaaaaaaaaaaaaa.y +
- bbbbbbbbbbbbbbbb)
-" "
-CGPoint(x: aaaaaaaaaaaaaaa.x +
- |bbbbbbbbbbbbbbbb,
- y: aaaaaaaaaaaaaaa.y +
- bbbbbbbbbbbbbbbb)
-")
-
-(check-indentation indents-multiline-expressions/19
- "
-let x = 1
-|+ 1
-" "
-let x = 1
- |+ 1
-")
-
-(check-indentation indents-multiline-expressions/20
- "
-let x = foo ??
- |bar
-" "
-let x = foo ??
- |bar
-")
-
-(check-indentation indents-multiline-expressions/21
- "
-let foo = a +
- b +
- |c +
- d
-" "
-let foo = a +
- b +
- |c +
- d
-")
-
-(check-indentation indents-multiline-expressions/22
- "
-let foo = a +
- b +
- c +
- |d
-" "
-let foo = a +
- b +
- c +
- |d
-")
-
-(check-indentation indents-multiline-expressions/23
- "
-let x = bar
- .buz() ??
-|defaultValue
-" "
-let x = bar
- .buz() ??
- |defaultValue
-")
-
-(check-indentation indents-multiline-expressions/24
- "
-let foo =
- bar +
- |baz +
- a
-" "
-let foo =
- bar +
- |baz +
- a
-")
-
-(check-indentation indents-long-parameters/1
- "
-func foo() {
- timer = NSTimer.scheduledTimerWithTimeInterval(
- |1.0,
- target: self,
- selector: Selector(\"onTimer\"),
- userInfo: nil,
- repeats: true)
-}
-" "
-func foo() {
- timer = NSTimer.scheduledTimerWithTimeInterval(
- |1.0,
- target: self,
- selector: Selector(\"onTimer\"),
- userInfo: nil,
- repeats: true)
-}
-")
-
-(check-indentation indents-long-parameters/2
- "
-aaaaaa.aaaaaaaaaaaaaaaaaaaaa(
- |aaaaaaaaaaaaaaaaaaaaa
-)
-" "
-aaaaaa.aaaaaaaaaaaaaaaaaaaaa(
- |aaaaaaaaaaaaaaaaaaaaa
-)
-")
-
-(check-indentation indents-long-parameters/3
- "
-public func tableView(
-|tableView: UITableView,
- commitEditingStyle editingStyle: UITableViewCellEditingStyle,
- forRowAtIndexPath indexPath: NSIndexPath) {
-}
-" "
-public func tableView(
- |tableView: UITableView,
- commitEditingStyle editingStyle: UITableViewCellEditingStyle,
- forRowAtIndexPath indexPath: NSIndexPath) {
-}
-")
-
-(check-indentation indents-long-parameters/4
- "
-func a(
- |a: a,
- a: a,
- a: a) {
-}
-" "
-func a(
- |a: a,
- a: a,
- a: a) {
-}
-")
-
-(check-indentation indents-long-parameters/5
- "
-func foo() {
- timer = NSTimer.scheduledTimerWithTimeInterval(
- 1.0,
- target: self,
- selector: Selector(\"onTimer\"),
- userInfo: nil,
- repeats: true
-|)
-}
-" "
-func foo() {
- timer = NSTimer.scheduledTimerWithTimeInterval(
- 1.0,
- target: self,
- selector: Selector(\"onTimer\"),
- userInfo: nil,
- repeats: true
- |)
-}
-")
-
-(check-indentation indents-multiline-expressions-to-user-defined-offset/1
- "
-NSNotificationCenter.defaultCenter()
-|.postNotificationName(foo, object: nil)
-" "
-NSNotificationCenter.defaultCenter()
- |.postNotificationName(foo, object: nil)
-"
-((swift-indent-multiline-statement-offset 4)))
-
-(check-indentation indents-multiline-expressions-to-user-defined-offset/2
- "
-let json_ary = NSJSONSerialization
- |.JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-" "
-let json_ary = NSJSONSerialization
- |.JSONObjectWithData(data, options: nil, error: &json_err) as
NSArray
-"
-((swift-indent-multiline-statement-offset 4)))
-
-(check-indentation indents-multiline-expressions-to-user-defined-offset/3
- "
-let options = NSRegularExpressionOptions.CaseInsensitive &
-|NSRegularExpressionOptions.DotMatchesLineSeparators
-" "
-let options = NSRegularExpressionOptions.CaseInsensitive &
- |NSRegularExpressionOptions.DotMatchesLineSeparators
-"
-((swift-indent-multiline-statement-offset 4)))
-
-(check-indentation indents-type-annotations/1
- "
-typealias Foo = Bar<Foo.Baz, Foo>
- |foo
-" "
-typealias Foo = Bar<Foo.Baz, Foo>
-|foo
-")
-
-(check-indentation indents-type-annotations/2
- "
-typealias Foo = Bar<Foo.Baz,
-|Foo>
-" "
-typealias Foo = Bar<Foo.Baz,
- |Foo>
-")
-
-(check-indentation indents-type-works-with-less-operator/1
- "
-typealias Foo = Bar<Foo.Baz, Foo>
-let foo = bar <
-|baz
-" "
-typealias Foo = Bar<Foo.Baz, Foo>
-let foo = bar <
- |baz
-")
-
-(check-indentation indents-type-works-with-less-operator/2
- "
-typealias Foo = Bar<Foo.Baz, Foo>
-let foo = bar >
-|baz
-" "
-typealias Foo = Bar<Foo.Baz, Foo>
-let foo = bar >
- |baz
-")
-
-(check-indentation indents-multiline-operators-only-once/1
- "
-1 +
- 2 + 5 *
-|3
-" "
-1 +
- 2 + 5 *
- |3
-"
-)
-
-(check-indentation indents-multiline-operators-only-once/2
- "
-1 +
- 2 * 5 +
-|3
-" "
-1 +
- 2 * 5 +
- |3
-"
-)
-
-(check-indentation conditional-operator/1
- "
-let a = a
- |? a +
- 1
- : a +
- 1
-" "
-let a = a
- |? a +
- 1
- : a +
- 1
-")
-
-(check-indentation conditional-operator/2
- "
-let a = a
- ? a +
- |1
- : a +
- 1
-" "
-let a = a
- ? a +
- |1
- : a +
- 1
-")
-
-(check-indentation conditional-operator/3
- "
-let a = a
- ? a +
- 1
- |: a +
- 1
-" "
-let a = a
- ? a +
- 1
- |: a +
- 1
-")
-
-(check-indentation conditional-operator/4
- "
-let a = a
- ? a +
- 1
- : a +
- |1
-" "
-let a = a
- ? a +
- 1
- : a +
- |1
-")
-
-(check-indentation conditional-operator/5
- "
-let a = a ?
-|a : a
-" "
-let a = a ?
- |a : a
-")
-
-(check-indentation conditional-operator/6
- "
-let a = a ?
- |b :
- c
-" "
-let a = a ?
- |b :
- c
-")
-
-(check-indentation conditional-operator/7
- "
-let a = a ?
- b :
- |c
-" "
-let a = a ?
- b :
- |c
-")
-
-(check-indentation conditional-operator/8
- "
-let a = a //foo
- |? a +
- 1
- : a +
- 1
-" "
-let a = a //foo
- |? a +
- 1
- : a +
- 1
-")
-
-(check-indentation conditional-operator/9
- "
-func foo() {
- return order!.deliver ?
- |OrderViewTableDeliveryCells.lastCellIndex.rawValue :
- OrderViewTableTakeAwayCells.lastCellIndex.rawValue
-}
-" "
-func foo() {
- return order!.deliver ?
- |OrderViewTableDeliveryCells.lastCellIndex.rawValue :
- OrderViewTableTakeAwayCells.lastCellIndex.rawValue
-}
-")
-
-(check-indentation conditional-operator/10
- "
-func foo() {
- return order!.deliver ?
- OrderViewTableDeliveryCells.lastCellIndex.rawValue :
- |OrderViewTableTakeAwayCells.lastCellIndex.rawValue
-}
-" "
-func foo() {
- return order!.deliver ?
- OrderViewTableDeliveryCells.lastCellIndex.rawValue :
- |OrderViewTableTakeAwayCells.lastCellIndex.rawValue
-}
-")
-
-(check-indentation conditional-operator/11
- "
-let a = a ? a +
- 1
- |: a +
- 1
-" "
-let a = a ? a +
- 1
- |: a +
- 1
-")
-
-(check-indentation blank-line/1
- "
-func foo() {
- let a = 1
-
-|let b = 1
-}
-" "
-func foo() {
- let a = 1
-
- |let b = 1
-}
-")
-
-(check-indentation block-inside-parenthesis/3
- "
-\({
-|a
-})
-" "
-\({
- |a
-})
-")
-
-(check-indentation indent-long-if-else-if/1
- "
-if a {
- a
-} else if a {
- a
-} else if a {
- |a
-} else {
- a
-}
-" "
-if a {
- a
-} else if a {
- a
-} else if a {
- |a
-} else {
- a
-}
-")
-
-(check-indentation indent-long-if-else-if/2
- "
-if a {
- a
-} else if a {
- a
-} else if a {
- a
-|} else {
- a
-}
-" "
-if a {
- a
-} else if a {
- a
-} else if a {
- a
-|} else {
- a
-}
-")
-
-(check-indentation indent-long-if-else-if/3
- "
-class Foo {
- func a() {
- if a {
- a
- } else if b {
- |a
- } else if a {
- a
- } else {
- a
- }
- }
-}
-" "
-class Foo {
- func a() {
- if a {
- a
- } else if b {
- |a
- } else if a {
- a
- } else {
- a
- }
- }
-}
-")
-
-(check-indentation indent-long-if-else-if/4
- "
-class Foo {
- func a() {
- if a {
- a
- } else if b {
- a
- |} else if a {
- a
- } else {
- a
- }
- }
-}
-" "
-class Foo {
- func a() {
- if a {
- a
- } else if b {
- a
- |} else if a {
- a
- } else {
- a
- }
- }
-}
-")
-
-(check-indentation anonymous-function-as-a-argument/1
- "
-UIView.animateWithDuration(1.0,
- animations: {
-|})
-" "
-UIView.animateWithDuration(1.0,
- animations: {
- |})
-")
-
-(check-indentation anonymous-function-as-a-argument/2
- "
-UIView.animateWithDuration(
- 1.0,
- animations: {
-|})
-" "
-UIView.animateWithDuration(
- 1.0,
- animations: {
- |})
-")
-
-(check-indentation anonymous-function-as-a-argument/3
- "
-func foo() {
- UIView.animateWithDuration(1.0,
- animations: {
- |}
- ) {
- completed in
- }
-}
-" "
-func foo() {
- UIView.animateWithDuration(1.0,
- animations: {
- |}
- ) {
- completed in
- }
-}
-")
-
-(check-indentation anonymous-function-as-a-argument/4
- "
-func foo() {
- UIView.animateWithDuration(1.0,
- animations: {
- }
-|) {
- completed in
- }
-}
-" "
-func foo() {
- UIView.animateWithDuration(1.0,
- animations: {
- }
- |) {
- completed in
- }
-}
-")
-
-(check-indentation anonymous-function-as-a-argument/5
- "
-foo.bar(10,
- completionHandler: { complete in
- |foo
- }
-)
-" "
-foo.bar(10,
- completionHandler: { complete in
- |foo
- }
-)
-")
-
-(check-indentation anonymous-function-as-a-argument/6
- "
-foo.bar(10,
- completionHandler: {
- complete in
- |foo
- }
-)
-" "
-foo.bar(10,
- completionHandler: {
- complete in
- |foo
- }
-)
-")
-
-(check-indentation anonymous-function-as-a-argument/7
- "
-foo.bar(10,
- completionHandler: { (
- |bar, baz) in
- foo
- }
-)
-" "
-foo.bar(10,
- completionHandler: { (
- |bar, baz) in
- foo
- }
-)
-")
-
-(check-indentation anonymous-function-as-a-argument/8
- "
-foo.bar(10,
- completionHandler: { (bar, baz) -> Void in
- |foo
- })
-" "
-foo.bar(10,
- completionHandler: { (bar, baz) -> Void in
- |foo
- })
-")
-
-(check-indentation anonymous-function-as-a-argument/9
- "
-foo.bar(10,
- completionHandler: { complete in
-
- if foo {
- bar
- } else {
- |bar
- }
- }
-)
-" "
-foo.bar(10,
- completionHandler: { complete in
-
- if foo {
- bar
- } else {
- |bar
- }
- }
-)
-")
-
-(check-indentation anonymous-function-as-a-argument/10
- "
-foo.bar(10,
- completionHandler: { complete in
-
- if foo {
- bar
- } else {
- bar
- |}
- }
-)
-" "
-foo.bar(10,
- completionHandler: { complete in
-
- if foo {
- bar
- } else {
- bar
- |}
- }
-)
-")
-
-(check-indentation trailing-closure/1
- "
-a(){
- (b: String, c:String) -> String in
- |println(c)
-}
-" "
-a(){
- (b: String, c:String) -> String in
- |println(c)
-}
-")
-
-(check-indentation trailing-closure/2
- "
-a(){
- b,c in
- |println(c)
-}
-" "
-a(){
- b,c in
- |println(c)
-}
-")
-
-(check-indentation indents-expression-with-optional-type/1
- "
-var object: JsonObject?
- |var object: JsonObject
-" "
-var object: JsonObject?
-|var object: JsonObject
-")
-
-(check-indentation indents-expression-with-optional-type/2
- "
-var object: JsonObject<Foo>?
- |var object: JsonObject
-" "
-var object: JsonObject<Foo>?
-|var object: JsonObject
-")
-
-(check-indentation indents-expression-with-implicit-unwrapped-type/1
- "
-var object: JsonObject!
- |var object: JsonObject
-" "
-var object: JsonObject!
-|var object: JsonObject
-")
-
-(check-indentation indents-expression-with-implicit-unwrapped-type/2
- "
-var object: JsonObject<Foo>!
- |var object: JsonObject
-" "
-var object: JsonObject<Foo>!
-|var object: JsonObject
-")
-
-(check-indentation indents-expression-with-comment/1
- "
-func foo() {
- foo() // foo
- |foo()
-}
-" "
-func foo() {
- foo() // foo
- |foo()
-}
-")
-
-(check-indentation indents-expression-with-comment/2
- "
-func foo() {
- let x = 1 // foo
- |/ 1
-}
-" "
-func foo() {
- let x = 1 // foo
- |/ 1
-}
-")
-
-(check-indentation indents-expression-with-comment/3
- "
-func foo() {
- foo()
- //
- |foo()
-}
-" "
-func foo() {
- foo()
- //
- |foo()
-}
-")
-
-(check-indentation indents-guard-statement/1
- "
-guard let x = y else {
- |return
-}
-" "
-guard let x = y else {
- |return
-}
-")
-
-(provide 'indentation-tests)
-
-;;; indentation-tests.el ends here
diff --git a/test/swift-files/comment.swift b/test/swift-files/comment.swift
new file mode 100644
index 0000000..8c44d03
--- /dev/null
+++ b/test/swift-files/comment.swift
@@ -0,0 +1,35 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+// aaa
+// bbb
+// ccc
+/*
+ * aa
+ * aa
+ * aa
+ */
+
+/* */ class Foo {
+ // aaa
+ // bbb
+ // ccc // swift-mode:test:keep-indent
+ // ddd // swift-mode:test:known-bug
+ /* // swift-mode:test:known-bug
+ * aa
+ * aa // swift-mode:test:keep-indent
+ * aa
+ */
+}
+
+@Annotation(aaa)
+private
+ /* */ final /*
+ */ class /*
+ */ Foo /*
+ */ {
+ aaa()
+ bbb()
+}
diff --git a/test/swift-files/declarations.swift
b/test/swift-files/declarations.swift
new file mode 100644
index 0000000..3f9549b
--- /dev/null
+++ b/test/swift-files/declarations.swift
@@ -0,0 +1,376 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+// Constant declarations
+
+let
+ foo
+ .bar
+ =
+ bar
+ .baz
+
+class Foo {
+ @ABC
+ open
+ weak
+ let
+ (
+ x,
+ y
+ )
+ :
+ (
+ Int,
+ Int
+ )
+ =
+ xx
+
+ @ABC
+ final
+ unowned(safe)
+ fileprivate
+ let
+ Foo
+ .Bar(x)
+ :
+ Foo
+ .Bar
+ =
+ xx
+
+ let f
+ = g
+ :
+ (
+ Int,
+ Int
+ )
+ ->
+ throws
+ [
+ X
+ ]
+
+
+ let x = 1,
+ y = 1,
+ z = 1
+
+ let
+ x = 1,
+ y = 1,
+ z = 1
+
+ let x = 1
+ , y = 1
+ , z = 1
+
+ // Declaring multiple variables with single `let` statement doesn't seem to
+ // be popular. Rather, we choose saving columns for the first variable.
+ private final let x = foo
+ .foo // This is intended.
+ .foo,
+ y = foo
+ .then { x // This is intended.
+ in
+ foo
+
+ return foo
+ }
+ .then { x
+ in
+ foo
+
+ return foo
+ },
+ z = foo
+ .foo
+ .foo
+}
+
+// Variable declarations
+
+class Foo {
+ internal var x = foo
+ .foo
+ .foo,
+ y = foo
+ .foo
+ .foo,
+ z = foo
+ .foo
+ .foo
+
+ internal var x
+ : (Int, Int) {
+ foo()
+
+ return foo()
+ }
+
+ internal var x
+ : (Int, Int) {
+ @A
+ mutating
+ get {
+ foo()
+
+ return foo()
+ }
+
+ @A
+ mutating
+ set
+ (it) {
+ foo()
+ foo(it)
+ }
+ }
+
+ internal var x
+ : (Int, Int) {
+ @A
+ mutating
+ get
+
+ @A
+ mutating
+ set
+ }
+
+ internal var x
+ :
+ (Int, Int)
+ =
+ foo
+ .bar {
+ return thisIsFunctionBlock
+ } {
+ // This is bad, but cannot decide indentation without looking forward
+ // tokens.
+ @A
+ willSet(a) {
+ foo()
+ foo()
+ }
+
+ @A
+ didSet(a) {
+ foo()
+ foo()
+ }
+ } // This is bad
+
+ internal var x
+ :
+ (Int, Int) {
+ @A
+ willSet(a) {
+ foo()
+ foo()
+ }
+
+ @A
+ didSet(a) {
+ foo()
+ foo()
+ }
+ }
+}
+
+// Type alias declaration
+
+class Foo {
+ typealias A<B> = C
+ .D
+
+ @A
+ private typealias A<B>
+ =
+ C
+ .D
+}
+
+// Function declarations
+
+@A
+private
+ final
+ func
+ foo<A, B>(
+ x:
+ Int
+ y:
+ Int
+ =
+ 1
+ z
+ w:
+ Int
+ ...
+ )
+ throws
+ ->
+ [A]
+ where
+ A:
+ C,
+ B =
+ C<D> {
+ foo()
+ foo()
+}
+
+func
+ foo()
+ ->
+ @A
+ B {
+ foo()
+ foo()
+}
+
+// Enumeration declarations
+
+fileprivate
+ indirect
+ enum
+ Foo<A, B>
+ : X,
+ Y,
+ Z
+ where
+ A:
+ C,
+ B =
+ D<E> {
+ @A
+ case A
+ case B
+ case C,
+ D,
+ E
+ indirect
+ case
+ F(
+ x:
+ X,
+ y:
+ Y
+ ),
+ G,
+ H
+
+ func foo() {
+ }
+
+ case I
+ case J
+}
+
+fileprivate
+ enum
+ Foo<A, B>
+ :
+ Int
+ where
+ A:
+ C,
+ B =
+ D<E> {
+ case A =
+ 1, // swift-mode:test:known-bug
+ B =
+ 2,
+ C =
+ 3
+ case D
+ = 1, // swift-mode:test:known-bug
+ E
+ = 2,
+ F
+ = 3
+
+ func foo() {
+ }
+}
+
+
+enum Foo
+ : X,
+ Y,
+ Z {
+}
+
+enum Foo
+ : X
+ , Y
+ , Z
+{
+}
+
+// Struct declarations
+
+@A
+fileprivate
+ struct
+ Foo<A, B>
+ : Bar<A, B>,
+ Baz<A, B>,
+ AAA<A, B>
+ where
+ A:
+ C,
+ B =
+ D<E> {
+ func foo()
+ func foo()
+}
+
+// Protocol declarations
+
+protocol Foo {
+ func foo(x, y) -> throws (A, B)
+ init<A, B>(x: Int) throws
+ where
+ A: C
+ subscript(x: Int) -> Int {
+ get
+ set
+ }
+ associatedtype AAA = BBB
+ convenience
+ init(x: Int, y, Int)
+}
+
+// Operator declarations
+
+infix
+ operator
+ +++
+ :
+ precedenceGroupName
+
+prefix
+ operator
+ +++
+
+postfix
+ operator
+ +++
+
+precedencegroup
+ precedenceGroupName {
+ higherThan:
+ lowerGroupName
+ lowerThan:
+ higherGroupName
+ assignment:
+ false
+ associativity:
+ left
+}
diff --git a/test/swift-files/expressions.swift
b/test/swift-files/expressions.swift
new file mode 100644
index 0000000..c34bc21
--- /dev/null
+++ b/test/swift-files/expressions.swift
@@ -0,0 +1,571 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+// Prefix expressions
+// See also operators.swift
+
+foo(
+ +a,
+ +b,
+ &x
+)
+
+// Try operators
+
+let foo = try
+ a() + try
+ b()
+
+let foo = try!
+ a() + try!
+ b()
+
+let foo = try?
+ a() + try?
+ b()
+
+let foo = a+try
+ a() +b+try
+ b()
+
+let foo = a+try!
+ a() + b+try!
+ b()
+
+let foo = a+try?
+ a() + b+try?
+ b()
+
+// Binary expressions
+// See also operators.swift
+
+let foo = 1 +
+ /* */ 2 +
+ 3 + 4 +
+ /* */ 5
+
+let foo = 1 +
+ 2 +
+ 3 + 4 + // swift-mode:test:keep-indent
+ 5
+
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 4)
+
+let foo = 1 +
+ 2 +
+ 3 + 4 +
+ 5
+
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+
+// Ternary conditional operator
+
+let foo = a()
+ ? b()
+ : c()
+
+let foo = a() ?
+ b() :
+ c()
+
+// Type-casting operators
+
+let foo = a is
+ A || b is
+ B
+
+let foo = a
+ is A || b
+ is B
+
+let foo = a as
+ A +++ b as
+ B
+
+let foo = a
+ as A +++ b
+ as B
+
+let foo = a as?
+ A +++ b as?
+ B
+
+let foo = a
+ as? A +++ b
+ as? B
+
+let foo = a as!
+ A +++ b as!
+ B
+
+let foo = a
+ as! A +++ b
+ as! B
+
+// Literal expression
+
+// Special literal
+
+let foo =
+ #file
+
+let foo = #file
+ +++ #function
+
+if
+ #file == a {
+}
+
+// Array literal
+
+let x = [
+ 1,
+ 2,
+ 3, 4,
+ 5
+]
+
+let x = [
+ 1,
+ 2,
+ 3, 4,
+ 5,
+]
+
+let x =
+ [
+ 1,
+ 2,
+ 3, 4,
+ 5
+ ]
+
+let x = [ 1,
+ 2,
+ 3, 4,
+ 5 ]
+
+let x =
+ [ 1
+ , 2
+ , 3, 4
+ , 5
+ ]
+
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
3)
+
+let x = [
+ 1,
+ 2,
+ 3, 4,
+ 5
+]
+
+let x = [
+ 1,
+ 2,
+ 3, 4,
+ 5,
+]
+
+let x =
+ [
+ 1,
+ 2,
+ 3, 4,
+ 5
+ ]
+
+let x = [ 1,
+ 2,
+ 3, 4,
+ 5 ]
+
+let x =
+ [ 1
+ , 2
+ , 3, 4
+ , 5 ]
+
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+
+// Dictionary literal
+
+let x = [
+ aaa:
+ aaa
+ + aaa,
+ aaa:
+ aaa
+ + aaa,
+ aaa: aaa, aaa:
+ aaa
+ + aaa,
+ aaa
+ : aaa
+ + aaa,
+ aaa: aaa, aaa
+ : aaa
+ + aaa,
+ aaa
+ : aaa
+ + aaa
+]
+
+let x =
+ [
+ aaa:
+ aaa
+ + aaa,
+ aaa:
+ aaa
+ + aaa,
+ aaa: aaa, aaa:
+ aaa
+ + aaa,
+ aaa
+ : aaa
+ + aaa,
+ aaa: aaa, aaa
+ : aaa
+ + aaa,
+ aaa
+ : aaa
+ + aaa
+ ]
+
+let x = [ aaa:
+ aaa
+ + aaa,
+ aaa:
+ aaa
+ + aaa,
+ aaa: aaa, aaa:
+ aaa
+ + aaa,
+ aaa:
+ aaa
+ + aaa
+ aaa
+ : aaa
+ + aaa,
+ aaa: aaa, aaa
+ : aaa
+ + aaa,
+ aaa
+ : aaa
+ + aaa ]
+
+let x = [
+ :
+]
+
+let x =
+ [
+ :
+ ]
+
+let x = [ :
+]
+
+// Closure expressions
+
+let x = {
+ println("Hello, World!")
+ println("Hello, World!")
+}
+
+let x = { x in
+ println("Hello, World! " + x)
+ println("Hello, World! " + x)
+}
+
+let x = { x
+ in
+ println("Hello, World! " + x)
+ println("Hello, World! " + x)
+}
+
+let x = {
+ x in
+ println("Hello, World! " + x)
+ println("Hello, World! " + x)
+}
+
+let x = {
+ x
+ in
+ println("Hello, World! " + x)
+ println("Hello, World! " + x)
+}
+
+let x = { (
+ x: Int,
+ y: Int
+ )
+ ->
+ throws
+ Foo
+ in
+ println("Hello, World! " + x + y)
+ println("Hello, World! " + x + y)
+
+ return foo
+}
+
+let x = { [
+ weak
+ self,
+ unowned(unsafe)
+ foo
+ ]
+ (
+ x: Int,
+ y: Int
+ )
+ throws
+ ->
+ Foo
+ in
+ println("Hello, World! " + x + y)
+ println("Hello, World! " + x + y)
+
+ return foo
+}
+
+let x = {
+ [
+ weak self,
+ weak foo
+ ]
+ (
+ x: Int,
+ y: Int
+ )
+ throws
+ ->
+ Foo
+ in
+ println("Hello, World! " + x + y)
+ println("Hello, World! " + x + y)
+
+ return foo
+}
+
+
+let x = { a,
+ b,
+ c, d,
+ e
+ in
+ println("Hello, World! " + x + y)
+}
+
+let x = {
+ a,
+ b,
+ c, d,
+ e
+ in
+ println("Hello, World! " + x + y)
+}
+
+let x = { a
+ , b
+ , c, d
+ , e
+ in
+ println("Hello, World! " + x + y)
+}
+
+// Implicit member expressions
+
+x =
+ .aaa
+
+// Parenthesized expressions
+
+let x = (
+ a,
+ b, c,
+ d,
+ e,
+ ++,
+ **, --,
+ aaa
+)
+
+let x = (
+ aaa:
+ a,
+ aaa: b, aaa:
+ c,
+ aaa:
+ d,
+ aaa
+ :e,
+ aaa:
+ ++,
+ aaa: **, aaa:
+ --,
+ aaa:
+ aaa
+)
+
+let x =
+ (
+ 1,
+ 2,
+ 3, 4,
+ 5
+ )
+
+let x = ( 1,
+ 2,
+ 3, 4,
+ 5 )
+
+let x =
+ ( 1
+ , 2
+ , 3, 4
+ , 5
+ )
+
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
3)
+
+
+let x = (
+ a,
+ b, c,
+ d,
+ e,
+ ++,
+ **, --,
+ aaa
+)
+
+let x = (
+ aaa:
+ a,
+ aaa: b, aaa:
+ c,
+ aaa:
+ d,
+ aaa
+ :e,
+ aaa:
+ ++,
+ aaa: **, aaa:
+ --,
+ aaa:
+ aaa
+)
+
+let x =
+ (
+ 1,
+ 2,
+ 3, 4,
+ 5
+ )
+
+let x = ( 1,
+ 2,
+ 3, 4,
+ 5 )
+
+let x =
+ ( 1
+ , 2
+ , 3, 4
+ , 5
+ )
+
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+
+// Selector expressions
+
+let x =
+ #selector(
+ Foo.bar(
+ _:,
+ aaa:,
+ bbb:
+ )
+ )
+
+let x =
+ #selector(
+ getter:
+ Foo.ppp
+ )
+
+// Funcation call expressions and explicit member expressions
+
+let x =
+ foo(a,
+ b,
+ c)
+
+let x =
+ foo(
+ a,
+ b,
+ c
+ )
+
+let x = foo
+ .bar(a:
+ aaa,
+ b:
+ bbb(c:
+ c,
+ c:
+ c) { x in
+ foo
+ bar
+ },
+ c:
+ aaaa[
+ aaa
+ ]
+ ) { aaa in
+ aaa
+ aaa
+ aaa
+ }
+
+let x = foo
+ .bar() { a in
+ aaa
+ }
+
+let x = foo
+ .bar() {
+ a in
+ aaa
+ }
+
+let x = foo
+ .bar() {
+ a
+ in
+ aaa
+ }
+
+foo
+(bar) // this is not a function call
+
+// Subscript expression
+
+foo[
+ 1,
+ 2, 3,
+ 4
+]
+
+foo
+[1] // this is not a subscript expression
diff --git a/test/swift-files/identifiers.swift
b/test/swift-files/identifiers.swift
new file mode 100644
index 0000000..7bff27f
--- /dev/null
+++ b/test/swift-files/identifiers.swift
@@ -0,0 +1,40 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+
+// Backquoted identifier must behave like normal identifier
+
+enum `switch` {
+ case 1
+}
+
+do {
+} catch `case`
+ where a
+
+
+let foo = `var`
+ .then {
+ }
+
+let x = `where` +
+ a
+
+
+// Keywords after dot must behave like normal identifier
+//
https://github.com/apple/swift-evolution/blob/master/proposals/0071-member-keywords.md
+
+let foo = foo.var
+ .then {
+ }
+
+let x = foo.where +
+ a
+
+// Unicode identifiers
+
+let こんにちは = 你好 +
+ 안녕하세요 +
+ 😊
diff --git a/test/swift-files/operators.swift b/test/swift-files/operators.swift
new file mode 100644
index 0000000..7f95ef6
--- /dev/null
+++ b/test/swift-files/operators.swift
@@ -0,0 +1,70 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+
+// Simple case
+
+let x = 1 +
+ 2 +
+ 3 + 4 +
+ 5
+
+let x = 1
+ + 2
+ + 3 + 4
+ + 5
+
+// User defined operator
+
+let x = 1 +++
+ 2 /=-+!*%<>&|^?~
+ 3 +++ 4 +++
+ 5
+
+// Prefix operators and postfix operators
+
+let x = 1
++++foo()
+
+let x = 1+++
+foo()
+
+// Comments precede over operators
+
+let x = 1 +// abc
+ 2 +/* abc*/
+ 3
+
+// Comments behave like whitespaces
+//
https://github.com/apple/swift-evolution/blob/master/proposals/0037-clarify-comments-and-operators.md
+let x = 1
+/*a*/+++foo()
+
+let x = 1
+ /*a*/+++ foo()
+
+let x = 1+++//
+foo()
+
+let x = 1+++/*a*/
+foo()
+
+let x = 1 +++/*a*/
+ foo()
+
+// Operators with dot
+
+// This must be equal to let x = (a.++.) a
+let x = a.++.
+b
+
+// This must be equal to let x = (a++) . a
+let x = a++.
+ a
+
+// Unicode operators
+
+let x = a ×
+ a // swift-mode:test:known-bug
diff --git a/test/swift-files/statements.swift
b/test/swift-files/statements.swift
new file mode 100644
index 0000000..67c6a28
--- /dev/null
+++ b/test/swift-files/statements.swift
@@ -0,0 +1,805 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+// For-in statements
+
+for x in xs {
+ foo()
+ foo()
+}
+
+for x
+ in xs {
+ foo()
+ foo()
+}
+
+for x in
+ xs {
+ foo()
+ foo()
+}
+
+for x
+ in
+ xs {
+ foo()
+ foo()
+}
+
+for
+ x
+ in
+ xs {
+ foo()
+ foo()
+}
+
+for
+ x
+ in xs
+ .foo() { // swift-mode:test:known-bug
+ foo()
+ foo()
+}
+
+for
+ (
+ x,
+ y
+ )
+ in
+ xs
+ .foo() +++ { z in // swift-mode:test:known-bug
+ bar()
+ } {
+ foo()
+ foo()
+}
+
+for
+ case
+ ( // swift-mode:test:known-bug
+ x,
+ y
+ )
+ in
+ xs
+ .foo() +++ { z in // swift-mode:test:known-bug
+ bar()
+ bar()
+ } {
+ foo()
+ foo()
+}
+
+for case
+ ( // swift-mode:test:known-bug
+ x,
+ y
+ )
+ in
+ xs
+ .foo() +++ { z in // swift-mode:test:known-bug
+ bar()
+ bar()
+ } {
+ foo()
+ foo()
+}
+
+
+for Foo
+ .Bar(x) // swift-mode:test:known-bug
+ in
+ xs {
+ foo()
+ foo()
+}
+
+for
+ Foo
+ .Bar(x) // swift-mode:test:known-bug
+ in
+ xs {
+ foo()
+ foo()
+}
+
+
+
+for x as
+ Foo // swift-mode:test:known-bug
+ in
+ xs {
+ foo()
+ foo()
+}
+
+
+for x
+ in
+ xs
+ .foo // swift-mode:test:known-bug
+ where // swift-mode:test:known-bug
+ aaa
+ .bbb(x) {
+ foo()
+ foo()
+}
+
+for x
+ in
+ xs where
+ aaa
+ .bbb(x) {
+ foo()
+ foo()
+}
+
+for x
+ in
+ xs
+ where aaa
+ .bbb(x) { // swift-mode:test:known-bug
+ foo()
+ foo()
+}
+
+for x
+ in
+ xs where aaa
+ .bbb(x) { // swift-mode:test:known-bug
+ foo()
+ foo()
+}
+
+for
+ x in xs
+ where
+ aaa.bbb(x) {
+ foo()
+ foo()
+}
+
+// While statements
+
+while foo
+ .bar() +++ { x in
+ foo()
+ foo()
+ } {
+ foo()
+ foo()
+}
+
+while
+ foo
+ .bar() +++ { x in
+ foo()
+ foo()
+ } {
+ foo()
+ foo()
+}
+
+while
+ let
+ x
+ =
+ xx,
+ var
+ y
+ =
+ yy,
+ x
+ ==
+ y,
+ case
+ (
+ a,
+ b
+ )
+ =
+ ab {
+ foo()
+ foo()
+}
+
+while let
+ x
+ =
+ xx,
+ var
+ y
+ =
+ yy,
+ x
+ ==
+ y,
+ case
+ (
+ a,
+ b
+ )
+ =
+ ab {
+ foo()
+ foo()
+}
+
+
+while let
+ x
+ =
+ xx
+ , var
+ y
+ =
+ yy
+ , x
+ ==
+ y
+ , case
+ (
+ a,
+ b
+ )
+ =
+ ab
+{
+ foo()
+ foo()
+}
+
+// Repeat-while statements
+
+repeat {
+ foo()
+ foo()
+} while foo
+ .bar() // swift-mode:test:known-bug
+ .baz()
+
+repeat {
+ foo()
+ foo()
+} while
+ foo
+ .bar() // swift-mode:test:known-bug
+ .baz()
+
+repeat {
+ foo()
+ foo()
+}
+ while
+ foo
+ .bar() // swift-mode:test:known-bug
+ .baz()
+
+repeat {
+ foo()
+ foo()
+}
+ while foo
+ .bar() // swift-mode:test:known-bug
+ .baz()
+
+// If statement
+
+if x
+ .foo()
+ .bar() {
+ foo()
+ foo()
+}
+
+if
+ x
+ .foo()
+ .bar() {
+ foo()
+ foo()
+}
+
+if
+ let
+ x
+ =
+ xx,
+ var
+ y
+ =
+ yy,
+ x
+ ==
+ y,
+ case
+ (
+ a,
+ b
+ )
+ =
+ ab {
+ foo()
+ foo()
+}
+
+if foo() {
+ foo()
+ foo()
+ foo()
+} else if foo() {
+ foo()
+ foo()
+ foo()
+} else if foo
+ .bar()
+ .baz() +++ { x in
+ return x
+ },
+ foo
+ .bar()
+ .baz() +++ { x in
+ return x
+ } {
+ foo()
+ foo()
+ foo()
+} else if
+ foo
+ .bar()
+ .baz() +++ { x in
+ return x
+ },
+ foo
+ .bar()
+ .baz() +++ { x in
+ return x
+ } {
+ foo()
+ foo()
+ foo()
+}
+
+// Guard statement
+
+guard
+ foo
+ .foo() else {
+ bar()
+ bar()
+}
+
+guard
+ foo
+ .foo()
+else {
+ bar()
+ bar()
+}
+
+guard foo
+ .foo()
+ .foo() +++ { x in
+ foo()
+ } else {
+ bar()
+ bar()
+}
+
+guard
+ foo
+ .foo()
+ .foo() +++ { x in
+ foo()
+ } else {
+ bar()
+ bar()
+}
+
+guard
+ let
+ x
+ =
+ xx,
+ var
+ y
+ =
+ yy,
+ x
+ ==
+ y,
+ case
+ (
+ a,
+ b
+ )
+ =
+ ab
+else {
+ foo()
+ foo()
+}
+
+guard
+ let
+ x
+ =
+ xx,
+ var
+ y
+ =
+ yy,
+ x
+ ==
+ y,
+ case
+ (
+ a,
+ b
+ )
+ =
+ ab else {
+ foo() // swift-mode:test:known-bug
+ foo()
+} // swift-mode:test:known-bug
+
+// Switch statement
+
+switch foo
+ .bar {
+case foo:
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+} // swift-mode:test:known-bug
+
+switch
+ foo
+ .bar {
+case foo:
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+} // swift-mode:test:known-bug
+
+
+switch foo {
+case foo:
+ foo()
+ .bar()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case .P(let x)
+ where
+ foo
+ .bar(),
+ .Q(let x)
+ where
+ foo
+ .bar(),
+ .R(let x)
+ where
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case let .P(x)
+ where
+ foo
+ .bar(),
+ let .Q(x)
+ where
+ foo
+ .bar(),
+ let .R(x)
+ where
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ let .P(x)
+ where
+ foo
+ .bar(),
+ let .Q(x)
+ where
+ foo
+ .bar(),
+ let .R(x)
+ where
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ let .P(x)
+ where
+ foo
+ .bar(),
+ let .Q(x)
+ where
+ foo
+ .bar(),
+ let .R(x)
+ where
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case let
+ .P(x) // swift-mode:test:known-bug
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ .Q(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ .R(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ let
+ .P(x) // swift-mode:test:known-bug
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ .Q(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ .R(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ let Foo
+ .P(x) // swift-mode:test:known-bug
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let Foo
+ .Q(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let Foo
+ .R(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar():
+ foo()
+ foo()
+case
+ Foo
+ .P, // swift-mode:test:known-bug
+ Foo
+ .Q,
+ Foo
+ .R:
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ let
+ Foo // swift-mode:test:known-bug
+ .P(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ Foo
+ .Q(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let
+ Foo
+ .R(x)
+ where // swift-mode:test:known-bug
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+switch foo {
+case
+ is
+ Foo // swift-mode:test:known-bug
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ is
+ Foo
+ where // swift-mode:test:known-bug
+ foo
+ .bar(),
+ let Foo
+ .Bar
+ .Baz
+ where // swift-mode:test:known-bug
+ foo
+ .bar():
+ foo()
+ foo()
+default:
+ foo()
+ foo()
+}
+
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 2)
+
+switch foo {
+ case foo:
+ foo() // swift-mode:test:known-bug
+ foo()
+ default:
+ foo() // swift-mode:test:known-bug
+ foo()
+}
+
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+
+
+// Labeled statements
+
+
+foo:
+ if foo
+ .bar == baz {
+}
+
+foo:
+ if
+ foo
+ .bar == baz {
+}
+
+
+foo:
+ for
+ x
+ in
+ xs {
+ foo()
+ foo()
+}
+
+// Control transfer statements
+
+while foo() {
+ break
+ continue
+ return
+ foo()
+ throw
+ foo()
+
+ switch foo() {
+ case A:
+ foo()
+ fallthrough
+ case B:
+ foo()
+ fallthrough
+ default:
+ foo()
+ }
+}
+
+// Defer statements
+
+defer {
+ foo()
+ bar()
+ baz()
+}
+
+// Do statements
+
+do {
+} catch Foo
+ .Bar(x)
+ where // swift-mode:test:known-bug
+ foo()
+ .bar() {
+ foo()
+ foo()
+} catch
+ Foo // swift-mode:test:known-bug
+ .Bar(x)
+ where
+ foo()
+ .bar() {
+ foo()
+ foo()
+} catch
+ where // swift-mode:test:known-bug
+ foo()
+ .bar() {
+ foo()
+ foo()
+}
+
+// Conditional control statements
+
+func foo() {
+ #if foo
+ foo()
+ foo()
+ #elsif foo
+ foo()
+ foo()
+ #else
+ foo()
+ foo()
+ #end
+}
diff --git a/test/swift-files/types.swift b/test/swift-files/types.swift
new file mode 100644
index 0000000..e058e44
--- /dev/null
+++ b/test/swift-files/types.swift
@@ -0,0 +1,274 @@
+// swift-mode:test:eval (setq-local swift-mode:basic-offset 4)
+// swift-mode:test:eval (setq-local swift-mode:parenthesized-expression-offset
2)
+// swift-mode:test:eval (setq-local swift-mode:multiline-statement-offset 2)
+// swift-mode:test:eval (setq-local swift-mode:switch-case-offset 0)
+
+// Simple types
+
+let foo: A
+ = abc
+
+let foo:
+ A = abc
+
+let foo
+ :A = abc
+
+class Foo:
+ A,
+ B, C,
+ D {
+}
+
+class Foo
+ : A,
+ B, C,
+ D {
+}
+
+
+class Foo: A
+ , B , C
+ , D
+{
+}
+
+class Foo
+ : A
+ , B , C
+ , D
+{
+}
+
+
+// Types with attribute
+
+let foo: @A A
+ = abc
+
+let foo: @A
+ A = abc
+
+let foo:
+ @A
+ A = abc
+
+let foo
+ :@A
+ A = abc
+
+class Foo:
+ @A
+ A,
+ B {
+}
+
+class Foo
+ : @A
+ A, // swift-mode:test:known-bug
+ B {
+}
+
+class Foo: @A
+ A // swift-mode:test:known-bug
+ , B
+{
+}
+
+class Foo
+ : @A
+ A // swift-mode:test:known-bug
+ , B
+{
+}
+
+// Member types
+
+let foo:
+ /* */ A.
+ /* */ B = abc
+
+let foo:
+ /* */ A
+ /* */ .B = abc
+
+class Foo:
+ A.
+ B, // swift-mode:test:known-bug
+ A.
+ B,
+ A
+ .B {
+}
+
+class Foo
+ : A.
+ B, // swift-mode:test:known-bug
+ A.
+ B,
+ A
+ .B {
+}
+
+class Foo: A.
+ B, // swift-mode:test:known-bug
+ , A.
+ B
+ , A
+ .B
+{
+}
+
+class Foo
+ : A.
+ B // swift-mode:test:known-bug
+ , A.
+ B,
+ , A
+ .B {
+}
+
+// Array types
+
+let foo: [
+ A
+]
+ = abc
+
+let foo:
+ [
+ A
+ ] = abc
+
+let foo
+ :[
+ A
+ ] = abc
+
+// Tuple types
+
+let foo: (
+ /* */ A,
+ B
+)
+ = abc
+
+let foo:
+ (
+ /* */ A,
+ B
+ ) = abc
+
+let foo
+ :(
+ /* */ A,
+ B
+ ) = abc
+
+// Dictionary types
+
+let foo: [
+ /* */ A:
+ B
+]
+ = abc
+
+let foo:
+ [
+ /* */ A:
+ B
+ ] = abc
+
+let foo
+ :[
+ /* */ A:
+ B
+ ] = abc
+
+// Function types
+
+let foo: (
+ A,
+ B
+)
+ ->
+ throws (
+ A,
+ B
+ )
+ ->
+ throws
+ [
+ A
+ ]
+ = abc
+
+
+let foo:
+ (
+ A,
+ B
+ )
+ ->
+ throws
+ (
+ A,
+ B
+ )
+ ->
+ throws
+ [
+ B
+ ]
+ = abc
+
+let foo
+ :(
+ A,
+ B
+ )
+ ->
+ throws
+ B
+ = abc
+
+let foo:
+ (A, B)
+ ->
+ rethrows
+ B
+ = abc
+
+let foo
+ :(A, B)
+ ->
+ rethrows
+ B
+ = abc
+
+
+// Optional types
+
+let foo: A?
+ = abc
+
+let foo:
+ A? = abc
+
+let foo: A!
+ = abc
+
+let foo:
+ A! = abc
+
+// Protocol composition types
+
+let foo: protocol<A<[B]>,
+ C<(D, E)>>
+ = a
+
+let foo: protocol<
+ A, // swift-mode:test:known-bug
+ B
+> // swift-mode:test:known-bug
+ = a
diff --git a/test/swift-mode-test-indent.el b/test/swift-mode-test-indent.el
new file mode 100644
index 0000000..caad818
--- /dev/null
+++ b/test/swift-mode-test-indent.el
@@ -0,0 +1,164 @@
+;;; swift-mode-test-indent.el --- Test for swift-mode: indentation -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2016 taku0
+
+;; Authors: taku0 (http://github.com/taku0)
+;;
+;; Version: 2.1
+;; Package-Requires: ((emacs "24.4"))
+;; Keywords: languages swift
+;; URL: https://github.com/swift-emacs/swift-mode
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Test for swift-mode: indentation.
+;; Execute swift-mode:run-test:indent interactively or in batch mode.
+
+;;; Code:
+
+(require 'swift-mode)
+(require 'swift-mode-indent)
+
+(defvar swift-mode:test:basedir
+ (file-name-directory (or load-file-name buffer-file-name)))
+
+(defun swift-mode:setup-error-buffer ()
+ "Initialize and switch to the error buffer.
+
+Return the error-buffer"
+ (switch-to-buffer (get-buffer-create "*swift-mode-test-indent*"))
+ (fundamental-mode)
+ (setq view-read-only nil)
+ (erase-buffer)
+ (current-buffer))
+
+(defun swift-mode:run-test:indent ()
+ "Run indentation test for swift-mode."
+ (interactive)
+ (let ((error-buffer
+ (if noninteractive nil (swift-mode:setup-error-buffer)))
+ (current-line 0)
+ (error-count 0))
+ (setq default-directory
+ (concat (file-name-as-directory swift-mode:test:basedir)
+ "swift-files"))
+
+ (dolist (swift-file (file-expand-wildcards "*.swift"))
+ (with-temp-buffer
+ (switch-to-buffer (current-buffer))
+ (insert-file-contents-literally swift-file)
+ (swift-mode)
+ (setq current-line 0)
+ (while (not (eobp))
+ (setq current-line (1+ current-line))
+ (cond
+ ((looking-at ".*//.*swift-mode:test:keep-indent")
+ nil)
+
+ ((= (line-beginning-position) (line-end-position))
+ ;; Empty line
+ nil)
+
+ (t
+ (when (looking-at ".*//.*swift-mode:test:eval\\(.*\\)")
+ (eval-region (match-beginning 1) (match-end 1)))
+ (unless
+ (swift-mode:test-current-line-indent
+ swift-file current-line error-buffer)
+ (setq error-count (1+ error-count)))))
+ (forward-line))))
+ (when (= error-count 0)
+ (swift-mode:print-message error-buffer "no regressions\n"))
+ (when (not noninteractive)
+ (compilation-mode))))
+
+(defun swift-mode:test-current-line-indent
+ (swift-file current-line error-buffer)
+ "Run indentation test for swift-mode on current line.
+
+SWIFT-FILE is the filename of the current test case.
+CURRENT-LINE is the current line number.
+ERROR-BUFFER is the buffer to output errors."
+ (back-to-indentation)
+ (let ((original-indent (current-column))
+ computed-indent
+ (known-bug (looking-at ".*//.*swift-mode:test:known-bug")))
+ (delete-horizontal-space)
+ (when (= original-indent 0)
+ (indent-line-to 1))
+
+ (swift-mode:indent-line)
+ (back-to-indentation)
+ (setq computed-indent (current-column))
+ (indent-line-to original-indent)
+
+ (when (/= original-indent computed-indent)
+ (swift-mode:show-error
+ error-buffer swift-file current-line
+ (if known-bug "warning" "error")
+ (concat
+ (if known-bug "(knwon bug) " "")
+ "expected "
+ (prin1-to-string original-indent)
+ " but "
+ (prin1-to-string computed-indent))))
+
+ (when (and (= original-indent computed-indent) known-bug)
+ (swift-mode:show-error
+ error-buffer swift-file current-line
+ "info"
+ "known-bug is fixed somehow"))
+
+ (= original-indent computed-indent)))
+
+(defun swift-mode:show-error (error-buffer file line level message)
+ "Show an error message to the ERROR-BUFFER or stdout.
+
+If the Emacs is in the batch mode, the message is printed to the stdout.
+Otherwise, the message is appended to the ERROR-BUFFER.
+
+FILE is the filename of the test case.
+LINE is the line number of the error.
+LEVEL is the error level (e.g. error, warning).
+MESSAGE is the error message."
+ (let ((formatted
+ (concat
+ "swift-mode-test:"
+ file
+ ":"
+ (prin1-to-string line)
+ ": "
+ level
+ ": "
+ message
+ "\n")))
+ (swift-mode:print-message error-buffer formatted)))
+
+(defun swift-mode:print-message (error-buffer message)
+ "Print a message to the ERROR-BUFFER or stdout.
+
+If the Emacs is in the batch mode, MESSAGE is printed to the stdout.
+Otherwise, MESSAGE is appended to the ERROR-BUFFER."
+ (if noninteractive
+ (princ message)
+ (with-current-buffer error-buffer
+ (insert-and-inherit message))))
+
+(provide 'swift-mode-test-indent)
+
+;;; swift-mode-test-indent.el ends here
- [nongnu] elpa/swift-mode 3aec61f 279/496: Update Emacs version requirement in README, (continued)
- [nongnu] elpa/swift-mode 3aec61f 279/496: Update Emacs version requirement in README, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 6793bd9 281/496: Indent according to operators precedence, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode add2ae9 282/496: Merge pull request #111 from uk-ar/indent-according-to-prec, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 8889a6a 285/496: Merge pull request #112 from uk-ar/fix-multiline-expressions, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 064d4ee 287/496: Update acknowledgments section in readme, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode b7cc115 293/496: Merge pull request #116 from syohex/use-cl-lib, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode e9648b1 296/496: Use .el for file extension in distributed package., ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 1563e8b 300/496: Bump the development version to 0.5.0-snapshot, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode a5e1acf 297/496: Merge pull request #122 from N4tr0n/make-install-fix-issue120, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode cfaeaff 294/496: Update MELPA URL, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 9471669 304/496: Merge taku0/swift3-mode,
ELPA Syncer <=
- [nongnu] elpa/swift-mode 848d088 310/496: Fix indentation after attributes with arguments, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode cad72a1 306/496: Fix a link in README.md, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 0a75736 317/496: Fix indentation, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode c1f7ec2 321/496: Fix indentation of switch-case body, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 7423f68 324/496: Simplify code, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 58f31cc 340/496: Speed-up indentation for colon, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 0b1f29d 334/496: Fix indentation of setter, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 812d202 341/496: Fix REPL prompt corruption, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode f755479 333/496: Fix anchor highlighting, ELPA Syncer, 2021/08/29
- [nongnu] elpa/swift-mode 56ee9b2 359/496: Add comment style option, ELPA Syncer, 2021/08/29