|
1 | 1 | //! HTML formatting module
|
2 | 2 | //!
|
3 | 3 | //! This module contains a large number of `fmt::Display` implementations for
|
4 |
| -//! various types in `rustdoc::clean`. These implementations all currently |
5 |
| -//! assume that HTML output is desired, although it may be possible to redesign |
6 |
| -//! them in the future to instead emit any format desired. |
| 4 | +//! various types in `rustdoc::clean`. |
| 5 | +//! |
| 6 | +//! These implementations all emit HTML. As an internal implementation detail, |
| 7 | +//! some of them support an alternate format that emits text, but that should |
| 8 | +//! not be used external to this module. |
7 | 9 |
|
8 | 10 | use std::borrow::Cow;
|
9 | 11 | use std::cell::Cell;
|
10 |
| -use std::fmt; |
| 12 | +use std::fmt::{self, Write}; |
11 | 13 | use std::iter::{self, once};
|
12 | 14 |
|
13 | 15 | use rustc_ast as ast;
|
@@ -126,7 +128,6 @@ impl Buffer {
|
126 | 128 | // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
|
127 | 129 | // import).
|
128 | 130 | pub(crate) fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
|
129 |
| - use fmt::Write; |
130 | 131 | self.buffer.write_fmt(v).unwrap();
|
131 | 132 | }
|
132 | 133 |
|
@@ -279,8 +280,6 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
|
279 | 280 | indent: usize,
|
280 | 281 | ending: Ending,
|
281 | 282 | ) -> impl fmt::Display + 'a + Captures<'tcx> {
|
282 |
| - use fmt::Write; |
283 |
| - |
284 | 283 | display_fn(move |f| {
|
285 | 284 | let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
|
286 | 285 | !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
|
@@ -1306,6 +1305,28 @@ impl clean::BareFunctionDecl {
|
1306 | 1305 | }
|
1307 | 1306 | }
|
1308 | 1307 |
|
| 1308 | +// Implements Write but only counts the bytes "written". |
| 1309 | +struct WriteCounter(usize); |
| 1310 | + |
| 1311 | +impl std::fmt::Write for WriteCounter { |
| 1312 | + fn write_str(&mut self, s: &str) -> fmt::Result { |
| 1313 | + self.0 += s.len(); |
| 1314 | + Ok(()) |
| 1315 | + } |
| 1316 | +} |
| 1317 | + |
| 1318 | +// Implements Display by emitting the given number of spaces. |
| 1319 | +struct Indent(usize); |
| 1320 | + |
| 1321 | +impl fmt::Display for Indent { |
| 1322 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1323 | + (0..self.0).for_each(|_| { |
| 1324 | + f.write_char(' ').unwrap(); |
| 1325 | + }); |
| 1326 | + Ok(()) |
| 1327 | + } |
| 1328 | +} |
| 1329 | + |
1309 | 1330 | impl clean::FnDecl {
|
1310 | 1331 | pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>(
|
1311 | 1332 | &'a self,
|
@@ -1345,95 +1366,80 @@ impl clean::FnDecl {
|
1345 | 1366 | indent: usize,
|
1346 | 1367 | cx: &'a Context<'tcx>,
|
1347 | 1368 | ) -> impl fmt::Display + 'a + Captures<'tcx> {
|
1348 |
| - display_fn(move |f| self.inner_full_print(header_len, indent, f, cx)) |
| 1369 | + display_fn(move |f| { |
| 1370 | + // First, generate the text form of the declaration, with no line wrapping, and count the bytes. |
| 1371 | + let mut counter = WriteCounter(0); |
| 1372 | + write!(&mut counter, "{:#}", display_fn(|f| { self.inner_full_print(None, f, cx) })) |
| 1373 | + .unwrap(); |
| 1374 | + // If the text form was over 80 characters wide, we will line-wrap our output. |
| 1375 | + let line_wrapping_indent = |
| 1376 | + if header_len + counter.0 > 80 { Some(indent) } else { None }; |
| 1377 | + // Generate the final output. This happens to accept `{:#}` formatting to get textual |
| 1378 | + // output but in practice it is only formatted with `{}` to get HTML output. |
| 1379 | + self.inner_full_print(line_wrapping_indent, f, cx) |
| 1380 | + }) |
1349 | 1381 | }
|
1350 | 1382 |
|
1351 | 1383 | fn inner_full_print(
|
1352 | 1384 | &self,
|
1353 |
| - header_len: usize, |
1354 |
| - indent: usize, |
| 1385 | + // For None, the declaration will not be line-wrapped. For Some(n), |
| 1386 | + // the declaration will be line-wrapped, with an indent of n spaces. |
| 1387 | + line_wrapping_indent: Option<usize>, |
1355 | 1388 | f: &mut fmt::Formatter<'_>,
|
1356 | 1389 | cx: &Context<'_>,
|
1357 | 1390 | ) -> fmt::Result {
|
1358 | 1391 | let amp = if f.alternate() { "&" } else { "&" };
|
1359 |
| - let mut args = Buffer::html(); |
1360 |
| - let mut args_plain = Buffer::new(); |
| 1392 | + |
| 1393 | + write!(f, "(")?; |
| 1394 | + if let Some(n) = line_wrapping_indent { |
| 1395 | + write!(f, "\n{}", Indent(n + 4))?; |
| 1396 | + } |
1361 | 1397 | for (i, input) in self.inputs.values.iter().enumerate() {
|
| 1398 | + if i > 0 { |
| 1399 | + match line_wrapping_indent { |
| 1400 | + None => write!(f, ", ")?, |
| 1401 | + Some(n) => write!(f, ",\n{}", Indent(n + 4))?, |
| 1402 | + }; |
| 1403 | + } |
1362 | 1404 | if let Some(selfty) = input.to_self() {
|
1363 | 1405 | match selfty {
|
1364 | 1406 | clean::SelfValue => {
|
1365 |
| - args.push_str("self"); |
1366 |
| - args_plain.push_str("self"); |
| 1407 | + write!(f, "self")?; |
1367 | 1408 | }
|
1368 | 1409 | clean::SelfBorrowed(Some(ref lt), mtbl) => {
|
1369 |
| - write!(args, "{}{} {}self", amp, lt.print(), mtbl.print_with_space()); |
1370 |
| - write!(args_plain, "&{} {}self", lt.print(), mtbl.print_with_space()); |
| 1410 | + write!(f, "{}{} {}self", amp, lt.print(), mtbl.print_with_space())?; |
1371 | 1411 | }
|
1372 | 1412 | clean::SelfBorrowed(None, mtbl) => {
|
1373 |
| - write!(args, "{}{}self", amp, mtbl.print_with_space()); |
1374 |
| - write!(args_plain, "&{}self", mtbl.print_with_space()); |
| 1413 | + write!(f, "{}{}self", amp, mtbl.print_with_space())?; |
1375 | 1414 | }
|
1376 | 1415 | clean::SelfExplicit(ref typ) => {
|
1377 |
| - if f.alternate() { |
1378 |
| - write!(args, "self: {:#}", typ.print(cx)); |
1379 |
| - } else { |
1380 |
| - write!(args, "self: {}", typ.print(cx)); |
1381 |
| - } |
1382 |
| - write!(args_plain, "self: {:#}", typ.print(cx)); |
| 1416 | + write!(f, "self: ")?; |
| 1417 | + fmt::Display::fmt(&typ.print(cx), f)?; |
1383 | 1418 | }
|
1384 | 1419 | }
|
1385 | 1420 | } else {
|
1386 |
| - if i > 0 { |
1387 |
| - args.push_str("\n"); |
1388 |
| - } |
1389 | 1421 | if input.is_const {
|
1390 |
| - args.push_str("const "); |
1391 |
| - args_plain.push_str("const "); |
1392 |
| - } |
1393 |
| - write!(args, "{}: ", input.name); |
1394 |
| - write!(args_plain, "{}: ", input.name); |
1395 |
| - |
1396 |
| - if f.alternate() { |
1397 |
| - write!(args, "{:#}", input.type_.print(cx)); |
1398 |
| - } else { |
1399 |
| - write!(args, "{}", input.type_.print(cx)); |
| 1422 | + write!(f, "const ")?; |
1400 | 1423 | }
|
1401 |
| - write!(args_plain, "{:#}", input.type_.print(cx)); |
1402 |
| - } |
1403 |
| - if i + 1 < self.inputs.values.len() { |
1404 |
| - args.push_str(","); |
1405 |
| - args_plain.push_str(","); |
| 1424 | + write!(f, "{}: ", input.name)?; |
| 1425 | + fmt::Display::fmt(&input.type_.print(cx), f)?; |
1406 | 1426 | }
|
1407 | 1427 | }
|
1408 | 1428 |
|
1409 |
| - let mut args_plain = format!("({})", args_plain.into_inner()); |
1410 |
| - let mut args = args.into_inner(); |
1411 |
| - |
1412 | 1429 | if self.c_variadic {
|
1413 |
| - args.push_str(",\n ..."); |
1414 |
| - args_plain.push_str(", ..."); |
| 1430 | + match line_wrapping_indent { |
| 1431 | + None => write!(f, ", ...")?, |
| 1432 | + Some(n) => write!(f, "\n{}...", Indent(n + 4))?, |
| 1433 | + }; |
1415 | 1434 | }
|
1416 | 1435 |
|
1417 |
| - let arrow_plain = format!("{:#}", self.output.print(cx)); |
1418 |
| - let arrow = |
1419 |
| - if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }; |
1420 |
| - |
1421 |
| - let declaration_len = header_len + args_plain.len() + arrow_plain.len(); |
1422 |
| - let output = if declaration_len > 80 { |
1423 |
| - let full_pad = format!("\n{}", " ".repeat(indent + 4)); |
1424 |
| - let close_pad = format!("\n{}", " ".repeat(indent)); |
1425 |
| - format!( |
1426 |
| - "({pad}{args}{close}){arrow}", |
1427 |
| - pad = if self.inputs.values.is_empty() { "" } else { &full_pad }, |
1428 |
| - args = args.replace('\n', &full_pad), |
1429 |
| - close = close_pad, |
1430 |
| - arrow = arrow |
1431 |
| - ) |
1432 |
| - } else { |
1433 |
| - format!("({args}){arrow}", args = args.replace('\n', " "), arrow = arrow) |
| 1436 | + match line_wrapping_indent { |
| 1437 | + None => write!(f, ")")?, |
| 1438 | + Some(n) => write!(f, "\n{})", Indent(n))?, |
1434 | 1439 | };
|
1435 | 1440 |
|
1436 |
| - write!(f, "{}", output) |
| 1441 | + fmt::Display::fmt(&self.output.print(cx), f)?; |
| 1442 | + Ok(()) |
1437 | 1443 | }
|
1438 | 1444 | }
|
1439 | 1445 |
|
|
0 commit comments