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