From eca8bce08112a7e0621baad29a1be2fcd0c668b9 Mon Sep 17 00:00:00 2001 From: FireFly Date: Wed, 15 May 2024 15:24:03 -0700 Subject: [PATCH] lix-doc: don't chomp bold headings off There are a few places in nixpkgs lib where `**Foo**:` is used as a heading instead of the usual markdown `# Foo` ones. I think this is intentional with how it gets rendered in the manual, e.g. [`lib.lists.sortOn`][1]. [1]: https://nixos.org/manual/nixpkgs/stable/#function-library-lib.lists.sortOn `nix-doc` prints this as ``` *Laws**: ```nix sortOn f == sort (p: q: f p < f q) ``` ``` chomping off the first asterisk as part of `cleanup_single_line` that's meant to deal with `/** \n * \n * \n */` style doc comments. This also means the usage in lix ends up funny-looking with a trailing asterisk as if there's a footnote to pay attention to (which is how I first noticed it, heh) The fix: When cleaning up a single line and removing a prefix comment character, ensure it's followed by whitespace (or the last character of the line). Upstream-PR: https://github.com/lf-/nix-doc/pull/26 Change-Id: If2870c53a632f6bbbcca98a4bfbd72f5bef37879 --- lix-doc/src/lib.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/lix-doc/src/lib.rs b/lix-doc/src/lib.rs index 9c2e43f2f..27fe5c9b5 100644 --- a/lix-doc/src/lib.rs +++ b/lix-doc/src/lib.rs @@ -84,9 +84,13 @@ fn indented(s: &str, indent: usize) -> String { /// Cleans up a single line, erasing prefix single line comments but preserving indentation fn cleanup_single_line<'a>(s: &'a str) -> &'a str { let mut cmt_new_start = 0; - for (idx, ch) in s.char_indices() { + let mut iter = s.char_indices().peekable(); + while let Some((idx, ch)) = iter.next() { + // peek at the next character, with an explicit '\n' as "next character" at end of line + let (_, next_ch) = iter.peek().unwrap_or(&(0, '\n')); + // if we find a character, save the byte position after it as our new string start - if ch == '#' || ch == '*' { + if ch == '#' || (ch == '*' && next_ch.is_whitespace()) { cmt_new_start = idx + 1; break; } @@ -206,7 +210,7 @@ fn visit_lambda(name: String, lambda: &Lambda) -> SearchResult { SearchResult { identifier: name, doc: comment, - param_block + param_block, } } @@ -246,7 +250,7 @@ pub extern "C" fn nd_get_function_docs( filename: *const c_char, line: usize, col: usize, - ) -> *const c_char { +) -> *const c_char { let fname = unsafe { CStr::from_ptr(filename) }; fname .to_str() @@ -257,9 +261,9 @@ pub extern "C" fn nd_get_function_docs( eprintln!("panic!! {:#?}", e); e }) - .ok() + .ok() }) - .flatten() + .flatten() .and_then(|s| CString::new(s).ok()) .map(|s| s.into_raw() as *const c_char) .unwrap_or(ptr::null()) @@ -319,8 +323,16 @@ mod tests { let ex1 = " * a"; let ex2 = " # a"; let ex3 = " a"; + let ex4 = " *"; assert_eq!(cleanup_single_line(ex1), " a"); assert_eq!(cleanup_single_line(ex2), " a"); assert_eq!(cleanup_single_line(ex3), ex3); + assert_eq!(cleanup_single_line(ex4), ""); + } + + #[test] + fn test_single_line_retains_bold_headings() { + let ex1 = " **Foo**:"; + assert_eq!(cleanup_single_line(ex1), ex1); } }