writer.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. use crate::buffer::Buffer;
  2. use crate::collect_macros::byte_offset;
  3. use dioxus_rsx::{
  4. Attribute as AttributeType, AttributeName, AttributeValue as ElementAttrValue, BodyNode,
  5. Component, Element, ForLoop, IfChain, Spread, TemplateBody,
  6. };
  7. use proc_macro2::{LineColumn, Span};
  8. use quote::ToTokens;
  9. use std::{
  10. collections::{HashMap, VecDeque},
  11. fmt::{Result, Write},
  12. };
  13. use syn::{spanned::Spanned, token::Brace, Expr};
  14. #[derive(Debug)]
  15. pub struct Writer<'a> {
  16. pub raw_src: &'a str,
  17. pub src: Vec<&'a str>,
  18. pub cached_formats: HashMap<LineColumn, String>,
  19. pub comments: VecDeque<usize>,
  20. pub out: Buffer,
  21. }
  22. impl<'a> Writer<'a> {
  23. pub fn new(raw_src: &'a str) -> Self {
  24. let src = raw_src.lines().collect();
  25. Self {
  26. raw_src,
  27. src,
  28. cached_formats: HashMap::new(),
  29. comments: VecDeque::new(),
  30. out: Buffer::default(),
  31. }
  32. }
  33. pub fn consume(self) -> Option<String> {
  34. Some(self.out.buf)
  35. }
  36. pub fn write_rsx_call(&mut self, body: &TemplateBody) -> Result {
  37. match body.roots.len() {
  38. 0 => {}
  39. 1 if matches!(body.roots[0], BodyNode::Text(_)) => {
  40. write!(self.out, " ")?;
  41. self.write_ident(&body.roots[0])?;
  42. write!(self.out, " ")?;
  43. }
  44. _ => self.write_body_indented(&body.roots)?,
  45. }
  46. Ok(())
  47. }
  48. // Expects to be written directly into place
  49. pub fn write_ident(&mut self, node: &BodyNode) -> Result {
  50. match node {
  51. BodyNode::Element(el) => self.write_element(el),
  52. BodyNode::Component(component) => self.write_component(component),
  53. BodyNode::Text(text) => self.out.write_text(&text.input),
  54. BodyNode::RawExpr(exp) => self.write_raw_expr(exp.span()),
  55. BodyNode::ForLoop(forloop) => self.write_for_loop(forloop),
  56. BodyNode::IfChain(ifchain) => self.write_if_chain(ifchain),
  57. }
  58. }
  59. pub fn write_element(&mut self, el: &Element) -> Result {
  60. let Element {
  61. name,
  62. raw_attributes: attributes,
  63. children,
  64. spreads,
  65. brace,
  66. ..
  67. } = el;
  68. /*
  69. 1. Write the tag
  70. 2. Write the key
  71. 3. Write the attributes
  72. 4. Write the children
  73. */
  74. write!(self.out, "{name} {{")?;
  75. let brace = brace.unwrap_or_default();
  76. self.write_rsx_block(attributes, spreads, children, &brace)?;
  77. write!(self.out, "}}")?;
  78. Ok(())
  79. }
  80. pub fn write_component(
  81. &mut self,
  82. Component {
  83. name,
  84. fields,
  85. children,
  86. generics,
  87. spreads,
  88. brace,
  89. ..
  90. }: &Component,
  91. ) -> Result {
  92. // Write the path by to_tokensing it and then removing all whitespace
  93. let mut name = name.to_token_stream().to_string();
  94. name.retain(|c| !c.is_whitespace());
  95. write!(self.out, "{name}")?;
  96. // Same idea with generics, write those via the to_tokens method and then remove all whitespace
  97. if let Some(generics) = generics {
  98. let mut written = generics.to_token_stream().to_string();
  99. written.retain(|c| !c.is_whitespace());
  100. write!(self.out, "{written}")?;
  101. }
  102. write!(self.out, " {{")?;
  103. self.write_rsx_block(fields, spreads, &children.roots, brace)?;
  104. write!(self.out, "}}")?;
  105. Ok(())
  106. }
  107. pub fn write_raw_expr(&mut self, placement: Span) -> Result {
  108. /*
  109. We want to normalize the expr to the appropriate indent level.
  110. */
  111. let start = placement.start();
  112. let end = placement.end();
  113. // if the expr is on one line, just write it directly
  114. if start.line == end.line {
  115. // split counting utf8 chars
  116. let start = byte_offset(self.raw_src, start);
  117. let end = byte_offset(self.raw_src, end);
  118. let row = self.raw_src[start..end].trim();
  119. write!(self.out, "{row}")?;
  120. return Ok(());
  121. }
  122. // If the expr is multiline, we want to collect all of its lines together and write them out properly
  123. // This involves unshifting the first line if it's aligned
  124. let first_line = &self.src[start.line - 1];
  125. write!(self.out, "{}", &first_line[start.column..].trim_start())?;
  126. let prev_block_indent_level = self.out.indent.count_indents(first_line);
  127. for (id, line) in self.src[start.line..end.line].iter().enumerate() {
  128. writeln!(self.out)?;
  129. // check if this is the last line
  130. let line = {
  131. if id == (end.line - start.line) - 1 {
  132. &line[..end.column]
  133. } else {
  134. line
  135. }
  136. };
  137. // trim the leading whitespace
  138. let previous_indent = self.out.indent.count_indents(line);
  139. let offset = previous_indent.saturating_sub(prev_block_indent_level);
  140. let required_indent = self.out.indent_level + offset;
  141. self.out.write_tabs(required_indent)?;
  142. let line = line.trim_start();
  143. write!(self.out, "{line}")?;
  144. }
  145. Ok(())
  146. }
  147. pub fn write_attr_comments(&mut self, brace: &Brace, attr_span: Span) -> Result {
  148. // There's a chance this line actually shares the same line as the previous
  149. // Only write comments if the comments actually belong to this line
  150. //
  151. // to do this, we check if the attr span starts on the same line as the brace
  152. // if it doesn't, we write the comments
  153. let brace_line = brace.span.span().start().line;
  154. let attr_line = attr_span.start().line;
  155. if brace_line != attr_line {
  156. self.write_comments(attr_span)?;
  157. }
  158. Ok(())
  159. }
  160. pub fn write_comments(&mut self, child: Span) -> Result {
  161. // collect all comments upwards
  162. // make sure we don't collect the comments of the node that we're currently under.
  163. let start = child.start();
  164. let line_start = start.line - 1;
  165. for (id, line) in self.src[..line_start].iter().enumerate().rev() {
  166. if line.trim().starts_with("//") || line.is_empty() {
  167. if id != 0 {
  168. self.comments.push_front(id);
  169. }
  170. } else {
  171. break;
  172. }
  173. }
  174. let mut last_was_empty = false;
  175. while let Some(comment_line) = self.comments.pop_front() {
  176. let line = &self.src[comment_line];
  177. if line.is_empty() {
  178. if !last_was_empty {
  179. self.out.new_line()?;
  180. }
  181. last_was_empty = true;
  182. } else {
  183. last_was_empty = false;
  184. self.out.tabbed_line()?;
  185. write!(self.out, "{}", self.src[comment_line].trim())?;
  186. }
  187. }
  188. Ok(())
  189. }
  190. // Push out the indent level and write each component, line by line
  191. pub fn write_body_indented(&mut self, children: &[BodyNode]) -> Result {
  192. self.out.indent_level += 1;
  193. self.write_body_no_indent(children)?;
  194. self.out.indent_level -= 1;
  195. Ok(())
  196. }
  197. pub fn write_body_no_indent(&mut self, children: &[BodyNode]) -> Result {
  198. for child in children {
  199. if self.current_span_is_primary(child.span()) {
  200. self.write_comments(child.span())?;
  201. };
  202. self.out.tabbed_line()?;
  203. self.write_ident(child)?;
  204. }
  205. Ok(())
  206. }
  207. pub(crate) fn attr_value_len(&mut self, value: &ElementAttrValue) -> usize {
  208. match value {
  209. ElementAttrValue::AttrOptionalExpr { condition, value } => {
  210. let condition_len = self.retrieve_formatted_expr(condition).len();
  211. let value_len = self.attr_value_len(value);
  212. condition_len + value_len + 6
  213. }
  214. ElementAttrValue::AttrLiteral(lit) => lit.to_string().len(),
  215. ElementAttrValue::Shorthand(expr) => expr.span().line_length(),
  216. ElementAttrValue::AttrExpr(expr) => expr
  217. .as_expr()
  218. .map(|expr| self.attr_expr_len(&expr))
  219. .unwrap_or(100000),
  220. ElementAttrValue::EventTokens(closure) => closure
  221. .as_expr()
  222. .map(|expr| self.attr_expr_len(&expr))
  223. .unwrap_or(100000),
  224. }
  225. }
  226. fn attr_expr_len(&mut self, expr: &Expr) -> usize {
  227. let out = self.retrieve_formatted_expr(expr);
  228. if out.contains('\n') {
  229. 100000
  230. } else {
  231. out.len()
  232. }
  233. }
  234. pub(crate) fn is_short_attrs(
  235. &mut self,
  236. attributes: &[AttributeType],
  237. spreads: &[Spread],
  238. ) -> usize {
  239. let mut total = 0;
  240. // No more than 3 attributes before breaking the line
  241. if attributes.len() > 3 {
  242. return 100000;
  243. }
  244. for attr in attributes {
  245. if self.current_span_is_primary(attr.span()) {
  246. 'line: for line in self.src[..attr.span().start().line - 1].iter().rev() {
  247. match (line.trim().starts_with("//"), line.is_empty()) {
  248. (true, _) => return 100000,
  249. (_, true) => continue 'line,
  250. _ => break 'line,
  251. }
  252. }
  253. }
  254. let name_len = match &attr.name {
  255. AttributeName::BuiltIn(name) => {
  256. let name = name.to_string();
  257. name.len()
  258. }
  259. AttributeName::Custom(name) => name.value().len() + 2,
  260. AttributeName::Spread(_) => unreachable!(),
  261. };
  262. total += name_len;
  263. //
  264. if attr.can_be_shorthand() {
  265. total += 2;
  266. } else {
  267. total += self.attr_value_len(&attr.value);
  268. }
  269. total += 6;
  270. }
  271. for spread in spreads {
  272. let expr_len = self.retrieve_formatted_expr(&spread.expr).len();
  273. total += expr_len + 3;
  274. }
  275. total
  276. }
  277. #[allow(clippy::map_entry)]
  278. pub fn retrieve_formatted_expr(&mut self, expr: &Expr) -> &str {
  279. let loc = expr.span().start();
  280. if !self.cached_formats.contains_key(&loc) {
  281. let formatted = self.unparse_expr(expr);
  282. self.cached_formats.insert(loc, formatted);
  283. }
  284. self.cached_formats.get(&loc).unwrap().as_str()
  285. }
  286. fn write_for_loop(&mut self, forloop: &ForLoop) -> std::fmt::Result {
  287. write!(
  288. self.out,
  289. "for {} in ",
  290. forloop.pat.clone().into_token_stream(),
  291. )?;
  292. self.write_inline_expr(&forloop.expr)?;
  293. if forloop.body.is_empty() {
  294. write!(self.out, "}}")?;
  295. return Ok(());
  296. }
  297. self.write_body_indented(&forloop.body.roots)?;
  298. self.out.tabbed_line()?;
  299. write!(self.out, "}}")?;
  300. Ok(())
  301. }
  302. fn write_if_chain(&mut self, ifchain: &IfChain) -> std::fmt::Result {
  303. // Recurse in place by setting the next chain
  304. let mut branch = Some(ifchain);
  305. while let Some(chain) = branch {
  306. let IfChain {
  307. if_token,
  308. cond,
  309. then_branch,
  310. else_if_branch,
  311. else_branch,
  312. ..
  313. } = chain;
  314. write!(self.out, "{} ", if_token.to_token_stream(),)?;
  315. self.write_inline_expr(cond)?;
  316. self.write_body_indented(&then_branch.roots)?;
  317. if let Some(else_if_branch) = else_if_branch {
  318. // write the closing bracket and else
  319. self.out.tabbed_line()?;
  320. write!(self.out, "}} else ")?;
  321. branch = Some(else_if_branch);
  322. } else if let Some(else_branch) = else_branch {
  323. self.out.tabbed_line()?;
  324. write!(self.out, "}} else {{")?;
  325. self.write_body_indented(&else_branch.roots)?;
  326. branch = None;
  327. } else {
  328. branch = None;
  329. }
  330. }
  331. self.out.tabbed_line()?;
  332. write!(self.out, "}}")?;
  333. Ok(())
  334. }
  335. /// An expression within a for or if block that might need to be spread out across several lines
  336. fn write_inline_expr(&mut self, expr: &Expr) -> std::fmt::Result {
  337. let unparsed = self.unparse_expr(expr);
  338. let mut lines = unparsed.lines();
  339. let first_line = lines.next().unwrap();
  340. write!(self.out, "{first_line}")?;
  341. let mut was_multiline = false;
  342. for line in lines {
  343. was_multiline = true;
  344. self.out.tabbed_line()?;
  345. write!(self.out, "{line}")?;
  346. }
  347. if was_multiline {
  348. self.out.tabbed_line()?;
  349. write!(self.out, "{{")?;
  350. } else {
  351. write!(self.out, " {{")?;
  352. }
  353. Ok(())
  354. }
  355. }
  356. pub(crate) trait SpanLength {
  357. fn line_length(&self) -> usize;
  358. }
  359. impl SpanLength for Span {
  360. fn line_length(&self) -> usize {
  361. self.end().line - self.start().line
  362. }
  363. }