summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2023-02-06 17:09:00 +0000
committerLars Wirzenius <liw@liw.fi>2023-02-06 17:09:00 +0000
commit5107dc741bba0114012beefd09d0a46cc9989d67 (patch)
tree47145ea52d523526bc2e7d679ee062de4cc02e52
parent2ac4193a30c5ef6186666269c171b88fabd86143 (diff)
parentc0e44d18d56ed625df5ff0224fe170e4d18add09 (diff)
downloadriki-5107dc741bba0114012beefd09d0a46cc9989d67.tar.gz
Merge branch 'liw/links' into 'main'
feat: keep track of which pages a page links to See merge request larswirzenius/riki!73
-rw-r--r--src/bin/riki.rs33
-rw-r--r--src/directive/meta.rs7
-rw-r--r--src/page.rs17
-rw-r--r--src/pagespec.lalrpop1
-rw-r--r--src/pagespec.rs37
-rw-r--r--src/parser.rs6
-rw-r--r--src/site.rs8
-rw-r--r--src/token.rs4
-rw-r--r--src/wikitext.rs1
9 files changed, 106 insertions, 8 deletions
diff --git a/src/bin/riki.rs b/src/bin/riki.rs
index c1f9e4b..131326b 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.
@@ -227,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();
@@ -247,3 +250,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<PathBuf>,
+}
+
+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<String>,
date: Option<String>,
+ 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<String>,
mtime: SystemTime,
+ links_to: Vec<PathBuf>,
}
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/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<Expr> = {
Term: Box<Expr> = {
Glob => Box::new(Expr::Glob(<>)),
+ "link" "(" "." ")" => Box::new(Expr::LinksHereFunc),
"page" "(" <g:Glob> ")" => Box::new(Expr::PageFunc(<>)),
"!" <t:Term> => Box::new(Expr::Negate(t)),
"(" <e:Expr> ")" => 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<Self, PageSpecError> {
+ 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<Expr>),
Op(Box<Expr>, OpCode, Box<Expr>),
@@ -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<char> = glob.chars().collect();
let path: Vec<char> = 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);
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/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<Vec<Name>, SiteError> {
let whatchanged = git_whatchanged(self.name_builder.srcdir())?;
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 }
}
}
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)
}