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

feat: add --font-style arg #222

Closed
wants to merge 1 commit into from
Closed
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
17 changes: 17 additions & 0 deletions src/bin/silicon/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::{Context, Error};
use clipboard::{ClipboardContext, ClipboardProvider};
use image::Rgba;
use silicon::directories::PROJECT_DIRS;
use silicon::font::FontStyle;
use silicon::formatter::{ImageFormatter, ImageFormatterBuilder};
use silicon::utils::{Background, ShadowAdder, ToRgba};
use std::ffi::OsString;
Expand Down Expand Up @@ -57,6 +58,17 @@ fn parse_font_str(s: &str) -> Vec<(String, f32)> {
result
}

fn parse_font_style_str(s: &str) -> FontStyle {
let s = s.to_lowercase();
match s.as_str() {
"regular" => FontStyle::REGULAR,
"italic" => FontStyle::ITALIC,
"bold" => FontStyle::BOLD,
"bolditalic" => FontStyle::BOLDITALIC,
_ => panic!("parse font_style error"),
}
}

fn parse_line_range(s: &str) -> Result<Vec<u32>, ParseIntError> {
let mut result = vec![];
for range in s.split(';') {
Expand Down Expand Up @@ -113,6 +125,10 @@ pub struct Config {
#[structopt(long, short, value_name = "FONT", parse(from_str = parse_font_str))]
pub font: Option<FontList>,

/// The font style. eg. 'regular'
#[structopt(long, value_name = "FONT_STYLE",default_value="regular", parse(from_str = parse_font_style_str))]
pub font_style: FontStyle,

/// Lines to high light. rg. '1-3; 4'
#[structopt(long, value_name = "LINES", parse(try_from_str = parse_line_range))]
pub highlight_lines: Option<Lines>,
Expand Down Expand Up @@ -276,6 +292,7 @@ impl Config {
.window_title(self.window_title.clone())
.line_number(!self.no_line_number)
.font(self.font.clone().unwrap_or_default())
.font_style(self.font_style.clone())
.round_corner(!self.no_round_corner)
.shadow_adder(self.get_shadow_adder()?)
.tab_width(self.tab_width)
Expand Down
2 changes: 1 addition & 1 deletion src/bin/silicon/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ fn run() -> Result<(), Error> {

let mut formatter = config.get_formatter()?;

let image = formatter.format(&highlight, &theme);
let image = formatter.format(&highlight, &theme, config.font_style);

if config.to_clipboard {
dump_image_to_clipboard(&image)?;
Expand Down
33 changes: 22 additions & 11 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! use silicon::font::{FontCollection, FontStyle};
//!
//! let mut image = RgbImage::new(250, 100);
//! let font = FontCollection::new(&[("Hack", 27.0), ("FiraCode", 27.0)]).unwrap();
//! let font = FontCollection::new(&[("Hack", 27.0), ("FiraCode", 27.0)],FontStyle::REGULAR).unwrap();
//!
//! font.draw_text_mut(&mut image, Rgb([255, 0, 0]), 0, 0, FontStyle::REGULAR, "Hello, world");
//! ```
Expand All @@ -30,8 +30,9 @@ use std::sync::Arc;
use syntect::highlighting;

/// Font style
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub enum FontStyle {
#[default]
REGULAR,
ITALIC,
BOLD,
Expand Down Expand Up @@ -63,6 +64,7 @@ use FontStyle::*;
pub struct ImageFont {
pub fonts: HashMap<FontStyle, Font>,
pub size: f32,
pub style: FontStyle,
}

impl Default for ImageFont {
Expand Down Expand Up @@ -92,16 +94,21 @@ impl Default for ImageFont {
fonts.insert(style, font);
}

Self { fonts, size: 26.0 }
Self {
fonts,
size: 26.0,
..Default::default()
}
}
}

impl ImageFont {
pub fn new(name: &str, size: f32) -> Result<Self, FontError> {
pub fn new(name: &str, size: f32, style: FontStyle) -> Result<Self, FontError> {
// Silicon already contains Hack font
if name == "Hack" {
let font = ImageFont {
size,
style,
..Default::default()
};
return Ok(font);
Expand Down Expand Up @@ -145,7 +152,7 @@ impl ImageFont {
}
}

Ok(Self { fonts, size })
Ok(Self { fonts, size, style })
}

/// Get a font by style. If there is no such a font, it will return the REGULAR font.
Expand All @@ -162,7 +169,8 @@ impl ImageFont {

/// Get the height of the font
pub fn get_font_height(&self) -> u32 {
let font = self.get_regular();
debug!("current font style:{:?}", self.style);
let font = self.get_by_style(self.style);
let metrics = font.metrics();
((metrics.ascent - metrics.descent) / metrics.units_per_em as f32 * self.size).ceil() as u32
}
Expand All @@ -182,11 +190,14 @@ impl Default for FontCollection {

impl FontCollection {
/// Create a FontCollection with several fonts.
pub fn new<S: AsRef<str>>(font_list: &[(S, f32)]) -> Result<Self, FontError> {
pub fn new<S: AsRef<str>>(
font_list: &[(S, f32)],
font_style: FontStyle,
) -> Result<Self, FontError> {
let mut fonts = vec![];
for (name, size) in font_list {
let name = name.as_ref();
match ImageFont::new(name, *size) {
match ImageFont::new(name, *size, font_style) {
Ok(font) => fonts.push(font),
Err(err) => eprintln!("[error] Error occurs when load font `{}`: {}", name, err),
}
Expand Down Expand Up @@ -331,8 +342,8 @@ impl FontCollection {
}

/// Get the width of the given text
pub fn get_text_len(&self, text: &str) -> u32 {
self.layout(text, REGULAR).1
pub fn get_text_len(&self, text: &str, style: FontStyle) -> u32 {
self.layout(text, style).1
}

/// Draw the text to a image
Expand All @@ -350,7 +361,7 @@ impl FontCollection {
I: GenericImage,
<I::Pixel as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
{
let metrics = self.0[0].get_regular().metrics();
let metrics = self.0[0].get_by_style(style).metrics();
let offset =
(metrics.descent / metrics.units_per_em as f32 * self.0[0].size).round() as i32;

Expand Down
53 changes: 36 additions & 17 deletions src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub struct ImageFormatter {
/// font of english character, should be mono space font
/// Default: Hack (builtin)
font: FontCollection,
/// font of english character, should be mono space font
/// Default: Hack (builtin)
font_style: FontStyle,
/// Highlight lines
highlight_lines: Vec<u32>,
/// Shadow adder
Expand All @@ -61,6 +64,8 @@ pub struct ImageFormatterBuilder<S> {
line_number: bool,
/// Font of english character, should be mono space font
font: Vec<(S, f32)>,
/// FontStyle of font
font_style: FontStyle,
/// Highlight lines
highlight_lines: Vec<u32>,
/// Whether show the window controls
Expand Down Expand Up @@ -115,6 +120,12 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
self
}

/// Set the font
pub fn font_style(mut self, font_style: FontStyle) -> Self {
self.font_style = font_style;
self
}

/// Whether show the windows controls
pub fn window_controls(mut self, show: bool) -> Self {
self.window_controls = show;
Expand Down Expand Up @@ -155,7 +166,7 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
let font = if self.font.is_empty() {
FontCollection::default()
} else {
FontCollection::new(&self.font)?
FontCollection::new(&self.font, self.font_style)?
};

let title_bar = self.window_controls || self.window_title.is_some();
Expand All @@ -177,6 +188,7 @@ impl<S: AsRef<str> + Default> ImageFormatterBuilder<S> {
shadow_adder: self.shadow_adder,
tab_width: self.tab_width,
font,
font_style: self.font_style,
line_offset: self.line_offset,
})
}
Expand Down Expand Up @@ -215,14 +227,14 @@ impl ImageFormatter {
self.code_pad
+ if self.line_number {
let tmp = format!("{:>width$}", 0, width = self.line_number_chars as usize);
2 * self.line_number_pad + self.font.get_text_len(&tmp)
2 * self.line_number_pad + self.font.get_text_len(&tmp, self.font_style)
} else {
0
}
}

/// create
fn create_drawables(&self, v: &[Vec<(Style, &str)>]) -> Drawable {
fn create_drawables(&self, v: &[Vec<(Style, &str)>], style: FontStyle) -> Drawable {
// tab should be replaced to whitespace so that it can be rendered correctly
let tab = " ".repeat(self.tab_width as usize);
let mut drawables = vec![];
Expand All @@ -232,21 +244,23 @@ impl ImageFormatter {
let height = self.get_line_y(i as u32);
let mut width = self.get_left_pad();

for (style, text) in tokens {
for (style_, text) in tokens {
let text = text.trim_end_matches('\n').replace('\t', &tab);
if text.is_empty() {
continue;
}

drawables.push((
width,
height,
Some(style.foreground),
style.font_style.into(),
text.to_owned(),
));
if style == style_.font_style.into() {
drawables.push((
width,
height,
Some(style_.foreground),
style,
text.to_owned(),
));
}

width += self.font.get_text_len(&text);
width += self.font.get_text_len(&text, self.font_style);

max_width = max_width.max(width);
}
Expand All @@ -255,7 +269,7 @@ impl ImageFormatter {

if self.window_title.is_some() {
let title = self.window_title.as_ref().unwrap();
let title_width = self.font.get_text_len(title);
let title_width = self.font.get_text_len(title, self.font_style);

let ctrls_offset = if self.window_controls {
self.window_controls_width + self.title_bar_pad
Expand All @@ -268,7 +282,7 @@ impl ImageFormatter {
ctrls_offset + self.title_bar_pad,
self.title_bar_pad + ctrls_center - self.font.get_font_height() / 2,
None,
FontStyle::BOLD,
style,
title.to_string(),
));

Expand Down Expand Up @@ -298,7 +312,7 @@ impl ImageFormatter {
color,
self.code_pad,
self.get_line_y(i),
FontStyle::REGULAR,
self.font_style,
&line_mumber,
);
}
Expand All @@ -322,7 +336,12 @@ impl ImageFormatter {
}

// TODO: use &T instead of &mut T ?
pub fn format(&mut self, v: &[Vec<(Style, &str)>], theme: &Theme) -> DynamicImage {
pub fn format(
&mut self,
v: &[Vec<(Style, &str)>],
theme: &Theme,
style: FontStyle,
) -> DynamicImage {
if self.line_number {
self.line_number_chars =
(((v.len() + self.line_offset as usize) as f32).log10() + 1.0).floor() as u32;
Expand All @@ -331,7 +350,7 @@ impl ImageFormatter {
self.line_number_pad = 0;
}

let drawables = self.create_drawables(v);
let drawables = self.create_drawables(v, style);

let size = self.get_image_size(drawables.max_width, drawables.max_lineno);

Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! use silicon::utils::ShadowAdder;
//! use silicon::formatter::ImageFormatterBuilder;
//! use silicon::assets::HighlightingAssets;
//! use silicon::font::FontStyle;
//!
//! let ha = HighlightingAssets::new();
//! let (ps, ts) = (ha.syntax_set, ha.theme_set);
Expand All @@ -30,7 +31,7 @@
//! .shadow_adder(ShadowAdder::default())
//! .build()
//! .unwrap();
//! let image = formatter.format(&highlight, theme);
//! let image = formatter.format(&highlight, theme,FontStyle::REGULAR);
//!
//! image.save("hello.png").unwrap();
//! ```
Expand Down