Added alarm labels.
This commit is contained in:
parent
320453474c
commit
299ef7fbe6
6 changed files with 155 additions and 75 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -12,13 +12,14 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"termion",
|
"termion",
|
||||||
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
|
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
|
@ -74,3 +75,9 @@ dependencies = [
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"redox_termios",
|
"redox_termios",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||||
|
|
|
@ -9,3 +9,4 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
termion = "1.5.6"
|
termion = "1.5.6"
|
||||||
signal-hook = "0.3.8"
|
signal-hook = "0.3.8"
|
||||||
|
unicode-segmentation = "1.7.1"
|
||||||
|
|
45
src/alarm.rs
45
src/alarm.rs
|
@ -2,8 +2,8 @@ use std::io::Write;
|
||||||
use std::process::{Command, Stdio, Child};
|
use std::process::{Command, Stdio, Child};
|
||||||
use termion::{color, cursor, style};
|
use termion::{color, cursor, style};
|
||||||
use termion::raw::RawTerminal;
|
use termion::raw::RawTerminal;
|
||||||
use crate::{Clock, Config, Layout, Position};
|
use crate::{Clock, Layout, Position};
|
||||||
use crate::common::COLOR;
|
use crate::common::{COLOR, Config, str_length};
|
||||||
|
|
||||||
|
|
||||||
pub struct Countdown {
|
pub struct Countdown {
|
||||||
|
@ -55,7 +55,7 @@ impl Countdown {
|
||||||
|
|
||||||
pub struct Alarm {
|
pub struct Alarm {
|
||||||
time: u32,
|
time: u32,
|
||||||
display: String,
|
label: String,
|
||||||
color_index: usize,
|
color_index: usize,
|
||||||
exceeded: bool,
|
exceeded: bool,
|
||||||
}
|
}
|
||||||
|
@ -78,15 +78,25 @@ impl AlarmRoster {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse string and add as alarm.
|
// Parse string and add as alarm.
|
||||||
pub fn add(&mut self, buffer: &String)
|
pub fn add(&mut self, input: &String) -> Result<(), &str> {
|
||||||
-> Result<(), &str> {
|
|
||||||
|
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
let mut time: u32 = 0;
|
let mut time: u32 = 0;
|
||||||
|
let mut label: String;
|
||||||
|
let time_str: &str;
|
||||||
|
|
||||||
|
if let Some(i) = input.find('/') {
|
||||||
|
label = input[(i + 1)..].trim().to_string();
|
||||||
|
// TODO: Make decision yes/no.
|
||||||
|
//label.truncate(24);
|
||||||
|
time_str = &input[..i].trim();
|
||||||
|
} else {
|
||||||
|
label = input.clone();
|
||||||
|
time_str = &input.trim();
|
||||||
|
}
|
||||||
|
|
||||||
// Parse input into seconds.
|
// Parse input into seconds.
|
||||||
if buffer.find(':').is_some() {
|
if time_str.contains(':') {
|
||||||
for sub in buffer.rsplit(':') {
|
for sub in time_str.rsplit(':') {
|
||||||
if !sub.is_empty() {
|
if !sub.is_empty() {
|
||||||
match sub.parse::<u32>() {
|
match sub.parse::<u32>() {
|
||||||
// Valid.
|
// Valid.
|
||||||
|
@ -101,9 +111,9 @@ impl AlarmRoster {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Parse as seconds only.
|
// Parse as seconds only.
|
||||||
match buffer.parse::<u32>() {
|
match time_str.parse::<u32>() {
|
||||||
Ok(d) => time = d,
|
Ok(d) => time = d,
|
||||||
Err(_) => return Err("Could not parse as <u32>."),
|
Err(_) => return Err("Could not parse as integer."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +121,9 @@ impl AlarmRoster {
|
||||||
if time == 0 { return Err("Evaluates to zero.") };
|
if time == 0 { return Err("Evaluates to zero.") };
|
||||||
if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") };
|
if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") };
|
||||||
|
|
||||||
let mut display = buffer.clone();
|
label.shrink_to_fit();
|
||||||
display.shrink_to_fit();
|
|
||||||
|
|
||||||
let alarm = Alarm {
|
let alarm = Alarm {
|
||||||
display,
|
label,
|
||||||
time,
|
time,
|
||||||
color_index: (self.list.len() % COLOR.len()),
|
color_index: (self.list.len() % COLOR.len()),
|
||||||
exceeded: false,
|
exceeded: false,
|
||||||
|
@ -181,7 +189,7 @@ impl AlarmRoster {
|
||||||
let mut col =
|
let mut col =
|
||||||
layout.roster.col
|
layout.roster.col
|
||||||
+ 3
|
+ 3
|
||||||
+ alarm.display.len() as u16;
|
+ str_length(&alarm.label);
|
||||||
let mut line = layout.roster.line + index;
|
let mut line = layout.roster.line + index;
|
||||||
|
|
||||||
// Compensate for "hidden" items in the alarm roster.
|
// Compensate for "hidden" items in the alarm roster.
|
||||||
|
@ -240,7 +248,7 @@ impl AlarmRoster {
|
||||||
color::Bg(COLOR[alarm.color_index]),
|
color::Bg(COLOR[alarm.color_index]),
|
||||||
color::Bg(color::Reset),
|
color::Bg(color::Reset),
|
||||||
style::Bold,
|
style::Bold,
|
||||||
alarm.display,
|
alarm.label,
|
||||||
style::Reset)
|
style::Reset)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,7 +257,7 @@ impl AlarmRoster {
|
||||||
cursor::Goto(layout.roster.col, layout.roster.line + index),
|
cursor::Goto(layout.roster.col, layout.roster.line + index),
|
||||||
color::Bg(COLOR[alarm.color_index]),
|
color::Bg(COLOR[alarm.color_index]),
|
||||||
color::Bg(color::Reset),
|
color::Bg(color::Reset),
|
||||||
alarm.display)
|
alarm.label)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
index += 1;
|
index += 1;
|
||||||
|
@ -260,7 +268,8 @@ impl AlarmRoster {
|
||||||
pub fn width(&self) -> u16 {
|
pub fn width(&self) -> u16 {
|
||||||
let mut width: u16 = 0;
|
let mut width: u16 = 0;
|
||||||
for alarm in &self.list {
|
for alarm in &self.list {
|
||||||
if alarm.display.len() as u16 > width { width = alarm.display.len() as u16; }
|
let length = str_length(&alarm.label);
|
||||||
|
if length > width { width = length };
|
||||||
}
|
}
|
||||||
// Actual width is 3 columns wider if it's not 0.
|
// Actual width is 3 columns wider if it's not 0.
|
||||||
if width == 0 { 0 } else { width.saturating_add(3) }
|
if width == 0 { 0 } else { width.saturating_add(3) }
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use termion::color;
|
use termion::color;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub plain: bool,
|
||||||
|
pub quit: bool,
|
||||||
|
pub command: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_length(input: &str) -> u16 {
|
||||||
|
let length = UnicodeSegmentation::graphemes(input, true).count();
|
||||||
|
length as u16
|
||||||
|
}
|
||||||
|
|
||||||
pub const COLOR: [&dyn color::Color; 6] = [
|
pub const COLOR: [&dyn color::Color; 6] = [
|
||||||
&color::Cyan,
|
&color::Cyan,
|
||||||
&color::Magenta,
|
&color::Magenta,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use crate::Config;
|
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
// If screen size falls below these values we skip computation of new
|
// If screen size falls below these values we skip computation of new
|
||||||
|
@ -30,6 +29,7 @@ pub struct Layout {
|
||||||
pub roster_height: u16,
|
pub roster_height: u16,
|
||||||
pub buffer: Position,
|
pub buffer: Position,
|
||||||
pub error: Position,
|
pub error: Position,
|
||||||
|
pub cursor: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
|
@ -52,6 +52,7 @@ impl Layout {
|
||||||
roster_height: 0,
|
roster_height: 0,
|
||||||
buffer: Position {col: 0, line: 0},
|
buffer: Position {col: 0, line: 0},
|
||||||
error: Position {col: 0, line: 0},
|
error: Position {col: 0, line: 0},
|
||||||
|
cursor: Position {col: 1, line: 1},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +81,11 @@ impl Layout {
|
||||||
self.compute(hours);
|
self.compute(hours);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_hold(&self, other: &str) -> bool {
|
||||||
|
// Only valid for ascii strings.
|
||||||
|
self.width >= other.len() as u16
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the position of various elements based on the size of the
|
// Compute the position of various elements based on the size of the
|
||||||
// terminal.
|
// terminal.
|
||||||
fn compute(&mut self, display_hours: bool) {
|
fn compute(&mut self, display_hours: bool) {
|
||||||
|
@ -140,6 +146,9 @@ impl Layout {
|
||||||
line: self.height,
|
line: self.height,
|
||||||
col: 12,
|
col: 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Cursor. Column will be set by main loop.
|
||||||
|
self.cursor.line = self.buffer.line;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_roster_width(&mut self, width: u16) {
|
pub fn set_roster_width(&mut self, width: u16) {
|
||||||
|
|
149
src/main.rs
149
src/main.rs
|
@ -1,5 +1,6 @@
|
||||||
extern crate termion;
|
extern crate termion;
|
||||||
extern crate signal_hook;
|
extern crate signal_hook;
|
||||||
|
extern crate unicode_segmentation;
|
||||||
mod alarm;
|
mod alarm;
|
||||||
mod clock;
|
mod clock;
|
||||||
mod common;
|
mod common;
|
||||||
|
@ -19,6 +20,7 @@ use termion::input::TermRead;
|
||||||
use clock::Clock;
|
use clock::Clock;
|
||||||
use alarm::{Countdown, AlarmRoster, exec_command};
|
use alarm::{Countdown, AlarmRoster, exec_command};
|
||||||
use layout::{Layout, Position};
|
use layout::{Layout, Position};
|
||||||
|
use common::{Config, str_length};
|
||||||
|
|
||||||
|
|
||||||
const NAME: &str = env!("CARGO_PKG_NAME");
|
const NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
|
@ -44,6 +46,8 @@ const MENUBAR: &str =
|
||||||
"[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit";
|
"[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit";
|
||||||
const MENUBAR_SHORT: &str =
|
const MENUBAR_SHORT: &str =
|
||||||
"[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit";
|
"[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit";
|
||||||
|
const MENUBAR_INS: &str =
|
||||||
|
"Format: HH:MM:SS/LABEL [ENTER] Accept [ESC] Cancel [CTR-C] Quit";
|
||||||
// Needed for signal_hook.
|
// Needed for signal_hook.
|
||||||
const SIGTSTP: usize = signal_hook::consts::SIGTSTP as usize;
|
const SIGTSTP: usize = signal_hook::consts::SIGTSTP as usize;
|
||||||
const SIGWINCH: usize = signal_hook::consts::SIGWINCH as usize;
|
const SIGWINCH: usize = signal_hook::consts::SIGWINCH as usize;
|
||||||
|
@ -53,12 +57,6 @@ const SIGINT: usize = signal_hook::consts::SIGINT as usize;
|
||||||
const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize;
|
const SIGUSR1: usize = signal_hook::consts::SIGUSR1 as usize;
|
||||||
const SIGUSR2: usize = signal_hook::consts::SIGUSR2 as usize;
|
const SIGUSR2: usize = signal_hook::consts::SIGUSR2 as usize;
|
||||||
|
|
||||||
pub struct Config {
|
|
||||||
plain: bool,
|
|
||||||
quit: bool,
|
|
||||||
command: Option<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut config = Config {
|
let mut config = Config {
|
||||||
|
@ -78,8 +76,11 @@ fn main() {
|
||||||
let mut layout = Layout::new(&config);
|
let mut layout = Layout::new(&config);
|
||||||
let mut clock = Clock::new();
|
let mut clock = Clock::new();
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
let mut buffer_updated: bool = false;
|
let mut buffer_updated = false;
|
||||||
let mut countdown = Countdown::new();
|
let mut countdown = Countdown::new();
|
||||||
|
// True if in insert mode.
|
||||||
|
let mut insert_mode = false;
|
||||||
|
let mut update_menu = true;
|
||||||
// Child process of exec_command().
|
// Child process of exec_command().
|
||||||
let mut spawned: Option<std::process::Child> = None;
|
let mut spawned: Option<std::process::Child> = None;
|
||||||
|
|
||||||
|
@ -140,6 +141,47 @@ fn main() {
|
||||||
// Process input.
|
// Process input.
|
||||||
if let Some(key) = input_keys.next() {
|
if let Some(key) = input_keys.next() {
|
||||||
match key.expect("Error reading input") {
|
match key.expect("Error reading input") {
|
||||||
|
// Enter.
|
||||||
|
Key::Char('\n') => {
|
||||||
|
if !buffer.is_empty() {
|
||||||
|
if let Err(e) = alarm_roster.add(&buffer) {
|
||||||
|
// Error while processing input buffer.
|
||||||
|
error_msg(&mut stdout, &layout, e);
|
||||||
|
} else {
|
||||||
|
// Input buffer processed without error.
|
||||||
|
layout.set_roster_width(alarm_roster.width());
|
||||||
|
layout.force_redraw = true;
|
||||||
|
}
|
||||||
|
buffer.clear();
|
||||||
|
insert_mode = false;
|
||||||
|
update_menu = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Escape ^W, and ^U clear input buffer.
|
||||||
|
Key::Esc | Key::Ctrl('w') | Key::Ctrl('u') => {
|
||||||
|
buffer.clear();
|
||||||
|
insert_mode = false;
|
||||||
|
update_menu = true;
|
||||||
|
layout.force_redraw = true;
|
||||||
|
buffer_updated = true;
|
||||||
|
},
|
||||||
|
// Backspace.
|
||||||
|
Key::Backspace => {
|
||||||
|
// Delete last char in buffer.
|
||||||
|
if buffer.pop().is_some() {
|
||||||
|
if buffer.is_empty() {
|
||||||
|
insert_mode = false;
|
||||||
|
update_menu = true;
|
||||||
|
layout.force_redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer_updated = true;
|
||||||
|
},
|
||||||
|
// Forward every char if in insert mode.
|
||||||
|
Key::Char(c) if insert_mode => {
|
||||||
|
buffer.push(c);
|
||||||
|
buffer_updated = true;
|
||||||
|
},
|
||||||
// Reset clock on 'r'.
|
// Reset clock on 'r'.
|
||||||
Key::Char('r') => {
|
Key::Char('r') => {
|
||||||
clock.reset();
|
clock.reset();
|
||||||
|
@ -180,33 +222,12 @@ fn main() {
|
||||||
// Jump to the start of the main loop.
|
// Jump to the start of the main loop.
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
// Enter.
|
|
||||||
Key::Char('\n') => {
|
|
||||||
if !buffer.is_empty() {
|
|
||||||
if let Err(e) = alarm_roster.add(&buffer) {
|
|
||||||
// Error while processing input buffer.
|
|
||||||
error_msg(&mut stdout, &layout, e);
|
|
||||||
} else {
|
|
||||||
// Input buffer processed without error.
|
|
||||||
layout.set_roster_width(alarm_roster.width());
|
|
||||||
layout.force_redraw = true;
|
|
||||||
}
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Escape ^W, and ^U clear input buffer.
|
|
||||||
Key::Esc | Key::Ctrl('w') | Key::Ctrl('u') => {
|
|
||||||
buffer.clear();
|
|
||||||
buffer_updated = true;
|
|
||||||
},
|
|
||||||
// Backspace.
|
|
||||||
Key::Backspace => {
|
|
||||||
// Delete last char in buffer.
|
|
||||||
if buffer.pop().is_some() { buffer_updated = true };
|
|
||||||
},
|
|
||||||
Key::Char(c) => {
|
Key::Char(c) => {
|
||||||
if c.is_ascii_digit() {
|
if c.is_ascii_digit() {
|
||||||
buffer.push(c);
|
buffer.push(c);
|
||||||
|
insert_mode = true;
|
||||||
|
update_menu = true;
|
||||||
|
layout.force_redraw = true;
|
||||||
buffer_updated = true;
|
buffer_updated = true;
|
||||||
} else if !buffer.is_empty() && c == ':' {
|
} else if !buffer.is_empty() && c == ':' {
|
||||||
buffer.push(':');
|
buffer.push(':');
|
||||||
|
@ -220,7 +241,7 @@ fn main() {
|
||||||
|
|
||||||
// Update input buffer display.
|
// Update input buffer display.
|
||||||
if buffer_updated {
|
if buffer_updated {
|
||||||
draw_buffer(&mut stdout, &layout, &buffer);
|
draw_buffer(&mut stdout, &mut layout, &buffer);
|
||||||
buffer_updated = false;
|
buffer_updated = false;
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -274,27 +295,34 @@ fn main() {
|
||||||
// Clear the window and redraw menu bar, alarm roster and buffer if
|
// Clear the window and redraw menu bar, alarm roster and buffer if
|
||||||
// requested.
|
// requested.
|
||||||
if layout.force_redraw {
|
if layout.force_redraw {
|
||||||
write!(stdout,
|
write!(stdout, "{}", clear::All).unwrap();
|
||||||
"{}{}{}{}{}",
|
|
||||||
clear::All,
|
|
||||||
cursor::Goto(1, 1),
|
|
||||||
style::Faint,
|
|
||||||
// Use a compressed version of the menu bar if necessary.
|
|
||||||
if layout.width >= MENUBAR.len() as u16 {
|
|
||||||
MENUBAR
|
|
||||||
} else if layout.width >= MENUBAR_SHORT.len() as u16 {
|
|
||||||
MENUBAR_SHORT
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
style::Reset,)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Redraw list of alarms.
|
// Redraw list of alarms.
|
||||||
alarm_roster.draw(&mut stdout, &mut layout);
|
alarm_roster.draw(&mut stdout, &mut layout);
|
||||||
|
|
||||||
// Redraw buffer.
|
// Redraw buffer.
|
||||||
draw_buffer(&mut stdout, &layout, &buffer);
|
draw_buffer(&mut stdout, &mut layout, &buffer);
|
||||||
|
|
||||||
|
// Schedule menu redraw.
|
||||||
|
update_menu = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if update_menu {
|
||||||
|
update_menu = false;
|
||||||
|
write!(stdout,
|
||||||
|
"{}{}{}{}",
|
||||||
|
cursor::Goto(1, 1),
|
||||||
|
style::Faint,
|
||||||
|
// Switch menu bars. Use a compressed version or none at
|
||||||
|
// all if necessary.
|
||||||
|
match insert_mode {
|
||||||
|
true if layout.can_hold(MENUBAR_INS) => MENUBAR_INS,
|
||||||
|
false if layout.can_hold(MENUBAR) => MENUBAR,
|
||||||
|
false if layout.can_hold(MENUBAR_SHORT) => MENUBAR_SHORT,
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
style::Reset,)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
clock.draw(&mut stdout, &layout);
|
clock.draw(&mut stdout, &layout);
|
||||||
|
@ -304,6 +332,15 @@ fn main() {
|
||||||
countdown.draw(&mut stdout);
|
countdown.draw(&mut stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move cursor to buffer position.
|
||||||
|
if insert_mode {
|
||||||
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}",
|
||||||
|
cursor::Goto(layout.cursor.col, layout.cursor.line))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Check any spawned child process.
|
// Check any spawned child process.
|
||||||
if let Some(ref mut child) = spawned {
|
if let Some(ref mut child) = spawned {
|
||||||
match child.try_wait() {
|
match child.try_wait() {
|
||||||
|
@ -493,22 +530,25 @@ fn restore_after_suspend<W: Write>(stdout: &mut RawTerminal<W>) {
|
||||||
// Draw input buffer.
|
// Draw input buffer.
|
||||||
fn draw_buffer<W: Write>(
|
fn draw_buffer<W: Write>(
|
||||||
stdout: &mut RawTerminal<W>,
|
stdout: &mut RawTerminal<W>,
|
||||||
layout: &Layout,
|
layout: &mut Layout,
|
||||||
buffer: &String,
|
buffer: &String,
|
||||||
) {
|
) {
|
||||||
if !buffer.is_empty() {
|
if !buffer.is_empty() {
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
"{}{}Add alarm: {}",
|
"{}{}Add alarm: {}{}",
|
||||||
cursor::Goto(layout.buffer.col, layout.buffer.line),
|
cursor::Goto(layout.buffer.col, layout.buffer.line),
|
||||||
clear::CurrentLine,
|
clear::CurrentLine,
|
||||||
|
cursor::Show,
|
||||||
buffer)
|
buffer)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
layout.cursor.col = layout.buffer.col + 11 + str_length(buffer);
|
||||||
} else {
|
} else {
|
||||||
// Clear buffer display.
|
// Clear buffer display.
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
"{}{}",
|
"{}{}{}",
|
||||||
cursor::Goto(layout.buffer.col, layout.buffer.line),
|
cursor::Goto(layout.buffer.col, layout.buffer.line),
|
||||||
clear::CurrentLine)
|
clear::CurrentLine,
|
||||||
|
cursor::Hide)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,11 +556,12 @@ fn draw_buffer<W: Write>(
|
||||||
// Draw error message.
|
// Draw error message.
|
||||||
fn error_msg<W: Write>(stdout: &mut RawTerminal<W>, layout: &Layout, msg: &str) {
|
fn error_msg<W: Write>(stdout: &mut RawTerminal<W>, layout: &Layout, msg: &str) {
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
"{}{}{}{}",
|
"{}{}{}{}{}",
|
||||||
cursor::Goto(layout.error.col, layout.error.line),
|
cursor::Goto(layout.error.col, layout.error.line),
|
||||||
color::Fg(color::LightRed),
|
color::Fg(color::LightRed),
|
||||||
msg,
|
msg,
|
||||||
color::Fg(color::Reset))
|
color::Fg(color::Reset),
|
||||||
|
cursor::Hide)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue