fix_getters_utils/collectors/
doc_code.rs1use std::path::{Path, PathBuf};
4
5use crate::{GetterCollection, IdentificationMode, Scope, TokenStreamGetterCollector};
6
7#[derive(Debug)]
16pub struct DocCodeGetterCollector<P: TokenStreamGetterCollector> {
17 code: String,
18 state: State,
19 identification_mode: IdentificationMode,
20 getter_collection: P::GetterCollection,
21 path: PathBuf,
22}
23
24impl<P: TokenStreamGetterCollector> DocCodeGetterCollector<P> {
25 pub fn new(
30 path: &Path,
31 identification_mode: IdentificationMode,
32 getter_collection: &P::GetterCollection,
33 ) -> Self {
34 let mut getter_collection = P::GetterCollection::clone(getter_collection);
35 getter_collection.disable_doc_alias();
36
37 DocCodeGetterCollector {
38 code: String::with_capacity(512),
39 state: State::None,
40 identification_mode,
41 getter_collection,
42 path: path.to_owned(),
43 }
44 }
45
46 pub fn have_attribute(&mut self, node: &syn::Attribute) {
52 if let Some((_, cursor)) = syn::buffer::TokenBuffer::new2(node.tokens.clone())
53 .begin()
54 .punct()
55 {
56 if let Some((literal, _)) = cursor.literal() {
57 self.process(
58 &literal.to_string().trim_matches('"').trim(),
59 literal.span().start().line,
60 );
61 }
62 }
63 }
64
65 fn process(&mut self, doc_line: &str, offset: usize) {
66 if doc_line.starts_with("```") {
67 if !self.state.is_code_block() {
68 self.getter_collection.set_offset(offset);
70 if doc_line.len() == 3 || doc_line.ends_with("rust") {
71 self.state = State::RustCodeBlock;
72 } else {
73 self.state = State::CodeBlock;
74 };
75 } else {
76 if self.state.is_rust() {
78 self.collect();
79 }
80 self.state = State::None;
81 }
82 } else if self.state.is_rust() && !doc_line.starts_with('#') {
83 self.code.push_str(&doc_line.replace('\\', &""));
84 self.code.push('\n');
85 }
86 }
87
88 fn collect(&mut self) {
89 match syn::parse_str::<proc_macro2::TokenStream>(&self.code) {
90 Ok(syntax_tree) => P::collect(
91 &self.path,
92 &Scope::Documentation,
93 &syntax_tree,
94 self.identification_mode,
95 &self.getter_collection,
96 ),
97 Err(_err) => {
98 #[cfg(feature = "log")]
99 log::warn!(
100 "{:?} doc @ {}: {:?}",
101 self.path,
102 self.getter_collection.offset(),
103 _err
104 );
105 }
106 }
107
108 self.code.clear();
109 }
110}
111
112#[derive(Debug)]
113enum State {
114 None,
115 CodeBlock,
116 RustCodeBlock,
117}
118
119impl State {
120 fn is_code_block(&self) -> bool {
121 matches!(self, State::RustCodeBlock | State::CodeBlock)
122 }
123
124 fn is_rust(&self) -> bool {
125 matches!(self, State::RustCodeBlock)
126 }
127}