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

Generalise julia-indent-hanging to cover more cases #162

Closed
wants to merge 3 commits into from

Conversation

ajhalme
Copy link
Contributor

@ajhalme ajhalme commented Aug 22, 2021

Having looked at the indentation code for a bit, I decided to tackle issue #155 just to learn more about this stuff.

The reported issue is concerned with indentation in situations where an operator is the last token on the line.

In ESS, R code is formatted like so:

# ESS 18.10.2

sample1 <- left_join(df1, df2, by = c("longname1", "longname2", "longname3", "longname4")) %>%
    do_stuff

sample2 <-left_join(df1, df2, by = c("longname1", "longname2",
                                     "longname3", "longname4",
                                     "longname5", "longname6")) %>%
    do_stuff

sample3 <-
    left_join(df1, df2, by = c("longname1",
                               "longname2", "longname3", "longname4")) %>%
    do_stuff

sample4 <-
    left_join(df1,
              df2, by = c("longname1", "longname2",
                          "longname3", "longname4")) %>%
    do_stuff

Similar code in Julia is currently formatted like so:

sample1 = @pipe leftjoin(df1, df2, on = [:longname1, :longname2, :longname3, :longname4]) |>
    do_stuff

sample2 = @pipe leftjoin(df1, df2, on = [:longname1, :longname2,
                                         :longname3, :longname4,
                                         :longname5, :longname6]) |>
                                             do_stuff

sample3 =
    @pipe leftjoin(df1, df2, on = [:longname1,
                                   :longname2, :longname3, :longname4]) |>
                                       do_stuff

sample4 =
    @pipe leftjoin(df1,
                   df2, on = [:longname1, :longname2,
                              :longname3, :longname4]) |>
                                  do_stuff

In other words, in some cases featuring the hanging operator -- here the pipe, |> -- julia-mode is not indenting the subsequent line as neatly as ESS indents R.

This PR generalises the existing hanging operator indentation routine, julia-indent-hanging, by iterating over the hanging line scanner and by introducing an additional check for detecting split parentheses. (This is powered by the existing julia-parent-indent function.)

This fixes indentation for cases where:

  1. two hanging operators are NOT on adjacent lines, OR

  2. a multi-line parenthesis expression is followed by a hanging operator.

With this PR, the above examples indent as below, which is arguably nicer. Other indentation should not be affected.

sample1 = @pipe leftjoin(df1, df2, on = [:longname1, :longname2, :longname3, :longname4]) |>
    do_stuff

sample2 = @pipe leftjoin(df1, df2, on = [:longname1, :longname2,
                                         :longname3, :longname4,
                                         :longname5, :longname6]) |>
    do_stuff

sample3 =
    @pipe leftjoin(df1, df2, on = [:longname1,
                                   :longname2, :longname3, :longname4]) |>
    do_stuff

sample4 =
    @pipe leftjoin(df1,
                   df2, on = [:longname1, :longname2,
                              :longname3, :longname4]) |>
    do_stuff

1. Situations where two hanging operators are NOT on adjacent lines.

2. Situations where a multi-line parenthesis expression is followed
by a hanging operator.
Copy link
Collaborator

@tpapp tpapp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for doing this, I made a minor suggestion but this is already very well written.

julia-mode.el Outdated
(setq best-indent (+ (current-indentation) julia-indent-offset)))
(setq prev-indent (current-indentation))
(setq prev-paren-indent (julia-paren-indent))))
best-indent)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When (> (julia-prev-line-skip-blank-or-comment) 0) is nil, I think this just returns best-indent which is nil. Would it make sense to just bail early, eg

(when (> (julia-prev-line-skip-blank-or-comment) 0)
  (save-excursion
    (let* ((prev-indent (current-indentation))
           (prev-paren-indent (julia-paren-indent))
           (hanging-match (julia--hanging-operator-p))
           (double-hanging)
           (best-indent))
      ;; Base case: one preceding hanging operator => increase indent from preceding line
      (if hanging-match
          (setq best-indent (+ (current-indentation) julia-indent-offset)))
      ;; Loop rows back until we run out of indentation or hit a second hanging indent
      (while (and hanging-match
                  (not double-hanging)
                  (> (current-indentation) 0)
                  (> (julia-prev-line-skip-blank-or-comment) 0))
        (setq double-hanging (julia--hanging-operator-p))
        ;; Special case: two hanging operator indents already => use the first one
        (when double-hanging
          (setq best-indent prev-indent))
        ;; Special case: open paren followed by one hanging operator
        (when (and (not double-hanging) prev-paren-indent)
          (setq best-indent (+ (current-indentation) julia-indent-offset)))
        (setq prev-indent (current-indentation))
        (setq prev-paren-indent (julia-paren-indent)))
      best-indent)))

(note: did not test this, and this is just a style suggestion, feel free to ignore)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, makes sense.

(when (> (julia-prev-line-skip-blank-or-comment) 0)
  (save-excursion

has to be

  (save-excursion
     (when (> (julia-prev-line-skip-blank-or-comment) 0)

or calling the indentation moves (point) back by one row. Somehow it also seemed to get caught in an infinite loop or something.

Swapping the two rows works fine, tests pass. I've pushed a patch with these changes.

@tpapp
Copy link
Collaborator

tpapp commented Aug 23, 2021

I would appreciate if someone else could please review this, but I pinged quite a few people yesterday so I will wait a bit.

@ajhalme ajhalme closed this Oct 28, 2021
@ajhalme ajhalme deleted the pipe-indentation branch October 28, 2021 22:15
@tpapp
Copy link
Collaborator

tpapp commented Oct 29, 2021

@ajhalme: why did you close this?

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

Successfully merging this pull request may close these issues.

2 participants