mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 01:18:21 +00:00
move syntax highlighting into compononent (see #725)
This commit is contained in:
parent
afa10fe756
commit
eab8fc202b
3 changed files with 172 additions and 79 deletions
|
|
@ -20,6 +20,7 @@ mod rename_branch;
|
|||
mod reset;
|
||||
mod revision_files;
|
||||
mod stashmsg;
|
||||
mod syntax_text;
|
||||
mod tag_commit;
|
||||
mod textinput;
|
||||
mod utils;
|
||||
|
|
@ -45,6 +46,7 @@ pub use rename_branch::RenameBranchComponent;
|
|||
pub use reset::ResetComponent;
|
||||
pub use revision_files::RevisionFilesComponent;
|
||||
pub use stashmsg::StashMsgComponent;
|
||||
pub use syntax_text::SyntaxTextComponent;
|
||||
pub use tag_commit::TagCommitComponent;
|
||||
pub use textinput::{InputType, TextInputComponent};
|
||||
pub use utils::filetree::FileTreeItemKind;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use super::{
|
||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||
DrawableComponent, EventState,
|
||||
DrawableComponent, EventState, SyntaxTextComponent,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
queue::{InternalEvent, Queue},
|
||||
strings::{self, order},
|
||||
ui::{self, style::SharedTheme, AsyncSyntaxJob},
|
||||
ui::{self, style::SharedTheme},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use async_utils::AsyncSingleJob;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitId, TreeFile},
|
||||
AsyncNotification, CWD,
|
||||
|
|
@ -17,15 +16,14 @@ use asyncgit::{
|
|||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use filetree::{FileTree, MoveSelection};
|
||||
use itertools::Either;
|
||||
use std::{
|
||||
cell::Cell, collections::BTreeSet, convert::From, path::Path,
|
||||
};
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
text::{Span, Text},
|
||||
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
||||
text::Span,
|
||||
widgets::{Block, Borders, Clear},
|
||||
Frame,
|
||||
};
|
||||
|
||||
|
|
@ -39,9 +37,8 @@ pub struct RevisionFilesComponent {
|
|||
theme: SharedTheme,
|
||||
//TODO: store TreeFiles in `tree`
|
||||
files: Vec<TreeFile>,
|
||||
current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
||||
async_highlighting:
|
||||
AsyncSingleJob<AsyncSyntaxJob, AsyncNotification>,
|
||||
// current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
||||
current_file: SyntaxTextComponent,
|
||||
tree: FileTree,
|
||||
scroll_top: Cell<usize>,
|
||||
revision: Option<CommitId>,
|
||||
|
|
@ -61,13 +58,12 @@ impl RevisionFilesComponent {
|
|||
queue: queue.clone(),
|
||||
title: String::new(),
|
||||
tree: FileTree::default(),
|
||||
async_highlighting: AsyncSingleJob::new(
|
||||
sender.clone(),
|
||||
AsyncNotification::SyntaxHighlighting,
|
||||
scroll_top: Cell::new(0),
|
||||
current_file: SyntaxTextComponent::new(
|
||||
sender,
|
||||
key_config.clone(),
|
||||
),
|
||||
theme,
|
||||
scroll_top: Cell::new(0),
|
||||
current_file: None,
|
||||
files: Vec::new(),
|
||||
revision: None,
|
||||
visible: false,
|
||||
|
|
@ -99,24 +95,12 @@ impl RevisionFilesComponent {
|
|||
|
||||
///
|
||||
pub fn update(&mut self, ev: AsyncNotification) {
|
||||
if ev == AsyncNotification::SyntaxHighlighting {
|
||||
if let Some(job) = self.async_highlighting.get_last() {
|
||||
if let Some((path, content)) =
|
||||
self.current_file.as_mut()
|
||||
{
|
||||
if let Some(syntax) = (*job.text).clone() {
|
||||
if syntax.path() == Path::new(path) {
|
||||
*content = Either::Left(syntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.current_file.update(ev);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn any_work_pending(&self) -> bool {
|
||||
self.async_highlighting.is_pending()
|
||||
self.current_file.any_work_pending()
|
||||
}
|
||||
|
||||
fn tree_item_to_span<'a>(
|
||||
|
|
@ -170,48 +154,15 @@ impl RevisionFilesComponent {
|
|||
.unwrap_or_default()
|
||||
.to_string()
|
||||
}) {
|
||||
let already_loaded = self
|
||||
.current_file
|
||||
.as_ref()
|
||||
.map(|(current_file, _)| current_file == &file)
|
||||
.unwrap_or_default();
|
||||
|
||||
if !already_loaded {
|
||||
self.load_file(file);
|
||||
if let Some(item) = self
|
||||
.files
|
||||
.iter()
|
||||
.find(|f| f.path.ends_with(Path::new(&file)))
|
||||
{
|
||||
self.current_file.load_file(file, item);
|
||||
}
|
||||
} else {
|
||||
self.current_file = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn load_file(&mut self, path: String) {
|
||||
let path_path = Path::new(&path);
|
||||
if let Some(item) =
|
||||
self.files.iter().find(|f| f.path.ends_with(path_path))
|
||||
{
|
||||
//TODO: fetch file content async aswell
|
||||
match sync::tree_file_content(CWD, item) {
|
||||
Ok(content) => {
|
||||
self.async_highlighting.spawn(
|
||||
AsyncSyntaxJob::new(
|
||||
content.clone(),
|
||||
path.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
self.current_file =
|
||||
Some((path, Either::Right(content)))
|
||||
}
|
||||
Err(e) => {
|
||||
self.current_file = Some((
|
||||
path,
|
||||
Either::Right(format!(
|
||||
"error loading file: {}",
|
||||
e
|
||||
)),
|
||||
))
|
||||
}
|
||||
}
|
||||
self.current_file.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -281,17 +232,7 @@ impl DrawableComponent for RevisionFilesComponent {
|
|||
items,
|
||||
);
|
||||
|
||||
let content = Paragraph::new(
|
||||
self.current_file.as_ref().map_or_else(
|
||||
|| Text::from(""),
|
||||
|(_, content)| match content {
|
||||
Either::Left(syn) => syn.into(),
|
||||
Either::Right(s) => Text::from(s.as_str()),
|
||||
},
|
||||
),
|
||||
)
|
||||
.wrap(Wrap { trim: false });
|
||||
f.render_widget(content, chunks[1]);
|
||||
self.current_file.draw(f, chunks[1])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
150
src/components/syntax_text.rs
Normal file
150
src/components/syntax_text.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use super::{
|
||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||
EventState,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
ui::{self, AsyncSyntaxJob},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use async_utils::AsyncSingleJob;
|
||||
use asyncgit::{
|
||||
sync::{self, TreeFile},
|
||||
AsyncNotification, CWD,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use itertools::Either;
|
||||
use std::{convert::From, path::Path};
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::Rect,
|
||||
text::Text,
|
||||
widgets::{Paragraph, Wrap},
|
||||
Frame,
|
||||
};
|
||||
|
||||
pub struct SyntaxTextComponent {
|
||||
current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
||||
async_highlighting:
|
||||
AsyncSingleJob<AsyncSyntaxJob, AsyncNotification>,
|
||||
_key_config: SharedKeyConfig,
|
||||
}
|
||||
|
||||
impl SyntaxTextComponent {
|
||||
///
|
||||
pub fn new(
|
||||
sender: &Sender<AsyncNotification>,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
async_highlighting: AsyncSingleJob::new(
|
||||
sender.clone(),
|
||||
AsyncNotification::SyntaxHighlighting,
|
||||
),
|
||||
current_file: None,
|
||||
_key_config: key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self, ev: AsyncNotification) {
|
||||
if ev == AsyncNotification::SyntaxHighlighting {
|
||||
if let Some(job) = self.async_highlighting.get_last() {
|
||||
if let Some((path, content)) =
|
||||
self.current_file.as_mut()
|
||||
{
|
||||
if let Some(syntax) = (*job.text).clone() {
|
||||
if syntax.path() == Path::new(path) {
|
||||
*content = Either::Left(syntax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn any_work_pending(&self) -> bool {
|
||||
self.async_highlighting.is_pending()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn clear(&mut self) {
|
||||
self.current_file = None;
|
||||
}
|
||||
|
||||
///
|
||||
pub fn load_file(&mut self, path: String, item: &TreeFile) {
|
||||
let already_loaded = self
|
||||
.current_file
|
||||
.as_ref()
|
||||
.map(|(current_file, _)| current_file == &path)
|
||||
.unwrap_or_default();
|
||||
|
||||
if !already_loaded {
|
||||
//TODO: fetch file content async aswell
|
||||
match sync::tree_file_content(CWD, item) {
|
||||
Ok(content) => {
|
||||
self.async_highlighting.spawn(
|
||||
AsyncSyntaxJob::new(
|
||||
content.clone(),
|
||||
path.clone(),
|
||||
),
|
||||
);
|
||||
|
||||
self.current_file =
|
||||
Some((path, Either::Right(content)))
|
||||
}
|
||||
Err(e) => {
|
||||
self.current_file = Some((
|
||||
path,
|
||||
Either::Right(format!(
|
||||
"error loading file: {}",
|
||||
e
|
||||
)),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for SyntaxTextComponent {
|
||||
fn draw<B: Backend>(
|
||||
&self,
|
||||
f: &mut Frame<B>,
|
||||
area: Rect,
|
||||
) -> Result<()> {
|
||||
let content =
|
||||
Paragraph::new(self.current_file.as_ref().map_or_else(
|
||||
|| Text::from(""),
|
||||
|(_, content)| match content {
|
||||
Either::Left(syn) => syn.into(),
|
||||
Either::Right(s) => Text::from(s.as_str()),
|
||||
},
|
||||
))
|
||||
.wrap(Wrap { trim: false });
|
||||
f.render_widget(content, area);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for SyntaxTextComponent {
|
||||
fn commands(
|
||||
&self,
|
||||
_out: &mut Vec<CommandInfo>,
|
||||
_force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
//TODO: scrolling
|
||||
CommandBlocking::PassingOn
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
_event: crossterm::event::Event,
|
||||
) -> Result<EventState> {
|
||||
//TODO: scrolling
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue