Skip to content

Commit cd239da

Browse files
Improve indentation handling in documentation comments
Added logic to restore indentation for documentation comments by mapping line indices to their leading spaces. Enhanced text processing to handle both exact and partial line matches for improved formatting.
1 parent e33e7dc commit cd239da

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

crates/cairo-lang-doc/src/parser.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ impl<'db> DocumentationCommentParser<'db> {
8383
item_id: DocumentableItemId<'db>,
8484
documentation_comment: String,
8585
) -> Vec<DocumentationCommentToken<'db>> {
86+
// Build a map of line indices to their leading indentation (number of spaces)
87+
// before markdown parsing removes them.
88+
let line_indents: Vec<usize> = documentation_comment
89+
.lines()
90+
.map(|line| line.len() - line.trim_start().len())
91+
.collect();
92+
8693
let mut tokens = Vec::new();
8794
let mut current_link: Option<CommentLinkToken<'db>> = None;
8895
let mut is_indented_code_block = false;
@@ -139,7 +146,88 @@ impl<'db> DocumentationCommentParser<'db> {
139146
if is_indented_code_block {
140147
format!(" {text}")
141148
} else {
142-
text.to_string()
149+
// Process text line by line to restore indentation
150+
let text_str = text.as_ref();
151+
let lines: Vec<&str> = text_str.split_inclusive('\n').collect();
152+
153+
let mut result = String::new();
154+
for (line_idx, line) in lines.iter().enumerate() {
155+
let trimmed_line = line.trim();
156+
157+
// Check if this is the start of a new line in the original text
158+
let is_new_line = line_idx == 0
159+
&& (tokens.is_empty()
160+
|| tokens
161+
.last()
162+
.and_then(|last| {
163+
if let DocumentationCommentToken::Content(
164+
content,
165+
) = last
166+
{
167+
Some(content.ends_with('\n'))
168+
} else {
169+
None
170+
}
171+
})
172+
.unwrap_or(true));
173+
174+
// For each non-empty line, try to find matching line in
175+
// original text
176+
if !trimmed_line.is_empty() && (is_new_line || line_idx > 0) {
177+
// Find the line in original text that matches this content
178+
// Try exact match first, then partial match
179+
let mut found_line_num = None;
180+
for (i, orig_line) in
181+
documentation_comment.lines().enumerate()
182+
{
183+
let trimmed_orig = orig_line.trim();
184+
// Exact match (most reliable)
185+
if trimmed_orig == trimmed_line {
186+
found_line_num = Some(i);
187+
break;
188+
}
189+
}
190+
191+
// If no exact match, try partial match
192+
if found_line_num.is_none() {
193+
for (i, orig_line) in
194+
documentation_comment.lines().enumerate()
195+
{
196+
let trimmed_orig = orig_line.trim();
197+
// Check if one is a prefix of the other (for cases
198+
// where markdown splits text)
199+
if (trimmed_line.len() >= 5
200+
&& trimmed_orig.starts_with(
201+
&trimmed_line[..trimmed_line
202+
.len()
203+
.min(trimmed_orig.len())],
204+
))
205+
|| (trimmed_orig.len() >= 5
206+
&& trimmed_line.starts_with(
207+
&trimmed_orig[..trimmed_orig
208+
.len()
209+
.min(trimmed_line.len())],
210+
))
211+
{
212+
found_line_num = Some(i);
213+
break;
214+
}
215+
}
216+
}
217+
218+
if let Some(line_num) = found_line_num
219+
&& line_num < line_indents.len()
220+
{
221+
let indent = line_indents[line_num];
222+
if indent > 0 {
223+
result.push_str(&" ".repeat(indent));
224+
}
225+
}
226+
}
227+
result.push_str(line);
228+
}
229+
230+
if result.is_empty() { text.to_string() } else { result }
143231
}
144232
};
145233
tokens.push(DocumentationCommentToken::Content(text));

0 commit comments

Comments
 (0)