Skip to content

Commit

Permalink
Handle escape sequences in doc-comments
Browse files Browse the repository at this point in the history
  • Loading branch information
KateMorley committed Oct 13, 2023
1 parent e8efc82 commit 09c702a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
24 changes: 24 additions & 0 deletions argh/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,30 @@ Options:
);
}

#[test]
fn escaped_doc_comment_description() {
#[derive(FromArgs)]
/// A \description\:
/// \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~\
struct Cmd {
#[argh(switch)]
/// a \description\:
/// \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~\
_s: bool,
}

assert_help_string::<Cmd>(
r###"Usage: test_arg_0 [--s]
A \description: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~\
Options:
--s a \description: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~\
--help display usage information
"###,
);
}

#[test]
fn explicit_long_value_for_option() {
#[derive(FromArgs, Debug)]
Expand Down
31 changes: 28 additions & 3 deletions argh_derive/src/parse_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
return;
};

// Don't replace an existing description.
// Don't replace an existing explicit description.
if slot.as_ref().map(|d| d.explicit).unwrap_or(false) {
return;
}
Expand All @@ -509,14 +509,39 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
let lit_str = if let Some(previous) = slot {
let previous = &previous.content;
let previous_span = previous.span();
syn::LitStr::new(&(previous.value() + &*lit_str.value()), previous_span)
syn::LitStr::new(&(previous.value() + &unescape_doc(lit_str.value())), previous_span)
} else {
lit_str.clone()
syn::LitStr::new(&unescape_doc(lit_str.value()), lit_str.span())
};
*slot = Some(Description { explicit: false, content: lit_str });
}
}

/// Replaces escape sequences in doc-comments with the characters they represent.
///
/// Rustdoc understands CommonMark escape sequences consisting of a backslash followed by an ASCII
/// punctuation character. Any other backslash is treated as a literal backslash.
fn unescape_doc(s: String) -> String {
let mut result = String::with_capacity(s.len());

let mut characters = s.chars().peekable();
while let Some(mut character) = characters.next() {
if character == '\\' && characters.peek().map_or(false, |next| next.is_ascii_punctuation())
{
character = characters.next().unwrap()
}

// Braces must be escaped as this string will be used as a format string
if character == '{' || character == '}' {
result.push(character);
}

result.push(character);
}

result
}

fn parse_attr_description(errors: &Errors, m: &syn::MetaNameValue, slot: &mut Option<Description>) {
let lit_str =
if let Some(lit_str) = errors.expect_lit_str(&m.value) { lit_str } else { return };
Expand Down

0 comments on commit 09c702a

Please sign in to comment.