From 47752720b4404d7618176d57954794469bc91bd2 Mon Sep 17 00:00:00 2001 From: Thomas Eppers Date: Wed, 20 Oct 2021 17:50:12 +0200 Subject: [PATCH] created a new struct for a layout without opening a yaml file --- src/main.rs | 2 +- src/{ui.rs => ui/default.rs} | 22 +----- src/ui/mod.rs | 32 ++++++++ src/ui/no_yaml.rs | 138 +++++++++++++++++++++++++++++++++ src/widget/repo_entry.rs | 2 - src/widget/service_switcher.rs | 14 +--- src/widget/tag_list.rs | 1 - 7 files changed, 178 insertions(+), 33 deletions(-) rename src/{ui.rs => ui/default.rs} (93%) create mode 100644 src/ui/mod.rs create mode 100644 src/ui/no_yaml.rs diff --git a/src/main.rs b/src/main.rs index bbf8b5c..73fff72 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,5 +26,5 @@ pub struct Opt { fn main() { //parse parameter let opt = Opt::from_args(); - ui::Ui::run(&opt); + ui::create_ui(&opt); } diff --git a/src/ui.rs b/src/ui/default.rs similarity index 93% rename from src/ui.rs rename to src/ui/default.rs index 2687547..5d84bba 100644 --- a/src/ui.rs +++ b/src/ui/default.rs @@ -1,8 +1,7 @@ -use std::sync::mpsc; use std::{io, thread}; +use crate::Opt; use termion::event::Key; -use termion::input::TermRead; use termion::raw::IntoRawMode; use tui::backend::TermionBackend; use tui::layout::{Constraint, Direction, Layout}; @@ -12,7 +11,6 @@ use crate::widget::info; use crate::widget::repo_entry; use crate::widget::service_switcher; use crate::widget::tag_list; -use crate::Opt; pub struct Ui { state: State, @@ -56,7 +54,7 @@ impl Ui { state: State::SelectService, repo: repo_entry::RepoEntry::new(repo_id), tags: tag_list::TagList::with_status("Tags are empty"), - services: service_switcher::ServiceSwitcher::new(&opt.config), + services: service_switcher::ServiceSwitcher::new(&opt.config).unwrap(), info: info::Info::new("Select image of edit Repository"), }; @@ -70,7 +68,7 @@ impl Ui { let mut terminal = Terminal::new(backend).unwrap(); //setup input thread - let receiver = ui.spawn_stdin_channel(); + let receiver = super::spawn_stdin_channel(); //core interaction loop 'core: loop { @@ -212,18 +210,4 @@ impl Ui { terminal.clear().unwrap(); } - - /// create a thread for catching input and send them to core loop - pub fn spawn_stdin_channel(&self) -> mpsc::Receiver { - let (tx, rx) = mpsc::channel::(); - - thread::spawn(move || loop { - let stdin = io::stdin(); - for c in stdin.keys() { - tx.send(c.unwrap()).unwrap(); - } - }); - thread::sleep(std::time::Duration::from_millis(64)); - rx - } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 0000000..7a93c24 --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,32 @@ +mod default; +mod no_yaml; + +use std::sync::mpsc; +use std::{io, thread}; + +use crate::Opt; +use termion::input::TermRead; + +use crate::widget::service_switcher; + +pub fn create_ui(opt: &Opt) { + let service_result = service_switcher::ServiceSwitcher::new(&opt.config); + match service_result { + None => no_yaml::NoYaml::run(opt), + Some(_) => default::Ui::run(opt), + } +} + +/// create a thread for catching input and send them to core loop +pub fn spawn_stdin_channel() -> mpsc::Receiver { + let (tx, rx) = mpsc::channel::(); + + thread::spawn(move || loop { + let stdin = io::stdin(); + for c in stdin.keys() { + tx.send(c.unwrap()).unwrap(); + } + }); + thread::sleep(std::time::Duration::from_millis(64)); + rx +} diff --git a/src/ui/no_yaml.rs b/src/ui/no_yaml.rs new file mode 100644 index 0000000..298b64c --- /dev/null +++ b/src/ui/no_yaml.rs @@ -0,0 +1,138 @@ +use std::{io, thread}; + +use termion::event::Key; +use termion::raw::IntoRawMode; +use tui::backend::TermionBackend; +use tui::layout::{Constraint, Direction, Layout}; +use tui::Terminal; + +use crate::widget::info; +use crate::widget::repo_entry; +use crate::widget::tag_list; +use crate::Opt; + +#[derive(PartialEq, Clone)] +pub enum State { + EditRepo, + SelectTag, +} + +impl std::iter::Iterator for State { + type Item = Self; + + fn next(&mut self) -> Option { + match self { + State::EditRepo => *self = State::SelectTag, + State::SelectTag => *self = State::EditRepo, + } + Some(self.clone()) + } +} + +pub struct NoYaml { + state: State, + repo: repo_entry::RepoEntry, + tags: tag_list::TagList, + info: info::Info, +} + +impl NoYaml { + pub fn run(opt: &Opt) { + let (repo, load_repo) = match &opt.repo { + None => ( + repo_entry::RepoEntry::new( + "enter a repository or select one from docker-compose.yml", + ), + false, + ), + Some(repo_id) => (repo_entry::RepoEntry::new(repo_id), true), + }; + + let mut ui = NoYaml { + state: State::EditRepo, + repo, + tags: tag_list::TagList::with_status("Tags are empty"), + info: info::Info::new("edit the Repository widget to load tags"), + }; + + // load tags if a repository was given thorugh paramter + if load_repo { + ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + } + + //setup tui + let stdout = io::stdout().into_raw_mode().unwrap(); + let backend = TermionBackend::new(stdout); + let mut terminal = Terminal::new(backend).unwrap(); + + //setup input thread + let receiver = super::spawn_stdin_channel(); + + //core interaction loop + 'core: loop { + //draw + terminal + .draw(|rect| { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Length(3), + Constraint::Min(7), + Constraint::Length(2), + ] + .as_ref(), + ) + .split(rect.size()); + + rect.render_widget(ui.repo.render(ui.state == State::EditRepo), chunks[0]); + let (list, state) = ui.tags.render(ui.state == State::SelectTag); + rect.render_stateful_widget(list, chunks[1], state); + rect.render_widget(ui.info.render(), chunks[2]); + }) + .unwrap(); + + //handle input + match receiver.try_recv() { + Ok(Key::Ctrl('q')) => break 'core, + Ok(Key::Char('\t')) => { + ui.state.next(); + } + Ok(Key::Ctrl('r')) => { + ui.repo.confirm(); + ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + } + Ok(Key::Ctrl('n')) => match ui.tags.next_page() { + Err(e) => ui.info.set_info(&format!("{}", e)), + Ok(_) => (), + }, + Ok(Key::Ctrl('p')) => match ui.tags.prev_page() { + Err(e) => ui.info.set_info(&format!("{}", e)), + Ok(_) => (), + }, + Ok(Key::Char('\n')) => match ui.state { + State::EditRepo => { + ui.repo.confirm(); + ui.tags = tag_list::TagList::with_repo(ui.repo.get()); + } + _ => (), + }, + Ok(Key::Char(key)) => match ui.state { + State::EditRepo => { + ui.info.set_info("Editing Repository"); + ui.repo.handle_input(Key::Char(key)); + } + State::SelectTag => { + ui.tags.handle_input(Key::Char(key)); + } + }, + _ => (), + } + + //sleep for 32ms (30 fps) + thread::sleep(std::time::Duration::from_millis(32)); + } + + terminal.clear().unwrap(); + } +} diff --git a/src/widget/repo_entry.rs b/src/widget/repo_entry.rs index e49902a..0322c33 100644 --- a/src/widget/repo_entry.rs +++ b/src/widget/repo_entry.rs @@ -3,8 +3,6 @@ use tui::layout::Alignment; use tui::style::{Color, Style}; use tui::widgets::{Block, Borders, Paragraph}; -use crate::ui::State; - pub struct RepoEntry { text: String, old_text: String, diff --git a/src/widget/service_switcher.rs b/src/widget/service_switcher.rs index f68f88d..fa9776e 100644 --- a/src/widget/service_switcher.rs +++ b/src/widget/service_switcher.rs @@ -9,7 +9,6 @@ use tui::style::{Color, Style}; use tui::widgets::{Block, Borders, List, ListState}; use crate::repo; -use crate::ui::State; #[derive(Debug)] pub enum Error { @@ -34,7 +33,7 @@ pub struct ServiceSwitcher { } impl ServiceSwitcher { - pub fn new(file: &Option) -> Self { + pub fn new(file: &Option) -> Option { let mut file_list = vec![ PathBuf::from("docker-compose.yml"), PathBuf::from("docker-compose.yaml"), @@ -55,21 +54,16 @@ impl ServiceSwitcher { } }; - return Self { + return Some(Self { list, state: ListState::default(), changed: false, opened_file: file, - }; + }); } //could not find docker-compose file - Self { - list: vec![format!("No docker-compose file found")], - state: ListState::default(), - changed: false, - opened_file: PathBuf::new(), - } + None } pub fn render(&mut self, colored: bool) -> (List, &mut ListState) { diff --git a/src/widget/tag_list.rs b/src/widget/tag_list.rs index b469a5e..681427d 100644 --- a/src/widget/tag_list.rs +++ b/src/widget/tag_list.rs @@ -5,7 +5,6 @@ use tui::style::{Color, Style}; use tui::widgets::{Block, Borders, List, ListState}; use crate::tags; -use crate::ui::State; #[derive(Debug)] pub enum Error {