lisette_emit/output/
mod.rs1pub mod imports;
2
3use std::io::{self, Write};
4use std::process::{Command, Stdio};
5
6use diagnostics::LisetteDiagnostic;
7
8use self::imports::format_import;
9
10#[derive(Clone, Debug)]
11pub struct OutputFile {
12 pub name: String,
13 pub source: String,
14 pub imports: Vec<(String, String)>,
17 pub package_name: String,
18 pub diagnostics: Vec<LisetteDiagnostic>,
19}
20
21impl OutputFile {
22 pub fn to_go(&self) -> String {
23 let unformatted = self.render_unformatted();
24 gofmt(&unformatted).unwrap_or(unformatted)
25 }
26
27 pub fn to_go_unformatted(&self) -> String {
28 self.render_unformatted()
29 }
30
31 fn render_unformatted(&self) -> String {
32 let mut output = OutputCollector::new();
33
34 output.collect(format!("package {}", self.package_name));
35
36 match self.imports.as_slice() {
37 [] => {}
38 [(path, alias)] => {
39 output.collect(format!("import {}", format_import(path, alias)));
40 }
41 entries => {
42 output.collect("import (");
43 for (path, alias) in entries {
44 output.collect(format_import(path, alias));
45 }
46 output.collect(")");
47 }
48 }
49
50 output.collect(&self.source);
51 output.render()
52 }
53}
54
55fn gofmt(code: &str) -> Result<String, io::Error> {
56 let mut child = Command::new("gofmt")
57 .stdin(Stdio::piped())
58 .stdout(Stdio::piped())
59 .stderr(Stdio::piped())
60 .spawn()?;
61
62 let Some(mut stdin) = child.stdin.take() else {
63 return Err(io::Error::other("Failed to open stdin"));
64 };
65
66 stdin.write_all(code.as_bytes())?;
67 drop(stdin);
68
69 let output = child.wait_with_output()?;
70
71 if !output.status.success() {
72 return Err(io::Error::other("gofmt failed"));
73 }
74
75 Ok(String::from_utf8_lossy(&output.stdout).into_owned())
76}
77
78#[derive(Default)]
79pub(crate) struct OutputCollector {
80 output: Vec<String>,
81}
82
83impl OutputCollector {
84 pub(crate) fn new() -> Self {
85 Self::default()
86 }
87
88 pub(crate) fn render(&self) -> String {
89 self.output.join("\n")
90 }
91
92 pub(crate) fn collect(&mut self, line: impl Into<String>) {
93 self.output.push(line.into());
94 }
95
96 pub(crate) fn collect_with_blank(&mut self, line: impl Into<String>) {
97 self.output.push(line.into());
98 self.output.push(String::new());
99 }
100}