Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function indentation #5

Closed
pveber opened this issue Apr 29, 2014 · 12 comments
Closed

Function indentation #5

pveber opened this issue Apr 29, 2014 · 12 comments

Comments

@pveber
Copy link

pveber commented Apr 29, 2014

Version 2.0.8 indents function bodys the following way

let g x = h x ~f:(fun y ->
                  y + 1
                 )

while olders versions used to indent it this way:

let g x = h x ~f:(fun y ->
  y + 1
)

Is there a simple way to revert to the old behavior? Thanks!

@Chris00
Copy link
Member

Chris00 commented May 4, 2014

I personally like the new behavior. But a configuration option would be nice I guess.

@pveber
Copy link
Author

pveber commented May 5, 2014

The behaviour changed at commit 3933dc4, when SMIE became the default, but nowadays disabling SMIE doesn't revert to the old indentation (which is a good thing of course)

@mjambon
Copy link

mjambon commented Oct 10, 2014

A parameter to set a maximum indentation with respect to the previous non-empty line would work great for me. I'm used to the following style:

with_connection (fun conn ->
  do_something conn x;
  ...
)

and

logf `Info "User %s has %i new messages"
  (Uid.to_string uid)
  (List.length new_messages);

How can I achieve this? If the feature seems reasonable but needs to be added, what part of the code should I look at?

@sheijk
Copy link

sheijk commented Oct 25, 2014

This new behaviour is very annoying when working on a code base that has been indented using the old behaviour. Also not everyone likes to use indentation for alignment. So some configurable options would be really nice here. Or would the "proper" solution be to just go with ocp-indent?

@monnier
Copy link
Contributor

monnier commented Oct 26, 2014

This new behaviour is very annoying when working on a code base that
has been indented using the old behaviour. Also not everyone likes to
use indentation for alignment. So some configurable options would be
really nice here.

There's clearly some interest in providing some way for SMIE modes to
use a slightly different kind of indentation style (for sh-mode, this
would look like a notion of "continued line").

I'd be happy to provide it, but I generally find it difficult to find
an actual rule that works acceptably for "all" cases.

Or would the "proper" solution be to just go with ocp-indent?

E.g. let's take Martin's example:

let x = with_connection (fun conn ->
do_something conn x;
...
)

and let's pass it to ocp-indent:

let x = with_connection (fun conn ->
do_something conn x;
...
)

OK, it looks like ocp-indent found a set of rules that cover this case
in the way you expect. Let's try to tweak the example by adding another
argument to that function:

let x = with_connection (fun conn ->
do_something conn x;
...
)
toto

gets indented by ocp-indent as:

let x = with_connection (fun conn ->
do_something conn x;
...
)
toto

I don't know about you, but I consider the above indentation as a bug.
Not to imply that ocp-indent is crap (Tuareg's SMIE indentation has its
share of bugs), but the problem is that I don't know how to come up with
an indentation rule that gets you what you want without suffering from
such bad indentation cases.

And ocp-indent has an "easier" problem than we do, because by design, it
has the complete parse tree at hand, so it could trivially check if
there's an additional argument after the "(fun conn -> ...)" and use
another rule in that case. Tuareg's SMIE code could also look past the
(fun conn -> ...) to decide how to indent, but it's generally considered
undesirable to change the indentation depending on code in
subsequent lines.

Martin's suggestion to just "bound" the additional indentation could
work, but it's still not great. It would probably look like:

let x = with_connection (fun conn ->
do_something conn x;
...
)
toto

in the best case, and if it's not supported by additional changes it
could very well look like:

let x = with_connection (fun conn ->
do_something conn x;
...
)
toto

which I find rather unpalatable.

    Stefan

@pveber
Copy link
Author

pveber commented Oct 27, 2014

For the record, I installed ocp-indent via opam, and added a

(require 'ocp-indent)

in my .emacs to avoid the problem. I agree though that the example given by Stefan is not well handled by ocp-indent, but I still prefer it to the current SMIE behaviour. Of course that's a matter of taste.

@monnier
Copy link
Contributor

monnier commented Oct 29, 2014

[ Somehow my first email reply was included above, but my second was ignored. So here it is, inserted via the web interface instead. ]

Regarding indentation of:

logf `Info "User %s has %i new messages"
  (Uid.to_string uid)
  (List.length new_messages);

Could you try the patch below, then (setq smie-indent-align-args nil)
and see if you like the result?

-- Stefan

