Skip to content

Commit

Permalink
feat: add support of config file
Browse files Browse the repository at this point in the history
  • Loading branch information
Aloxaf committed Dec 15, 2020
1 parent 1e30894 commit 2c35f82
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 57 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 5 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ repository = "https://github.com/Aloxaf/silicon"
license = "MIT"
edition = "2018"

[lib]
name = "silicon"
path = "src/lib.rs"

[[bin]]
name = "silicon"
path = "src/bin.rs"

[dependencies]
dirs = "3.0"
imageproc = "0.22.0"
Expand All @@ -26,6 +18,8 @@ tempfile = "3.1.0"
conv = "0.3.3"
pathfinder_geometry = "0.5.1"
log = "0.4.11"
lazy_static = "1.4.0"
shell-words = { version = "1.0.0", optional = true }

[target.'cfg(target_os = "macos")'.dependencies]
pasteboard = "0.1.1"
Expand Down Expand Up @@ -61,5 +55,7 @@ features = ["termcolor", "atty", "humantime"]
optional = true

[features]
# fearures required for silicon as a application
# disable it when using as a library
default = ["bin"]
bin = ["structopt", "env_logger", "anyhow"]
bin = ["structopt", "env_logger", "anyhow", "shell-words"]
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ Silicon reads syntax-definition and theme cache from bat's cache directory.

