branch: elpa/scala-mode commit d357a77a9067b5403e5e44a1f02f6d9f501c8e89 Author: Heikki Vesalainen <heikkivesalai...@yahoo.com> Commit: Heikki Vesalainen <heikkivesalai...@yahoo.com>
New 'scala-indent:align-parameters' customization variable --- Examples.md | 7 +-- README.md | 31 ++++++++++++-- scala-mode-indent.el | 118 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 114 insertions(+), 42 deletions(-) diff --git a/Examples.md b/Examples.md index cc03df1..b4f801f 100644 --- a/Examples.md +++ b/Examples.md @@ -124,8 +124,8 @@ val someLongName = aFunctionCall(aCollection map ( name => value )) -trait Foo extends Map[Option[x] forSome { - type x <: String +trait Foo extends Map[Option[x] forSome { + type x <: String }, Boolean] val someLongName = aFunctionCall( @@ -160,7 +160,8 @@ val someLongName = aFunctionCall(aCollection map ( name => )) val someLongName = aFunctionCall("foo". - length) + length + ) trait Foo extends Map[Option[x] forSome { type x <: String diff --git a/README.md b/README.md index 81986d9..6b8e5b8 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,9 @@ will toggle between the modes. ### Value expressions (scala-indent:indent-value-expression) -When set to t (default), blocks in value expressions will be indented -one extra step to make the 'val', 'var' or 'def' stand out. For example: +When this variable is set to t (default), blocks in value expressions +will be indented one extra step to make the 'val', 'var' or 'def' +stand out. For example: ``` val x = try { @@ -105,6 +106,30 @@ val x = try { } ``` +### Parameter lists (scala-indent:align-parameters) + +When this variable is set to 't' (default), parameters and run-on +lines in parameter lists will always align under and acording to the +first parameter. + +``` +val x = equals(List(1,2,3) map (x => + x + 1)) + +val y = List( "Alpha", "Bravo", + "Charlie" ) +``` + +When the variable is set to nil, the same will be as: + +``` +val x = equals(List(1,2,3) map (x => + x + 1)) + +val y = List( "Alpha", "Bravo", + "Charlie" ) +``` + ## Motion Basic emacs motion will work as expected. The forward-sexp and @@ -141,4 +166,4 @@ Mode development: Heikki Vesalainen Contributors and valuable feedback: - Ray Racine - Eiríkr Åsheim (aka Erik Osheim) -- Seth Tisue \ No newline at end of file +- Seth Tisue diff --git a/scala-mode-indent.el b/scala-mode-indent.el index c1fba0b..4a0b60c 100644 --- a/scala-mode-indent.el +++ b/scala-mode-indent.el @@ -38,6 +38,32 @@ val x = try { :type 'boolean :group 'scala) +(defcustom scala-indent:align-parameters t + "Whether or not to indent parameter lists so that next + parameter lines always align under the first parameter. When + non-nil, indentation will be + +def foo(x: Int, y: List[Int] + z: Int) + +val x = foo(1, List(1, 2, 3) map (i => + i + 1 + ), 2) + +When nil, the same will indent as + +def foo(x: Int, y: List[Int] + z: Int) + +val x = foo(1, List(1, 2, 3) map (i => + i + 1 + ), 2) +" + :type 'boolean + :group 'scala) + + + (defconst scala-indent:eager-strategy 0 "See 'scala-indent:run-on-strategy'") (defconst scala-indent:operator-strategy 1 @@ -117,7 +143,7 @@ it is nilled." "Skip sexps backwards until reaches beginning of line (i.e. the point is at the first non whitespace or comment character). It does not move outside enclosin list. Returns the current point or -nil if the beginnig of line could not be reached because of +nil if the beginning of line could not be reached because of enclosing list." (let ((code-beg (scala-lib:point-after (scala-syntax:beginning-of-code-line)))) @@ -131,6 +157,26 @@ enclosing list." (unless (> (point) code-beg) (point)))) +(defun scala-indent:align-anchor () + "Go to beginning of line, if a) scala-indent:align-parameters +is nil or backward-sexp-to-beginning-of-line is non-nil. This has +the effect of staying within lists if +scala-indent:align-parameters is non-nil." + (when (or (scala-indent:backward-sexp-to-beginning-of-line) + (not scala-indent:align-parameters)) + (back-to-indentation))) + +(defun scala-indent:value-expression-lead (start anchor) + ;; calculate an indent lead. The lead is one indent step if there is + ;; a '=' between anchor and start, otherwise 0. + (if (and scala-indent:indent-value-expression + (ignore-errors + (save-excursion + (let ((block-beg (nth 1 (syntax-ppss start)))) + (goto-char anchor) + (scala-syntax:has-char-before ?= block-beg))))) + scala-indent:step 0)) + ;;; ;;; Run-on ;;; @@ -267,8 +313,7 @@ is not on a run-on line." (while (and (scala-indent:run-on-line-p nil strategy) (scala-syntax:skip-backward-ignorable) (scala-indent:backward-sexp-to-beginning-of-line))) - (when (scala-indent:backward-sexp-to-beginning-of-line) - (back-to-indentation)) + (scala-indent:align-anchor) (point))) (defconst scala-indent:double-indent-re @@ -301,8 +346,9 @@ is not on a run-on line." ;; (= (point) end))) ;; 0) ;; else normal indent - (t - scala-indent:step))))) + (t (+ (if scala-indent:align-parameters 0 + (scala-indent:value-expression-lead start anchor)) + scala-indent:step)))))) (defconst scala-indent:special-align-re (regexp-opt '("yield" "else" "catch" "finally") 'words)) @@ -367,15 +413,17 @@ special word found. Special words include 'yield', 'else', (defun scala-indent:goto-list-anchor-impl (point) (goto-char point) ;; find the first element of the list - (forward-comment (buffer-size)) - (if (= (line-number-at-pos point) - (line-number-at-pos)) - (goto-char point) - (beginning-of-line)) - - ;; align list with first non-whitespace character - (skip-syntax-forward " ") - (point)) + (if (not scala-indent:align-parameters) + (progn (back-to-indentation) (point)) + (forward-comment (buffer-size)) + (if (= (line-number-at-pos point) + (line-number-at-pos)) + (goto-char point) + (beginning-of-line)) + + ;; align list with first non-whitespace character + (skip-syntax-forward " ") + (point))) (defun scala-indent:goto-list-anchor (&optional point) "Moves back to the point whose column will be used to indent @@ -385,6 +433,11 @@ point or nil if the point is not in a list element > 1." (when list-beg (scala-indent:goto-list-anchor-impl list-beg)))) +(defun scala-indent:resolve-list-step (start anchor) + (if scala-indent:align-parameters + 0 + (scala-indent:resolve-block-step start anchor))) + (defun scala-indent:for-enumerators-p (&optional point) "Returns the point after opening parentheses if the current point (or point 'point') is in a block of enumerators. Return nil @@ -419,14 +472,15 @@ point or nil if the point is not in a enumerator element > 1." (regexp-opt '("if" "else" "yield" "for" "try" "finally" "catch") 'words)) (defun scala-indent:body-p (&optional point) - "Returns the position of '=' or '=>' (TODO: not ATM) symbol if -current point (or point 'point) is on a line that follows said -symbol, or nil if not." + "Returns the position of '=', 'if or 'else if' (TODO: or '=>') +symbol if current point (or point 'point) is on a line that +follows said symbol, or nil if not." (save-excursion (when point (goto-char point)) (scala-syntax:beginning-of-code-line) (or (scala-syntax:looking-back-token scala-syntax:body-start-re 3) (progn + ;; if, else if (when (scala-syntax:looking-back-token ")" 1) (goto-char (match-end 0)) (backward-list)) @@ -445,10 +499,10 @@ symbol, or nil if not." (if (looking-at scala-indent:value-keyword-re) (point) (when (scala-indent:backward-sexp-to-beginning-of-line) - (scala-indent:goto-run-on-anchor nil - scala-indent:keywords-only-strategy)) - (when (scala-indent:backward-sexp-to-beginning-of-line) - (back-to-indentation)) + (scala-indent:goto-run-on-anchor + nil + scala-indent:keywords-only-strategy)) + (scala-indent:align-anchor) (point))))) (defun scala-indent:resolve-body-step (start &optional anchor) @@ -481,23 +535,14 @@ anchor for calculating block indent for current point (or point (when (scala-indent:backward-sexp-to-beginning-of-line) (scala-indent:goto-run-on-anchor nil scala-indent:keywords-only-strategy)) - (when (scala-indent:backward-sexp-to-beginning-of-line) - (back-to-indentation)) + (scala-indent:align-anchor) (point))))) (defun scala-indent:resolve-block-step (start anchor) "Resolves the appropriate indent step for block line at position 'start' relative to the block anchor 'anchor'." (let - ;;; calculate a lead that is used for all steps. The lead is one - ;;; indent step if there is a '=' between anchor and start, - ;;; otherwise 0. - ((lead (if (and scala-indent:indent-value-expression (ignore-errors - (save-excursion - (let ((block-beg (nth 1 (syntax-ppss start)))) - (goto-char anchor) - (scala-syntax:has-char-before ?= block-beg))))) - scala-indent:step 0))) + ((lead (scala-indent:value-expression-lead start anchor))) (cond ;; at end of buffer ((= start (point-max)) (+ scala-indent:step lead)) @@ -545,7 +590,8 @@ start with opening parenthesis." (goto-char parentheses-beg) (cond ;; case 1 - ((and (= (char-after) ?\() + ((and scala-indent:align-parameters + (= (char-after) ?\() (scala-indent:run-on-p) (scala-syntax:looking-back-token ")" 1)) (scala-syntax:backward-parameter-groups) @@ -606,7 +652,7 @@ nothing was applied." (anchor (funcall rule-statement point))) (if anchor (progn -; (message "indenting acording to %s at %d" rule-statement anchor) + (message "indenting acording to %s at %d" rule-statement anchor) (when (/= anchor (point)) (error (format "Assertion error: anchor=%d, point=%d" anchor (point)))) (+ (current-column) @@ -622,9 +668,9 @@ point 'point'. Returns the new column, or nil if the indent cannot be determined." (or (scala-indent:apply-indent-rules `((scala-indent:goto-open-parentheses-anchor scala-indent:resolve-open-parentheses-step) - (scala-indent:goto-for-enumerators-anchor 0) + (scala-indent:goto-for-enumerators-anchor scala-indent:resolve-list-step) (scala-indent:goto-special-align-anchor 0) - (scala-indent:goto-list-anchor 0) + (scala-indent:goto-list-anchor scala-indent:resolve-list-step) (scala-indent:goto-body-anchor scala-indent:resolve-body-step) (scala-indent:goto-run-on-anchor scala-indent:resolve-run-on-step) (scala-indent:goto-block-anchor scala-indent:resolve-block-step)