nu_protocol/engine/
description.rs

1use crate::{ModuleId, Span};
2use std::collections::HashMap;
3
4/// Organizes documentation comments for various primitives
5#[derive(Debug, Clone)]
6pub(super) struct Doccomments {
7    // TODO: Move decl doccomments here
8    module_comments: HashMap<ModuleId, Vec<Span>>,
9}
10
11impl Doccomments {
12    pub fn new() -> Self {
13        Doccomments {
14            module_comments: HashMap::new(),
15        }
16    }
17
18    pub fn add_module_comments(&mut self, module_id: ModuleId, comments: Vec<Span>) {
19        self.module_comments.insert(module_id, comments);
20    }
21
22    pub fn get_module_comments(&self, module_id: ModuleId) -> Option<&[Span]> {
23        self.module_comments.get(&module_id).map(|v| v.as_ref())
24    }
25
26    /// Overwrite own values with the other
27    pub fn merge_with(&mut self, other: Doccomments) {
28        self.module_comments.extend(other.module_comments);
29    }
30}
31
32impl Default for Doccomments {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38pub(super) fn build_desc(comment_lines: &[&[u8]]) -> (String, String) {
39    let mut description = String::new();
40
41    let mut num_spaces = 0;
42    let mut first = true;
43
44    // Use the comments to build the item/command description
45    for contents in comment_lines {
46        let comment_line = if first {
47            // Count the number of spaces still at the front, skipping the '#'
48            let mut pos = 1;
49            while pos < contents.len() {
50                if let Some(b' ') = contents.get(pos) {
51                    // continue
52                } else {
53                    break;
54                }
55                pos += 1;
56            }
57
58            num_spaces = pos;
59
60            first = false;
61
62            String::from_utf8_lossy(&contents[pos..]).to_string()
63        } else {
64            let mut pos = 1;
65
66            while pos < contents.len() && pos < num_spaces {
67                if let Some(b' ') = contents.get(pos) {
68                    // continue
69                } else {
70                    break;
71                }
72                pos += 1;
73            }
74
75            String::from_utf8_lossy(&contents[pos..]).to_string()
76        };
77
78        if !description.is_empty() {
79            description.push('\n');
80        }
81        description.push_str(&comment_line);
82    }
83
84    if let Some((brief_desc, extra_desc)) = description.split_once("\r\n\r\n") {
85        (brief_desc.to_string(), extra_desc.to_string())
86    } else if let Some((brief_desc, extra_desc)) = description.split_once("\n\n") {
87        (brief_desc.to_string(), extra_desc.to_string())
88    } else {
89        (description, String::default())
90    }
91}