You can find the steps to add new syntaxes / themes for bat here: [sharkdp/bat#adding-new-syntaxes--language-definitions](https://github.com/sharkdp/bat#adding-new-syntaxes--language-definitions).

## Configuration file

You can write some common args to `silicon --config-file`.

Example:
```shell
# enable shadow
--shadow-color '#555'
--background '#fff'
--shadow-blur-radius 30
--no-window-controls
```

# Related projects

- [vim-silicon](https://github.com/segeljakt/vim-silicon)
Expand Down
38 changes: 35 additions & 3 deletions src/config.rs → src/bin/silicon/config.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
use crate::formatter::{ImageFormatter, ImageFormatterBuilder};
use crate::utils::{Background, ShadowAdder, ToRgba};
use anyhow::{Context, Error};
use clipboard::{ClipboardContext, ClipboardProvider};
use image::Rgba;
use silicon::directories::PROJECT_DIRS;
use silicon::formatter::{ImageFormatter, ImageFormatterBuilder};
use silicon::utils::{Background, ShadowAdder, ToRgba};
use std::ffi::OsString;
use std::fs::File;
use std::io::{stdin, Read};
use std::num::ParseIntError;
use std::path::PathBuf;
use structopt::clap::AppSettings::ColoredHelp;
use structopt::StructOpt;
use syntect::highlighting::{Theme, ThemeSet};
use syntect::parsing::{SyntaxReference, SyntaxSet};

pub fn config_file() -> PathBuf {
std::env::var("SILICON_CONFIG_PATH")
.ok()
.map(PathBuf::from)
.filter(|config_path| config_path.is_file())
.unwrap_or_else(|| PROJECT_DIRS.config_dir().join("config"))
}

pub fn get_args_from_config_file() -> Vec<OsString> {
let args = std::fs::read_to_string(config_file())
.ok()
.and_then(|content| {
content
.split('\n')
.map(|line| line.trim())
.filter(|line| !line.starts_with('#') && !line.is_empty())
.map(|line| shell_words::split(line))
.collect::<Result<Vec<_>, _>>()
.ok()
})
.unwrap_or_default();
args.iter().flatten().map(OsString::from).collect()
}

fn parse_str_color(s: &str) -> Result<Rgba<u8>, Error> {
Ok(s.to_rgba()
.map_err(|_| format_err!("Invalid color: `{}`", s))?)
Expand Down Expand Up @@ -54,6 +81,7 @@ type Lines = Vec<u32>;

#[derive(StructOpt, Debug)]
#[structopt(name = "silicon")]
#[structopt(global_setting(ColoredHelp))]
pub struct Config {
/// Background image
#[structopt(long, value_name = "IMAGE", conflicts_with = "background")]
Expand All @@ -69,6 +97,10 @@ pub struct Config {
)]
pub background: Rgba<u8>,

/// Show the path of silicon config file
#[structopt(long)]
pub config_file: bool,

/// Read input from clipboard.
#[structopt(long)]
pub from_clipboard: bool,
Expand Down Expand Up @@ -110,7 +142,7 @@ pub struct Config {
short,
long,
value_name = "PATH",
required_unless_one = &["list-fonts", "list-themes", "to-clipboard"]
required_unless_one = &["config-file", "list-fonts", "list-themes", "to-clipboard"]
)]
pub output: Option<PathBuf>,

Expand Down
23 changes: 12 additions & 11 deletions src/bin.rs → src/bin/silicon/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
#[macro_use]
extern crate log;
#[macro_use]
extern crate anyhow;

use crate::config::Config;
use crate::utils::*;
use anyhow::Error;
use image::DynamicImage;
use structopt::StructOpt;
Expand All @@ -20,12 +16,10 @@ use {image::ImageOutputFormat, pasteboard::Pasteboard};
#[cfg(target_os = "linux")]
use {image::ImageOutputFormat, std::process::Command};

pub mod blur;
pub mod config;
pub mod error;
pub mod font;
pub mod formatter;
pub mod utils;
mod config;
use config::Config;
use silicon::utils::init_syntect;
use crate::config::{get_args_from_config_file, config_file};

#[cfg(target_os = "linux")]
pub fn dump_image_to_clipboard(image: &DynamicImage) -> Result<(), Error> {
Expand Down Expand Up @@ -81,7 +75,11 @@ pub fn dump_image_to_clipboard(_image: &DynamicImage) -> Result<(), Error> {
}

fn run() -> Result<(), Error> {
let config: Config = Config::from_args();
let mut args = get_args_from_config_file();
let mut args_cli = std::env::args_os();
args.insert(0, args_cli.next().unwrap());
args.extend(args_cli);
let config: Config = Config::from_iter(args);

let (ps, ts) = init_syntect();

Expand All @@ -96,6 +94,9 @@ fn run() -> Result<(), Error> {
println!("{}", font);
}
return Ok(());
} else if config.config_file {
println!("{}", config_file().to_string_lossy());
return Ok(());
}

let (syntax, code) = config.get_source_code(&ps)?;
Expand Down
63 changes: 63 additions & 0 deletions src/directories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use lazy_static::lazy_static;
use std::env;
use std::path::{Path, PathBuf};

pub struct SiliconProjectDirs {
cache_dir: PathBuf,
config_dir: PathBuf,
}

impl SiliconProjectDirs {
fn new() -> Option<Self> {
let cache_dir = Self::get_cache_dir()?;

#[cfg(target_os = "macos")]
let config_dir_op = env::var_os("XDG_CONFIG_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".config")));

#[cfg(not(target_os = "macos"))]
let config_dir_op = dirs::config_dir();

let config_dir = config_dir_op.map(|d| d.join("silicon"))?;

Some(Self {
cache_dir,
config_dir,
})
}

// silicon use bat's cache directory
fn get_cache_dir() -> Option<PathBuf> {
// on all OS prefer BAT_CACHE_PATH if set
let cache_dir_op = env::var_os("BAT_CACHE_PATH").map(PathBuf::from);
if cache_dir_op.is_some() {
return cache_dir_op;
}

#[cfg(target_os = "macos")]
let cache_dir_op = env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".cache")));

#[cfg(not(target_os = "macos"))]
let cache_dir_op = dirs::cache_dir();

cache_dir_op.map(|d| d.join("bat"))
}

pub fn cache_dir(&self) -> &Path {
&self.cache_dir
}

pub fn config_dir(&self) -> &Path {
&self.config_dir
}
}

lazy_static! {
pub static ref PROJECT_DIRS: SiliconProjectDirs =
SiliconProjectDirs::new().expect("Could not get home directory");
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
extern crate log;

pub mod blur;
pub mod directories;
pub mod error;
pub mod font;
pub mod formatter;
Expand Down
46 changes: 12 additions & 34 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,27 @@
use crate::directories::PROJECT_DIRS;
use crate::error::ParseColorError;
use image::imageops::{crop, resize, FilterType};
use image::Pixel;
use image::{DynamicImage, GenericImage, GenericImageView, Rgba, RgbaImage};
use imageproc::drawing::{draw_filled_rect_mut, draw_line_segment_mut};
use imageproc::rect::Rect;
use std::env;
use std::path::PathBuf;
use syntect::dumps;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;

// Copied from https://github.com/sharkdp/bat/blob/12a1fe3ad417f7694c4490b94b793387c7a7b536/src/bin/bat/directories.rs#L35
fn get_cache_dir() -> Option<PathBuf> {
// on all OS prefer BAT_CACHE_PATH if set
let cache_dir_op = env::var_os("BAT_CACHE_PATH").map(PathBuf::from);
if cache_dir_op.is_some() {
return cache_dir_op;
}

#[cfg(target_os = "macos")]
let cache_dir_op = env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".cache")));

#[cfg(not(target_os = "macos"))]
let cache_dir_op = dirs::cache_dir();

cache_dir_op.map(|d| d.join("bat"))
}

pub fn read_from_bat_cache() -> Option<(SyntaxSet, ThemeSet)> {
get_cache_dir().and_then(|cache_dir| {
let syntax_cache = cache_dir.join("syntaxes.bin");
let theme_cache = cache_dir.join("themes.bin");
if syntax_cache.exists() && theme_cache.exists() {
if let (Ok(a), Ok(b)) = (
dumps::from_dump_file(syntax_cache),
dumps::from_dump_file(theme_cache),
) {
return Some((a, b));
}
let cache_dir = PROJECT_DIRS.cache_dir();
let syntax_cache = cache_dir.join("syntaxes.bin");
let theme_cache = cache_dir.join("themes.bin");
if syntax_cache.exists() && theme_cache.exists() {
if let (Ok(a), Ok(b)) = (
dumps::from_dump_file(syntax_cache),
dumps::from_dump_file(theme_cache),
) {
return Some((a, b));
}
None
})
}
None
}

/// Load the default SyntaxSet and ThemeSet.
Expand Down

0 comments on commit 2c35f82

Please sign in to comment.