From f6c1ef58dfea3ce79d91e1c6edaa7541224b01e6 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 9 Aug 2020 12:15:14 -0700 Subject: [PATCH] Indent continuations after | and && This indents continuations after pipes and conjunctions if they contain a newline. Example: cmd1 && cmd2 But it avoids the "double indent" if it indented unconditionally: cmd1 | begin cmd2 end More work towards improving #7252 --- src/parse_util.cpp | 35 ++++++++++++++++++++++++++++++----- tests/checks/indent.fish | 32 ++++++++++++++++---------------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/parse_util.cpp b/src/parse_util.cpp index ca6c53190..c347683bb 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -590,7 +590,8 @@ std::vector parse_util_compute_indents(const wcstring &src) { // Visit all of our nodes. When we get a job_list or case_item_list, increment indent while // visiting its children. struct indent_visitor_t { - explicit indent_visitor_t(std::vector &indents) : indents(indents) {} + indent_visitor_t(const wcstring &src, std::vector &indents) + : src(src), indents(indents) {} void visit(const node_t &node) { int inc = 0; @@ -612,9 +613,25 @@ std::vector parse_util_compute_indents(const wcstring &src) { } break; - // Increment indents for piped remainders. - case type_t::job_continuation_list: - if (node.as()->count() > 0) { + // Increment indents for job_continuation_t if it contains a newline. + // This is a bit of a hack - it indents cases like: + // cmd1 | + // ....cmd2 + // but avoids "double indenting" if there's no newline: + // cmd1 | while cmd2 + // ....cmd3 + // end + // See #7252. + case type_t::job_continuation: + if (has_newline(node.as()->newlines)) { + inc = 1; + dec = 1; + } + break; + + // Likewise for && and ||. + case type_t::job_conjunction_continuation: + if (has_newline(node.as()->newlines)) { inc = 1; dec = 1; } @@ -675,6 +692,11 @@ std::vector parse_util_compute_indents(const wcstring &src) { indent -= dec; } + /// \return whether a maybe_newlines node contains at least one newline. + bool has_newline(const maybe_newlines_t &nls) const { + return nls.source(src).find(L'\n') != wcstring::npos; + } + // The one-past-the-last index of the most recently encountered leaf node. // We use this to populate the indents even if there's no tokens in the range. size_t last_leaf_end{0}; @@ -682,6 +704,9 @@ std::vector parse_util_compute_indents(const wcstring &src) { // The last indent which we assigned. int last_indent{-1}; + // The source we are indenting. + const wcstring &src; + // List of indents, which we populate. std::vector &indents; @@ -690,7 +715,7 @@ std::vector parse_util_compute_indents(const wcstring &src) { int indent{-1}; }; - indent_visitor_t iv(indents); + indent_visitor_t iv(src, indents); node_visitor(iv).accept(ast.top()); // All newlines now get the *next* indent. diff --git a/tests/checks/indent.fish b/tests/checks/indent.fish index a19b818eb..17ffedca5 100644 --- a/tests/checks/indent.fish +++ b/tests/checks/indent.fish @@ -233,9 +233,9 @@ begin # comment end ' | $fish_indent -#CHECK: begin -#CHECK: {{ }}# comment -#CHECK: end +#CHECK: {{^}}begin +#CHECK: {{^ }}# comment +#CHECK: {{^}}end echo -n ' begin @@ -243,17 +243,17 @@ cmd # comment end ' | $fish_indent -#CHECK: begin -#CHECK: {{ }}cmd -#CHECK: {{ }}# comment -#CHECK: end +#CHECK: {{^}}begin +#CHECK: {{^ }}cmd +#CHECK: {{^ }}# comment +#CHECK: {{^}}end echo -n ' cmd \\ continuation ' | $fish_indent -#CHECK: cmd \ -#CHECK: {{ }}continuation +#CHECK: {{^}}cmd \ +#CHECK: {{^ }}continuation echo -n ' begin @@ -261,10 +261,10 @@ cmd \ continuation end ' | $fish_indent -#CHECK: begin -#CHECK: {{ }}cmd \ -#CHECK: {{ }}{{ }}continuation -#CHECK: end +#CHECK: {{^}}begin +#CHECK: {{^ }}cmd \ +#CHECK: {{^ }}{{ }}continuation +#CHECK: {{^}}end echo -n ' @@ -350,15 +350,15 @@ echo 'foo && # bar' | $fish_indent #CHECK: {{^}}foo && -#CHECK: {{^}}# -#CHECK: {{^}}bar +#CHECK: {{^ }}# +#CHECK: {{ }}bar echo 'command 1 | command 1 cont || command 2' | $fish_indent #CHECK: {{^}}command 1 | #CHECK: {{^ }}command 1 cont || -#CHECK: {{^}}command 2 +#CHECK: {{^ }}command 2 echo " foo" | fish_indent --check echo $status