=== modified file 'lisp/emacs-lisp/smie.el'
--- lisp/emacs-lisp/smie.el 2014-07-21 01:58:43 +0000
+++ lisp/emacs-lisp/smie.el 2014-10-26 20:10:29 +0000
@@ -1177,6 +1177,7 @@
            (not (eobp))
            ;; Could be an open-paren.
            (forward-char 1))
+               ;; FIXME: Add better hook here!
           (funcall smie--hanging-eolp-function)
                (point))))))

@@ -1666,6 +1667,9 @@
         (+ (smie-indent-virtual) (smie-indent--offset 'basic))) ;
        (t (smie-indent-virtual))))))                            ;An infix.

+(defvar smie-indent-align-args t
+  "Non-nil if indentation should try to align arguments.")
+
 (defun smie-indent-exps ()
   ;; Indentation of sequences of simple expressions without
   ;; intervening keywords or operators.  E.g. "a b c" or "g (balbla) f".
@@ -1700,12 +1704,12 @@
         ;; We're the first expression of the list.  In that case, the
         ;; indentation should be (have been) determined by its context.
         nil)
-       (arg
+       ((and arg smie-indent-align-args)
         ;; There's a previous element, and it's not special (it's not
         ;; the function), so let's just align with that one.
         (goto-char (car positions))
         (current-column))
-       ((cdr positions)
+       ((and (cdr positions) smie-indent-align-args)
         ;; We skipped some args plus the function and bumped into something.
         ;; Align with the first arg.
         (goto-char (cadr positions))

@monnier
Copy link
Contributor

monnier commented Oct 29, 2014

OK, I have another work-in-progress patch which (combined with the previous (setq smie-indent-align-args nil)) can do the following:

let quux list = List.map list ~f:(fun item ->
                    print_item item
                  )

This is still not what ocp-indent does, but it's a step in that direction. I think I can get pretty close to ocp-indent's behaviour with one more change (specifically when indenting args in "blabla = fun args").

@sheijk
Copy link

sheijk commented Oct 31, 2014

@monnier I think your comment just ended up here #24.

With the patch applied (on top of Emacs 24.4) and smie-indent-align-args set to nil the example you give indents like this. This looks broken to me. But maybe I'm just asking for different things than the original reporter.

let () =
  logf `Info "User %s has %i new messages"
    (Uid.to_string uid)
      (List.length new_messages)

I guess it will not be feasible to reproduce tuareg-mode's old indentation behavior exactly with smie.

@samoht
Copy link
Member

samoht commented Oct 31, 2014

btw, having unit tests could help for this kinds of issues. See for instance the ocp-indent ones (and the failing ones)

monnier added a commit that referenced this issue Oct 2, 2015
(derived-mode-p): Assume Emacs > 21.
(tuareg-smie-grammar): Add dummy "-dlpd-" terminal.
(tuareg-smie-forward-token): Fix handling of "|]".
(tuareg-smie-backward-token): Refine last fix so we also recognize
"exception" right after "with".
(tuareg-smie-rules): Add special rule to reduce indentation depth for
CPS-style code (see Issue #5).
(tuareg--eval-when-macrop): New macro.
(tuareg--hanging-eolp-advice): New function.
(tuareg--common-mode-setup): Use them for smie--hanging-eolp-function.
(tuareg-mode): Call tuareg-make-indentation-regexps even if we use SMIE,
since we still have code that uses the tuareg_indent functions.
(tuareg-beginning-of-phrase-syms-re): Remove variable.
(tuareg-beginning-of-phrase-syms): Redefine.
(tuareg--beginning-of-phrase): Remove case made redundant by
earlier changes.
(tuareg-discover-phrase): Make sure we select a region *around* point.
(tuareg-split-long-list): Fix handling when tail is nil.
monnier added a commit that referenced this issue Oct 2, 2015
(tuareg-smie--args): New function.
(tuareg--common-mode-setup): Use it (Issue #5).
@monnier
Copy link
Contributor

monnier commented Oct 2, 2015

I installed a patch that introduces a new config var tuareg-indent-align-with-first-arg which should let you express your preference for the "logf" example above.

@monnier
Copy link
Contributor

monnier commented Oct 3, 2015

Could you guys try the latest code and see how you like the result? Some of the changes depend on a new (and undocumented :-( ) feature in Emacs-24.5, so make sure you try it in Emacs-24.5 (it should not break in older Emacsen, but it won't give the same indentation results).

I'll close this issue now, so if the result is not "good enough", please open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants