Extract borrow of FontSystem from Buffer
This commit is contained in:
parent
bff5aaaea3
commit
057b5b6fa9
12 changed files with 381 additions and 216 deletions
|
|
@ -112,6 +112,7 @@ pub enum Message {
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open(&mut self, path: PathBuf) {
|
pub fn open(&mut self, path: PathBuf) {
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
|
let mut editor = editor.borrow_with(&FONT_SYSTEM);
|
||||||
match editor.load_text(&path, self.attrs) {
|
match editor.load_text(&path, self.attrs) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
log::info!("opened '{}'", path.display());
|
log::info!("opened '{}'", path.display());
|
||||||
|
|
@ -237,13 +238,15 @@ impl Application for Window {
|
||||||
}
|
}
|
||||||
Message::FontSizeChanged(font_size) => {
|
Message::FontSizeChanged(font_size) => {
|
||||||
self.font_size = font_size;
|
self.font_size = font_size;
|
||||||
|
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
editor.buffer_mut().set_metrics(font_size.to_metrics());
|
editor
|
||||||
|
.borrow_with(&FONT_SYSTEM)
|
||||||
|
.buffer_mut()
|
||||||
|
.set_metrics(font_size.to_metrics());
|
||||||
}
|
}
|
||||||
Message::WrapChanged(wrap) => {
|
Message::WrapChanged(wrap) => {
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
editor.buffer_mut().set_wrap(wrap);
|
editor.borrow_with(&FONT_SYSTEM).buffer_mut().set_wrap(wrap);
|
||||||
}
|
}
|
||||||
Message::AlignmentChanged(align) => {
|
Message::AlignmentChanged(align) => {
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
|
|
@ -360,13 +363,13 @@ impl Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_attrs<'a, T: Edit<'a>>(editor: &mut T, attrs: Attrs<'a>) {
|
fn update_attrs<T: Edit>(editor: &mut T, attrs: Attrs) {
|
||||||
editor.buffer_mut().lines.iter_mut().for_each(|line| {
|
editor.buffer_mut().lines.iter_mut().for_each(|line| {
|
||||||
line.set_attrs_list(AttrsList::new(attrs));
|
line.set_attrs_list(AttrsList::new(attrs));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_alignment<'a, T: Edit<'a>>(editor: &mut T, align: Align) {
|
fn update_alignment<T: Edit>(editor: &mut T, align: Align) {
|
||||||
let current_line = editor.cursor().line;
|
let current_line = editor.cursor().line;
|
||||||
if let Some(select) = editor.select_opt() {
|
if let Some(select) = editor.select_opt() {
|
||||||
let (start, end) = match select.line.cmp(¤t_line) {
|
let (start, end) = match select.line.cmp(¤t_line) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use crate::FONT_SYSTEM;
|
||||||
|
|
||||||
use super::text;
|
use super::text;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced_native::{
|
iced_native::{
|
||||||
|
|
@ -66,11 +68,11 @@ pub fn text_box<Editor>(editor: &Mutex<Editor>) -> TextBox<Editor> {
|
||||||
TextBox::new(editor)
|
TextBox::new(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'editor, Editor, Message, Renderer> Widget<Message, Renderer> for TextBox<'a, Editor>
|
impl<'a, Editor, Message, Renderer> Widget<Message, Renderer> for TextBox<'a, Editor>
|
||||||
where
|
where
|
||||||
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
|
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
|
||||||
Renderer::Theme: StyleSheet,
|
Renderer::Theme: StyleSheet,
|
||||||
Editor: Edit<'editor>,
|
Editor: Edit,
|
||||||
{
|
{
|
||||||
fn tag(&self) -> tree::Tag {
|
fn tag(&self) -> tree::Tag {
|
||||||
tree::Tag::of::<State>()
|
tree::Tag::of::<State>()
|
||||||
|
|
@ -93,7 +95,10 @@ where
|
||||||
|
|
||||||
//TODO: allow lazy shape
|
//TODO: allow lazy shape
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
editor.buffer_mut().shape_until(i32::max_value());
|
editor
|
||||||
|
.borrow_with(&FONT_SYSTEM)
|
||||||
|
.buffer_mut()
|
||||||
|
.shape_until(i32::max_value());
|
||||||
|
|
||||||
let mut layout_lines = 0;
|
let mut layout_lines = 0;
|
||||||
for line in editor.buffer().lines.iter() {
|
for line in editor.buffer().lines.iter() {
|
||||||
|
|
@ -162,6 +167,8 @@ where
|
||||||
|
|
||||||
let view_w = viewport.width.min(layout.bounds().width) - self.padding.horizontal() as f32;
|
let view_w = viewport.width.min(layout.bounds().width) - self.padding.horizontal() as f32;
|
||||||
let view_h = viewport.height.min(layout.bounds().height) - self.padding.vertical() as f32;
|
let view_h = viewport.height.min(layout.bounds().height) - self.padding.vertical() as f32;
|
||||||
|
let mut editor = editor.borrow_with(&FONT_SYSTEM);
|
||||||
|
|
||||||
editor.buffer_mut().set_size(view_w, view_h);
|
editor.buffer_mut().set_size(view_w, view_h);
|
||||||
|
|
||||||
editor.shape_as_needed();
|
editor.shape_as_needed();
|
||||||
|
|
@ -232,6 +239,7 @@ where
|
||||||
) -> Status {
|
) -> Status {
|
||||||
let state = tree.state.downcast_mut::<State>();
|
let state = tree.state.downcast_mut::<State>();
|
||||||
let mut editor = self.editor.lock().unwrap();
|
let mut editor = self.editor.lock().unwrap();
|
||||||
|
let mut editor = editor.borrow_with(&FONT_SYSTEM);
|
||||||
|
|
||||||
let mut status = Status::Ignored;
|
let mut status = Status::Ignored;
|
||||||
match event {
|
match event {
|
||||||
|
|
@ -330,12 +338,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'editor, Editor, Message, Renderer> From<TextBox<'a, Editor>>
|
impl<'a, Editor, Message, Renderer> From<TextBox<'a, Editor>> for Element<'a, Message, Renderer>
|
||||||
for Element<'a, Message, Renderer>
|
|
||||||
where
|
where
|
||||||
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
|
Renderer: renderer::Renderer + image::Renderer<Handle = image::Handle>,
|
||||||
Renderer::Theme: StyleSheet,
|
Renderer::Theme: StyleSheet,
|
||||||
Editor: Edit<'editor>,
|
Editor: Edit,
|
||||||
{
|
{
|
||||||
fn from(text_box: TextBox<'a, Editor>) -> Self {
|
fn from(text_box: TextBox<'a, Editor>) -> Self {
|
||||||
Self::new(text_box)
|
Self::new(text_box)
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@ fn main() {
|
||||||
#[cfg(feature = "vi")]
|
#[cfg(feature = "vi")]
|
||||||
let mut editor = cosmic_text::ViEditor::new(editor);
|
let mut editor = cosmic_text::ViEditor::new(editor);
|
||||||
|
|
||||||
|
let mut editor = editor.borrow_with(&font_system);
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.buffer_mut()
|
.buffer_mut()
|
||||||
.set_size(window.width() as f32 - line_x * 2.0, window.height() as f32);
|
.set_size(window.width() as f32 - line_x * 2.0, window.height() as f32);
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,17 @@ use orbclient::{EventOption, Renderer, Window, WindowFlag};
|
||||||
use std::{env, fs, process, time::Instant};
|
use std::{env, fs, process, time::Instant};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
fn redraw(window: &mut Window, editor: &mut Editor<'_>, swash_cache: &mut SwashCache) {
|
fn redraw(
|
||||||
|
window: &mut Window,
|
||||||
|
editor: &mut Editor,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
swash_cache: &mut SwashCache,
|
||||||
|
) {
|
||||||
let bg_color = orbclient::Color::rgb(0x34, 0x34, 0x34);
|
let bg_color = orbclient::Color::rgb(0x34, 0x34, 0x34);
|
||||||
let font_color = Color::rgb(0xFF, 0xFF, 0xFF);
|
let font_color = Color::rgb(0xFF, 0xFF, 0xFF);
|
||||||
|
|
||||||
|
let mut editor = editor.borrow_with(font_system);
|
||||||
|
|
||||||
editor.shape_as_needed();
|
editor.shape_as_needed();
|
||||||
if editor.buffer().redraw() {
|
if editor.buffer().redraw() {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
@ -55,10 +62,14 @@ fn main() {
|
||||||
let font_size_default = 1; // Body
|
let font_size_default = 1; // Body
|
||||||
|
|
||||||
let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]);
|
let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]);
|
||||||
buffer.set_size(window.width() as f32, window.height() as f32);
|
buffer
|
||||||
|
.borrow_with(&font_system)
|
||||||
|
.set_size(window.width() as f32, window.height() as f32);
|
||||||
|
|
||||||
let mut editor = Editor::new(buffer);
|
let mut editor = Editor::new(buffer);
|
||||||
|
|
||||||
|
let mut editor = editor.borrow_with(&font_system);
|
||||||
|
|
||||||
let mut swash_cache = SwashCache::new();
|
let mut swash_cache = SwashCache::new();
|
||||||
|
|
||||||
let text = if let Some(arg) = env::args().nth(1) {
|
let text = if let Some(arg) = env::args().nth(1) {
|
||||||
|
|
@ -128,7 +139,7 @@ fn main() {
|
||||||
// Finally, normal enter
|
// Finally, normal enter
|
||||||
editor.action(Action::Enter);
|
editor.action(Action::Enter);
|
||||||
|
|
||||||
redraw(&mut window, &mut editor, &mut swash_cache);
|
redraw(&mut window, &mut editor, &font_system, &mut swash_cache);
|
||||||
|
|
||||||
for event in window.events() {
|
for event in window.events() {
|
||||||
if let EventOption::Quit(_) = event.to_option() {
|
if let EventOption::Quit(_) = event.to_option() {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ fn main() {
|
||||||
Metrics::new(32.0, 44.0).scale(display_scale),
|
Metrics::new(32.0, 44.0).scale(display_scale),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let mut editor = editor.borrow_with(&font_system);
|
||||||
|
|
||||||
editor
|
editor
|
||||||
.buffer_mut()
|
.buffer_mut()
|
||||||
.set_size(window.width() as f32, window.height() as f32);
|
.set_size(window.width() as f32, window.height() as f32);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ fn main() {
|
||||||
// A Buffer provides shaping and layout for a UTF-8 string, create one per text widget
|
// A Buffer provides shaping and layout for a UTF-8 string, create one per text widget
|
||||||
let mut buffer = Buffer::new(&font_system, metrics);
|
let mut buffer = Buffer::new(&font_system, metrics);
|
||||||
|
|
||||||
|
let mut buffer = buffer.borrow_with(&font_system);
|
||||||
|
|
||||||
// Set a size for the text buffer, in pixels
|
// Set a size for the text buffer, in pixels
|
||||||
let width = 80u16;
|
let width = 80u16;
|
||||||
let height = 25u16;
|
let height = 25u16;
|
||||||
|
|
|
||||||
207
src/buffer.rs
207
src/buffer.rs
|
|
@ -10,7 +10,10 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
use crate::{Attrs, AttrsList, BufferLine, FontSystem, LayoutGlyph, LayoutLine, ShapeLine, Wrap};
|
use crate::{
|
||||||
|
Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, FontSystem, LayoutGlyph, LayoutLine,
|
||||||
|
ShapeLine, Wrap,
|
||||||
|
};
|
||||||
|
|
||||||
/// Current cursor location
|
/// Current cursor location
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
|
@ -169,8 +172,8 @@ impl<'a> LayoutRun<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator of visible text lines, see [`LayoutRun`]
|
/// An iterator of visible text lines, see [`LayoutRun`]
|
||||||
pub struct LayoutRunIter<'a, 'b> {
|
pub struct LayoutRunIter<'b> {
|
||||||
buffer: &'b Buffer<'a>,
|
buffer: &'b Buffer,
|
||||||
line_i: usize,
|
line_i: usize,
|
||||||
layout_i: usize,
|
layout_i: usize,
|
||||||
remaining_len: usize,
|
remaining_len: usize,
|
||||||
|
|
@ -178,8 +181,8 @@ pub struct LayoutRunIter<'a, 'b> {
|
||||||
total_layout: i32,
|
total_layout: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> LayoutRunIter<'a, 'b> {
|
impl<'b> LayoutRunIter<'b> {
|
||||||
pub fn new(buffer: &'b Buffer<'a>) -> Self {
|
pub fn new(buffer: &'b Buffer) -> Self {
|
||||||
let total_layout_lines: usize = buffer
|
let total_layout_lines: usize = buffer
|
||||||
.lines
|
.lines
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -215,7 +218,7 @@ impl<'a, 'b> LayoutRunIter<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> {
|
impl<'b> Iterator for LayoutRunIter<'b> {
|
||||||
type Item = LayoutRun<'b>;
|
type Item = LayoutRun<'b>;
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
|
@ -258,7 +261,7 @@ impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> ExactSizeIterator for LayoutRunIter<'a, 'b> {}
|
impl<'b> ExactSizeIterator for LayoutRunIter<'b> {}
|
||||||
|
|
||||||
/// Metrics of text
|
/// Metrics of text
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
|
@ -296,8 +299,7 @@ impl fmt::Display for Metrics {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A buffer of text that is shaped and laid out
|
/// A buffer of text that is shaped and laid out
|
||||||
pub struct Buffer<'a> {
|
pub struct Buffer {
|
||||||
font_system: &'a FontSystem,
|
|
||||||
/// [BufferLine]s (or paragraphs) of text in the buffer
|
/// [BufferLine]s (or paragraphs) of text in the buffer
|
||||||
pub lines: Vec<BufferLine>,
|
pub lines: Vec<BufferLine>,
|
||||||
metrics: Metrics,
|
metrics: Metrics,
|
||||||
|
|
@ -309,17 +311,16 @@ pub struct Buffer<'a> {
|
||||||
wrap: Wrap,
|
wrap: Wrap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Buffer<'a> {
|
impl Buffer {
|
||||||
/// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`]
|
/// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`]
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Will panic if `metrics.line_height` is zero.
|
/// Will panic if `metrics.line_height` is zero.
|
||||||
pub fn new(font_system: &'a FontSystem, metrics: Metrics) -> Self {
|
pub fn new(font_system: &FontSystem, metrics: Metrics) -> Self {
|
||||||
assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
|
assert_ne!(metrics.line_height, 0.0, "line height cannot be 0");
|
||||||
|
|
||||||
let mut buffer = Self {
|
let mut buffer = Self {
|
||||||
font_system,
|
|
||||||
lines: Vec::new(),
|
lines: Vec::new(),
|
||||||
metrics,
|
metrics,
|
||||||
width: 0.0,
|
width: 0.0,
|
||||||
|
|
@ -328,23 +329,28 @@ impl<'a> Buffer<'a> {
|
||||||
redraw: false,
|
redraw: false,
|
||||||
wrap: Wrap::Word,
|
wrap: Wrap::Word,
|
||||||
};
|
};
|
||||||
buffer.set_text("", Attrs::new());
|
buffer.set_text(font_system, "", Attrs::new());
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn relayout(&mut self) {
|
pub fn borrow_with<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
font_system: &'a FontSystem,
|
||||||
|
) -> BorrowedWithFontSystem<'a, Buffer> {
|
||||||
|
BorrowedWithFontSystem {
|
||||||
|
inner: self,
|
||||||
|
font_system,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn relayout(&mut self, font_system: &FontSystem) {
|
||||||
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
||||||
let instant = std::time::Instant::now();
|
let instant = std::time::Instant::now();
|
||||||
|
|
||||||
for line in &mut self.lines {
|
for line in &mut self.lines {
|
||||||
if line.shape_opt().is_some() {
|
if line.shape_opt().is_some() {
|
||||||
line.reset_layout();
|
line.reset_layout();
|
||||||
line.layout(
|
line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
|
||||||
self.font_system,
|
|
||||||
self.metrics.font_size,
|
|
||||||
self.width,
|
|
||||||
self.wrap,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -354,8 +360,7 @@ impl<'a> Buffer<'a> {
|
||||||
log::debug!("relayout: {:?}", instant.elapsed());
|
log::debug!("relayout: {:?}", instant.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
|
pub(crate) fn shape_until(&mut self, font_system: &FontSystem, lines: i32) -> i32 {
|
||||||
pub fn shape_until(&mut self, lines: i32) -> i32 {
|
|
||||||
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
||||||
let instant = std::time::Instant::now();
|
let instant = std::time::Instant::now();
|
||||||
|
|
||||||
|
|
@ -369,12 +374,7 @@ impl<'a> Buffer<'a> {
|
||||||
if line.shape_opt().is_none() {
|
if line.shape_opt().is_none() {
|
||||||
reshaped += 1;
|
reshaped += 1;
|
||||||
}
|
}
|
||||||
let layout = line.layout(
|
let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
|
||||||
self.font_system,
|
|
||||||
self.metrics.font_size,
|
|
||||||
self.width,
|
|
||||||
self.wrap,
|
|
||||||
);
|
|
||||||
total_layout += layout.len() as i32;
|
total_layout += layout.len() as i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,8 +387,7 @@ impl<'a> Buffer<'a> {
|
||||||
total_layout
|
total_layout
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shape lines until cursor, also scrolling to include cursor in view
|
pub(crate) fn shape_until_cursor(&mut self, font_system: &FontSystem, cursor: Cursor) {
|
||||||
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
|
|
||||||
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
|
||||||
let instant = std::time::Instant::now();
|
let instant = std::time::Instant::now();
|
||||||
|
|
||||||
|
|
@ -402,12 +401,7 @@ impl<'a> Buffer<'a> {
|
||||||
if line.shape_opt().is_none() {
|
if line.shape_opt().is_none() {
|
||||||
reshaped += 1;
|
reshaped += 1;
|
||||||
}
|
}
|
||||||
let layout = line.layout(
|
let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap);
|
||||||
self.font_system,
|
|
||||||
self.metrics.font_size,
|
|
||||||
self.width,
|
|
||||||
self.wrap,
|
|
||||||
);
|
|
||||||
if line_i == cursor.line {
|
if line_i == cursor.line {
|
||||||
let layout_cursor = self.layout_cursor(&cursor);
|
let layout_cursor = self.layout_cursor(&cursor);
|
||||||
layout_i += layout_cursor.layout as i32;
|
layout_i += layout_cursor.layout as i32;
|
||||||
|
|
@ -430,15 +424,14 @@ impl<'a> Buffer<'a> {
|
||||||
self.scroll = layout_i - (lines - 1);
|
self.scroll = layout_i - (lines - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.shape_until_scroll();
|
self.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shape lines until scroll
|
pub(crate) fn shape_until_scroll(&mut self, font_system: &FontSystem) {
|
||||||
pub fn shape_until_scroll(&mut self) {
|
|
||||||
let lines = self.visible_lines();
|
let lines = self.visible_lines();
|
||||||
|
|
||||||
let scroll_end = self.scroll + lines;
|
let scroll_end = self.scroll + lines;
|
||||||
let total_layout = self.shape_until(scroll_end);
|
let total_layout = self.shape_until(font_system, scroll_end);
|
||||||
|
|
||||||
self.scroll = cmp::max(0, cmp::min(total_layout - (lines - 1), self.scroll));
|
self.scroll = cmp::max(0, cmp::min(total_layout - (lines - 1), self.scroll));
|
||||||
}
|
}
|
||||||
|
|
@ -473,26 +466,22 @@ impl<'a> Buffer<'a> {
|
||||||
LayoutCursor::new(cursor.line, 0, 0)
|
LayoutCursor::new(cursor.line, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get [`FontSystem`] used by this [`Buffer`]
|
pub(crate) fn line_shape(
|
||||||
pub fn font_system(&self) -> &'a FontSystem {
|
&mut self,
|
||||||
self.font_system
|
font_system: &FontSystem,
|
||||||
|
line_i: usize,
|
||||||
|
) -> Option<&ShapeLine> {
|
||||||
|
let line = self.lines.get_mut(line_i)?;
|
||||||
|
Some(line.shape(font_system))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shape the provided line index and return the result
|
pub(crate) fn line_layout(
|
||||||
pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
|
&mut self,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
line_i: usize,
|
||||||
|
) -> Option<&[LayoutLine]> {
|
||||||
let line = self.lines.get_mut(line_i)?;
|
let line = self.lines.get_mut(line_i)?;
|
||||||
Some(line.shape(self.font_system))
|
Some(line.layout(font_system, self.metrics.font_size, self.width, self.wrap))
|
||||||
}
|
|
||||||
|
|
||||||
/// Lay out the provided line index and return the result
|
|
||||||
pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
|
|
||||||
let line = self.lines.get_mut(line_i)?;
|
|
||||||
Some(line.layout(
|
|
||||||
self.font_system,
|
|
||||||
self.metrics.font_size,
|
|
||||||
self.width,
|
|
||||||
self.wrap,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current [`Metrics`]
|
/// Get the current [`Metrics`]
|
||||||
|
|
@ -500,17 +489,12 @@ impl<'a> Buffer<'a> {
|
||||||
self.metrics
|
self.metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current [`Metrics`]
|
fn set_metrics(&mut self, font_system: &FontSystem, metrics: Metrics) {
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Will panic if `metrics.font_size` is zero.
|
|
||||||
pub fn set_metrics(&mut self, metrics: Metrics) {
|
|
||||||
if metrics != self.metrics {
|
if metrics != self.metrics {
|
||||||
assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
|
assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
|
||||||
self.metrics = metrics;
|
self.metrics = metrics;
|
||||||
self.relayout();
|
self.relayout(font_system);
|
||||||
self.shape_until_scroll();
|
self.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -519,12 +503,11 @@ impl<'a> Buffer<'a> {
|
||||||
self.wrap
|
self.wrap
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current [`Wrap`]
|
pub(crate) fn set_wrap(&mut self, font_system: &FontSystem, wrap: Wrap) {
|
||||||
pub fn set_wrap(&mut self, wrap: Wrap) {
|
|
||||||
if wrap != self.wrap {
|
if wrap != self.wrap {
|
||||||
self.wrap = wrap;
|
self.wrap = wrap;
|
||||||
self.relayout();
|
self.relayout(font_system);
|
||||||
self.shape_until_scroll();
|
self.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,16 +516,15 @@ impl<'a> Buffer<'a> {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current buffer dimensions
|
pub(crate) fn set_size(&mut self, font_system: &FontSystem, width: f32, height: f32) {
|
||||||
pub fn set_size(&mut self, width: f32, height: f32) {
|
|
||||||
let clamped_width = width.max(0.0);
|
let clamped_width = width.max(0.0);
|
||||||
let clamped_height = height.max(0.0);
|
let clamped_height = height.max(0.0);
|
||||||
|
|
||||||
if clamped_width != self.width || clamped_height != self.height {
|
if clamped_width != self.width || clamped_height != self.height {
|
||||||
self.width = clamped_width;
|
self.width = clamped_width;
|
||||||
self.height = clamped_height;
|
self.height = clamped_height;
|
||||||
self.relayout();
|
self.relayout(font_system);
|
||||||
self.shape_until_scroll();
|
self.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,8 +546,7 @@ impl<'a> Buffer<'a> {
|
||||||
(self.height / self.metrics.line_height) as i32
|
(self.height / self.metrics.line_height) as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set text of buffer, using provided attributes for each line by default
|
pub(crate) fn set_text(&mut self, font_system: &FontSystem, text: &str, attrs: Attrs) {
|
||||||
pub fn set_text(&mut self, text: &str, attrs: Attrs<'a>) {
|
|
||||||
self.lines.clear();
|
self.lines.clear();
|
||||||
for line in text.lines() {
|
for line in text.lines() {
|
||||||
self.lines
|
self.lines
|
||||||
|
|
@ -579,7 +560,7 @@ impl<'a> Buffer<'a> {
|
||||||
|
|
||||||
self.scroll = 0;
|
self.scroll = 0;
|
||||||
|
|
||||||
self.shape_until_scroll();
|
self.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if a redraw is needed
|
/// True if a redraw is needed
|
||||||
|
|
@ -593,7 +574,7 @@ impl<'a> Buffer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the visible layout runs for rendering and other tasks
|
/// Get the visible layout runs for rendering and other tasks
|
||||||
pub fn layout_runs<'b>(&'b self) -> LayoutRunIter<'a, 'b> {
|
pub fn layout_runs(&self) -> LayoutRunIter {
|
||||||
LayoutRunIter::new(self)
|
LayoutRunIter::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -698,10 +679,14 @@ impl<'a> Buffer<'a> {
|
||||||
new_cursor_opt
|
new_cursor_opt
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the buffer
|
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
|
pub(crate) fn draw<F>(
|
||||||
where
|
&self,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
cache: &mut crate::SwashCache,
|
||||||
|
color: Color,
|
||||||
|
mut f: F,
|
||||||
|
) where
|
||||||
F: FnMut(i32, i32, u32, u32, Color),
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
{
|
{
|
||||||
for run in self.layout_runs() {
|
for run in self.layout_runs() {
|
||||||
|
|
@ -713,10 +698,70 @@ impl<'a> Buffer<'a> {
|
||||||
None => color,
|
None => color,
|
||||||
};
|
};
|
||||||
|
|
||||||
cache.with_pixels(self.font_system, cache_key, glyph_color, |x, y, color| {
|
cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| {
|
||||||
f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color);
|
f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> BorrowedWithFontSystem<'a, Buffer> {
|
||||||
|
/// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines
|
||||||
|
pub fn shape_until(&mut self, lines: i32) -> i32 {
|
||||||
|
self.inner.shape_until(self.font_system, lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shape lines until cursor, also scrolling to include cursor in view
|
||||||
|
pub fn shape_until_cursor(&mut self, cursor: Cursor) {
|
||||||
|
self.inner.shape_until_cursor(self.font_system, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shape lines until scroll
|
||||||
|
pub fn shape_until_scroll(&mut self) {
|
||||||
|
self.inner.shape_until_scroll(self.font_system);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shape the provided line index and return the result
|
||||||
|
pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> {
|
||||||
|
self.inner.line_shape(self.font_system, line_i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lay out the provided line index and return the result
|
||||||
|
pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> {
|
||||||
|
self.inner.line_layout(self.font_system, line_i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the current [`Metrics`]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if `metrics.font_size` is zero.
|
||||||
|
pub fn set_metrics(&mut self, metrics: Metrics) {
|
||||||
|
self.inner.set_metrics(self.font_system, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the current [`Wrap`]
|
||||||
|
pub fn set_wrap(&mut self, wrap: Wrap) {
|
||||||
|
self.inner.set_wrap(self.font_system, wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the current buffer dimensions
|
||||||
|
pub fn set_size(&mut self, width: f32, height: f32) {
|
||||||
|
self.inner.set_size(self.font_system, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set text of buffer, using provided attributes for each line by default
|
||||||
|
pub fn set_text(&mut self, text: &str, attrs: Attrs) {
|
||||||
|
self.inner.set_text(self.font_system, text, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the buffer
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
|
{
|
||||||
|
self.inner.draw(self.font_system, cache, color, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,22 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
use crate::{Action, Affinity, AttrsList, Buffer, BufferLine, Cursor, Edit, LayoutCursor};
|
use crate::{
|
||||||
|
Action, Affinity, AttrsList, Buffer, BufferLine, Cursor, Edit, FontSystem, LayoutCursor,
|
||||||
|
};
|
||||||
|
|
||||||
/// A wrapper of [`Buffer`] for easy editing
|
/// A wrapper of [`Buffer`] for easy editing
|
||||||
pub struct Editor<'a> {
|
pub struct Editor {
|
||||||
buffer: Buffer<'a>,
|
buffer: Buffer,
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
cursor_x_opt: Option<i32>,
|
cursor_x_opt: Option<i32>,
|
||||||
select_opt: Option<Cursor>,
|
select_opt: Option<Cursor>,
|
||||||
cursor_moved: bool,
|
cursor_moved: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Editor<'a> {
|
impl Editor {
|
||||||
/// Create a new [`Editor`] with the provided [`Buffer`]
|
/// Create a new [`Editor`] with the provided [`Buffer`]
|
||||||
pub fn new(buffer: Buffer<'a>) -> Self {
|
pub fn new(buffer: Buffer) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer,
|
buffer,
|
||||||
cursor: Cursor::default(),
|
cursor: Cursor::default(),
|
||||||
|
|
@ -33,10 +35,10 @@ impl<'a> Editor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_layout_cursor(&mut self, cursor: LayoutCursor) {
|
fn set_layout_cursor(&mut self, font_system: &FontSystem, cursor: LayoutCursor) {
|
||||||
let layout = self
|
let layout = self
|
||||||
.buffer
|
.buffer
|
||||||
.line_layout(cursor.line)
|
.line_layout(font_system, cursor.line)
|
||||||
.expect("layout not found");
|
.expect("layout not found");
|
||||||
|
|
||||||
let layout_line = match layout.get(cursor.layout) {
|
let layout_line = match layout.get(cursor.layout) {
|
||||||
|
|
@ -68,12 +70,12 @@ impl<'a> Editor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Edit<'a> for Editor<'a> {
|
impl Edit for Editor {
|
||||||
fn buffer(&self) -> &Buffer<'a> {
|
fn buffer(&self) -> &Buffer {
|
||||||
&self.buffer
|
&self.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_mut(&mut self) -> &mut Buffer<'a> {
|
fn buffer_mut(&mut self) -> &mut Buffer {
|
||||||
&mut self.buffer
|
&mut self.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,12 +94,12 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_as_needed(&mut self) {
|
fn shape_as_needed(&mut self, font_system: &FontSystem) {
|
||||||
if self.cursor_moved {
|
if self.cursor_moved {
|
||||||
self.buffer.shape_until_cursor(self.cursor);
|
self.buffer.shape_until_cursor(font_system, self.cursor);
|
||||||
self.cursor_moved = false;
|
self.cursor_moved = false;
|
||||||
} else {
|
} else {
|
||||||
self.buffer.shape_until_scroll();
|
self.buffer.shape_until_scroll(font_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -279,7 +281,7 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
self.cursor.index = self.buffer.lines[self.cursor.line].text().len() - after_len;
|
self.cursor.index = self.buffer.lines[self.cursor.line].text().len() - after_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(&mut self, action: Action) {
|
fn action(&mut self, font_system: &FontSystem, action: Action) {
|
||||||
let old_cursor = self.cursor;
|
let old_cursor = self.cursor;
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
|
|
@ -333,9 +335,9 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
.map(|shape| shape.rtl);
|
.map(|shape| shape.rtl);
|
||||||
if let Some(rtl) = rtl_opt {
|
if let Some(rtl) = rtl_opt {
|
||||||
if rtl {
|
if rtl {
|
||||||
self.action(Action::Next);
|
self.action(font_system, Action::Next);
|
||||||
} else {
|
} else {
|
||||||
self.action(Action::Previous);
|
self.action(font_system, Action::Previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,9 +348,9 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
.map(|shape| shape.rtl);
|
.map(|shape| shape.rtl);
|
||||||
if let Some(rtl) = rtl_opt {
|
if let Some(rtl) = rtl_opt {
|
||||||
if rtl {
|
if rtl {
|
||||||
self.action(Action::Previous);
|
self.action(font_system, Action::Previous);
|
||||||
} else {
|
} else {
|
||||||
self.action(Action::Next);
|
self.action(font_system, Action::Next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -373,7 +375,7 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
cursor.glyph = cursor_x as usize; //TODO: glyph x position
|
cursor.glyph = cursor_x as usize; //TODO: glyph x position
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_layout_cursor(cursor);
|
self.set_layout_cursor(font_system, cursor);
|
||||||
}
|
}
|
||||||
Action::Down => {
|
Action::Down => {
|
||||||
//TODO: make this preserve X as best as possible!
|
//TODO: make this preserve X as best as possible!
|
||||||
|
|
@ -381,7 +383,7 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
|
|
||||||
let layout_len = self
|
let layout_len = self
|
||||||
.buffer
|
.buffer
|
||||||
.line_layout(cursor.line)
|
.line_layout(font_system, cursor.line)
|
||||||
.expect("layout not found")
|
.expect("layout not found")
|
||||||
.len();
|
.len();
|
||||||
|
|
||||||
|
|
@ -402,18 +404,18 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
cursor.glyph = cursor_x as usize; //TODO: glyph x position
|
cursor.glyph = cursor_x as usize; //TODO: glyph x position
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_layout_cursor(cursor);
|
self.set_layout_cursor(font_system, cursor);
|
||||||
}
|
}
|
||||||
Action::Home => {
|
Action::Home => {
|
||||||
let mut cursor = self.buffer.layout_cursor(&self.cursor);
|
let mut cursor = self.buffer.layout_cursor(&self.cursor);
|
||||||
cursor.glyph = 0;
|
cursor.glyph = 0;
|
||||||
self.set_layout_cursor(cursor);
|
self.set_layout_cursor(font_system, cursor);
|
||||||
self.cursor_x_opt = None;
|
self.cursor_x_opt = None;
|
||||||
}
|
}
|
||||||
Action::End => {
|
Action::End => {
|
||||||
let mut cursor = self.buffer.layout_cursor(&self.cursor);
|
let mut cursor = self.buffer.layout_cursor(&self.cursor);
|
||||||
cursor.glyph = usize::max_value();
|
cursor.glyph = usize::max_value();
|
||||||
self.set_layout_cursor(cursor);
|
self.set_layout_cursor(font_system, cursor);
|
||||||
self.cursor_x_opt = None;
|
self.cursor_x_opt = None;
|
||||||
}
|
}
|
||||||
Action::ParagraphStart => {
|
Action::ParagraphStart => {
|
||||||
|
|
@ -427,10 +429,10 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
self.buffer.set_redraw(true);
|
self.buffer.set_redraw(true);
|
||||||
}
|
}
|
||||||
Action::PageUp => {
|
Action::PageUp => {
|
||||||
self.action(Action::Vertical(-self.buffer.size().1 as i32));
|
self.action(font_system, Action::Vertical(-self.buffer.size().1 as i32));
|
||||||
}
|
}
|
||||||
Action::PageDown => {
|
Action::PageDown => {
|
||||||
self.action(Action::Vertical(self.buffer.size().1 as i32));
|
self.action(font_system, Action::Vertical(self.buffer.size().1 as i32));
|
||||||
}
|
}
|
||||||
Action::Vertical(px) => {
|
Action::Vertical(px) => {
|
||||||
// TODO more efficient
|
// TODO more efficient
|
||||||
|
|
@ -438,12 +440,12 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
match lines.cmp(&0) {
|
match lines.cmp(&0) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
for _ in 0..-lines {
|
for _ in 0..-lines {
|
||||||
self.action(Action::Up);
|
self.action(font_system, Action::Up);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
for _ in 0..lines {
|
for _ in 0..lines {
|
||||||
self.action(Action::Down);
|
self.action(font_system, Action::Down);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ordering::Equal => {}
|
Ordering::Equal => {}
|
||||||
|
|
@ -459,7 +461,7 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
// Filter out special chars (except for tab), use Action instead
|
// Filter out special chars (except for tab), use Action instead
|
||||||
log::debug!("Refusing to insert control character {:?}", character);
|
log::debug!("Refusing to insert control character {:?}", character);
|
||||||
} else if character == '\n' {
|
} else if character == '\n' {
|
||||||
self.action(Action::Enter);
|
self.action(font_system, Action::Enter);
|
||||||
} else {
|
} else {
|
||||||
let mut str_buf = [0u8; 8];
|
let mut str_buf = [0u8; 8];
|
||||||
let str_ref = character.encode_utf8(&mut str_buf);
|
let str_ref = character.encode_utf8(&mut str_buf);
|
||||||
|
|
@ -619,9 +621,9 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
.map(|shape| shape.rtl);
|
.map(|shape| shape.rtl);
|
||||||
if let Some(rtl) = rtl_opt {
|
if let Some(rtl) = rtl_opt {
|
||||||
if rtl {
|
if rtl {
|
||||||
self.action(Action::NextWord);
|
self.action(font_system, Action::NextWord);
|
||||||
} else {
|
} else {
|
||||||
self.action(Action::PreviousWord);
|
self.action(font_system, Action::PreviousWord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -632,9 +634,9 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
.map(|shape| shape.rtl);
|
.map(|shape| shape.rtl);
|
||||||
if let Some(rtl) = rtl_opt {
|
if let Some(rtl) = rtl_opt {
|
||||||
if rtl {
|
if rtl {
|
||||||
self.action(Action::PreviousWord);
|
self.action(font_system, Action::PreviousWord);
|
||||||
} else {
|
} else {
|
||||||
self.action(Action::NextWord);
|
self.action(font_system, Action::NextWord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -673,8 +675,13 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
|
|
||||||
/// Draw the editor
|
/// Draw the editor
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
|
fn draw<F>(
|
||||||
where
|
&self,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
cache: &mut crate::SwashCache,
|
||||||
|
color: Color,
|
||||||
|
mut f: F,
|
||||||
|
) where
|
||||||
F: FnMut(i32, i32, u32, u32, Color),
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
{
|
{
|
||||||
let font_size = self.buffer.metrics().font_size;
|
let font_size = self.buffer.metrics().font_size;
|
||||||
|
|
@ -833,14 +840,9 @@ impl<'a> Edit<'a> for Editor<'a> {
|
||||||
None => color,
|
None => color,
|
||||||
};
|
};
|
||||||
|
|
||||||
cache.with_pixels(
|
cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| {
|
||||||
self.buffer.font_system(),
|
f(x_int + x, line_y as i32 + y_int + y, 1, 1, color);
|
||||||
cache_key,
|
});
|
||||||
glyph_color,
|
|
||||||
|x, y, color| {
|
|
||||||
f(x_int + x, line_y as i32 + y_int + y, 1, 1, color);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use alloc::string::String;
|
||||||
|
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
use crate::Color;
|
use crate::Color;
|
||||||
use crate::{AttrsList, Buffer, Cursor};
|
use crate::{AttrsList, BorrowedWithFontSystem, Buffer, Cursor, FontSystem};
|
||||||
|
|
||||||
pub use self::editor::*;
|
pub use self::editor::*;
|
||||||
mod editor;
|
mod editor;
|
||||||
|
|
@ -78,12 +78,25 @@ pub enum Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait to allow easy replacements of [`Editor`], like `SyntaxEditor`
|
/// A trait to allow easy replacements of [`Editor`], like `SyntaxEditor`
|
||||||
pub trait Edit<'a> {
|
pub trait Edit {
|
||||||
|
fn borrow_with<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
font_system: &'a FontSystem,
|
||||||
|
) -> BorrowedWithFontSystem<'a, Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
BorrowedWithFontSystem {
|
||||||
|
inner: self,
|
||||||
|
font_system,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the internal [`Buffer`]
|
/// Get the internal [`Buffer`]
|
||||||
fn buffer(&self) -> &Buffer<'a>;
|
fn buffer(&self) -> &Buffer;
|
||||||
|
|
||||||
/// Get the internal [`Buffer`], mutably
|
/// Get the internal [`Buffer`], mutably
|
||||||
fn buffer_mut(&mut self) -> &mut Buffer<'a>;
|
fn buffer_mut(&mut self) -> &mut Buffer;
|
||||||
|
|
||||||
/// Get the current cursor position
|
/// Get the current cursor position
|
||||||
fn cursor(&self) -> Cursor;
|
fn cursor(&self) -> Cursor;
|
||||||
|
|
@ -95,7 +108,7 @@ pub trait Edit<'a> {
|
||||||
fn set_select_opt(&mut self, select_opt: Option<Cursor>);
|
fn set_select_opt(&mut self, select_opt: Option<Cursor>);
|
||||||
|
|
||||||
/// Shape lines until scroll, after adjusting scroll if the cursor moved
|
/// Shape lines until scroll, after adjusting scroll if the cursor moved
|
||||||
fn shape_as_needed(&mut self);
|
fn shape_as_needed(&mut self, font_system: &FontSystem);
|
||||||
|
|
||||||
/// Copy selection
|
/// Copy selection
|
||||||
fn copy_selection(&mut self) -> Option<String>;
|
fn copy_selection(&mut self) -> Option<String>;
|
||||||
|
|
@ -109,11 +122,40 @@ pub trait Edit<'a> {
|
||||||
fn insert_string(&mut self, data: &str, attrs_list: Option<AttrsList>);
|
fn insert_string(&mut self, data: &str, attrs_list: Option<AttrsList>);
|
||||||
|
|
||||||
/// Perform an [Action] on the editor
|
/// Perform an [Action] on the editor
|
||||||
fn action(&mut self, action: Action);
|
fn action(&mut self, font_system: &FontSystem, action: Action);
|
||||||
|
|
||||||
/// Draw the editor
|
/// Draw the editor
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
|
fn draw<F>(&self, font_system: &FontSystem, cache: &mut crate::SwashCache, color: Color, f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(i32, i32, u32, u32, Color);
|
F: FnMut(i32, i32, u32, u32, Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Edit> BorrowedWithFontSystem<'a, T> {
|
||||||
|
/// Get the internal [`Buffer`], mutably
|
||||||
|
pub fn buffer_mut(&mut self) -> BorrowedWithFontSystem<Buffer> {
|
||||||
|
BorrowedWithFontSystem {
|
||||||
|
inner: self.inner.buffer_mut(),
|
||||||
|
font_system: self.font_system,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shape lines until scroll, after adjusting scroll if the cursor moved
|
||||||
|
pub fn shape_as_needed(&mut self) {
|
||||||
|
self.inner.shape_as_needed(self.font_system);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform an [Action] on the editor
|
||||||
|
pub fn action(&mut self, action: Action) {
|
||||||
|
self.inner.action(self.font_system, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the editor
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
|
{
|
||||||
|
self.inner.draw(self.font_system, cache, color, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ use syntect::highlighting::{
|
||||||
};
|
};
|
||||||
use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet};
|
use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet};
|
||||||
|
|
||||||
use crate::{Action, AttrsList, Buffer, Color, Cursor, Edit, Editor, Style, Weight, Wrap};
|
use crate::{
|
||||||
|
Action, AttrsList, BorrowedWithFontSystem, Buffer, Color, Cursor, Edit, Editor, FontSystem,
|
||||||
|
Style, Weight, Wrap,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct SyntaxSystem {
|
pub struct SyntaxSystem {
|
||||||
pub syntax_set: SyntaxSet,
|
pub syntax_set: SyntaxSet,
|
||||||
|
|
@ -27,7 +30,7 @@ impl SyntaxSystem {
|
||||||
|
|
||||||
/// A wrapper of [`Editor`] with syntax highlighting provided by [`SyntaxSystem`]
|
/// A wrapper of [`Editor`] with syntax highlighting provided by [`SyntaxSystem`]
|
||||||
pub struct SyntaxEditor<'a> {
|
pub struct SyntaxEditor<'a> {
|
||||||
editor: Editor<'a>,
|
editor: Editor,
|
||||||
syntax_system: &'a SyntaxSystem,
|
syntax_system: &'a SyntaxSystem,
|
||||||
syntax: &'a SyntaxReference,
|
syntax: &'a SyntaxReference,
|
||||||
theme: &'a Theme,
|
theme: &'a Theme,
|
||||||
|
|
@ -41,11 +44,7 @@ impl<'a> SyntaxEditor<'a> {
|
||||||
/// A good default theme name is "base16-eighties.dark".
|
/// A good default theme name is "base16-eighties.dark".
|
||||||
///
|
///
|
||||||
/// Returns None if theme not found
|
/// Returns None if theme not found
|
||||||
pub fn new(
|
pub fn new(buffer: Buffer, syntax_system: &'a SyntaxSystem, theme_name: &str) -> Option<Self> {
|
||||||
buffer: Buffer<'a>,
|
|
||||||
syntax_system: &'a SyntaxSystem,
|
|
||||||
theme_name: &str,
|
|
||||||
) -> Option<Self> {
|
|
||||||
let editor = Editor::new(buffer);
|
let editor = Editor::new(buffer);
|
||||||
let syntax = syntax_system.syntax_set.find_syntax_plain_text();
|
let syntax = syntax_system.syntax_set.find_syntax_plain_text();
|
||||||
let theme = syntax_system.theme_set.themes.get(theme_name)?;
|
let theme = syntax_system.theme_set.themes.get(theme_name)?;
|
||||||
|
|
@ -61,21 +60,17 @@ impl<'a> SyntaxEditor<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load text from a file, and also set syntax to the best option
|
|
||||||
///
|
|
||||||
/// ## Errors
|
|
||||||
///
|
|
||||||
/// Returns an [`io::Error`] if reading the file fails
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn load_text<P: AsRef<Path>>(
|
pub(crate) fn load_text<P: AsRef<Path>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
font_system: &FontSystem,
|
||||||
path: P,
|
path: P,
|
||||||
attrs: crate::Attrs<'a>,
|
attrs: crate::Attrs,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
let text = fs::read_to_string(path)?;
|
let text = fs::read_to_string(path)?;
|
||||||
self.editor.buffer_mut().set_text(&text, attrs);
|
self.editor.buffer_mut().set_text(font_system, &text, attrs);
|
||||||
|
|
||||||
//TODO: re-use text
|
//TODO: re-use text
|
||||||
self.syntax = match self.syntax_system.syntax_set.find_syntax_for_file(path) {
|
self.syntax = match self.syntax_system.syntax_set.find_syntax_for_file(path) {
|
||||||
|
|
@ -115,12 +110,12 @@ impl<'a> SyntaxEditor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Edit<'a> for SyntaxEditor<'a> {
|
impl<'a> Edit for SyntaxEditor<'a> {
|
||||||
fn buffer(&self) -> &Buffer<'a> {
|
fn buffer(&self) -> &Buffer {
|
||||||
self.editor.buffer()
|
self.editor.buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_mut(&mut self) -> &mut Buffer<'a> {
|
fn buffer_mut(&mut self) -> &mut Buffer {
|
||||||
self.editor.buffer_mut()
|
self.editor.buffer_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,7 +131,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> {
|
||||||
self.editor.set_select_opt(select_opt);
|
self.editor.set_select_opt(select_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_as_needed(&mut self) {
|
fn shape_as_needed(&mut self, font_system: &FontSystem) {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
|
|
||||||
|
|
@ -201,7 +196,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> {
|
||||||
line.set_wrap(Wrap::Word);
|
line.set_wrap(Wrap::Word);
|
||||||
|
|
||||||
//TODO: efficiently do syntax highlighting without having to shape whole buffer
|
//TODO: efficiently do syntax highlighting without having to shape whole buffer
|
||||||
buffer.line_shape(line_i);
|
buffer.line_shape(font_system, line_i);
|
||||||
|
|
||||||
let cache_item = (parse_state.clone(), highlight_state.clone());
|
let cache_item = (parse_state.clone(), highlight_state.clone());
|
||||||
if line_i < self.syntax_cache.len() {
|
if line_i < self.syntax_cache.len() {
|
||||||
|
|
@ -226,7 +221,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.editor.shape_as_needed();
|
self.editor.shape_as_needed(font_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_selection(&mut self) -> Option<String> {
|
fn copy_selection(&mut self) -> Option<String> {
|
||||||
|
|
@ -241,18 +236,36 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> {
|
||||||
self.editor.insert_string(data, attrs_list);
|
self.editor.insert_string(data, attrs_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(&mut self, action: Action) {
|
fn action(&mut self, font_system: &FontSystem, action: Action) {
|
||||||
self.editor.action(action);
|
self.editor.action(font_system, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the editor
|
/// Draw the editor
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
fn draw<F>(&self, cache: &mut crate::SwashCache, _color: Color, mut f: F)
|
fn draw<F>(
|
||||||
where
|
&self,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
cache: &mut crate::SwashCache,
|
||||||
|
_color: Color,
|
||||||
|
mut f: F,
|
||||||
|
) where
|
||||||
F: FnMut(i32, i32, u32, u32, Color),
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
{
|
{
|
||||||
let size = self.buffer().size();
|
let size = self.buffer().size();
|
||||||
f(0, 0, size.0 as u32, size.1 as u32, self.background_color());
|
f(0, 0, size.0 as u32, size.1 as u32, self.background_color());
|
||||||
self.editor.draw(cache, self.foreground_color(), f);
|
self.editor
|
||||||
|
.draw(font_system, cache, self.foreground_color(), f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> BorrowedWithFontSystem<'b, SyntaxEditor<'a>> {
|
||||||
|
/// Load text from a file, and also set syntax to the best option
|
||||||
|
///
|
||||||
|
/// ## Errors
|
||||||
|
///
|
||||||
|
/// Returns an [`io::Error`] if reading the file fails
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn load_text<P: AsRef<Path>>(&mut self, path: P, attrs: crate::Attrs) -> io::Result<()> {
|
||||||
|
self.inner.load_text(self.font_system, path, attrs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
107
src/edit/vi.rs
107
src/edit/vi.rs
|
|
@ -2,7 +2,10 @@ use alloc::string::String;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use crate::{Action, AttrsList, Buffer, Color, Cursor, Edit, SyntaxEditor};
|
use crate::{
|
||||||
|
Action, AttrsList, BorrowedWithFontSystem, Buffer, Color, Cursor, Edit, FontSystem,
|
||||||
|
SyntaxEditor,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
|
|
@ -26,14 +29,14 @@ impl<'a> ViEditor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load text from a file, and also set syntax to the best option
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn load_text<P: AsRef<std::path::Path>>(
|
pub(crate) fn load_text<P: AsRef<std::path::Path>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
font_system: &FontSystem,
|
||||||
path: P,
|
path: P,
|
||||||
attrs: crate::Attrs<'a>,
|
attrs: crate::Attrs,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
self.editor.load_text(path, attrs)
|
self.editor.load_text(font_system, path, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the default background color
|
/// Get the default background color
|
||||||
|
|
@ -47,12 +50,12 @@ impl<'a> ViEditor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Edit<'a> for ViEditor<'a> {
|
impl<'a> Edit for ViEditor<'a> {
|
||||||
fn buffer(&self) -> &Buffer<'a> {
|
fn buffer(&self) -> &Buffer {
|
||||||
self.editor.buffer()
|
self.editor.buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_mut(&mut self) -> &mut Buffer<'a> {
|
fn buffer_mut(&mut self) -> &mut Buffer {
|
||||||
self.editor.buffer_mut()
|
self.editor.buffer_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +71,8 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
self.editor.set_select_opt(select_opt);
|
self.editor.set_select_opt(select_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape_as_needed(&mut self) {
|
fn shape_as_needed(&mut self, font_system: &FontSystem) {
|
||||||
self.editor.shape_as_needed()
|
self.editor.shape_as_needed(font_system);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_selection(&mut self) -> Option<String> {
|
fn copy_selection(&mut self) -> Option<String> {
|
||||||
|
|
@ -84,7 +87,7 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
self.editor.insert_string(data, attrs_list);
|
self.editor.insert_string(data, attrs_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(&mut self, action: Action) {
|
fn action(&mut self, font_system: &FontSystem, action: Action) {
|
||||||
let old_mode = self.mode;
|
let old_mode = self.mode;
|
||||||
|
|
||||||
match self.mode {
|
match self.mode {
|
||||||
|
|
@ -92,18 +95,18 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
Action::Insert(c) => match c {
|
Action::Insert(c) => match c {
|
||||||
// Enter insert mode after cursor
|
// Enter insert mode after cursor
|
||||||
'a' => {
|
'a' => {
|
||||||
self.editor.action(Action::Right);
|
self.editor.action(font_system, Action::Right);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
}
|
}
|
||||||
// Enter insert mode at end of line
|
// Enter insert mode at end of line
|
||||||
'A' => {
|
'A' => {
|
||||||
self.editor.action(Action::End);
|
self.editor.action(font_system, Action::End);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
}
|
}
|
||||||
// Change mode
|
// Change mode
|
||||||
'c' => {
|
'c' => {
|
||||||
if self.editor.select_opt().is_some() {
|
if self.editor.select_opt().is_some() {
|
||||||
self.editor.action(Action::Delete);
|
self.editor.action(font_system, Action::Delete);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
} else {
|
} else {
|
||||||
//TODO: change to next cursor movement
|
//TODO: change to next cursor movement
|
||||||
|
|
@ -112,7 +115,7 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
// Delete mode
|
// Delete mode
|
||||||
'd' => {
|
'd' => {
|
||||||
if self.editor.select_opt().is_some() {
|
if self.editor.select_opt().is_some() {
|
||||||
self.editor.action(Action::Delete);
|
self.editor.action(font_system, Action::Delete);
|
||||||
} else {
|
} else {
|
||||||
//TODO: delete to next cursor movement
|
//TODO: delete to next cursor movement
|
||||||
}
|
}
|
||||||
|
|
@ -124,33 +127,33 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
// Enter insert mode at start of line
|
// Enter insert mode at start of line
|
||||||
'I' => {
|
'I' => {
|
||||||
//TODO: soft home, skip whitespace
|
//TODO: soft home, skip whitespace
|
||||||
self.editor.action(Action::Home);
|
self.editor.action(font_system, Action::Home);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
}
|
}
|
||||||
// Create line after and enter insert mode
|
// Create line after and enter insert mode
|
||||||
'o' => {
|
'o' => {
|
||||||
self.editor.action(Action::End);
|
self.editor.action(font_system, Action::End);
|
||||||
self.editor.action(Action::Enter);
|
self.editor.action(font_system, Action::Enter);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
}
|
}
|
||||||
// Create line before and enter insert mode
|
// Create line before and enter insert mode
|
||||||
'O' => {
|
'O' => {
|
||||||
self.editor.action(Action::Home);
|
self.editor.action(font_system, Action::Home);
|
||||||
self.editor.action(Action::Enter);
|
self.editor.action(font_system, Action::Enter);
|
||||||
self.editor.shape_as_needed(); // TODO: do not require this?
|
self.editor.shape_as_needed(font_system); // TODO: do not require this?
|
||||||
self.editor.action(Action::Up);
|
self.editor.action(font_system, Action::Up);
|
||||||
self.mode = Mode::Insert;
|
self.mode = Mode::Insert;
|
||||||
}
|
}
|
||||||
// Left
|
// Left
|
||||||
'h' => self.editor.action(Action::Left),
|
'h' => self.editor.action(font_system, Action::Left),
|
||||||
// Top of screen
|
// Top of screen
|
||||||
//TODO: 'H' => self.editor.action(Action::ScreenHigh),
|
//TODO: 'H' => self.editor.action(Action::ScreenHigh),
|
||||||
// Down
|
// Down
|
||||||
'j' => self.editor.action(Action::Down),
|
'j' => self.editor.action(font_system, Action::Down),
|
||||||
// Up
|
// Up
|
||||||
'k' => self.editor.action(Action::Up),
|
'k' => self.editor.action(font_system, Action::Up),
|
||||||
// Right
|
// Right
|
||||||
'l' => self.editor.action(Action::Right),
|
'l' => self.editor.action(font_system, Action::Right),
|
||||||
// Bottom of screen
|
// Bottom of screen
|
||||||
//TODO: 'L' => self.editor.action(Action::ScreenLow),
|
//TODO: 'L' => self.editor.action(Action::ScreenLow),
|
||||||
// Middle of screen
|
// Middle of screen
|
||||||
|
|
@ -168,23 +171,23 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
if self.editor.select_opt().is_some() {
|
if self.editor.select_opt().is_some() {
|
||||||
self.editor.set_select_opt(None);
|
self.editor.set_select_opt(None);
|
||||||
} else {
|
} else {
|
||||||
self.editor.action(Action::Home);
|
self.editor.action(font_system, Action::Home);
|
||||||
self.editor.set_select_opt(Some(self.editor.cursor()));
|
self.editor.set_select_opt(Some(self.editor.cursor()));
|
||||||
//TODO: set cursor_x_opt to max
|
//TODO: set cursor_x_opt to max
|
||||||
self.editor.action(Action::End);
|
self.editor.action(font_system, Action::End);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove character at cursor
|
// Remove character at cursor
|
||||||
'x' => self.editor.action(Action::Delete),
|
'x' => self.editor.action(font_system, Action::Delete),
|
||||||
// Remove character before cursor
|
// Remove character before cursor
|
||||||
'X' => self.editor.action(Action::Backspace),
|
'X' => self.editor.action(font_system, Action::Backspace),
|
||||||
// Go to start of line
|
// Go to start of line
|
||||||
'0' => self.editor.action(Action::Home),
|
'0' => self.editor.action(font_system, Action::Home),
|
||||||
// Go to end of line
|
// Go to end of line
|
||||||
'$' => self.editor.action(Action::End),
|
'$' => self.editor.action(font_system, Action::End),
|
||||||
// Go to start of line after whitespace
|
// Go to start of line after whitespace
|
||||||
//TODO: implement this
|
//TODO: implement this
|
||||||
'^' => self.editor.action(Action::Home),
|
'^' => self.editor.action(font_system, Action::Home),
|
||||||
// Enter command mode
|
// Enter command mode
|
||||||
':' => {
|
':' => {
|
||||||
self.mode = Mode::Command;
|
self.mode = Mode::Command;
|
||||||
|
|
@ -199,18 +202,18 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
_ => self.editor.action(action),
|
_ => self.editor.action(font_system, action),
|
||||||
},
|
},
|
||||||
Mode::Insert => match action {
|
Mode::Insert => match action {
|
||||||
Action::Escape => {
|
Action::Escape => {
|
||||||
let cursor = self.cursor();
|
let cursor = self.cursor();
|
||||||
let layout_cursor = self.buffer().layout_cursor(&cursor);
|
let layout_cursor = self.buffer().layout_cursor(&cursor);
|
||||||
if layout_cursor.glyph > 0 {
|
if layout_cursor.glyph > 0 {
|
||||||
self.editor.action(Action::Left);
|
self.editor.action(font_system, Action::Left);
|
||||||
}
|
}
|
||||||
self.mode = Mode::Normal;
|
self.mode = Mode::Normal;
|
||||||
}
|
}
|
||||||
_ => self.editor.action(action),
|
_ => self.editor.action(font_system, action),
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
//TODO: other modes
|
//TODO: other modes
|
||||||
|
|
@ -224,8 +227,13 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
|
fn draw<F>(
|
||||||
where
|
&self,
|
||||||
|
font_system: &FontSystem,
|
||||||
|
cache: &mut crate::SwashCache,
|
||||||
|
color: Color,
|
||||||
|
mut f: F,
|
||||||
|
) where
|
||||||
F: FnMut(i32, i32, u32, u32, Color),
|
F: FnMut(i32, i32, u32, u32, Color),
|
||||||
{
|
{
|
||||||
let font_size = self.buffer().metrics().font_size;
|
let font_size = self.buffer().metrics().font_size;
|
||||||
|
|
@ -421,15 +429,22 @@ impl<'a> Edit<'a> for ViEditor<'a> {
|
||||||
None => color,
|
None => color,
|
||||||
};
|
};
|
||||||
|
|
||||||
cache.with_pixels(
|
cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| {
|
||||||
self.buffer().font_system(),
|
f(x_int + x, line_y as i32 + y_int + y, 1, 1, color);
|
||||||
cache_key,
|
});
|
||||||
glyph_color,
|
|
||||||
|x, y, color| {
|
|
||||||
f(x_int + x, line_y as i32 + y_int + y, 1, 1, color);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> BorrowedWithFontSystem<'b, ViEditor<'a>> {
|
||||||
|
/// Load text from a file, and also set syntax to the best option
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn load_text<P: AsRef<std::path::Path>>(
|
||||||
|
&mut self,
|
||||||
|
path: P,
|
||||||
|
attrs: crate::Attrs,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
self.inner.load_text(self.font_system, path, attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
pub use self::no_std::*;
|
pub use self::no_std::*;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
|
|
@ -10,3 +12,22 @@ mod std;
|
||||||
|
|
||||||
// re-export fontdb
|
// re-export fontdb
|
||||||
pub use fontdb;
|
pub use fontdb;
|
||||||
|
|
||||||
|
pub struct BorrowedWithFontSystem<'a, T> {
|
||||||
|
pub(crate) inner: &'a mut T,
|
||||||
|
pub(crate) font_system: &'a FontSystem,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Deref for BorrowedWithFontSystem<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> DerefMut for BorrowedWithFontSystem<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue