1#[cfg(feature = "vimdoc")]
2pub mod vimdoc;
3
4pub mod lexer;
5pub mod parser;
6
7use std::{fmt::Display, str::FromStr};
8
9use chumsky::prelude::Simple;
10
11use parser::{
12 Alias, Brief, Class, Divider, Field, Func, Module, Node, Param, Return, See, Tag, Type, Usage,
13};
14
15use crate::lexer::TagType;
16
17pub trait Visitor {
18 type R;
19 type S;
20 fn module(&self, n: &Module, s: &Self::S) -> Self::R;
21 fn divider(&self, n: &Divider, s: &Self::S) -> Self::R;
22 fn brief(&self, n: &Brief, s: &Self::S) -> Self::R;
23 fn tag(&self, n: &Tag, s: &Self::S) -> Self::R;
24 fn func(&self, n: &Func, s: &Self::S) -> Self::R;
25 fn params(&self, n: &[Param], s: &Self::S) -> Self::R;
26 fn r#returns(&self, n: &[Return], s: &Self::S) -> Self::R;
27 fn class(&self, n: &Class, s: &Self::S) -> Self::R;
28 fn fields(&self, n: &[Field], s: &Self::S) -> Self::R;
29 fn alias(&self, n: &Alias, s: &Self::S) -> Self::R;
30 fn r#type(&self, n: &Type, s: &Self::S) -> Self::R;
31 fn toc(&self, n: &str, nodes: &[Node], s: &Self::S) -> Self::R;
32 fn see(&self, n: &See, s: &Self::S) -> Self::R;
33 fn usage(&self, n: &Usage, s: &Self::S) -> Self::R;
34}
35
36pub trait Accept<T: Visitor> {
37 fn accept(&self, n: &T, s: &T::S) -> T::R;
38}
39
40pub trait Nodes {
41 fn nodes(&self) -> &Vec<Node>;
42}
43
44pub trait FromEmmy: Display {
45 type Settings;
46 fn from_emmy(t: &impl Nodes, s: &Self::Settings) -> Self;
47}
48
49pub trait AsDoc<T: FromEmmy> {
50 fn as_doc(&self, s: &T::Settings) -> T;
51}
52
53#[derive(Debug, Default, PartialEq, Eq)]
54pub enum Layout {
55 #[default]
56 Default,
57 Compact(u8),
58 Mini(u8),
59}
60
61impl FromStr for Layout {
62 type Err = ();
63 fn from_str(s: &str) -> Result<Self, Self::Err> {
64 match s {
65 "default" => Ok(Self::Default),
66 x => {
67 let mut val = x.splitn(2, ':');
68 match (val.next(), val.next()) {
69 (Some("compact"), n) => Ok(Self::Compact(
70 n.map_or(0, |x| x.parse().unwrap_or_default()),
71 )),
72 (Some("mini"), n) => {
73 Ok(Self::Mini(n.map_or(0, |x| x.parse().unwrap_or_default())))
74 }
75 _ => Err(()),
76 }
77 }
78 }
79 }
80}
81
82#[derive(Debug)]
83pub struct Settings {
84 pub prefix_func: bool,
86 pub prefix_alias: bool,
88 pub prefix_class: bool,
90 pub prefix_type: bool,
92 pub expand_opt: bool,
94 pub layout: Layout,
96 pub indent_width: usize,
98}
99
100impl Default for Settings {
101 fn default() -> Self {
102 Self {
103 prefix_func: false,
104 prefix_alias: false,
105 prefix_class: false,
106 prefix_type: false,
107 expand_opt: false,
108 layout: Layout::default(),
109 indent_width: 4,
110 }
111 }
112}
113
114#[derive(Debug, Default)]
115pub struct LemmyHelp {
116 nodes: Vec<Node>,
117}
118
119impl Nodes for LemmyHelp {
120 fn nodes(&self) -> &Vec<Node> {
121 &self.nodes
122 }
123}
124
125impl<T: FromEmmy> AsDoc<T> for LemmyHelp {
126 fn as_doc(&self, s: &T::Settings) -> T {
127 T::from_emmy(self, s)
128 }
129}
130
131impl LemmyHelp {
132 pub fn new() -> Self {
140 Self { nodes: vec![] }
141 }
142
143 pub fn parse(&mut self, src: &str) -> Result<&Self, Vec<Simple<TagType>>> {
166 self.nodes.append(&mut Node::new(src)?);
167
168 Ok(self)
169 }
170
171 pub fn for_help(
173 &mut self,
174 src: &str,
175 settings: &Settings,
176 ) -> Result<&Self, Vec<Simple<TagType>>> {
177 let mut nodes = Node::new(src)?;
178
179 if let Some(Node::Export(export)) = nodes.pop() {
180 let module = match nodes.iter().rev().find(|x| matches!(x, Node::Module(_))) {
181 Some(Node::Module(m)) => m.name.to_owned(),
182 _ => export.to_owned(),
183 };
184
185 for ele in nodes {
186 match ele {
187 Node::Export(..) => {}
188 Node::Func(mut func) => {
189 if func.prefix.left.as_deref() == Some(&export) {
190 if settings.prefix_func {
191 func.prefix.right = Some(module.to_owned());
192 }
193 self.nodes.push(Node::Func(func));
194 }
195 }
196 Node::Type(mut typ) => {
197 if typ.prefix.left.as_deref() == Some(&export) {
198 if settings.prefix_type {
199 typ.prefix.right = Some(module.to_owned());
200 }
201 self.nodes.push(Node::Type(typ));
202 }
203 }
204 Node::Alias(mut alias) => {
205 if settings.prefix_alias {
206 alias.prefix.right = Some(module.to_owned());
207 }
208 self.nodes.push(Node::Alias(alias))
209 }
210 Node::Class(mut class) => {
211 if settings.prefix_class {
212 class.prefix.right = Some(module.to_owned());
213 }
214 self.nodes.push(Node::Class(class))
215 }
216 _ => self.nodes.push(ele),
217 }
218 }
219 };
220
221 Ok(self)
222 }
223}