1use std::path::Path;
2use std::{fs, str};
3
4use rustc_errors::DiagCtxtHandle;
5use rustc_span::edition::Edition;
6use serde::Serialize;
7
8use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
9
10#[derive(Clone, Debug, Serialize)]
11pub(crate) struct ExternalHtml {
12 pub(crate) in_header: String,
15 pub(crate) before_content: String,
18 pub(crate) after_content: String,
21}
22
23impl ExternalHtml {
24 pub(crate) fn load(
25 in_header: &[String],
26 before_content: &[String],
27 after_content: &[String],
28 md_before_content: &[String],
29 md_after_content: &[String],
30 nightly_build: bool,
31 dcx: DiagCtxtHandle<'_>,
32 id_map: &mut IdMap,
33 edition: Edition,
34 playground: &Option<Playground>,
35 ) -> Option<ExternalHtml> {
36 let codes = ErrorCodes::from(nightly_build);
37 let ih = load_external_files(in_header, dcx)?;
38 let bc = {
39 let mut bc = load_external_files(before_content, dcx)?;
40 let m_bc = load_external_files(md_before_content, dcx)?;
41 Markdown {
42 content: &m_bc,
43 links: &[],
44 ids: id_map,
45 error_codes: codes,
46 edition,
47 playground,
48 heading_offset: HeadingOffset::H2,
49 }
50 .write_into(&mut bc)
51 .unwrap();
52 bc
53 };
54 let ac = {
55 let mut ac = load_external_files(after_content, dcx)?;
56 let m_ac = load_external_files(md_after_content, dcx)?;
57 Markdown {
58 content: &m_ac,
59 links: &[],
60 ids: id_map,
61 error_codes: codes,
62 edition,
63 playground,
64 heading_offset: HeadingOffset::H2,
65 }
66 .write_into(&mut ac)
67 .unwrap();
68 ac
69 };
70 Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
71 }
72}
73
74pub(crate) enum LoadStringError {
75 ReadFail,
76 BadUtf8,
77}
78
79pub(crate) fn load_string<P: AsRef<Path>>(
80 file_path: P,
81 dcx: DiagCtxtHandle<'_>,
82) -> Result<String, LoadStringError> {
83 let file_path = file_path.as_ref();
84 let contents = match fs::read(file_path) {
85 Ok(bytes) => bytes,
86 Err(e) => {
87 dcx.struct_err(format!(
88 "error reading `{file_path}`: {e}",
89 file_path = file_path.display()
90 ))
91 .emit();
92 return Err(LoadStringError::ReadFail);
93 }
94 };
95 match str::from_utf8(&contents) {
96 Ok(s) => Ok(s.to_string()),
97 Err(_) => {
98 dcx.err(format!("error reading `{}`: not UTF-8", file_path.display()));
99 Err(LoadStringError::BadUtf8)
100 }
101 }
102}
103
104fn load_external_files(names: &[String], dcx: DiagCtxtHandle<'_>) -> Option<String> {
105 let mut out = String::new();
106 for name in names {
107 let Ok(s) = load_string(name, dcx) else { return None };
108 out.push_str(&s);
109 out.push('\n');
110 }
111 Some(out)
112}