|
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