update in a loop

This commit is contained in:
Stephan Dilly 2020-03-16 23:03:13 +01:00
parent c5e7b1b8ae
commit 955ef55d8d
5 changed files with 127 additions and 49 deletions

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"editor.formatOnSave": true,
"workbench.settings.enableNaturalLanguageSearch": false,
"telemetry.enableTelemetry": false,
}

View file

@ -1,8 +1,8 @@
use crate::git_status::StatusLists;
use crate::git_utils;
use crate::git_utils::Diff;
use crate::git_utils::DiffLine;
use crossterm::event::{Event, KeyCode};
use git2::{Repository, Status};
use git_utils::DiffLineType;
use std::cmp;
use std::path::Path;
@ -16,8 +16,7 @@ use tui::{
#[derive(Default)]
pub struct App {
status_items: Vec<String>,
index_items: Vec<String>,
status: StatusLists,
status_select: Option<usize>,
diff: Diff,
offset: u16,
@ -32,49 +31,27 @@ impl App {
}
impl App {
//
pub fn fetch_status(&mut self) {
let repo = match Repository::init("./") {
Ok(repo) => repo,
Err(e) => panic!("failed to init: {}", e),
};
///
fn fetch_status(&mut self) {
let new_status = StatusLists::new();
if repo.is_bare() {
panic!("bare repo")
}
if self.status != new_status {
self.status = new_status;
let statuses = repo.statuses(None).unwrap();
self.status_items = Vec::new();
self.index_items = Vec::new();
for e in statuses.iter() {
let status: Status = e.status();
if status.is_ignored() {
continue;
}
if git_utils::on_index(&status) {
self.index_items
.push(format!("{} ({:?})", e.path().unwrap().to_string(), status))
self.status_select = if self.status.wt_items.len() > 0 {
Some(0)
} else {
self.status_items.push(e.path().unwrap().to_string())
}
None
};
}
self.status_select = if self.status_items.len() > 0 {
Some(0)
} else {
None
};
self.update_diff();
}
///
fn update_diff(&mut self) {
let new_diff = match self.status_select {
Some(i) => git_utils::get_diff(Path::new(self.status_items[i].as_str())),
Some(i) => git_utils::get_diff(Path::new(self.status.wt_items[i].path.as_str())),
None => Diff::default(),
};
@ -100,7 +77,7 @@ impl App {
f,
left_chunks[0],
"Status".to_string(),
self.status_items.as_slice(),
self.status.wt_items_pathlist().as_slice(),
self.status_select,
);
@ -108,7 +85,7 @@ impl App {
f,
left_chunks[1],
"Index".to_string(),
self.index_items.as_slice(),
self.status.index_items_pathlist().as_slice(),
None,
);
@ -173,8 +150,12 @@ impl App {
}
}
pub fn update(&mut self) {
self.fetch_status();
}
fn input(&mut self, delta: i32) {
let items_len = self.status_items.len();
let items_len = self.status.wt_items.len();
if items_len > 0 {
if let Some(i) = self.status_select {
let mut i = i as i32;

85
src/git_status.rs Normal file
View file

@ -0,0 +1,85 @@
use crate::git_utils;
use git2::Repository;
use git2::{Status, StatusOptions, StatusShow};
#[derive(PartialEq)]
pub enum StatusItemType {
New,
Modified,
Deleted,
Renamed,
Typechange,
}
impl From<Status> for StatusItemType {
fn from(s: Status) -> Self {
if s.is_index_new() || s.is_wt_new() {
Self::New
} else if s.is_index_deleted() || s.is_wt_deleted() {
Self::Deleted
} else if s.is_index_renamed() || s.is_wt_renamed() {
Self::Renamed
} else if s.is_index_typechange() || s.is_wt_typechange() {
Self::Typechange
} else {
Self::Modified
}
}
}
#[derive(Default, PartialEq)]
pub struct StatusItem {
pub path: String,
pub status: Option<StatusItemType>,
}
#[derive(Default, PartialEq)]
pub struct StatusLists {
pub wt_items: Vec<StatusItem>,
pub index_items: Vec<StatusItem>,
}
impl StatusLists {
///
pub fn new() -> Self {
let mut res = Self::default();
let repo = git_utils::repo();
res.wt_items = Self::get(&repo, StatusShow::Workdir);
res.index_items = Self::get(&repo, StatusShow::Index);
res
}
fn get(repo: &Repository, show: StatusShow) -> Vec<StatusItem> {
let mut res = Vec::new();
let statuses = repo
.statuses(Some(StatusOptions::default().show(show)))
.unwrap();
for e in statuses.iter() {
let status: Status = e.status();
if status.is_ignored() {
continue;
}
res.push(StatusItem {
path: e.path().unwrap().to_string(),
status: Some(StatusItemType::from(status)),
});
}
res
}
///
pub fn wt_items_pathlist(&self) -> Vec<String> {
self.wt_items.iter().map(|e| e.path.clone()).collect()
}
///
pub fn index_items_pathlist(&self) -> Vec<String> {
self.index_items.iter().map(|e| e.path.clone()).collect()
}
}

View file

@ -1,6 +1,7 @@
use git2::{DiffFormat, DiffOptions, Repository, Status};
use git2::{DiffFormat, DiffOptions, Repository};
use std::path::Path;
///
#[derive(Copy, Clone, PartialEq)]
pub enum DiffLineType {
None,
@ -15,22 +16,20 @@ impl Default for DiffLineType {
}
}
///
#[derive(Default, PartialEq)]
pub struct DiffLine {
pub content: String,
pub line_type: DiffLineType,
}
///
#[derive(Default, PartialEq)]
pub struct Diff(pub Vec<DiffLine>);
///
pub fn get_diff(p: &Path) -> Diff {
let repo = Repository::init("./").unwrap();
if repo.is_bare() {
panic!("bare repo")
}
let repo = repo();
let mut opt = DiffOptions::new();
opt.pathspec(p);
@ -72,6 +71,12 @@ pub fn get_diff(p: &Path) -> Diff {
}
///
pub fn on_index(s: &Status) -> bool {
s.is_index_new() || s.is_index_modified()
pub fn repo() -> Repository {
let repo = Repository::init("./").unwrap();
if repo.is_bare() {
panic!("bare repo")
}
repo
}

View file

@ -1,15 +1,16 @@
mod app;
mod poll;
mod git_status;
mod git_utils;
mod poll;
use app::App;
use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand, Result,
};
use poll::PollResult;
use std::{io, time::Duration};
use tui::{backend::CrosstermBackend, Terminal};
use poll::PollResult;
fn main() -> Result<()> {
enable_raw_mode()?;
@ -22,9 +23,10 @@ fn main() -> Result<()> {
terminal.clear()?;
let mut app = App::default();
app.fetch_status();
loop {
app.update();
terminal.draw(|mut f| app.draw(&mut f))?;
if let PollResult::Event(e) = poll::poll(Duration::from_millis(200)) {