aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml84
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/app/impl_self.rs8
-rw-r--r--src/app/impl_view.rs19
-rw-r--r--src/command.rs74
6 files changed, 157 insertions, 32 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..c8ccbae
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,84 @@
1name: Rust
2
3on:
4 push:
5 tags:
6 - '*'
7
8jobs:
9 rustfmt:
10 runs-on: ubuntu-latest
11 steps:
12 - uses: actions/checkout@v1
13 - run: rustup component add rustfmt
14 - run: cargo fmt -- --check
15
16 build-linux:
17 runs-on: ubuntu-latest
18
19 steps:
20 - name: Checkout
21 uses: actions/checkout@v1
22 # cache the build assets so they dont recompile every time.
23 - name: Cache Rust dependencies
24 uses: actions/[email protected]
25 with:
26 path: target
27 key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
28 restore-keys: |
29 ${{ runner.OS }}-build-
30 - name: Install latest rust toolchain
31 uses: actions-rs/toolchain@v1
32 with:
33 toolchain: beta
34 default: true
35 override: true
36 - name: Install system dependencies
37 run: |
38 sudo apt-get update \
39 && sudo apt-get install -y \
40 libdbus-1-dev
41 - name: Build
42 run: cargo build --all --release && strip target/release/dijo
43
44 - name: Upload binaries to release
45 uses: svenstaro/upload-release-action@v1-release
46 with:
47 repo_token: ${{ secrets.GITHUB_TOKEN }}
48 file: target/release/dijo
49 asset_name: dijo-x86_64-linux
50 tag: ${{ github.ref }}
51 overwrite: true
52
53 build-apple:
54 runs-on: macos-latest
55
56 steps:
57 - name: Checkout
58 uses: actions/checkout@v1
59 - name: Cache Rust dependencies
60 uses: actions/[email protected]
61 with:
62 path: target
63 key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
64 restore-keys: |
65 ${{ runner.OS }}-build-
66 - name: Install latest rust toolchain
67 uses: actions-rs/toolchain@v1
68 with:
69 toolchain: beta
70 target: x86_64-apple-darwin
71 default: true
72 override: true
73
74 - name: Build for mac
75 run: cargo build --all --release && strip target/release/dijo
76
77 - name: Upload binaries to release
78 uses: svenstaro/upload-release-action@v1-release
79 with:
80 repo_token: ${{ secrets.GITHUB_TOKEN }}
81 file: target/release/dijo
82 asset_name: dijo-x86_64-apple
83 tag: ${{ github.ref }}
84 overwrite: true
diff --git a/Cargo.lock b/Cargo.lock
index bda3c1e..a299289 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -260,7 +260,7 @@ dependencies = [
260 260
261[[package]] 261[[package]]
262name = "dijo" 262name = "dijo"
263version = "0.1.5" 263version = "0.2.0"
264dependencies = [ 264dependencies = [
265 "chrono", 265 "chrono",
266 "clap", 266 "clap",
diff --git a/Cargo.toml b/Cargo.toml
index 3f297b8..f215503 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "dijo" 2name = "dijo"
3version = "0.1.5" 3version = "0.2.0"
4authors = ["Akshay <[email protected]>"] 4authors = ["Akshay <[email protected]>"]
5edition = "2018" 5edition = "2018"
6description = "Scriptable, curses-based, digital habit tracker" 6description = "Scriptable, curses-based, digital habit tracker"
diff --git a/src/app/impl_self.rs b/src/app/impl_self.rs
index 8a84cb2..1dfe268 100644
--- a/src/app/impl_self.rs
+++ b/src/app/impl_self.rs
@@ -54,6 +54,10 @@ impl App {
54 } 54 }
55 } 55 }
56 56
57 pub fn list_habits(&self) -> Vec<String> {
58 self.habits.iter().map(|x| x.name()).collect::<Vec<_>>()
59 }
60
57 pub fn delete_by_name(&mut self, name: &str) { 61 pub fn delete_by_name(&mut self, name: &str) {
58 let old_len = self.habits.len(); 62 let old_len = self.habits.len();
59 self.habits.retain(|h| h.name() != name); 63 self.habits.retain(|h| h.name() != name);
@@ -141,7 +145,7 @@ impl App {
141 let completed = total - remaining; 145 let completed = total - remaining;
142 146
143 let timestamp = if self.view_month_offset == 0 { 147 let timestamp = if self.view_month_offset == 0 {
144 format!("{}", Local::now().date().format("%d/%b/%y"),) 148 format!("{}", Local::now().naive_local().date().format("%d/%b/%y"),)
145 } else { 149 } else {
146 let months = self.view_month_offset; 150 let months = self.view_month_offset;
147 format!("{}", format!("{} months ago", months),) 151 format!("{}", format!("{} months ago", months),)
@@ -270,7 +274,7 @@ impl App {
270 self.message.set_message("help <command>|commands|keys") 274 self.message.set_message("help <command>|commands|keys")
271 } 275 }
272 } 276 }
273 Command::Quit => self.save_state(), 277 Command::Quit | Command::Write => self.save_state(),
274 Command::MonthNext => self.sift_forward(), 278 Command::MonthNext => self.sift_forward(),
275 Command::MonthPrev => self.sift_backward(), 279 Command::MonthPrev => self.sift_backward(),
276 Command::Blank => {} 280 Command::Blank => {}
diff --git a/src/app/impl_view.rs b/src/app/impl_view.rs
index 892b00c..0dfd20b 100644
--- a/src/app/impl_view.rs
+++ b/src/app/impl_view.rs
@@ -102,25 +102,6 @@ impl View for App {
102 self.set_focus(Absolute::Down); 102 self.set_focus(Absolute::Down);
103 return EventResult::Consumed(None); 103 return EventResult::Consumed(None);
104 } 104 }
105 Event::Char('d') => {
106 if self.habits.is_empty() {
107 return EventResult::Consumed(None);
108 }
109 self.habits.remove(self.focus);
110 self.focus = self.focus.checked_sub(1).unwrap_or(0);
111 return EventResult::Consumed(None);
112 }
113 Event::Char('w') => {
114 // helper bind to test write to file
115 let j = serde_json::to_string_pretty(&self.habits).unwrap();
116 let mut file = File::create("foo.txt").unwrap();
117 file.write_all(j.as_bytes()).unwrap();
118 return EventResult::Consumed(None);
119 }
120 Event::Char('q') => {
121 self.save_state();
122 return EventResult::with_cb(|s| s.quit());
123 }
124 Event::Char('v') => { 105 Event::Char('v') => {
125 if self.habits.is_empty() { 106 if self.habits.is_empty() {
126 return EventResult::Consumed(None); 107 return EventResult::Consumed(None);
diff --git a/src/command.rs b/src/command.rs
index 29908f4..38d48e9 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -1,21 +1,75 @@
1use std::fmt; 1use std::fmt;
2 2
3use cursive::event::{Event, EventResult, Key};
3use cursive::theme::{BaseColor, Color, ColorStyle}; 4use cursive::theme::{BaseColor, Color, ColorStyle};
4use cursive::view::Resizable; 5use cursive::view::Resizable;
5use cursive::views::{EditView, LinearLayout, TextView}; 6use cursive::views::{EditView, LinearLayout, OnEventView, TextView};
6use cursive::Cursive; 7use cursive::Cursive;
7 8
8use crate::{app::App, CONFIGURATION}; 9use crate::{app::App, CONFIGURATION};
9 10
11static COMMANDS: &'static [&'static str] = &[
12 "add",
13 "add-auto",
14 "delete",
15 "track-up",
16 "track-down",
17 "month-prev",
18 "month-next",
19 "quit",
20 "write",
21 "help",
22];
23
24fn get_command_completion(prefix: &str) -> Option<String> {
25 let first_match = COMMANDS.iter().filter(|&x| x.starts_with(prefix)).next();
26 return first_match.map(|&x| x.into());
27}
28
29fn get_habit_completion(prefix: &str, habit_names: &[String]) -> Option<String> {
30 let first_match = habit_names.iter().filter(|&x| x.starts_with(prefix)).next();
31 eprintln!("{:?}| {:?}", prefix, first_match);
32 return first_match.map(|x| x.into());
33}
34
10pub fn open_command_window(s: &mut Cursive) { 35pub fn open_command_window(s: &mut Cursive) {
11 let command_window = EditView::new() 36 let habit_list: Vec<String> = s
12 .filler(" ") 37 .call_on_name("Main", |view: &mut App| {
13 .on_submit(call_on_app) 38 return view.list_habits();
14 .style(ColorStyle::new( 39 })
15 Color::Dark(BaseColor::Black), 40 .unwrap();
16 Color::Dark(BaseColor::White), 41 let style = ColorStyle::new(Color::Dark(BaseColor::Black), Color::Dark(BaseColor::White));
17 )) 42 let command_window = OnEventView::new(
18 .fixed_width(CONFIGURATION.view_width * CONFIGURATION.grid_width); 43 EditView::new()
44 .filler(" ")
45 .on_submit(call_on_app)
46 .style(style),
47 )
48 .on_event_inner(
49 Event::Key(Key::Tab),
50 move |view: &mut EditView, _: &Event| {
51 let contents = view.get_content();
52 if !contents.contains(" ") {
53 let completion = get_command_completion(&*contents);
54 if let Some(c) = completion {
55 let cb = view.set_content(c);
56 return Some(EventResult::Consumed(Some(cb)));
57 };
58 return None;
59 } else {
60 let word = contents.split(' ').last().unwrap();
61 let completion = get_habit_completion(word, &habit_list);
62 eprintln!("{:?} | {:?}", completion, contents);
63 if let Some(c) = completion {
64 let cb =
65 view.set_content(format!("{}", contents) + c.strip_prefix(word).unwrap());
66 return Some(EventResult::Consumed(Some(cb)));
67 };
68 return None;
69 }
70 },
71 )
72 .fixed_width(CONFIGURATION.view_width * CONFIGURATION.grid_width);
19 s.call_on_name("Frame", |view: &mut LinearLayout| { 73 s.call_on_name("Frame", |view: &mut LinearLayout| {
20 let mut commandline = LinearLayout::horizontal() 74 let mut commandline = LinearLayout::horizontal()
21 .child(TextView::new(":")) 75 .child(TextView::new(":"))
@@ -60,6 +114,7 @@ pub enum Command {
60 TrackUp(String), 114 TrackUp(String),
61 TrackDown(String), 115 TrackDown(String),
62 Help(Option<String>), 116 Help(Option<String>),
117 Write,
63 Quit, 118 Quit,
64 Blank, 119 Blank,
65} 120}
@@ -144,6 +199,7 @@ impl Command {
144 "mprev" | "month-prev" => return Ok(Command::MonthPrev), 199 "mprev" | "month-prev" => return Ok(Command::MonthPrev),
145 "mnext" | "month-next" => return Ok(Command::MonthNext), 200 "mnext" | "month-next" => return Ok(Command::MonthNext),
146 "q" | "quit" => return Ok(Command::Quit), 201 "q" | "quit" => return Ok(Command::Quit),
202 "w" | "write" => return Ok(Command::Write),
147 "" => return Ok(Command::Blank), 203 "" => return Ok(Command::Blank),
148 s => return Err(CommandLineError::InvalidCommand(s.into())), 204 s => return Err(CommandLineError::InvalidCommand(s.into())),
149 } 205 }