git.delta.rocks / jrsonnet / refs/commits / 016538aa1e6d

difftreelog

source

cmds/jrsonnet-fmt/src/comments.rs3.9 KiBsourcehistory
1use dprint_core::formatting::PrintItems;2use jrsonnet_rowan_parser::{nodes::TriviaKind, AstToken};34use crate::{children::ChildTrivia, p, pi};56pub enum CommentLocation {7	/// Above local, field, other things8	AboveItem,9	/// After item10	ItemInline,11	/// After all items in object12	EndOfItems,13}1415pub fn format_comments(comments: &ChildTrivia, loc: CommentLocation) -> PrintItems {16	let mut pi = p!(new:);1718	for c in comments {19		match c.kind() {20			TriviaKind::Whitespace => {}21			TriviaKind::MultiLineComment => {22				let mut text = c23					.text()24					.strip_prefix("/*")25					.expect("ml comment starts with /*")26					.strip_suffix("*/")27					.expect("ml comment ends with */");28				// doc-style comment, /**29				let doc = if text.starts_with('*') {30					text = &text[1..];31					true32				} else {33					false34				};35				// Is comment starts with text immediatly, i.e /*text36				let mut immediate_start = true;37				let mut lines = text38					.split('\n')39					.map(|l| l.trim_end())40					.skip_while(|l| {41						if l.is_empty() {42							immediate_start = false;43							true44						} else {45							false46						}47					})48					.collect::<Vec<_>>();49				while lines.last().map(|l| l.is_empty()).unwrap_or(false) {50					lines.pop();51				}52				if lines.len() == 1 && !doc {53					p!(pi: str("/* ") str(lines[0].trim()) str(" */") nl)54				} else if !lines.is_empty() {55					fn common_ws_prefix<'a>(a: &'a str, b: &str) -> &'a str {56						let offset = a57							.bytes()58							.zip(b.bytes())59							.take_while(|(a, b)| a == b && (a.is_ascii_whitespace() || *a == b'*'))60							.count();61						&a[..offset]62					}63					// First line is not empty, extract ws prefix of it64					let mut common_ws_padding = if immediate_start && lines.len() > 1 {65						common_ws_prefix(lines[1], lines[1])66					} else {67						common_ws_prefix(lines[0], lines[0])68					};69					for line in lines70						.iter()71						.skip(if immediate_start { 2 } else { 1 })72						.filter(|l| !l.is_empty())73					{74						common_ws_padding = common_ws_prefix(common_ws_padding, line);75					}76					for line in lines77						.iter_mut()78						.skip(if immediate_start { 1 } else { 0 })79						.filter(|l| !l.is_empty())80					{81						*line = line82							.strip_prefix(common_ws_padding)83							.expect("all non-empty lines start with this padding");84					}8586					p!(pi: str("/*"));87					if doc {88						p!(pi: str("*"));89					}90					p!(pi: nl);91					for mut line in lines {92						if doc {93							p!(pi: str(" *"));94						}95						if line.is_empty() {96							p!(pi: nl);97						} else {98							if doc {99								p!(pi: str(" "));100							}101							while let Some(new_line) = line.strip_prefix('\t') {102								if doc {103									p!(pi: str("    "));104								} else {105									p!(pi: tab);106								}107								line = new_line;108							}109							p!(pi: str(line) nl)110						}111					}112					if doc {113						p!(pi: str(" "));114					}115					p!(pi: str("*/") nl)116				}117			}118			// TODO: Keep common padding for multiple continous lines of single-line comments119			// I.e120			// ```121			// #  Line1122			// #    Line2123			// ```124			// Should be reformatted as125			// ```126			// # Line1127			// #   Line2128			// ```129			// But currently comment formatter is not aware of continous comment lines, and reformats it as130			// ```131			// # Line1132			// # Line2133			// ```134			TriviaKind::SingleLineHashComment => {135				if matches!(loc, CommentLocation::ItemInline) {136					p!(pi: str(" "))137				}138				p!(pi: str("# ") str(c.text().strip_prefix('#').expect("hash comment starts with #").trim()));139				if !matches!(loc, CommentLocation::ItemInline) {140					p!(pi: nl)141				}142			}143			TriviaKind::SingleLineSlashComment => {144				if matches!(loc, CommentLocation::ItemInline) {145					p!(pi: str(" "))146				}147				p!(pi: str("// ") str(c.text().strip_prefix("//").expect("comment starts with //").trim()));148				if !matches!(loc, CommentLocation::ItemInline) {149					p!(pi: nl)150				}151			}152			// Garbage in - garbage out153			TriviaKind::ErrorCommentTooShort => p!(pi: str("/*/")),154			TriviaKind::ErrorCommentUnterminated => p!(pi: str(c.text())),155		}156	}157158	pi159}