Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 21 additions & 39 deletions librubyfmt/src/format_prism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3666,47 +3666,29 @@ fn format_conditional_node<'src>(
// For while/until, always use the inline format for modifiers, since
// some transformations are unsafe.
// For if/unless, check if we should convert to block form.
let should_convert_to_block = match conditional {
Conditional::While(_) | Conditional::Until(_) => false,
match conditional {
Conditional::While(_) | Conditional::Until(_) => {
// Always use inline format for while/until modifiers
format_inline_conditional(
ps,
conditional.predicate(),
conditional.statements(),
conditional_keyword,
);
}
Conditional::If(_) | Conditional::Unless(_) => {
let predicate = conditional.predicate();
let statements = conditional.statements();
let predicate_start_line =
ps.get_line_number_for_offset(predicate.location().start_offset());
let predicate_end_line =
ps.get_line_number_for_offset(predicate.location().end_offset());
if predicate_start_line != predicate_end_line {
true
} else {
// Check if it renders multiline due to length
ps.will_render_as_multiline(|next_ps| {
format_inline_conditional(
next_ps,
predicate,
statements,
conditional_keyword,
)
})
}
ps.conditional_layout_of(
conditional_keyword,
|ps| format_node(ps, conditional.predicate()),
|ps| {
if let Some(statements) = conditional.statements()
&& let Some(first_statement) = statements.body().iter().next()
{
format_node(ps, first_statement);
}
},
);
}
};

if should_convert_to_block {
format_conditional_block_form(
ps,
conditional_keyword,
conditional.predicate(),
conditional.statements(),
conditional.subsequent_or_else(),
requires_end_keyword,
);
} else {
format_inline_conditional(
ps,
conditional.predicate(),
conditional.statements(),
conditional_keyword,
);
}
} else {
format_conditional_block_form(
Expand Down
14 changes: 13 additions & 1 deletion librubyfmt/src/line_tokens.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::heredoc_string::{HeredocKind, HeredocString};
use crate::render_targets::{BreakableCallChainEntry, BreakableEntry};
use crate::render_targets::{BreakableCallChainEntry, BreakableEntry, ConditionalLayoutEntry};
use crate::types::ColNumber;
use crate::util::get_indent;
use std::borrow::Cow;
Expand Down Expand Up @@ -215,6 +215,9 @@ impl<'src> From<ConcreteLineTokenAndTargets<'src>> for AbstractLineToken<'src> {
ConcreteLineTokenAndTargets::BreakableCallChainEntry(bcce) => {
AbstractLineToken::BreakableCallChainEntry(bcce)
}
ConcreteLineTokenAndTargets::ConditionalLayoutEntry(cle) => {
AbstractLineToken::ConditionalLayoutEntry(cle)
}
}
}
}
Expand All @@ -224,6 +227,7 @@ pub enum ConcreteLineTokenAndTargets<'src> {
ConcreteLineToken(ConcreteLineToken<'src>),
BreakableEntry(BreakableEntry<'src>),
BreakableCallChainEntry(BreakableCallChainEntry<'src>),
ConditionalLayoutEntry(ConditionalLayoutEntry<'src>),
}

impl<'src> ConcreteLineTokenAndTargets<'src> {
Expand Down Expand Up @@ -251,6 +255,7 @@ pub enum AbstractLineToken<'src> {
SoftIndent { depth: u32 },
BreakableEntry(BreakableEntry<'src>),
BreakableCallChainEntry(BreakableCallChainEntry<'src>),
ConditionalLayoutEntry(ConditionalLayoutEntry<'src>),
}

impl<'src> AbstractLineToken<'src> {
Expand Down Expand Up @@ -278,6 +283,9 @@ impl<'src> AbstractLineToken<'src> {
Self::BreakableCallChainEntry(bcce) => {
out.push(ConcreteLineTokenAndTargets::BreakableCallChainEntry(bcce));
}
Self::ConditionalLayoutEntry(cle) => {
out.push(ConcreteLineTokenAndTargets::ConditionalLayoutEntry(cle))
}
}
}

Expand Down Expand Up @@ -305,6 +313,9 @@ impl<'src> AbstractLineToken<'src> {
Self::BreakableCallChainEntry(bcce) => {
out.push(ConcreteLineTokenAndTargets::BreakableCallChainEntry(bcce));
}
Self::ConditionalLayoutEntry(cle) => {
out.push(ConcreteLineTokenAndTargets::ConditionalLayoutEntry(cle))
}
}
}

Expand Down Expand Up @@ -376,6 +387,7 @@ impl<'src> AbstractLineToken<'src> {
Self::ConcreteLineToken(clt) => clt.len(),
Self::BreakableEntry(be) => be.single_line_len(),
Self::BreakableCallChainEntry(bcce) => bcce.single_line_len(),
Self::ConditionalLayoutEntry(cle) => cle.inline_single_line_len(),
}
}
}
48 changes: 47 additions & 1 deletion librubyfmt/src/parser_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::heredoc_string::{HeredocKind, HeredocString};
use crate::line_tokens::*;
use crate::render_queue_writer::{MAX_LINE_LENGTH, RenderQueueWriter};
use crate::render_targets::{
BaseQueue, Breakable, BreakableCallChainEntry, BreakableEntry, MultilineHandling,
BaseQueue, Breakable, BreakableCallChainEntry, BreakableEntry, ConditionalLayoutEntry,
MultilineHandling,
};
use crate::types::{ColNumber, LineNumber, SourceOffset};
use log::debug;
Expand Down Expand Up @@ -968,6 +969,51 @@ impl<'src> ParserState<'src> {
f(&mut next_ps);
next_ps
}

/// Format a conditional modifier expression (e.g., `x if y` or `x unless y`).
pub(crate) fn conditional_layout_of<FP, FS>(
&mut self,
keyword: &'static str,
format_predicate: FP,
format_statement: FS,
) where
FP: FnOnce(&mut ParserState<'src>),
FS: FnOnce(&mut ParserState<'src>),
{
// Save and clear any pending comments to prevent them from being
// inserted into the conditional layout
let saved_comments = self.comments_to_insert.take();

let entry = ConditionalLayoutEntry::new(keyword, self.current_spaces());
self.breakable_entry_stack
.push(Breakable::InlineConditional(entry));

self.with_start_of_line(false, |ps| {
ps.new_block(format_predicate);
});

self.breakable_entry_stack
.last_mut()
.expect("just pushed InlineConditional")
.as_conditional_layout_mut()
.expect("just pushed InlineConditional")
.switch_to_statement();

self.with_start_of_line(false, |ps| {
ps.new_block(format_statement);
});

let cle = self
.breakable_entry_stack
.pop()
.expect("just pushed InlineConditional")
.into_conditional_layout()
.expect("InlineConditional always returns Some from into_conditional_layout");

self.comments_to_insert = saved_comments;

self.push_target(ConcreteLineTokenAndTargets::ConditionalLayoutEntry(cle));
}
}

pub fn line_difference_requires_newline(to_line: LineNumber, from_line: LineNumber) -> bool {
Expand Down
17 changes: 16 additions & 1 deletion librubyfmt/src/render_queue_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::heredoc_string::HeredocKind;
use crate::intermediary::{BlanklineReason, Intermediary};
use crate::line_tokens::*;
use crate::render_targets::{
AbstractTokenTarget, BreakableCallChainEntry, BreakableEntry, ConvertType,
AbstractTokenTarget, BreakableCallChainEntry, BreakableEntry, ConditionalLayoutEntry,
ConvertType,
};
#[cfg(debug_assertions)]
use log::debug;
Expand Down Expand Up @@ -115,6 +116,9 @@ impl<'src> RenderQueueWriter<'src> {
ConcreteLineTokenAndTargets::BreakableCallChainEntry(bcce) => {
Self::format_breakable_call_chain_entry(accum, bcce)
}
ConcreteLineTokenAndTargets::ConditionalLayoutEntry(cle) => {
Self::format_conditional_layout_entry(accum, cle)
}
ConcreteLineTokenAndTargets::ConcreteLineToken(x) => match x {
BeginCallChainIndent => accum.additional_indent += 1,
EndCallChainIndent => accum.additional_indent -= 1,
Expand Down Expand Up @@ -268,6 +272,17 @@ impl<'src> RenderQueueWriter<'src> {
}
}

fn format_conditional_layout_entry(
accum: &mut Intermediary<'src>,
cle: ConditionalLayoutEntry<'src>,
) {
if cle.should_use_block_form(accum.current_line_length()) {
Self::render_as(accum, cle.into_block_tokens());
} else {
Self::render_as(accum, cle.into_inline_tokens());
}
}

fn renders_over_max_line_length(
accum: &Intermediary<'src>,
breakable: &dyn AbstractTokenTarget<'src>,
Expand Down
Loading