branch: elpa/swift-mode commit ca6437a079036f8a101b492374d1884b8c50e1c6 Merge: 699e896 0fcf3ab Author: Bozhidar Batsov <bozhi...@batsov.com> Commit: Bozhidar Batsov <bozhi...@batsov.com>
Merge pull request #29 from ap4y/master Set of improvements and fixes #1 --- swift-mode.el | 82 ++++++++++++++++++++++++++++---- test/font-lock-tests.el | 7 +++ test/indentation-tests.el | 116 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 190 insertions(+), 15 deletions(-) diff --git a/swift-mode.el b/swift-mode.el index 1e289cb..4447b58 100644 --- a/swift-mode.el +++ b/swift-mode.el @@ -66,7 +66,7 @@ (smie-merge-prec2s (smie-bnf->prec2 '((id) - (type) + (type (type) (type "<T" types "T>")) (types (type) (type "," type)) (class-decl-exp (id) (id ":" types)) @@ -95,7 +95,7 @@ (class-level-sts (class-level-st) (class-level-st ";" class-level-st)) (class-level-st (decl) - ("override" "func" func-header "{" insts "}")) + ("DECSPEC" "func" func-header "{" insts "}")) (func-header (id "(" func-params ")")) (func-param (decl-exp) ("...")) @@ -108,7 +108,7 @@ (dot-exp "{" insts "}") (method-call) (method-call "{" insts "}") - ("enum" decl-exp "{" enum-cases "}") + ("enum" decl-exp "{" enum-body "}") ("switch" exp "{" switch-body "}") (if-clause) ("for" for-head "{" insts "}") @@ -127,7 +127,8 @@ (op-exp (exp "OP" exp)) (enum-cases (assign-exp) - (enum-cases "case" enum-cases)) + (enum-cases ";" "ecase" enum-cases)) + (enum-body (enum-cases) (insts)) (case-exps (guard-exp)) (cases (case-exps ":" insts) @@ -144,6 +145,7 @@ '((nonassoc "{") (assoc ",") (assoc ";") (assoc ":")) '((assoc "in") (assoc "where") (assoc "OP")) '((assoc "else")) + '((assoc ";") (assoc "ecase")) '((assoc "case"))) (smie-precs->prec2 @@ -178,6 +180,9 @@ "*" "/" "%" "&*" "&/" "&%" "&" "<<" ">>"))) +(defvar swift-smie--decl-specifier-regexp + (regexp-opt '("class" "mutating" "override" "static" "unowned" "weak"))) + (defun swift-smie--implicit-semi-p () (save-excursion (not (or (memq (char-before) '(?\{ ?\[ ?\,)) @@ -189,11 +194,31 @@ ((and (looking-at "\n") (swift-smie--implicit-semi-p)) (if (eolp) (forward-char 1) (forward-comment 1)) ";") + ((looking-at "{") (forward-char 1) "{") ((looking-at "}") (forward-char 1) "}") + + ((looking-at ",") (forward-char 1) ",") + + ((looking-at "<") (forward-char 1) + (if (looking-at "[[:upper:]]") "<T" "OP")) + ((looking-at ">") (forward-char 1) + (if (looking-back "[[:space:]]>" 2 t) "OP" "T>")) + ((looking-at swift-smie--operators-regexp) (goto-char (match-end 0)) "OP") - (t (smie-default-forward-token)))) + + ((looking-at swift-smie--decl-specifier-regexp) + (goto-char (match-end 0)) "DECSPEC") + + (t (let ((tok (smie-default-forward-token))) + (cond + ((equal tok "case") + (if (looking-at ".+\\(,\\|:\\)") + "case" + "ecase")) + (t tok)))) + )) (defun swift-smie--backward-token () (let ((pos (point))) @@ -202,11 +227,31 @@ ((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) + (if (looking-at "<[[:upper:]]") "<T" "OP")) + ((eq (char-before) ?>) (backward-char 1) + (if (looking-back "[[:space:]]" 1 t) "OP" "T>")) + ((looking-back swift-smie--operators-regexp (- (point) 3) t) (goto-char (match-beginning 0)) "OP") - (t (smie-default-backward-token))))) + + ((looking-back swift-smie--decl-specifier-regexp (- (point) 8) t) + (goto-char (match-beginning 0)) "DECSPEC") + + (t (let ((tok (smie-default-backward-token))) + (cond + ((equal tok "case") + (if (looking-at ".+\\(,\\|:\\)") + "case" + "ecase")) + (t tok)))) + ))) (defun swift-smie-rules (kind token) (pcase (cons kind token) @@ -224,6 +269,10 @@ (if (smie-rule-parent-p "{") swift-indent-offset (smie-rule-parent)))) + + (`(:before . "(") + (if (smie-rule-next-p "[") (smie-rule-parent))) + (`(:before . "[") (smie-rule-parent)) )) ;;; Font lock @@ -234,6 +283,9 @@ (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")) @@ -249,9 +301,15 @@ "nonmutating" "operator" "override" "postfix" "precedence" "prefix" "right" "set" "unowned" "unowned(safe)" "unowned(unsafe)" "weak" "willSet" "convenience")) +(defvar swift-mode--attribute-keywords + '("assignment" "class_protocol" "exported" "final" "lazy" "noreturn" + "NSCopying" "NSManaged" "objc" "optional" "required" "auto_closure" + "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 @@ -275,6 +333,14 @@ 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 @@ -338,9 +404,7 @@ (remove-text-properties start end '(swift-interpolation-match-data)) (funcall (syntax-propertize-rules - ((rx (or line-start (not (any "\\"))) - (zero-or-more "\\\\") - (group "\\(" (zero-or-more any) ")")) + ((rx (group "\\(" (*? any) ")")) (0 (ignore (swift-syntax-propertize-interpolation))))) start end))) diff --git a/test/font-lock-tests.el b/test/font-lock-tests.el index acd14b0..d1ddafc 100644 --- a/test/font-lock-tests.el +++ b/test/font-lock-tests.el @@ -187,6 +187,13 @@ test will fail." (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/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") (provide 'font-lock-tests) diff --git a/test/indentation-tests.el b/test/indentation-tests.el index 502e961..5f4d394 100644 --- a/test/indentation-tests.el +++ b/test/indentation-tests.el @@ -505,6 +505,21 @@ enum Foo: Bar { } ") +(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 { @@ -652,6 +667,17 @@ class Foo { } ") +(check-indentation indents-func-declaration/2 + " +class func Foo() { +|foo +} +" " +class func Foo() { + |foo +} +") + (check-indentation indents-declaration/1 " var foo = bar + baz @@ -683,11 +709,11 @@ let foo = [foo: bar, bar: baz] " let foo = [ |bar: baz - ] +] " " let foo = [ - |bar: baz - ] + |bar: baz +] ") (check-indentation indents-declaration/5 @@ -703,11 +729,89 @@ let foo = [foo, bar] " let foo = [ |bar - ] +] " " let foo = [ - |bar - ] + |bar +] +") + +(check-indentation indents-declaration/7 + " +var result = Dictionary<String, V>() + |foo +" " +var result = Dictionary<String, V>() +|foo +") + +(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-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 ") (provide 'indentation-tests)