1pub fn get_javadoc(input: &str, pos: usize) -> Option<String> {
2 find_content_string(&input[..pos]).map(parse_javadoc)
3}
4fn find_content_string(input: &str) -> Option<&str> {
5 let mut pos = 0;
6 let mut start_pos: Option<usize> = None;
7 let mut end_pos: Option<usize> = None;
8
9 enum FindState {
10 Idle,
11 LineCommentOrSomethingElse,
12 LineCommentOrSomethingElseBeforeSlash,
13 BeforeEndSlash,
14 InsideComment,
15 BeforeBeginStar,
16 BeforeBeginStarStar,
17 }
18
19 let mut state = FindState::Idle;
20
21 for current in input.chars().rev() {
22 pos += 1;
23 match state {
24 FindState::Idle => {
25 if current == '/' {
26 state = FindState::BeforeEndSlash;
27 } else if current != ' ' && current != '\n' && current != '\r' && current != '\t' {
28 state = FindState::LineCommentOrSomethingElse;
29 }
30 }
31 FindState::LineCommentOrSomethingElse => {
32 if current == '/' {
33 state = FindState::LineCommentOrSomethingElseBeforeSlash;
34 } else if current == '\n' {
35 break;
36 }
37 }
38 FindState::LineCommentOrSomethingElseBeforeSlash => {
39 if current == '/' {
40 state = FindState::Idle;
41 } else {
42 break;
43 }
44 }
45 FindState::BeforeEndSlash => {
46 state = if current == '*' {
47 end_pos = Some(pos);
48 FindState::InsideComment
49 } else {
50 FindState::Idle
51 };
52 }
53 FindState::InsideComment => {
54 if current == '*' {
55 state = FindState::BeforeBeginStar;
56 };
57 }
58 FindState::BeforeBeginStar => {
59 state = if current == '*' {
60 FindState::BeforeBeginStarStar
61 } else if current == '/' {
62 FindState::Idle
63 } else {
64 FindState::InsideComment
65 };
66 }
67 FindState::BeforeBeginStarStar => {
68 if current == '/' {
69 start_pos = Some(pos - 3);
70 break;
71 }
72
73 state = FindState::InsideComment;
74 }
75 }
76 }
77
78 match (start_pos, end_pos) {
79 (Some(start_pos), Some(end_pos)) => {
80 let start_pos = input.len() - start_pos;
81 let end_pos = input.len() - end_pos;
82
83 Some(&input[start_pos..end_pos])
84 }
85 _ => None,
86 }
87}
88
89fn parse_javadoc(s: &str) -> String {
90 let re = regex::Regex::new("\r?\n[ \t*]*\r?\n").unwrap();
92 let lines = re.split(s);
93
94 let re = regex::Regex::new("[ \t\r\n*]*\n[ \t\r\n*]*").unwrap();
96 let lines = lines.map(|s| {
97 let s = s.trim_matches(|c| c == '\r' || c == '\n' || c == ' ' || c == '\t' || c == '*');
98 re.replace_all(s, " ").to_string()
99 });
100
101 let re = regex::Regex::new("([^\n])[ \t]*@").unwrap();
103 let lines = lines.map(|s| re.replace_all(&s, "${1}\n@").to_string());
104
105 lines.collect::<Vec<_>>().join("\n")
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_find_content_string() {
114 let input = "/**TestJavaDoc*/";
115 assert_eq!(find_content_string(input), Some("TestJavaDoc"));
116
117 let input = r#"bla bla
118 /**
119 * TestJavaDoc
120 *
121 * End
122 */
123 // Comment"#;
124 assert_eq!(
125 find_content_string(input),
126 Some(
127 r#"
128 * TestJavaDoc
129 *
130 * End
131 "#
132 )
133 );
134
135 let input = r#"
136 /** Documentation before */
137 /** The real documentation */
138 /* Comment after */
139 // Line comment after
140 "#;
141 assert_eq!(find_content_string(input), Some(" The real documentation "),);
142
143 let input = r#"
144 /** Other documentation */
145 something else;
146 "#;
147 assert_eq!(find_content_string(input), None);
148
149 let input = r#"
150 something else;
151 /**The documentation*/
152 "#;
153 assert_eq!(find_content_string(input), Some("The documentation"));
154 }
155
156 #[test]
157 fn test_parse_javadoc() {
158 let input = "This is a javadoc\n * comment";
159 assert_eq!(parse_javadoc(input), "This is a javadoc comment");
160
161 let input = "\n * JavaDoc title\n *\n * JavaDoc text1\n * JavaDoc text2\n";
162 assert_eq!(
163 parse_javadoc(input),
164 "JavaDoc title\nJavaDoc text1 JavaDoc text2"
165 );
166
167 let input = r#"
168 * JavaDoc title
169 * @param Param1 Description
170 * @param Param2 Description
171 *
172 * Description
173 "#;
174 assert_eq!(
175 parse_javadoc(input),
176 "JavaDoc title\n@param Param1 Description\n@param Param2 Description\nDescription"
177 );
178 }
179}