From 528a4c1e20c2b9b8ecf451af72c77ae36e4f95b5 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Wed, 25 Jan 2023 19:22:44 +0200 Subject: feat: keep track of which pages a page links to Via wiki links or the meta link directive. Sponsored-by: author --- src/bin/riki.rs | 32 ++++++++++++++++++++++++++++++++ src/directive/meta.rs | 7 +++++++ src/page.rs | 17 ++++++++++++++++- src/site.rs | 8 +++++++- src/wikitext.rs | 1 + 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/bin/riki.rs b/src/bin/riki.rs index c1f9e4b..bff1a72 100644 --- a/src/bin/riki.rs +++ b/src/bin/riki.rs @@ -52,6 +52,7 @@ fn real_main() -> Result<(), RikiError> { Command::Timestamps(cmd) => cmd.run()?, Command::ParseDate(cmd) => cmd.run()?, Command::PageSpec(cmd) => cmd.run()?, + Command::Links(cmd) => cmd.run()?, } } @@ -77,6 +78,7 @@ enum Command { Timestamps(Timestamps), ParseDate(ParseDate), PageSpec(PageSpec), + Links(Links), } /// Build the site. @@ -247,3 +249,33 @@ impl PageSpec { Ok(()) } } + +/// List links in the pages listed on the command line. +#[derive(Parser)] +struct Links { + /// Directory where source files are. + srcdir: PathBuf, + + /// Path to pages whose links are to be listed. + pages: Vec, +} + +impl Links { + fn run(&self) -> Result<(), RikiError> { + let srcdir = canonicalize(&self.srcdir)?; + let mut site = Site::new(&srcdir, &PathBuf::from("/tmp")); + site.scan()?; + site.process()?; + + for path in self.pages.iter() { + if let Some(page) = site.page(path) { + println!("page: {:?}", page.meta().path().display()); + for path in page.meta().links_to() { + println!(" {}", path.display()); + } + } + } + + Ok(()) + } +} diff --git a/src/directive/meta.rs b/src/directive/meta.rs index 974a955..5e07eed 100644 --- a/src/directive/meta.rs +++ b/src/directive/meta.rs @@ -4,10 +4,13 @@ use crate::site::Site; use crate::time::parse_timestamp; use crate::wikitext::ParsedDirective; +use std::path::PathBuf; + #[derive(Default, Debug, Eq, PartialEq)] pub struct Meta { title: Option, date: Option, + link: PathBuf, } impl DirectiveImplementation for Meta { @@ -24,6 +27,9 @@ impl DirectiveImplementation for Meta { if let Some(date) = args.get("date") { meta.set_date(date); } + if let Some(link) = args.get("link") { + meta.link = PathBuf::from(link); + } meta } @@ -34,6 +40,7 @@ impl DirectiveImplementation for Meta { if let Some(mtime) = &self.date { meta.set_mtime(parse_timestamp(mtime)?); } + meta.add_link(&self.link); Ok(Processed::Markdown("".into())) } } diff --git a/src/page.rs b/src/page.rs index d84721c..453c29b 100644 --- a/src/page.rs +++ b/src/page.rs @@ -30,6 +30,7 @@ pub enum PageError { Parser(#[from] crate::parser::ParserError), } +#[derive(Debug)] pub struct Page { meta: PageMeta, unprocessed: UnprocessedPage, @@ -193,6 +194,7 @@ pub struct PageMeta { name: Name, title: Option, mtime: SystemTime, + links_to: Vec, } impl PageMeta { @@ -203,7 +205,12 @@ impl PageMeta { title, mtime, ); - Self { name, title, mtime } + Self { + name, + title, + mtime, + links_to: vec![], + } } pub fn destination_filename(&self) -> PathBuf { @@ -234,6 +241,14 @@ impl PageMeta { pub fn set_mtime(&mut self, mtime: SystemTime) { self.mtime = mtime; } + + pub fn add_link(&mut self, path: &Path) { + self.links_to.push(path.into()); + } + + pub fn links_to(&self) -> &[PathBuf] { + &self.links_to + } } #[derive(Debug, Default)] diff --git a/src/site.rs b/src/site.rs index 4d2ce29..cfd5017 100644 --- a/src/site.rs +++ b/src/site.rs @@ -93,7 +93,7 @@ impl Site { info!("add wikitext page {}", page.meta().path().display()); self.pages_that_will_exist.insert(&page); - debug!("parsing wikitext page {}", page.meta().path().display()); + trace!("parsing wikitext page {}", page.meta().path().display()); let mut parser = WikitextParser::new(page.wikitext(), &self.patterns); let page = UnprocessedPage::new(page.meta().clone(), &mut parser)?; page.prepare(self)?; @@ -151,6 +151,12 @@ impl Site { self.pages_that_will_exist.get_path(path).is_some() } + pub fn page(&self, path: &Path) -> Option<&MarkdownPage> { + self.markdown_pages + .iter() + .find(|&page| page.meta().path() == path) + } + fn all_files(&self) -> Result, SiteError> { let whatchanged = git_whatchanged(self.name_builder.srcdir())?; diff --git a/src/wikitext.rs b/src/wikitext.rs index 4d8578a..57dff88 100644 --- a/src/wikitext.rs +++ b/src/wikitext.rs @@ -48,6 +48,7 @@ impl Snippet { Snippet::WikiLink(w) => { let resolved = site.resolve(meta.path(), Path::new(w.target()))?; trace!("resolved {} to {}", w.target(), resolved.display()); + meta.add_link(&resolved); let link = format!("[{}]({})", w.link_text(), resolved.display()); Processed::Markdown(link) } -- cgit v1.2.1 From ca160fd27a31a030191055409d02fd7739a50179 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Wed, 25 Jan 2023 19:23:07 +0200 Subject: feat: lower some log messages from debug to trace for easier debug Sponsored-by: author --- src/parser.rs | 6 +++--- src/token.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 5e8238e..48e1a58 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use crate::token::{TokenKind, TokenParser, TokenPatterns}; use crate::wikitext::{ParsedDirective, Snippet, WikiLink, WikitextError}; use line_col::LineColLookup; -use log::{debug, trace}; +use log::trace; use std::collections::HashMap; #[derive(Debug, thiserror::Error)] @@ -34,7 +34,7 @@ impl WikitextParser { let mut positions = vec![]; loop { let token = p.parse(); - debug!("token {:?}", token); + trace!("token {:?}", token); if token.token == TokenKind::End { break; } @@ -65,7 +65,7 @@ impl WikitextParser { } let (line, col) = self.position(); - debug!("token at {}:{}", line, col); + trace!("token at {}:{}", line, col); let snippet = match &self.tokens[..] { [TokenKind::OpenBrackets, TokenKind::Word(target), TokenKind::CloseBrackets, ..] => { let wikilink = WikiLink::new(target, target); diff --git a/src/token.rs b/src/token.rs index c1d2abc..a290366 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,4 +1,4 @@ -use log::debug; +use log::trace; use regex::Regex; #[derive(Debug, Clone, Eq, PartialEq)] @@ -9,7 +9,7 @@ pub struct Token { impl Token { fn new(token: TokenKind, pos: usize) -> Self { - debug!("Token: token={:?} pos={}", token, pos); + trace!("Token: token={:?} pos={}", token, pos); Self { token, pos } } } -- cgit v1.2.1 From c0e44d18d56ed625df5ff0224fe170e4d18add09 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 6 Feb 2023 19:05:09 +0200 Subject: feat: placeholder for "link(.)" in pagespec Doesn't yet do anything useful. Sponsored-by: author --- src/bin/riki.rs | 1 + src/pagespec.lalrpop | 1 + src/pagespec.rs | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/bin/riki.rs b/src/bin/riki.rs index bff1a72..131326b 100644 --- a/src/bin/riki.rs +++ b/src/bin/riki.rs @@ -229,6 +229,7 @@ impl PageSpec { site.process()?; let pagespec = pagespec::PageSpec::new(&self.path, &self.pagespec)?; + debug!("pagespec: {:#?}", pagespec); for page in site.markdown_pages() { let path = page.meta().path(); diff --git a/src/pagespec.lalrpop b/src/pagespec.lalrpop index e1dd433..bc07744 100644 --- a/src/pagespec.lalrpop +++ b/src/pagespec.lalrpop @@ -9,6 +9,7 @@ pub Expr: Box = { Term: Box = { Glob => Box::new(Expr::Glob(<>)), + "link" "(" "." ")" => Box::new(Expr::LinksHereFunc), "page" "(" ")" => Box::new(Expr::PageFunc(<>)), "!" => Box::new(Expr::Negate(t)), "(" ")" => e, diff --git a/src/pagespec.rs b/src/pagespec.rs index 55c83fb..e3f617d 100644 --- a/src/pagespec.rs +++ b/src/pagespec.rs @@ -22,6 +22,11 @@ pub struct PageSpec { impl PageSpec { /// Create a new PageSpec. pub fn new(containing_page: &Path, spec: &str) -> Result { + trace!( + "PageSpec::new: containing_page={} spec={:?}", + containing_page.display(), + spec + ); let expr = pagespec::ExprParser::new() .parse(spec) .map_err(|e| PageSpecError::Parse(format!("{}", e)))?; @@ -59,6 +64,7 @@ pub enum PageSpecError { #[derive(Debug)] pub enum Expr { Glob(String), + LinksHereFunc, PageFunc(String), Negate(Box), Op(Box, OpCode, Box), @@ -69,6 +75,7 @@ impl Expr { trace!("Expr::matches: path={:?} self={:?}", path, self); match self { Self::Glob(glob) => glob_matches(glob, path), + Self::LinksHereFunc => links_here(site, container, path), // FIXME: check its page Self::PageFunc(glob) => page_matches(site, container, glob, path), // FIXME: check its page Self::Negate(expr) => !expr.matches(site, container, path), Self::Op(left, op, right) => match op { @@ -91,9 +98,16 @@ pub enum OpCode { } fn glob_matches(glob: &str, path: &str) -> bool { + trace!("glob_matches: glob={:?} path={:?}", glob, path); let glob: Vec = glob.chars().collect(); let path: Vec = path.chars().collect(); - glob_matches_helper(&glob, &path) + if glob_matches_helper(&glob, &path) { + trace!("glob_matches: match!"); + true + } else { + trace!("glob_matches: no match"); + false + } } fn glob_matches_helper(mut glob: &[char], mut path: &[char]) -> bool { @@ -134,6 +148,27 @@ fn glob_matches_helper(mut glob: &[char], mut path: &[char]) -> bool { glob.is_empty() && path.is_empty() } +fn links_here(site: &Site, container: &Path, path: &str) -> bool { + trace!( + "links_here: container={} path={:?}", + container.display(), + path + ); + let path = Path::new(path); + if let Some(page) = site.page(path) { + trace!("links_here: found page {}", path.display()); + for link in page.meta().links_to() { + trace!("links_here: page links to {}", link.display()); + if link == container { + trace!("links to container!"); + return true; + } + } + } + trace!("links_here: does not link to container"); + false +} + fn page_matches(site: &Site, container: &Path, glob: &str, path: &str) -> bool { if glob_matches(glob, path) { let full_path = container.join(path); -- cgit v1.2.1