asciidork_parser/tasks/
attr_refs.rs

1use crate::internal::*;
2
3pub trait AttrRefObserver {
4  fn attr_ref_replaced(&self, attr_name: &str, loc: SourceLocation);
5  fn attr_ref_missing(&self, attr_name: &str, loc: SourceLocation);
6}
7
8impl<'arena> Parser<'arena> {
9  pub(crate) fn set_source_file_attrs(&mut self) {
10    let source_file = self.lexer.source_file().clone();
11    match source_file {
12      SourceFile::Stdin { .. } => {}
13      SourceFile::Path(path) => {
14        let file_stem = path.file_stem();
15        let ext = path.extension();
16        self.insert_file_attr("docfilesuffix", ext.to_string());
17        self.insert_file_attr("docname", file_stem.to_string());
18        self.insert_file_attr("asciidork-docfilename", format!("{}{}", file_stem, ext));
19        match self.document.meta.safe_mode {
20          SafeMode::Server | SafeMode::Secure => {
21            self.insert_file_attr("docdir", "");
22            self.insert_file_attr("docfile", "");
23          }
24          SafeMode::Safe | SafeMode::Unsafe => {
25            self.insert_file_attr("docfile", path.to_string());
26            self.insert_file_attr("docdir", path.dirname().to_string());
27          }
28        }
29      }
30      SourceFile::Tmp => {}
31    };
32  }
33
34  pub(crate) fn push_token_replacing_attr_ref(
35    &mut self,
36    mut token: Token<'arena>,
37    line: &mut Line<'arena>,
38    drop_line: &mut bool,
39  ) -> Result<()> {
40    if token.kind(TokenKind::AttrRef) && self.ctx.subs.attr_refs() {
41      match self.document.meta.get(token.attr_name()) {
42        Some(AttrValue::String(attr_val)) => {
43          #[cfg(feature = "attr_ref_observation")]
44          if let Some(observer) = &self.attr_ref_observer {
45            observer.attr_ref_replaced(token.attr_name(), token.loc);
46          }
47          if !attr_val.is_empty() {
48            self.lexer.set_tmp_buf(attr_val, BufLoc::Repeat(token.loc));
49          }
50          line.push(token);
51        }
52        _ => {
53          #[cfg(feature = "attr_ref_observation")]
54          if let Some(observer) = &self.attr_ref_observer {
55            observer.attr_ref_missing(token.attr_name(), token.loc);
56          }
57          match self.document.meta.str("attribute-missing") {
58            Some("drop") => {}
59            Some("drop-line") => *drop_line = true,
60            val => {
61              token.kind = TokenKind::Word;
62              if val == Some("warn") {
63                self.err_token_full("Skipping reference to missing attribute", &token)?;
64              }
65              line.push(token);
66            }
67          }
68        }
69      }
70    } else {
71      line.push(token);
72    }
73    Ok(())
74  }
75
76  fn insert_file_attr(&mut self, key: &str, value: impl Into<AttrValue>) {
77    self
78      .document
79      .meta
80      .insert_job_attr(key, JobAttr::readonly(value))
81      .unwrap();
82  }
83
84  pub(crate) fn insert_doc_attr(
85    &mut self,
86    key: &str,
87    value: impl Into<AttrValue>,
88  ) -> std::result::Result<(), String> {
89    self.document.meta.insert_doc_attr(key, value)
90  }
91}