Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom pages and patches #142

Merged
merged 17 commits into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 58 additions & 7 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::iter;
use std::path::{Path, PathBuf};

use app_dirs::{get_app_root, AppDataType};
Expand All @@ -21,6 +22,30 @@ pub struct Cache {
os: OsType,
}

#[derive(Debug)]
niklasmohrin marked this conversation as resolved.
Show resolved Hide resolved
pub struct PageLookupResult {
page_path: PathBuf,
patch_path: Option<PathBuf>,
}

impl PageLookupResult {
pub fn with_page(page_path: PathBuf) -> Self {
Self {
page_path,
patch_path: None,
}
}

pub fn with_optional_patch(mut self, patch_path: Option<PathBuf>) -> Self {
self.patch_path = patch_path;
self
}

pub fn paths(&self) -> impl Iterator<Item = &Path> {
iter::once(self.page_path.as_path()).chain(self.patch_path.as_deref().into_iter())
}
}

impl Cache {
pub fn new<S>(url: S, os: OsType) -> Self
where
Expand Down Expand Up @@ -144,20 +169,34 @@ impl Cache {

/// Check for pages for a given platform in one of the given languages.
fn find_page_for_platform(
name: &str,
page_name: &str,
cache_dir: &Path,
platform: &str,
language_dirs: &[String],
) -> Option<PathBuf> {
language_dirs
.iter()
.map(|lang_dir| cache_dir.join(lang_dir).join(platform).join(name))
.map(|lang_dir| cache_dir.join(lang_dir).join(platform).join(page_name))
.find(|path| path.exists() && path.is_file())
}

/// Look up custom patch (<name>.patch). If it exists, store it in a variable.
fn find_patch(patch_name: &str, custom_pages_dir: Option<&Path>) -> Option<PathBuf> {
custom_pages_dir
.map(|custom_dir| custom_dir.join(patch_name))
.filter(|path| path.exists() && path.is_file())
}

/// Search for a page and return the path to it.
pub fn find_page(&self, name: &str, languages: &[String]) -> Option<PathBuf> {
pub fn find_page(
&self,
name: &str,
languages: &[String],
custom_pages_dir: Option<&Path>,
) -> Option<PageLookupResult> {
let page_filename = format!("{}.md", name);
let patch_filename = format!("{}.patch", name);
let custom_filename = format!("{}.page", name);

// Get cache dir
let cache_dir = match Self::get_cache_dir() {
Expand All @@ -179,16 +218,28 @@ impl Cache {
})
.collect();

// Try to find a platform specific path first.
// Look up custom page (<name>.page). If it exists, return it directly
if let Some(config_dir) = custom_pages_dir {
let custom_page = config_dir.join(custom_filename);
if custom_page.exists() && custom_page.is_file() {
return Some(PageLookupResult::with_page(custom_page));
}
niklasmohrin marked this conversation as resolved.
Show resolved Hide resolved
}

let maybe_patch = Self::find_patch(&patch_filename, custom_pages_dir.as_deref());

// Try to find a platform specific path next, append custom patch to it.
if let Some(pf) = self.get_platform_dir() {
let pf_path = Self::find_page_for_platform(&page_filename, &cache_dir, pf, &lang_dirs);
if pf_path.is_some() {
return pf_path;
if let Some(page) =
Self::find_page_for_platform(&page_filename, &cache_dir, pf, &lang_dirs)
{
return Some(PageLookupResult::with_page(page).with_optional_patch(maybe_patch));
}
}

// Did not find platform specific results, fall back to "common"
Self::find_page_for_platform(&page_filename, &cache_dir, "common", &lang_dirs)
.map(|page| PageLookupResult::with_page(page).with_optional_patch(maybe_patch))
}

/// Return the available pages.
Expand Down
29 changes: 28 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,22 @@ impl Default for RawUpdatesConfig {
}
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
struct RawDirectoriesConfig {
#[serde(default)]
pub custom_pages_dir: Option<PathBuf>,
}

impl Default for RawDirectoriesConfig {
fn default() -> Self {
Self {
custom_pages_dir: get_app_root(AppDataType::UserData, &crate::APP_INFO)
.map(|path| path.join("pages"))
.ok(),
}
dmaahs2017 marked this conversation as resolved.
Show resolved Hide resolved
}
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawConfig {
#[serde(default)]
Expand All @@ -156,6 +172,8 @@ struct RawConfig {
display: RawDisplayConfig,
#[serde(default)]
updates: RawUpdatesConfig,
#[serde(default)]
directories: RawDirectoriesConfig,
}

impl RawConfig {
Expand Down Expand Up @@ -194,11 +212,17 @@ pub struct UpdatesConfig {
pub auto_update_interval: Duration,
}

#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct DirectoriesConfig {
pub custom_pages_dir: Option<PathBuf>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Config {
pub style: StyleConfig,
pub display: DisplayConfig,
pub updates: UpdatesConfig,
pub directories: DirectoriesConfig,
}

impl From<RawConfig> for Config {
Expand All @@ -221,6 +245,9 @@ impl From<RawConfig> for Config {
raw_config.updates.auto_update_interval_hours * 3600,
),
},
directories: DirectoriesConfig {
custom_pages_dir: raw_config.directories.custom_pages_dir,
},
}
}
}
Expand Down
51 changes: 30 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::iter;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::process;

use ansi_term::{Color, Style};
Expand All @@ -41,7 +41,7 @@ mod formatter;
mod tokenizer;
mod types;

use crate::cache::Cache;
use crate::cache::{Cache, PageLookupResult};
use crate::config::{get_config_dir, get_config_path, make_default_config, Config, MAX_CACHE_AGE};
use crate::dedup::Dedup;
use crate::error::TealdeerError::{CacheError, ConfigError, UpdateError};
Expand Down Expand Up @@ -81,21 +81,27 @@ struct Args {
}

/// Print page by path
fn print_page(path: &Path, enable_markdown: bool, config: &Config) -> Result<(), String> {
fn print_page(
page: &PageLookupResult,
enable_markdown: bool,
config: &Config,
) -> Result<(), String> {
// Open file
let file = File::open(path).map_err(|msg| format!("Could not open file: {}", msg))?;
let reader = BufReader::new(file);

if enable_markdown {
// Print the raw markdown of the file.
for line in reader.lines() {
println!("{}", line.unwrap());
}
} else {
// Create tokenizer and print output
let mut tokenizer = Tokenizer::new(reader);
print_lines(&mut tokenizer, &config);
};
for path in page.paths() {
let file = File::open(path).map_err(|msg| format!("Could not open file: {}", msg))?;
let reader = BufReader::new(file);

if enable_markdown {
// Print the raw markdown of the file.
for line in reader.lines() {
println!("{}", line.unwrap());
}
} else {
// Create tokenizer and print output
let mut tokenizer = Tokenizer::new(reader);
print_lines(&mut tokenizer, &config);
};
}

Ok(())
}
Expand Down Expand Up @@ -427,7 +433,7 @@ fn main() {

// Render local file and exit
if let Some(ref file) = args.flag_render {
let path = PathBuf::from(file);
let path = PageLookupResult::with_page(PathBuf::from(file));
if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
eprintln!("{}", msg);
process::exit(1);
Expand Down Expand Up @@ -475,13 +481,16 @@ fn main() {
};

// Search for command in cache
if let Some(path) = cache.find_page(&command, &languages) {
if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
if let Some(page) = cache.find_page(
&command,
&languages,
config.directories.custom_pages_dir.as_deref(),
) {
if let Err(msg) = print_page(&page, args.flag_markdown, &config) {
eprintln!("{}", msg);
process::exit(1);
} else {
process::exit(0);
}
process::exit(0);
} else {
if !args.flag_quiet {
println!("Page {} not found in cache", &command);
Expand Down