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
This commit is contained in:
ridiculousfish 2020-08-09 12:15:14 -07:00
parent 9a53bf7d56
commit f6c1ef58df
2 changed files with 46 additions and 21 deletions

View File

@ -590,7 +590,8 @@ std::vector<int> 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<int> &indents) : indents(indents) {}
indent_visitor_t(const wcstring &src, std::vector<int> &indents)
: src(src), indents(indents) {}
void visit(const node_t &node) {
int inc = 0;
@ -612,9 +613,25 @@ std::vector<int> parse_util_compute_indents(const wcstring &src) {
}
break;
// Increment indents for piped remainders.
case type_t::job_continuation_list:
if (node.as<job_continuation_list_t>()->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<job_continuation_t>()->newlines)) {
inc = 1;
dec = 1;
}
break;
// Likewise for && and ||.
case type_t::job_conjunction_continuation:
if (has_newline(node.as<job_conjunction_continuation_t>()->newlines)) {
inc = 1;
dec = 1;
}
@ -675,6 +692,11 @@ std::vector<int> 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<int> 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<int> &indents;
@ -690,7 +715,7 @@ std::vector<int> 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.

View File

@ -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