add a files output template
This commit is contained in:
+10
-1
@@ -115,7 +115,7 @@ syntax_highlight = true
|
||||
# - `base16-ocean.dark`
|
||||
# - `base16-eighties.dark`
|
||||
# - `base16-mocha.dark`
|
||||
# - `InspiredGithub`
|
||||
# - `InspiredGitHub`
|
||||
# - `Solarized (dark)`
|
||||
# - `Solarized (light)`
|
||||
#
|
||||
@@ -317,6 +317,14 @@ tags = "tags.html"
|
||||
# This template executes many times.
|
||||
tag = "tag.html"
|
||||
|
||||
# Template responsible for displaying file tree.
|
||||
#
|
||||
# Called with the same variables as the `summary` page, this simply gives an
|
||||
# alternative locate to list the files in the root of the repository.
|
||||
#
|
||||
# This template executes once per repository.
|
||||
files = "files.html"
|
||||
|
||||
# Template responsible for displaying a single file.
|
||||
#
|
||||
# Called once per parsed file, with both the whole repository and the current
|
||||
@@ -373,6 +381,7 @@ branches = "%REPO%/branches%PAGE%.html"
|
||||
branch = "%REPO%/branch/%ID%.html"
|
||||
tags = "%REPO%/tags%PAGE%.html"
|
||||
tag = "%REPO%/tag/%ID%.html"
|
||||
files = "%REPO%/files.html"
|
||||
file = "%REPO%/file/%ID%.html"
|
||||
syntax_css = "%REPO%/file/syntax.css"
|
||||
dir = "%REPO%/dir/%ID%.html"
|
||||
|
||||
+23
-2
@@ -3,7 +3,7 @@ use crate::{
|
||||
git::{dir_listing, parse_repo, GitFile, GitRepo, GitsyMetadata},
|
||||
loud, louder, loudest, normal, normal_noln,
|
||||
settings::{GitsyCli, GitsyRepoDescriptions, GitsySettings, GitsySettingsRepo},
|
||||
template::{DirFilter, FileFilter, Pagination, TsDateFn, TsTimestampFn},
|
||||
template::{DirFilter, FileFilter, HexFilter, MaskFilter, OctFilter, Pagination, TsDateFn, TsTimestampFn},
|
||||
util::GitsyError,
|
||||
};
|
||||
use git2::{Error, Repository};
|
||||
@@ -169,6 +169,9 @@ impl GitsyGenerator {
|
||||
let mut tera = Tera::new(&template_path.to_string_lossy().to_string())?;
|
||||
tera.register_filter("only_files", FileFilter {});
|
||||
tera.register_filter("only_dirs", DirFilter {});
|
||||
tera.register_filter("hex", HexFilter {});
|
||||
tera.register_filter("oct", OctFilter {});
|
||||
tera.register_filter("mask", MaskFilter {});
|
||||
tera.register_function("ts_to_date", TsDateFn {});
|
||||
tera.register_function("ts_to_git_timestamp", TsTimestampFn {});
|
||||
Ok(tera)
|
||||
@@ -330,6 +333,8 @@ impl GitsyGenerator {
|
||||
if let Some(site_description) = &self.settings.site_description {
|
||||
local_ctx.insert("site_description", site_description);
|
||||
}
|
||||
local_ctx.insert("site_dir", &self.settings.outputs.output_dir());
|
||||
local_ctx.insert("site_assets", &self.settings.outputs.global_assets(None, None));
|
||||
local_ctx.insert("site_generated_ts", &generated_dt.timestamp());
|
||||
local_ctx.insert("site_generated_offset", &generated_dt.offset().local_minus_utc());
|
||||
|
||||
@@ -488,7 +493,7 @@ impl GitsyGenerator {
|
||||
repo_desc
|
||||
.syntax_highlight_theme
|
||||
.as_deref()
|
||||
.unwrap_or("base16-ocean.light"),
|
||||
.unwrap_or("base16-ocean.dark"),
|
||||
)
|
||||
.expect("Invalid syntax highlighting theme specified.");
|
||||
let css: String = css_for_theme_with_class_style(theme, syntect::html::ClassStyle::Spaced)
|
||||
@@ -549,6 +554,7 @@ impl GitsyGenerator {
|
||||
continue;
|
||||
}
|
||||
let listing = dir_listing(&repo, &dir).expect("Failed to parse file.");
|
||||
local_ctx.insert("dir", dir);
|
||||
local_ctx
|
||||
.try_insert("files", &listing)
|
||||
.expect("Failed to add dir to template engine.");
|
||||
@@ -564,6 +570,19 @@ impl GitsyGenerator {
|
||||
}
|
||||
}
|
||||
local_ctx.remove("files");
|
||||
local_ctx.remove("dir");
|
||||
}
|
||||
|
||||
if let Some(templ_file) = self.settings.templates.files.as_deref() {
|
||||
match tera.render(templ_file, &local_ctx) {
|
||||
Ok(rendered) => {
|
||||
repo_bytes +=
|
||||
self.write_rendered(&self.settings.outputs.files(Some(&summary), None), &rendered);
|
||||
}
|
||||
Err(x) => match x.kind {
|
||||
_ => error!("ERROR: {:?}", x),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if repo_desc.asset_files.is_some() {
|
||||
@@ -625,6 +644,8 @@ impl GitsyGenerator {
|
||||
if let Some(site_description) = &self.settings.site_description {
|
||||
global_ctx.insert("site_description", site_description);
|
||||
}
|
||||
global_ctx.insert("site_dir", &self.settings.outputs.output_dir());
|
||||
global_ctx.insert("site_assets", &self.settings.outputs.global_assets(None, None));
|
||||
global_ctx.insert("site_generated_ts", &generated_dt.timestamp());
|
||||
global_ctx.insert("site_generated_offset", &generated_dt.offset().local_minus_utc());
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use settings::{GitsyCli, GitsySettings};
|
||||
// TODO:
|
||||
//
|
||||
// * basic, light, dark, and fancy default themes
|
||||
// * specify default branch, use instead of HEAD
|
||||
// * better error propagation
|
||||
// * automated tests
|
||||
// * documentation + examples
|
||||
|
||||
@@ -76,6 +76,7 @@ pub struct GitsySettingsTemplates {
|
||||
pub branch: Option<String>,
|
||||
pub tags: Option<String>,
|
||||
pub tag: Option<String>,
|
||||
pub files: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub dir: Option<String>,
|
||||
pub error: Option<String>,
|
||||
@@ -93,6 +94,7 @@ pub struct GitsySettingsOutputs {
|
||||
pub branch: Option<String>,
|
||||
pub tags: Option<String>,
|
||||
pub tag: Option<String>,
|
||||
pub files: Option<String>,
|
||||
pub file: Option<String>,
|
||||
pub dir: Option<String>,
|
||||
pub error: Option<String>,
|
||||
@@ -159,12 +161,20 @@ impl GitsySettingsOutputs {
|
||||
output_path_fn!(branch, GitObject, full_hash, false, "%REPO%/branch/%ID%.html");
|
||||
output_path_fn!(tags, GitObject, full_hash, false, "%REPO%/tags%PAGE%.html");
|
||||
output_path_fn!(tag, GitObject, full_hash, false, "%REPO%/tag/%ID%.html");
|
||||
output_path_fn!(files, GitObject, full_hash, false, "%REPO%/files.html");
|
||||
output_path_fn!(file, GitFile, id, false, "%REPO%/file/%ID%.html");
|
||||
output_path_fn!(syntax_css, GitObject, full_hash, false, "%REPO%/file/syntax.css");
|
||||
output_path_fn!(dir, GitFile, id, false, "%REPO%/dir/%ID%.html");
|
||||
output_path_fn!(error, GitObject, full_hash, false, "404.html");
|
||||
output_path_fn!(global_assets, GitObject, full_hash, true, "assets/");
|
||||
output_path_fn!(repo_assets, GitObject, full_hash, true, "%REPO%/assets/");
|
||||
|
||||
pub fn output_dir(&self) -> String {
|
||||
self.path.clone().canonicalize()
|
||||
.expect(&format!("ERROR: unable to canonicalize output path: {}", self.path.display()))
|
||||
.to_str().expect(&format!("ERROR: unable to parse output path: {}", self.path.display()))
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default, Debug)]
|
||||
|
||||
+41
-1
@@ -3,7 +3,7 @@ use chrono::{naive::NaiveDateTime, offset::FixedOffset, DateTime};
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use tera::{to_value, try_get_value, Filter, Function, Value};
|
||||
use tera::{from_value, to_value, try_get_value, Filter, Function, Value};
|
||||
|
||||
fn ts_to_date(ts: i64, offset: Option<i64>, format: Option<String>) -> String {
|
||||
let offset = offset.unwrap_or(0);
|
||||
@@ -54,6 +54,46 @@ impl Filter for DirFilter {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HexFilter;
|
||||
impl Filter for HexFilter {
|
||||
fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
|
||||
let v: i64 = try_get_value!("hex", "value", i64, value);
|
||||
Ok(to_value(format!("{:x}", v)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OctFilter;
|
||||
impl Filter for OctFilter {
|
||||
fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
|
||||
let v: i64 = try_get_value!("oct", "value", i64, value);
|
||||
Ok(to_value(format!("{:o}", v)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MaskFilter;
|
||||
impl Filter for MaskFilter {
|
||||
fn filter(&self, value: &Value, args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
|
||||
let v: u64 = try_get_value!("mask", "value", u64, value);
|
||||
let mask: String = from_value(
|
||||
args.get("mask")
|
||||
.expect("ERROR: Tera mask filter called without `mask` parameter.")
|
||||
.clone(),
|
||||
)
|
||||
.expect("ERROR: Tera `mask` parameter is not valid.");
|
||||
let mask: u64 = match mask.starts_with("0x") {
|
||||
true => {
|
||||
let hexstr = mask.strip_prefix("0x").unwrap();
|
||||
u64::from_str_radix(hexstr, 16)
|
||||
.expect("ERROR: Tera `mask` parameter is invalid hex.")
|
||||
},
|
||||
false => {
|
||||
str::parse::<u64>(&mask).expect("ERROR: Tera `mask` parameter is not valid.")
|
||||
},
|
||||
};
|
||||
Ok(to_value(v & mask).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TsDateFn;
|
||||
impl Function for TsDateFn {
|
||||
fn call(&self, args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
|
||||
|
||||
Reference in New Issue
Block a user