Implement font features (#94)
This commit is contained in:
parent
2dc10aa611
commit
ad0ea04f93
@ -6,7 +6,6 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cairo-rs = "0.4"
|
cairo-rs = "0.4"
|
||||||
pango = "0.4"
|
|
||||||
pango-sys = "0.6"
|
pango-sys = "0.6"
|
||||||
pangocairo = "0.5"
|
pangocairo = "0.5"
|
||||||
pangocairo-sys = "0.7"
|
pangocairo-sys = "0.7"
|
||||||
@ -51,6 +50,10 @@ atty = "0.2"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
phf_codegen = "0.7"
|
phf_codegen = "0.7"
|
||||||
|
|
||||||
|
[dependencies.pango]
|
||||||
|
features = ["v1_38"]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
[dependencies.gtk]
|
[dependencies.gtk]
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
features = ["v3_22"]
|
features = ["v3_22"]
|
||||||
|
@ -52,8 +52,10 @@ function s:GuiFontCommand(fname, bang) abort
|
|||||||
call GuiFont(a:fname, a:bang ==# '!')
|
call GuiFont(a:fname, a:bang ==# '!')
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
command! -nargs=? -bang Guifont call s:GuiFontCommand("<args>", "<bang>")
|
command! -nargs=1 -bang Guifont call s:GuiFontCommand("<args>", "<bang>")
|
||||||
command! -nargs=? -bang GuiFont call s:GuiFontCommand("<args>", "<bang>")
|
command! -nargs=1 -bang GuiFont call s:GuiFontCommand("<args>", "<bang>")
|
||||||
|
|
||||||
|
command! -nargs=? GuiFontFeatures call rpcnotify(1, 'Gui', 'FontFeatures', <q-args>)
|
||||||
|
|
||||||
command! NGToggleSidebar call rpcnotify(1, 'Gui', 'Command', 'ToggleSidebar')
|
command! NGToggleSidebar call rpcnotify(1, 'Gui', 'Command', 'ToggleSidebar')
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ pub fn call_gui_event(
|
|||||||
) -> result::Result<(), String> {
|
) -> result::Result<(), String> {
|
||||||
match method {
|
match method {
|
||||||
"Font" => call!(ui->set_font(args: str)),
|
"Font" => call!(ui->set_font(args: str)),
|
||||||
|
"FontFeatures" => call!(ui->set_font_features(args: str)),
|
||||||
"Clipboard" => match try_str!(args[0]) {
|
"Clipboard" => match try_str!(args[0]) {
|
||||||
"Set" => match try_str!(args[1]) {
|
"Set" => match try_str!(args[1]) {
|
||||||
"*" => ui.clipboard_primary_set(try_str!(args[2])),
|
"*" => ui.clipboard_primary_set(try_str!(args[2])),
|
||||||
|
@ -8,18 +8,24 @@ use ui_model::StyledLine;
|
|||||||
use super::itemize::ItemizeIterator;
|
use super::itemize::ItemizeIterator;
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
state: ContextState,
|
font_metrics: FontMetrix,
|
||||||
|
font_features: FontFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(pango_context: pango::Context) -> Self {
|
pub fn new(pango_context: pango::Context) -> Self {
|
||||||
Context {
|
Context {
|
||||||
state: ContextState::new(pango_context),
|
font_metrics: FontMetrix::new(pango_context),
|
||||||
|
font_features: FontFeatures::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, pango_context: pango::Context) {
|
pub fn update(&mut self, pango_context: pango::Context) {
|
||||||
self.state = ContextState::new(pango_context);
|
self.font_metrics = FontMetrix::new(pango_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_font_features(&mut self, font_features: FontFeatures) {
|
||||||
|
self.font_features = font_features;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn itemize(&self, line: &StyledLine) -> Vec<sys_pango::Item> {
|
pub fn itemize(&self, line: &StyledLine) -> Vec<sys_pango::Item> {
|
||||||
@ -28,7 +34,7 @@ impl Context {
|
|||||||
ItemizeIterator::new(&line.line_str)
|
ItemizeIterator::new(&line.line_str)
|
||||||
.flat_map(|(offset, len)| {
|
.flat_map(|(offset, len)| {
|
||||||
sys_pango::pango_itemize(
|
sys_pango::pango_itemize(
|
||||||
&self.state.pango_context,
|
&self.font_metrics.pango_context,
|
||||||
&line.line_str,
|
&line.line_str,
|
||||||
offset,
|
offset,
|
||||||
len,
|
len,
|
||||||
@ -40,32 +46,34 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_layout(&self) -> pango::Layout {
|
pub fn create_layout(&self) -> pango::Layout {
|
||||||
pango::Layout::new(&self.state.pango_context)
|
pango::Layout::new(&self.font_metrics.pango_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn font_description(&self) -> &pango::FontDescription {
|
pub fn font_description(&self) -> &pango::FontDescription {
|
||||||
&self.state.font_desc
|
&self.font_metrics.font_desc
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn cell_metrics(&self) -> &CellMetrics {
|
pub fn cell_metrics(&self) -> &CellMetrics {
|
||||||
&self.state.cell_metrics
|
&self.font_metrics.cell_metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font_features(&self) -> &FontFeatures {
|
||||||
|
&self.font_features
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContextState {
|
struct FontMetrix {
|
||||||
pango_context: pango::Context,
|
pango_context: pango::Context,
|
||||||
cell_metrics: CellMetrics,
|
cell_metrics: CellMetrics,
|
||||||
font_desc: pango::FontDescription,
|
font_desc: pango::FontDescription,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextState {
|
impl FontMetrix {
|
||||||
pub fn new(pango_context: pango::Context) -> Self {
|
pub fn new(pango_context: pango::Context) -> Self {
|
||||||
let font_metrics = pango_context.get_metrics(None, None).unwrap();
|
let font_metrics = pango_context.get_metrics(None, None).unwrap();
|
||||||
let font_desc = pango_context.get_font_description().unwrap();
|
let font_desc = pango_context.get_font_description().unwrap();
|
||||||
|
|
||||||
ContextState {
|
FontMetrix {
|
||||||
pango_context,
|
pango_context,
|
||||||
cell_metrics: CellMetrics::new(&font_metrics),
|
cell_metrics: CellMetrics::new(&font_metrics),
|
||||||
font_desc,
|
font_desc,
|
||||||
@ -115,3 +123,34 @@ impl CellMetrics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FontFeatures {
|
||||||
|
features: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FontFeatures {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FontFeatures {
|
||||||
|
features: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(font_features: String) -> Self {
|
||||||
|
if font_features.trim().is_empty() {
|
||||||
|
return Self::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
FontFeatures {
|
||||||
|
features: Some(font_features)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_attr(&self, attr_list: &pango::AttrList, end_idx: usize) {
|
||||||
|
if let Some(ref features) = self.features {
|
||||||
|
let mut attr = sys_pango::attribute::new_features(features).unwrap();
|
||||||
|
attr.set_start_index(0);
|
||||||
|
attr.set_end_index(end_idx as u32);
|
||||||
|
attr_list.insert(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ mod context;
|
|||||||
mod itemize;
|
mod itemize;
|
||||||
mod model_clip_iterator;
|
mod model_clip_iterator;
|
||||||
|
|
||||||
pub use self::context::Context;
|
pub use self::context::{Context, FontFeatures};
|
||||||
pub use self::context::CellMetrics;
|
pub use self::context::CellMetrics;
|
||||||
use self::model_clip_iterator::{ModelClipIteratorFactory, RowView};
|
use self::model_clip_iterator::{ModelClipIteratorFactory, RowView};
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ pub fn shape_dirty(
|
|||||||
) {
|
) {
|
||||||
for line in ui_model.model_mut() {
|
for line in ui_model.model_mut() {
|
||||||
if line.dirty_line {
|
if line.dirty_line {
|
||||||
let styled_line = ui_model::StyledLine::from(line, color_model);
|
let styled_line = ui_model::StyledLine::from(line, color_model, ctx.font_features());
|
||||||
let items = ctx.itemize(&styled_line);
|
let items = ctx.itemize(&styled_line);
|
||||||
line.merge(&styled_line, &items);
|
line.merge(&styled_line, &items);
|
||||||
|
|
||||||
|
11
src/shell.rs
11
src/shell.rs
@ -276,6 +276,17 @@ impl State {
|
|||||||
self.on_redraw(&RepaintMode::All);
|
self.on_redraw(&RepaintMode::All);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_font_features(&mut self, font_features: String) {
|
||||||
|
let font_features = render::FontFeatures::from(font_features);
|
||||||
|
|
||||||
|
self.render_state
|
||||||
|
.borrow_mut()
|
||||||
|
.font_ctx
|
||||||
|
.update_font_features(font_features);
|
||||||
|
self.model.clear_glyphs();
|
||||||
|
self.on_redraw(&RepaintMode::All);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn open_file(&self, path: &str) {
|
pub fn open_file(&self, path: &str) {
|
||||||
if let Some(mut nvim) = self.nvim() {
|
if let Some(mut nvim) = self.nvim() {
|
||||||
nvim.command_async(&format!("e {}", path))
|
nvim.command_async(&format!("e {}", path))
|
||||||
|
12
src/sys/pango/attribute.rs
Normal file
12
src/sys/pango/attribute.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use pango_sys;
|
||||||
|
use pango;
|
||||||
|
|
||||||
|
use glib::translate::*;
|
||||||
|
|
||||||
|
pub fn new_features(features: &str) -> Option<pango::Attribute> {
|
||||||
|
unsafe {
|
||||||
|
from_glib_full(pango_sys::pango_attr_font_features_new(
|
||||||
|
features.to_glib_none().0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@ mod item;
|
|||||||
mod analysis;
|
mod analysis;
|
||||||
mod attr_iterator;
|
mod attr_iterator;
|
||||||
|
|
||||||
|
pub mod attribute;
|
||||||
|
|
||||||
pub use self::item::Item;
|
pub use self::item::Item;
|
||||||
pub use self::analysis::Analysis;
|
pub use self::analysis::Analysis;
|
||||||
pub use self::attr_iterator::{AttrIterator, AttrIteratorFactory};
|
pub use self::attr_iterator::{AttrIterator, AttrIteratorFactory};
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
use sys::pango as sys_pango;
|
||||||
|
use pango;
|
||||||
|
|
||||||
|
use render;
|
||||||
use color;
|
use color;
|
||||||
use super::cell::Cell;
|
use super::cell::Cell;
|
||||||
use super::item::Item;
|
use super::item::Item;
|
||||||
use sys::pango as sys_pango;
|
|
||||||
use pango;
|
|
||||||
|
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
pub line: Box<[Cell]>,
|
pub line: Box<[Cell]>,
|
||||||
@ -242,8 +244,7 @@ pub struct StyledLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StyledLine {
|
impl StyledLine {
|
||||||
pub fn from(line: &Line, color_model: &color::ColorModel) -> Self {
|
pub fn from(line: &Line, color_model: &color::ColorModel, font_features: &render::FontFeatures) -> Self {
|
||||||
|
|
||||||
let average_capacity = line.line.len() * 4 * 2; // code bytes * grapheme cluster
|
let average_capacity = line.line.len() * 4 * 2; // code bytes * grapheme cluster
|
||||||
|
|
||||||
let mut line_str = String::with_capacity(average_capacity);
|
let mut line_str = String::with_capacity(average_capacity);
|
||||||
@ -278,6 +279,7 @@ impl StyledLine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
style_attr.insert(&attr_list);
|
style_attr.insert(&attr_list);
|
||||||
|
font_features.insert_attr(&attr_list, line_str.len());
|
||||||
|
|
||||||
StyledLine {
|
StyledLine {
|
||||||
line_str,
|
line_str,
|
||||||
@ -410,7 +412,7 @@ mod tests {
|
|||||||
line[1].ch = "b".to_owned();
|
line[1].ch = "b".to_owned();
|
||||||
line[2].ch = "c".to_owned();
|
line[2].ch = "c".to_owned();
|
||||||
|
|
||||||
let styled_line = StyledLine::from(&line, &color::ColorModel::new());
|
let styled_line = StyledLine::from(&line, &color::ColorModel::new(), &render::FontFeatures::new());
|
||||||
assert_eq!("abc", styled_line.line_str);
|
assert_eq!("abc", styled_line.line_str);
|
||||||
assert_eq!(3, styled_line.cell_to_byte.len());
|
assert_eq!(3, styled_line.cell_to_byte.len());
|
||||||
assert_eq!(0, styled_line.cell_to_byte[0]);
|
assert_eq!(0, styled_line.cell_to_byte[0]);
|
||||||
|
Loading…
Reference in New Issue
Block a user