Path: blob/main/crates/wit-bindgen/src/source.rs
1693 views
use std::fmt::{self, Write};1use std::ops::Deref;23/// Helper structure to maintain indentation automatically when printing.4#[derive(Default)]5pub struct Source {6s: String,7indent: usize,8}910impl Source {11pub fn push_str(&mut self, src: &str) {12let lines = src.lines().collect::<Vec<_>>();13for (i, line) in lines.iter().enumerate() {14let trimmed = line.trim();15if trimmed.starts_with('}') && self.s.ends_with(" ") {16self.s.pop();17self.s.pop();18}19self.s.push_str(if lines.len() == 1 {20line21} else {22line.trim_start()23});24if trimmed.ends_with('{') {25self.indent += 1;26}27if trimmed.starts_with('}') {28// Note that a `saturating_sub` is used here to prevent a panic29// here in the case of invalid code being generated in debug30// mode. It's typically easier to debug those issues through31// looking at the source code rather than getting a panic.32self.indent = self.indent.saturating_sub(1);33}34if i != lines.len() - 1 || src.ends_with('\n') {35self.newline();36}37}38}3940pub fn indent(&mut self, amt: usize) {41self.indent += amt;42}4344pub fn deindent(&mut self, amt: usize) {45self.indent -= amt;46}4748fn newline(&mut self) {49self.s.push('\n');50for _ in 0..self.indent {51self.s.push_str(" ");52}53}5455pub fn as_mut_string(&mut self) -> &mut String {56&mut self.s57}58}5960impl Write for Source {61fn write_str(&mut self, s: &str) -> fmt::Result {62self.push_str(s);63Ok(())64}65}6667impl Deref for Source {68type Target = str;69fn deref(&self) -> &str {70&self.s71}72}7374impl From<Source> for String {75fn from(s: Source) -> String {76s.s77}78}7980#[cfg(test)]81mod tests {82use super::Source;8384#[test]85fn simple_append() {86let mut s = Source::default();87s.push_str("x");88assert_eq!(s.s, "x");89s.push_str("y");90assert_eq!(s.s, "xy");91s.push_str("z ");92assert_eq!(s.s, "xyz ");93s.push_str(" a ");94assert_eq!(s.s, "xyz a ");95s.push_str("\na");96assert_eq!(s.s, "xyz a \na");97}9899#[test]100fn newline_remap() {101let mut s = Source::default();102s.push_str("function() {\n");103s.push_str("y\n");104s.push_str("}\n");105assert_eq!(s.s, "function() {\n y\n}\n");106}107108#[test]109fn if_else() {110let mut s = Source::default();111s.push_str("if() {\n");112s.push_str("y\n");113s.push_str("} else if () {\n");114s.push_str("z\n");115s.push_str("}\n");116assert_eq!(s.s, "if() {\n y\n} else if () {\n z\n}\n");117}118119#[test]120fn trim_ws() {121let mut s = Source::default();122s.push_str(123"function() {124x125}",126);127assert_eq!(s.s, "function() {\n x\n}");128}129}130131132