From bb7db39e4bbe901d38235852d254129a833784ab Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Mon, 20 Jul 2020 21:30:13 +0300 Subject: [PATCH 01/41] Don't exit void when pressing unselect key --- src/screen.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index c35b158..2c4afc7 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -167,29 +167,31 @@ impl Screen { Action::LeftClick(x, y) => { let internal_coords = self.screen_to_internal_xy((x, y)); self.click_screen(internal_coords) - }, + } Action::RightClick(..) => { self.pop_focus(); - }, + } Action::Release(x, y) => { let internal_coords = self.screen_to_internal_xy((x, y)); self.release(internal_coords) - }, + } // Write character to selection Action::Char(c) if self.selected.is_some() => { self.append(c); - }, + } Action::Char('/') => { self.search_forward(); - }, + } Action::Char('?') => { self.search_backward(); - }, + } Action::Char(c) => { self.prefix_jump_to(c.to_string()); - }, + } Action::Help => self.help(), - Action::UnselectRet => return self.unselect().is_some(), + Action::UnselectRet => { + self.unselect(); + } Action::ScrollUp => self.scroll_up(), Action::ScrollDown => self.scroll_down(), Action::DeleteSelected => self.delete_selected(true), From 62d03411030ce4ae24c40afe4f639b793c42669d Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 4 Mar 2021 14:17:55 +0200 Subject: [PATCH 02/41] Use colours that are better suitable for light theme --- src/colors.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/colors.rs b/src/colors.rs index a238b00..ec0c410 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -4,14 +4,23 @@ pub fn random_fg_color() -> String { use termion::color::*; let colors: Vec = vec![ format!("{}", Fg(LightGreen)), - // format!("{}", Fg(LightBlack)), + format!("{}", Fg(LightBlack)), format!("{}", Fg(LightRed)), format!("{}", Fg(LightGreen)), - format!("{}", Fg(LightYellow)), - // format!("{}", Fg(LightBlue)), + //format!("{}", Fg(LightYellow)), + format!("{}", Fg(LightBlue)), format!("{}", Fg(LightMagenta)), format!("{}", Fg(LightCyan)), - format!("{}", Fg(LightWhite)), + //format!("{}", Fg(LightWhite)), + format!("{}", Fg(Green)), + format!("{}", Fg(Black)), + format!("{}", Fg(Red)), + format!("{}", Fg(Green)), + format!("{}", Fg(Yellow)), + format!("{}", Fg(Blue)), + format!("{}", Fg(Magenta)), + format!("{}", Fg(Cyan)), + //format!("{}", Fg(White)), ]; colors.choose(&mut rand::thread_rng()).unwrap().clone() } From 2c83e00611b497db2b8d076a5e70e71a424b2f1a Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 4 Mar 2021 16:33:33 +0200 Subject: [PATCH 03/41] Add modal keybinds option --- src/config.rs | 8 +++ src/screen.rs | 143 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 112 insertions(+), 39 deletions(-) diff --git a/src/config.rs b/src/config.rs index a3adbc5..d2d44bb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -48,6 +48,7 @@ pub enum Action { SelectParent, SelectNextSibling, SelectPrevSibling, + Insert, } fn to_action(input: String) -> Option { @@ -87,6 +88,7 @@ fn to_action(input: String) -> Option { "select_parent" => Some(Action::SelectParent), "select_next_sibling" => Some(Action::SelectNextSibling), "select_prev_sibling" => Some(Action::SelectPrevSibling), + "insert" => Some(Action::Insert), _ => None, } } @@ -126,6 +128,7 @@ fn to_key(raw_key: String) -> Option { #[derive(Debug, Clone)] pub struct Config { config: HashMap, + pub modal: bool, } impl Default for Config { @@ -172,6 +175,7 @@ impl Default for Config { ] .into_iter() .collect(), + modal: false, } } } @@ -204,6 +208,10 @@ impl Config { if line == "" || line.starts_with('#') { continue; } + if line == "modal" { + config.modal = true; + continue; + } // Zero based indexing inappropriate here. line_num += 1; diff --git a/src/screen.rs b/src/screen.rs index 713b3c0..c4b7148 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -27,6 +27,12 @@ use crate::{ Action, Config, Coords, Dir, Node, NodeID, Pack, TagDB, }; +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +struct Selection { + selected_id: NodeID, + inserting: bool, +} + pub struct Screen { pub max_id: u64, pub nodes: HashMap, @@ -42,7 +48,7 @@ pub struct Screen { // non-pub members are ephemeral drawing_root: NodeID, show_logs: bool, - selected: Option, + selected: Option, cut: Option, drawing_arrow: Option, lookup: HashMap, @@ -169,6 +175,13 @@ impl Screen { // return of false signals to the caller that we are done in this view pub fn handle_event(&mut self, evt: Event) -> bool { + // Write character to selection + if let Event::Key(Key::Char(k)) = evt { + if self.is_insert_mode() { + self.append(k); + return true; + } + } match self.config.map(evt) { Some(e) => match e { Action::LeftClick(x, y) => { @@ -182,20 +195,34 @@ impl Screen { let internal_coords = self.screen_to_internal_xy((x, y)); self.release(internal_coords) } - // Write character to selection - Action::Char(c) if self.selected.is_some() => { - self.append(c); - } Action::Char('/') => { self.search_forward(); } Action::Char('?') => { self.search_backward(); } - Action::Char(c) => { + Action::Char(c) if !self.config.modal => { self.prefix_jump_to(c.to_string()); } + Action::Char(_) => {} Action::Help => self.help(), + Action::Insert => { + if let Some(sel) = self.selected.as_mut() { + // Invalidate the grapheme cache, because an insertion cursor is being added + self.grapheme_cache.remove(&sel.selected_id); + sel.inserting = true + } + } + + Action::UnselectRet + if self.config.modal && self.selected.map(|s| s.inserting) == Some(true) => + { + if let Some(sel) = self.selected.as_mut() { + // Invalidate the grapheme cache, because an insertion cursor is being removed + self.grapheme_cache.remove(&sel.selected_id); + sel.inserting = false + } + } Action::UnselectRet => { self.unselect(); } @@ -206,7 +233,10 @@ impl Screen { Action::SelectDown => self.select_down(), Action::SelectLeft => self.select_left(), Action::SelectRight => self.select_right(), - Action::EraseChar => self.backspace(), + Action::EraseChar if self.is_insert_mode() => { + self.backspace() + } + Action::EraseChar => {} Action::CreateSibling => self.create_sibling(), Action::CreateChild => self.create_child(), Action::CreateFreeNode => self.create_free_node(), @@ -243,11 +273,11 @@ impl Screen { } fn cut_paste(&mut self) { - if let Some(selected_id) = self.selected { + if let Some(sel) = self.selected { if let Some(cut) = self.cut.take() { - self.reparent(cut, selected_id); + self.reparent(cut, sel.selected_id); } else { - self.cut = Some(selected_id); + self.cut = Some(sel.selected_id); } } else if let Some(cut) = self.cut.take() { let root = self.drawing_root; @@ -551,7 +581,7 @@ impl Screen { // want to accidentally execute rm -rf / return; } - let selected_id = self.selected.unwrap(); + let Selection { selected_id, .. } = self.selected.unwrap(); let content_opt = self.with_node(selected_id, |n| n.content.clone()); if content_opt.is_none() { @@ -709,7 +739,7 @@ impl Screen { let raw_node_opt = self.with_node(node_id, |n| n.clone()); if let Some(raw_node) = raw_node_opt { let node = self.format_node(&raw_node); - let width = 1 + (3 * depth as u16) + node.content.len() as u16; + let width = 2 + (3 * depth as u16) + node.content.len() as u16; let mut ret = vec![width]; let hide_stricken = self.with_node(node_id, |n| n.hide_stricken).unwrap(); if !node.collapsed { @@ -742,7 +772,7 @@ impl Screen { lazy_static! { static ref RE_DATE: Regex = Regex::new(r"\[(\S+)\]").unwrap(); } - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { // nuke node if it's empty and has no children let deletable = self .with_node_mut_no_meta(selected_id, |n| { @@ -771,7 +801,7 @@ impl Screen { } }); } - self.selected.take() + self.selected.take().map(|s| s.selected_id) } fn internal_to_screen_xy(&self, coords: Coords) -> Option { @@ -815,7 +845,10 @@ impl Screen { node_id }) .and_then(|id| { - self.selected = Some(node_id); + self.selected = Some(Selection { + selected_id: node_id, + inserting: !self.config.modal, + }); self.dragging_from = Some(coords); self.dragging_to = Some(coords); Some(id) @@ -834,14 +867,14 @@ impl Screen { fn toggle_stricken(&mut self) { trace!("toggle_stricken()"); - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { self.with_node_mut(selected_id, |node| node.toggle_stricken()); } } fn toggle_hide_stricken(&mut self) { trace!("toggle_hide_stricken()"); - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { self.with_node_mut(selected_id, |node| node.toggle_hide_stricken()); } } @@ -866,7 +899,7 @@ impl Screen { fn delete_selected(&mut self, reselect: bool) { trace!("delete_selected()"); - if let Some(selected_id) = self.selected.take() { + if let Some(Selection { selected_id, .. }) = self.selected.take() { let (_, height) = self.drawable_subtree_dims(selected_id).unwrap(); let coords = self.drawn_at.remove(&selected_id); // remove ref from parent @@ -962,7 +995,7 @@ impl Screen { fn toggle_collapsed(&mut self) { trace!("toggle_collapsed()"); - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { self.with_node_mut_no_meta(selected_id, |node| node.toggle_collapsed()); } } @@ -972,7 +1005,10 @@ impl Screen { } fn create_child(&mut self) { - if let Some(mut selected_id) = self.selected { + if let Some(Selection { + mut selected_id, .. + }) = self.selected + { if self .with_node(selected_id, |n| n.content.is_empty()) .unwrap() @@ -1017,7 +1053,10 @@ impl Screen { } fn create_sibling(&mut self) { - if let Some(mut selected_id) = self.selected { + if let Some(Selection { + mut selected_id, .. + }) = self.selected + { if self .with_node(selected_id, |n| n.content.is_empty()) .unwrap() @@ -1108,7 +1147,7 @@ impl Screen { fn backspace(&mut self) { trace!("backspace"); - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { if let Some(content) = self.with_node_mut(selected_id, |node| { let content = node.content.clone(); let chars = content.chars(); @@ -1125,7 +1164,7 @@ impl Screen { fn append(&mut self, c: char) { trace!("append({})", c); - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { if let Some(content) = self.with_node_mut(selected_id, |node| { node.content.push(c); node.content.clone() @@ -1214,7 +1253,7 @@ impl Screen { let dx = to.0 as i16 - from.0 as i16; let dy = to.1 as i16 - from.1 as i16; - let selected_id = if let Some(selected_id) = self.selected { + let selected_id = if let Some(Selection { selected_id, .. }) = self.selected { if self.is_parent(self.drawing_root, selected_id) { selected_id } else { @@ -1275,7 +1314,7 @@ impl Screen { } fn select_parent(&mut self) { - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { // If no parent, this should be a no-op. if let Some(parent_id) = self.parent(selected_id) { // If we're at a toplevel task (i.e., 0 is its parent ID), we don't want to @@ -1297,7 +1336,7 @@ impl Screen { fn select_neighbor(&mut self, dir: SearchDirection) -> Option { use SearchDirection::*; - let selected_id = self.selected?; + let selected_id = self.selected?.selected_id; let parent = self.nodes.get(&self.parent(selected_id)?)?; let selected_idx = parent.children.iter().position(|&id| id == selected_id)? as u64; @@ -1360,7 +1399,7 @@ impl Screen { } fn scroll_to_selected(&mut self) -> bool { - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { self.scroll_to_node(selected_id) } else { false @@ -1406,7 +1445,7 @@ impl Screen { } fn raise_selected(&mut self) { - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { if !self.exists(selected_id) { warn!("tried to raise deleted node"); return; @@ -1429,7 +1468,7 @@ impl Screen { } fn lower_selected(&mut self) { - if let Some(selected_id) = self.selected { + if let Some(Selection { selected_id, .. }) = self.selected { if !self.exists(selected_id) { warn!("tried to lower deleted node"); return; @@ -1526,7 +1565,7 @@ impl Screen { let cur = self .selected - .and_then(|s| self.bounds_for_lookup(s)) + .and_then(|s| self.bounds_for_lookup(s.selected_id)) .unwrap_or((rel_def_coords, rel_def_coords)); let mut node_costs = vec![]; @@ -1554,7 +1593,10 @@ impl Screen { .with_node_mut_no_meta(node_id, |node| node.selected = true) .is_some() { - self.selected = Some(node_id); + self.selected = Some(Selection { + selected_id: node_id, + inserting: !self.config.modal, + }); } } } @@ -1565,7 +1607,7 @@ impl Screen { warn!("click way off-screen"); return; } - let old = self.selected; + let old = self.selected.map(|s| s.selected_id); let new = self.try_select(coords); if old.is_none() && self.dragging_from.is_none() { self.create_anchor(coords); @@ -1671,11 +1713,11 @@ impl Screen { pub fn add_or_remove_arrow(&mut self) { if self.drawing_arrow.is_none() { - self.drawing_arrow = self.selected; + self.drawing_arrow = self.selected.map(|s| s.selected_id); return; } let from = self.drawing_arrow.take().unwrap(); - if let Some(arrow) = self.selected.map(|to| (from, to)) { + if let Some(arrow) = self.selected.map(|to| (from, to.selected_id)) { let (from, to) = arrow; if self.nodes.get(&from).is_some() && self.nodes.get(&to).is_some() { let contains = self.arrows.iter().fold(false, |acc, &(ref nl1, ref nl2)| { @@ -1885,12 +1927,13 @@ impl Screen { let reset = &*format!("{}", color::Fg(color::Reset)); let mut pre_meta = String::new(); + let mut post_content = String::new(); let mut buf = String::new(); // only actually print it if we're in-view if let Some((x, y)) = self.internal_to_screen_xy(internal_coords) { write!(pre_meta, "{}{}", cursor::Goto(x, y), color).unwrap(); - if node.selected { + if node.selected && !(self.config.modal && self.is_insert_mode()) { write!(&mut pre_meta, "{}", style::Invert).unwrap(); } write!(&mut buf, "{}", pre_meta).unwrap(); @@ -1914,20 +1957,32 @@ impl Screen { } else { write!(&mut buf, " ").unwrap(); } + + write!(&mut buf, "{}", node.content).unwrap(); + + // write cursor if this node is being inserted to + if node.selected && self.config.modal && self.is_insert_mode() { + write!(&mut post_content, "{} {}", style::Invert, reset).unwrap(); + write!(&mut buf, "{}", post_content).unwrap(); + } // keep color for selected & tree root Fg if !node.selected && prefix != "" { write!(&mut buf, "{}", reset).unwrap(); } - write!(&mut buf, "{}", node.content).unwrap(); - let max_width = (max(self.dims.0, 1 + x) - 1 - x) as usize; let visible_graphemes = self.grapheme_cache .get(&node.id) .cloned() .unwrap_or_else(|| { - let visible = buf.replace(reset, "").replace(&*pre_meta, ""); + let visible = if !post_content.is_empty() { + buf.replace(&*post_content, " ") + .replace(reset, "") + .replace(&*pre_meta, "") + } else { + buf.replace(reset, "").replace(&*pre_meta, "") + }; let vg = UnicodeSegmentation::graphemes(&*visible, true).count(); self.grapheme_cache.insert(node.id, vg); vg @@ -1949,7 +2004,13 @@ impl Screen { .get(&node.id) .cloned() .unwrap_or_else(|| { - let visible = buf.replace(reset, "").replace(&*pre_meta, ""); + let visible = if !post_content.is_empty() { + buf.replace(&*post_content, " ") + .replace(reset, "") + .replace(&*pre_meta, "") + } else { + buf.replace(reset, "").replace(&*pre_meta, "") + }; let vg = UnicodeSegmentation::graphemes(&*visible, true).count(); self.grapheme_cache.insert(node.id, vg); vg @@ -2367,6 +2428,10 @@ impl Screen { let plot = plot::bounded_count_sparkline(nodes, since as i64, until as i64, buckets); format!("|{}|", plot) } + + fn is_insert_mode(&self) -> bool { + self.selected.map(|s| s.inserting) == Some(true) + } } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] From 9270139a7b28774fabd00261c1670c488374569f Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 4 Mar 2021 16:45:26 +0200 Subject: [PATCH 04/41] Make arrows stable --- src/screen.rs | 24 ++++++++++++------------ src/serialization.rs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index a25d15a..eea2f45 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -30,7 +30,7 @@ use crate::{ pub struct Screen { pub max_id: u64, pub nodes: HashMap, - pub arrows: Vec<(NodeID, NodeID)>, + pub arrows: Vec<(NodeID, NodeID, String)>, pub work_path: Option, pub autosave_every: usize, pub config: Config, @@ -849,7 +849,7 @@ impl Screen { if let Some(node) = self.nodes.remove(&node_id) { // clean up any arrow state self.arrows - .retain(|&(ref from, ref to)| from != &node_id && to != &node_id); + .retain(|&(ref from, ref to, _)| from != &node_id && to != &node_id); // remove from tag_db self.tag_db.remove(node_id); @@ -1625,7 +1625,7 @@ impl Screen { debug!("testing that all arrows are existing nodes"); // no arrows that don't exist - for &(ref a, ref b) in &self.arrows { + for &(ref a, ref b, _) in &self.arrows { assert!(self.nodes.get(a).is_some()); assert!(self.nodes.get(b).is_some()); } @@ -1673,10 +1673,10 @@ impl Screen { return; } let from = self.drawing_arrow.take().unwrap(); - if let Some(arrow) = self.selected.map(|to| (from, to)) { - let (from, to) = arrow; + if let Some(arrow) = self.selected.map(|to| (from, to, random_fg_color())) { + let (from, to, _) = arrow; if self.nodes.get(&from).is_some() && self.nodes.get(&to).is_some() { - let contains = self.arrows.iter().fold(false, |acc, &(ref nl1, ref nl2)| { + let contains = self.arrows.iter().fold(false, |acc, &(ref nl1, ref nl2, _)| { if nl1 == &from && nl2 == &to { true } else { @@ -1764,9 +1764,9 @@ impl Screen { } // print arrows - for &(ref from, ref to) in &self.arrows { + for &(ref from, ref to, ref color) in &self.arrows { let (path, (direction1, direction2)) = self.path_between_nodes(*from, *to); - self.draw_path(path, direction1, direction2); + self.draw_path(path, direction1, direction2, color); } // conditionally print drag dest arrow @@ -1778,11 +1778,11 @@ impl Screen { if let Some(to_node) = self.lookup(to) { let (path, (direction1, direction2)) = self.path_between_nodes(*from_node, *to_node); - self.draw_path(path, direction1, direction2); + self.draw_path(path, direction1, direction2, &random_fg_color()); } else { let (path, (direction1, direction2)) = self.path_from_node_to_point(*from_node, to); - self.draw_path(path, direction1, direction2); + self.draw_path(path, direction1, direction2, &random_fg_color()); } } else { warn!("dragging_from set, but NOT dragging_to"); @@ -1992,13 +1992,13 @@ impl Screen { drawn } - fn draw_path(&self, internal_path: Vec, start_dir: Dir, dest_dir: Dir) { + fn draw_path(&self, internal_path: Vec, start_dir: Dir, dest_dir: Dir, color: &str) { let path: Vec<_> = internal_path .iter() .filter_map(|&c| self.internal_to_screen_xy(c)) .collect(); trace!("draw_path({:?}, {:?}, {:?})", path, start_dir, dest_dir); - print!("{}", random_fg_color()); + print!("{}", color); if path.len() == 1 { print!("{} ↺", cursor::Goto(path[0].0, path[0].1)) } else if path.len() > 1 { diff --git a/src/serialization.rs b/src/serialization.rs index cd84265..fe34bee 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -14,7 +14,7 @@ pub fn serialize_screen(screen: &Screen) -> Vec { let arrows = screen .arrows .iter() - .map(|&(from, to)| { + .map(|&(from, to, _)| { let mut arrow_pb = pb::Arrow::default(); arrow_pb.set_from_node(from); arrow_pb.set_to_node(to); @@ -127,7 +127,7 @@ pub fn deserialize_screen(data: Vec) -> Result Date: Thu, 4 Mar 2021 19:22:07 +0200 Subject: [PATCH 05/41] Improve help screen --- src/config.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/screen.rs | 2 +- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index d2d44bb..fdb238a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,53 @@ pub enum Action { Insert, } +impl fmt::Display for Action { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Action::LeftClick(..) | Action::RightClick(..) | Action::Release(..) => { + write!(f, "Other action") + } + Action::Arrow => write!(f, "Start or end arrow"), + Action::AutoArrange => write!(f, "Toggle automatic arrangement"), + Action::Char(c) => write!(f, "Input character {}", c), + Action::CreateChild => write!(f, "Create new child node"), + Action::CreateFreeNode => write!(f, "Create new free node"), + Action::CreateSibling => write!(f, "Create new sibling node"), + Action::DeleteSelected => write!(f, "Delete selected node"), + Action::DrillDown => write!(f, "Move down in hierarchy"), + Action::EnterCmd => write!(f, "Enter command"), + Action::EraseChar => write!(f, "Erase character"), + Action::ExecSelected => write!(f, "Execute node content"), + Action::FindTask => write!(f, "Autoassign task"), + Action::Help => write!(f, "Display help"), + Action::Insert => write!(f, "Enter insert mode"), + Action::LowerSelected => write!(f, "Move selected node down"), + Action::PopUp => write!(f, "Move up in hierarchy"), + Action::PrefixJump => write!(f, "Select by prefix"), + Action::Quit => write!(f, "Quit void"), + Action::RaiseSelected => write!(f, "Move selected node up"), + Action::Save => write!(f, "Save"), + Action::ScrollDown => write!(f, "Scroll view down"), + Action::ScrollUp => write!(f, "Scroll view up"), + Action::Search => write!(f, "Search for node"), + Action::SelectDown => write!(f, "Select next node down"), + Action::SelectLeft => write!(f, "Select next node left"), + Action::SelectNextSibling => write!(f, "Select next sibling"), + Action::SelectParent => write!(f, "Select parent node"), + Action::SelectPrevSibling => write!(f, "Select previous sibling"), + Action::SelectRight => write!(f, "Select next node right"), + Action::SelectUp => write!(f, "Select next node up"), + Action::ToggleCollapsed => write!(f, "Toggle collapsing of children"), + Action::ToggleCompleted => write!(f, "Toggle completed"), + Action::ToggleHideCompleted => write!(f, "Toggle hiding of completed tasks"), + Action::ToggleShowLogs => write!(f, "Toggle log"), + Action::UndoDelete => write!(f, "Undo deletion"), + Action::UnselectRet => write!(f, "Unselect node / leave insert mode"), + Action::YankPasteNode => write!(f, "Yank node"), + } + } +} + fn to_action(input: String) -> Option { match &*input { "unselect" => Some(Action::UnselectRet), @@ -180,11 +227,33 @@ impl Default for Config { } } +struct FmtKey(Key); + +impl fmt::Display for FmtKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.0 { + Key::PageDown => write!(f, "{}", "PgDn"), + Key::PageUp => write!(f, "{}", "PgUp"), + Key::Delete => write!(f, "{}", "Del"), + Key::Alt(c) => write!(f, "A-{}", FmtKey(Key::Char(*c))), + Key::Ctrl(c) => write!(f, "C-{}", FmtKey(Key::Char(*c))), + Key::Char(' ') => write!(f, "{}", "Space"), + Key::Char('\n') => write!(f, "{}", "Enter"), + Key::Char('\t') => write!(f, "{}", "Tab"), + Key::Char(c) => write!(f, "{}", c), + other => fmt::Debug::fmt(other, f), + } + } +} + impl fmt::Display for Config { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.modal { + writeln!(f, "Modal mode enabled.").unwrap(); + } writeln!(f, "Configured Hotkeys:").unwrap(); for (key, action) in &self.config { - writeln!(f, " {:?}: {:?}", action, key).unwrap(); + writeln!(f, " {}: {}", action, FmtKey(*key)).unwrap(); } Ok(()) } @@ -212,6 +281,10 @@ impl Config { config.modal = true; continue; } + if line == "no_defaults" { + config.config = HashMap::new(); + continue; + } // Zero based indexing inappropriate here. line_num += 1; diff --git a/src/screen.rs b/src/screen.rs index a959faa..2be3dca 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -128,8 +128,8 @@ impl Default for Screen { impl Screen { fn help(&mut self) { self.cleanup(); - println!("{}{}{}", cursor::Goto(1, 1), clear::All, self.config); self.start_raw_mode(); + println!("{}{}{}", cursor::Goto(1, 1), clear::All, self.config.to_string().replace("\n", "\r\n")); if self.single_key_prompt("").is_err() { // likely here because of testing } From 61af662818d909b708baf90844dffad6dff355d3 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 6 Mar 2021 09:16:30 +0200 Subject: [PATCH 06/41] Sort hotkey help based on description alphabetically --- src/config.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index fdb238a..30bdfbc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -252,9 +252,16 @@ impl fmt::Display for Config { writeln!(f, "Modal mode enabled.").unwrap(); } writeln!(f, "Configured Hotkeys:").unwrap(); - for (key, action) in &self.config { - writeln!(f, " {}: {}", action, FmtKey(*key)).unwrap(); - } + let mut hotkeys = self + .config + .iter() + .map(|(key, action)| format!(" {}: {}", action, FmtKey(*key))) + .collect::>(); + hotkeys.sort(); + hotkeys + .into_iter() + .map(|string| writeln!(f, "{}", string)) + .collect::, _>>()?; Ok(()) } } From 33600d12904ae1563231b24cefe1739269e55d15 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 7 Mar 2021 13:26:19 +0200 Subject: [PATCH 07/41] Fix removal of arrows and arrows getting duplicated --- src/screen.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 2be3dca..af1fea6 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1717,8 +1717,8 @@ impl Screen { return; } let from = self.drawing_arrow.take().unwrap(); - if let Some(arrow) = self.selected.map(|to| (from, to.selected_id, random_fg_color())) { - let (from, to, _) = arrow; + if let Some(arrow) = self.selected.map(|to| (from, to.selected_id)) { + let (from, to) = arrow; if self.nodes.get(&from).is_some() && self.nodes.get(&to).is_some() { let contains = self.arrows.iter().fold(false, |acc, &(ref nl1, ref nl2, _)| { if nl1 == &from && nl2 == &to { @@ -1728,9 +1728,9 @@ impl Screen { } }); if contains { - self.arrows.retain(|e| e != &arrow); + self.arrows.retain(|(old_from, old_to, _)| (*old_from, *old_to) != arrow); } else { - self.arrows.push(arrow); + self.arrows.push((from, to, random_fg_color())); } } } From 3e25dc70a6e41ab5602744333bb51b8a15549f75 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 7 Mar 2021 13:35:21 +0200 Subject: [PATCH 08/41] Ensure insert mode is applied when creating a new node --- src/screen.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index af1fea6..ce1a8d4 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1045,7 +1045,7 @@ impl Screen { selected.children.push(node_id); }); if added.is_some() { - self.select_node(node_id); + self.select_node_ensure_inserting(node_id); } else { self.delete_recursive(node_id); } @@ -1068,7 +1068,7 @@ impl Screen { // because that's not underneath the drawing root return; } - self.select_node(sel_parent); + self.select_node_ensure_inserting(sel_parent); selected_id = sel_parent; } let selected_id = selected_id; @@ -1093,7 +1093,7 @@ impl Screen { parent.children.insert(idx + 1, node_id); }); if added.is_some() { - self.select_node(node_id); + self.select_node_ensure_inserting(node_id); } else { self.delete_recursive(node_id); } @@ -1142,7 +1142,7 @@ impl Screen { node.parent_id = root; }); self.with_node_mut_no_meta(root, |root| root.children.push(node_id)); - self.select_node(node_id); + self.select_node_ensure_inserting(node_id); } fn backspace(&mut self) { @@ -1601,6 +1601,27 @@ impl Screen { } } + fn select_node_ensure_inserting(&mut self, node_id: NodeID) { + trace!("select_node({})", node_id); + self.unselect(); + if node_id != 0 { + // it's possible that unselecting above actually caused + // this node to be deleted, due to its parent (previous + // selection) being empty. To account for this, we need + // to only set self.selected to node_id if the with_node + // succeeds. + if self + .with_node_mut_no_meta(node_id, |node| node.selected = true) + .is_some() + { + self.selected = Some(Selection { + selected_id: node_id, + inserting: true, + }); + } + } + } + fn click_screen(&mut self, coords: Coords) { trace!("click_screen({:?})", coords); if coords.0 > self.dims.0 || coords.1 > self.view_y + self.dims.1 { From 47ed043405799385cb577c35bb7fac14a0832a98 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 7 Mar 2021 17:47:01 +0200 Subject: [PATCH 09/41] Indicate insert mode in the header line --- src/screen.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/screen.rs b/src/screen.rs index ce1a8d4..5d378ce 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2138,6 +2138,9 @@ impl Screen { if self.should_auto_arrange() { header_text.push_str(" [auto-arrange] "); } + if self.config.modal && self.is_insert_mode() { + header_text.push_str(" [insert] "); + } let (plot, finished_today) = self.last_week_of_done_tasks(); let plot_line = format!("│{}│({} today)", plot, finished_today); From 98ce31073fd4e8f10cdec3dc5a3e3d7c4ef6d4d7 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Mon, 8 Mar 2021 11:10:04 +0200 Subject: [PATCH 10/41] Add ignore tag for tasks, strip tags when executing nodes --- src/screen.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 5d378ce..bddc388 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -320,7 +320,7 @@ impl Screen { // pass } else if node.content.contains("#task") { task_roots.push(node.id); - } else { + } else if !node.content.contains("#ignr") { to_explore.append(&mut node.children); } } @@ -581,6 +581,9 @@ impl Screen { // want to accidentally execute rm -rf / return; } + lazy_static![ + static ref RE_TAG: Regex = Regex::new(r"([^#])#[^#\s]+").unwrap(); + ]; let Selection { selected_id, .. } = self.selected.unwrap(); let content_opt = self.with_node(selected_id, |n| n.content.clone()); @@ -588,7 +591,10 @@ impl Screen { error!("tried to exec deleted node"); return; } - let content = content_opt.unwrap(); + + // remove any tags from the exec + // except for those that are escaped as ## + let content = RE_TAG.replace_all(&content_opt.unwrap(), "$1").replace("##", "#"); info!("executing command: {}", content); if content.is_empty() { From 10255f03e8ad08e59084efd7b858e2d3f5ebc7a4 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Tue, 9 Mar 2021 14:46:31 +0200 Subject: [PATCH 11/41] Fix autotask ignore functionality --- src/screen.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/screen.rs b/src/screen.rs index bddc388..6fb10ba 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -320,7 +320,7 @@ impl Screen { // pass } else if node.content.contains("#task") { task_roots.push(node.id); - } else if !node.content.contains("#ignr") { + } else { to_explore.append(&mut node.children); } } @@ -328,6 +328,9 @@ impl Screen { let mut leaves = vec![]; while let Some(root_id) = task_roots.pop() { let node = self.with_node(root_id, |n| n.clone()).unwrap(); + if node.content.contains("#ignr") { + continue; + } let mut incomplete_children: Vec<_> = node .children .iter() From 06cf2ab0df0a4c1e364b5c7012581d877dcb3db0 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 11 Mar 2021 16:42:26 +0200 Subject: [PATCH 12/41] Fix autotask ignoring nodes with exclusively #ignr children --- src/screen.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 6fb10ba..afcc050 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -328,14 +328,11 @@ impl Screen { let mut leaves = vec![]; while let Some(root_id) = task_roots.pop() { let node = self.with_node(root_id, |n| n.clone()).unwrap(); - if node.content.contains("#ignr") { - continue; - } let mut incomplete_children: Vec<_> = node .children .iter() .cloned() - .filter(|&c| self.with_node(c, |c| !c.stricken).unwrap()) + .filter(|&c| self.with_node(c, |c| !c.stricken && !c.content.contains("#ignr")).unwrap()) .collect(); if incomplete_children.is_empty() { leaves.push(root_id); From ee45ad279bf0d2455d349d71e6e81e270532b5cc Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 14 Mar 2021 15:05:44 +0200 Subject: [PATCH 13/41] Let the user know when a node is being yanked --- src/screen.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/screen.rs b/src/screen.rs index afcc050..44e68ac 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,5 +1,6 @@ use std::{ self, + borrow::Cow, cmp::{max, min}, collections::{BTreeMap, BinaryHeap, HashMap, HashSet}, env, @@ -2147,6 +2148,15 @@ impl Screen { if self.config.modal && self.is_insert_mode() { header_text.push_str(" [insert] "); } + if let Some(cut) = self.cut { + let content = &self.nodes.get(&cut).unwrap().content; + let content_ellipsized = if content.len() >= 13 { + Cow::from(format!("{}...", &content[..10])) + } else { + Cow::from(content) + }; + header_text.push_str(&format!(" [yanking: {}] ", content_ellipsized)); + } let (plot, finished_today) = self.last_week_of_done_tasks(); let plot_line = format!("│{}│({} today)", plot, finished_today); From 2b318d7e67d133c683ab559590adf5c9b81e7bde Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 18 Mar 2021 18:12:03 +0200 Subject: [PATCH 14/41] Add config for configuring node marks --- src/config.rs | 47 +++++++++++++++++++++++++++++++++++------------ src/screen.rs | 8 ++++---- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/config.rs b/src/config.rs index 30bdfbc..710cd79 100644 --- a/src/config.rs +++ b/src/config.rs @@ -176,6 +176,10 @@ fn to_key(raw_key: String) -> Option { pub struct Config { config: HashMap, pub modal: bool, + pub stricken: String, + pub collapsed: String, + pub hide_stricken: String, + pub free_text: String, } impl Default for Config { @@ -223,6 +227,10 @@ impl Default for Config { .into_iter() .collect(), modal: false, + stricken: "☠".to_owned(), + collapsed: "⊞".to_owned(), + hide_stricken: "⚔".to_owned(), + free_text: "✏".to_owned(), } } } @@ -303,21 +311,36 @@ impl Config { return Err(Error::new(ErrorKind::Other, e)); } - let (raw_action, raw_key) = (parts[0], parts[1]); - - let key_opt = to_key(raw_key.to_owned()); - let action_opt = to_action(raw_action.to_owned()); + let (option, param) = (parts[0], parts[1]); + match (option, param) { + ("stricken", p) => { + config.stricken = p.to_owned(); + } + ("collapsed", p) => { + config.collapsed = p.to_owned(); + } + ("hide_stricken", p) => { + config.hide_stricken = p.to_owned(); + } + ("free_text", p) => { + config.free_text = p.to_owned(); + } + (raw_action, raw_key) => { + let key_opt = to_key(raw_key.to_owned()); + let action_opt = to_action(raw_action.to_owned()); - if key_opt.is_none() || action_opt.is_none() { - let e = format!("invalid config at line {}: {}", line_num, line); - error!("{}", e); - return Err(Error::new(ErrorKind::Other, e)); - } + if key_opt.is_none() || action_opt.is_none() { + let e = format!("invalid config at line {}: {}", line_num, line); + error!("{}", e); + return Err(Error::new(ErrorKind::Other, e)); + } - let key = key_opt.unwrap(); - let action = action_opt.unwrap(); + let key = key_opt.unwrap(); + let action = action_opt.unwrap(); - config.config.insert(key, action); + config.config.insert(key, action); + } + } } Ok(config) diff --git a/src/screen.rs b/src/screen.rs index 44e68ac..05decc8 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1975,13 +1975,13 @@ impl Screen { } } if node.stricken { - write!(&mut buf, "☠").unwrap(); + buf.write_str(&self.config.stricken).unwrap(); } else if node.collapsed { - write!(&mut buf, "⊞").unwrap(); + buf.write_str(&self.config.collapsed).unwrap(); } else if node.hide_stricken { - write!(&mut buf, "⚔").unwrap(); + buf.write_str(&self.config.hide_stricken).unwrap(); } else if node.free_text.is_some() { - write!(&mut buf, "✏").unwrap(); + buf.write_str(&self.config.free_text).unwrap(); } else { write!(&mut buf, " ").unwrap(); } From d56870b7403ff3071806488990871afd7bc3d700 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Mon, 22 Mar 2021 15:08:33 +0200 Subject: [PATCH 15/41] Don't save focus location when searching or autotasking This is unpleasant, as it doesn't allow the user to jump back in the hierarchy using the pop-up command consistenly. --- src/screen.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 05decc8..0ee8b62 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1442,10 +1442,6 @@ impl Screen { } } - // save old location and jump - let old_select = self.unselect().unwrap_or(0); - let breadcrumb = (self.drawing_root, old_select, self.view_y); - self.focus_stack.push(breadcrumb); self.drawing_root = cursor; self.select_node(node_id); self.draw(); From 0d85213979a153803787af5e9f7302a358b068bc Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Wed, 22 Sep 2021 19:16:10 +0300 Subject: [PATCH 16/41] Implement functionality for copying nodes --- src/config.rs | 16 +++--- src/node.rs | 10 ++++ src/screen.rs | 140 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 124 insertions(+), 42 deletions(-) diff --git a/src/config.rs b/src/config.rs index 710cd79..4f7be6d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -39,6 +39,7 @@ pub enum Action { ToggleShowLogs, EnterCmd, FindTask, + MovePasteNode, YankPasteNode, RaiseSelected, LowerSelected, @@ -72,6 +73,7 @@ impl fmt::Display for Action { Action::Help => write!(f, "Display help"), Action::Insert => write!(f, "Enter insert mode"), Action::LowerSelected => write!(f, "Move selected node down"), + Action::MovePasteNode => write!(f, "Move node"), Action::PopUp => write!(f, "Move up in hierarchy"), Action::PrefixJump => write!(f, "Select by prefix"), Action::Quit => write!(f, "Quit void"), @@ -127,6 +129,7 @@ fn to_action(input: String) -> Option { "enter_command" => Some(Action::EnterCmd), "find_task" => Some(Action::FindTask), "yank_paste_node" => Some(Action::YankPasteNode), + "move_paste_node" => Some(Action::MovePasteNode), "raise_selected" => Some(Action::RaiseSelected), "lower_selected" => Some(Action::LowerSelected), "search" => Some(Action::Search), @@ -221,6 +224,7 @@ impl Default for Config { (Ctrl('z'), Action::UndoDelete), (Ctrl('?'), Action::Help), (Alt('P'), Action::SelectParent), + (Alt('y'), Action::MovePasteNode), (Alt('n'), Action::SelectNextSibling), (Alt('p'), Action::SelectPrevSibling), ] @@ -240,14 +244,14 @@ struct FmtKey(Key); impl fmt::Display for FmtKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.0 { - Key::PageDown => write!(f, "{}", "PgDn"), - Key::PageUp => write!(f, "{}", "PgUp"), - Key::Delete => write!(f, "{}", "Del"), + Key::PageDown => write!(f, "PgDn"), + Key::PageUp => write!(f, "PgUp"), + Key::Delete => write!(f, "Del"), Key::Alt(c) => write!(f, "A-{}", FmtKey(Key::Char(*c))), Key::Ctrl(c) => write!(f, "C-{}", FmtKey(Key::Char(*c))), - Key::Char(' ') => write!(f, "{}", "Space"), - Key::Char('\n') => write!(f, "{}", "Enter"), - Key::Char('\t') => write!(f, "{}", "Tab"), + Key::Char(' ') => write!(f, "Space"), + Key::Char('\n') => write!(f, "Enter"), + Key::Char('\t') => write!(f, "Tab"), Key::Char(c) => write!(f, "{}", c), other => fmt::Debug::fmt(other, f), } diff --git a/src/node.rs b/src/node.rs index f8c45a4..2c08179 100644 --- a/src/node.rs +++ b/src/node.rs @@ -50,4 +50,14 @@ impl Node { } pub fn toggle_hide_stricken(&mut self) { self.hide_stricken = !self.hide_stricken; } + + pub fn new_from(other: &Self) -> Self { + Node { + color: random_fg_color(), + id: 0, + parent_id: 0, + selected: false, + ..other.clone() + } + } } diff --git a/src/screen.rs b/src/screen.rs index 0ee8b62..299f092 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -34,6 +34,13 @@ struct Selection { inserting: bool, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum Cut { + Move(NodeID), + Yank(NodeID), + Empty, +} + pub struct Screen { pub max_id: u64, pub nodes: HashMap, @@ -50,7 +57,7 @@ pub struct Screen { drawing_root: NodeID, show_logs: bool, selected: Option, - cut: Option, + cut: Cut, drawing_arrow: Option, lookup: HashMap, drawn_at: HashMap, @@ -95,7 +102,7 @@ impl Default for Screen { config: Config::default(), arrows: vec![], selected: None, - cut: None, + cut: Cut::Empty, drawing_arrow: None, nodes: HashMap::new(), lookup: HashMap::new(), @@ -130,7 +137,12 @@ impl Screen { fn help(&mut self) { self.cleanup(); self.start_raw_mode(); - println!("{}{}{}", cursor::Goto(1, 1), clear::All, self.config.to_string().replace("\n", "\r\n")); + println!( + "{}{}{}", + cursor::Goto(1, 1), + clear::All, + self.config.to_string().replace("\n", "\r\n") + ); if self.single_key_prompt("").is_err() { // likely here because of testing } @@ -150,6 +162,24 @@ impl Screen { id } + fn clone_node(&mut self, id: NodeID, new_parent_id: NodeID) -> Option { + info!("Try new node"); + let mut new_node = Node::new_from(self.nodes.get(&id)?); + info!("Made new node"); + let new_id = self.new_node_id(); + let new_children = new_node.children.iter().flat_map(|&child_id| { + self.clone_node(child_id, new_id) + }).collect(); + new_node.id = new_id; + new_node.children = new_children; + new_node.parent_id = new_parent_id; + + self.nodes.insert(new_id, new_node); + info!("Inserted new node"); + + Some(new_id) + } + pub fn with_node(&self, k: NodeID, mut f: F) -> Option where F: FnMut(&Node) -> B, @@ -234,9 +264,7 @@ impl Screen { Action::SelectDown => self.select_down(), Action::SelectLeft => self.select_left(), Action::SelectRight => self.select_right(), - Action::EraseChar if self.is_insert_mode() => { - self.backspace() - } + Action::EraseChar if self.is_insert_mode() => self.backspace(), Action::EraseChar => {} Action::CreateSibling => self.create_sibling(), Action::CreateChild => self.create_child(), @@ -255,7 +283,8 @@ impl Screen { Action::ToggleShowLogs => self.toggle_show_logs(), Action::EnterCmd => self.enter_cmd(), Action::FindTask => self.auto_task(), - Action::YankPasteNode => self.cut_paste(), + Action::YankPasteNode => self.cut_paste(true), + Action::MovePasteNode => self.cut_paste(false), Action::RaiseSelected => self.raise_selected(), Action::LowerSelected => self.lower_selected(), Action::Search => self.search_forward(), @@ -273,16 +302,35 @@ impl Screen { self.nodes.get(&node_id).is_some() } - fn cut_paste(&mut self) { - if let Some(sel) = self.selected { - if let Some(cut) = self.cut.take() { - self.reparent(cut, sel.selected_id); - } else { - self.cut = Some(sel.selected_id); + fn cut_paste(&mut self, yanking: bool) { + let can_cut = self.selected.is_some(); + let place = self.selected.map_or(self.drawing_root, |sel| sel.selected_id); + match self.cut { + Cut::Move(cut) => { + self.reparent(cut, place); + self.cut = Cut::Empty; } - } else if let Some(cut) = self.cut.take() { - let root = self.drawing_root; - self.reparent(cut, root); + Cut::Yank(cut) => { + if self.is_parent(cut, place) { + warn!("Can't copy a node into itself"); + return; + } + if let Some(new_id) = self.clone_node(cut, place) { + self.with_node_mut_no_meta(place, |parent_nd| { + parent_nd.children.push(new_id); + }); + } else { + info!("Yank failed somewhere"); + }; + self.cut = Cut::Empty; + } + Cut::Empty if yanking && can_cut => { + self.cut = Cut::Yank(place); + } + Cut::Empty if can_cut => { + self.cut = Cut::Move(place); + } + Cut::Empty => {} } } @@ -333,7 +381,10 @@ impl Screen { .children .iter() .cloned() - .filter(|&c| self.with_node(c, |c| !c.stricken && !c.content.contains("#ignr")).unwrap()) + .filter(|&c| { + self.with_node(c, |c| !c.stricken && !c.content.contains("#ignr")) + .unwrap() + }) .collect(); if incomplete_children.is_empty() { leaves.push(root_id); @@ -582,9 +633,9 @@ impl Screen { // want to accidentally execute rm -rf / return; } - lazy_static![ + lazy_static! { static ref RE_TAG: Regex = Regex::new(r"([^#])#[^#\s]+").unwrap(); - ]; + }; let Selection { selected_id, .. } = self.selected.unwrap(); let content_opt = self.with_node(selected_id, |n| n.content.clone()); @@ -595,7 +646,9 @@ impl Screen { // remove any tags from the exec // except for those that are escaped as ## - let content = RE_TAG.replace_all(&content_opt.unwrap(), "$1").replace("##", "#"); + let content = RE_TAG + .replace_all(&content_opt.unwrap(), "$1") + .replace("##", "#"); info!("executing command: {}", content); if content.is_empty() { @@ -1744,15 +1797,19 @@ impl Screen { if let Some(arrow) = self.selected.map(|to| (from, to.selected_id)) { let (from, to) = arrow; if self.nodes.get(&from).is_some() && self.nodes.get(&to).is_some() { - let contains = self.arrows.iter().fold(false, |acc, &(ref nl1, ref nl2, _)| { - if nl1 == &from && nl2 == &to { - true - } else { - acc - } - }); + let contains = self + .arrows + .iter() + .fold(false, |acc, &(ref nl1, ref nl2, _)| { + if nl1 == &from && nl2 == &to { + true + } else { + acc + } + }); if contains { - self.arrows.retain(|(old_from, old_to, _)| (*old_from, *old_to) != arrow); + self.arrows + .retain(|(old_from, old_to, _)| (*old_from, *old_to) != arrow); } else { self.arrows.push((from, to, random_fg_color())); } @@ -2144,14 +2201,25 @@ impl Screen { if self.config.modal && self.is_insert_mode() { header_text.push_str(" [insert] "); } - if let Some(cut) = self.cut { - let content = &self.nodes.get(&cut).unwrap().content; - let content_ellipsized = if content.len() >= 13 { - Cow::from(format!("{}...", &content[..10])) - } else { - Cow::from(content) - }; - header_text.push_str(&format!(" [yanking: {}] ", content_ellipsized)); + match self.cut { + Cut::Move(id) | Cut::Yank(id) => { + let content = &self.nodes.get(&id).unwrap().content; + let content_ellipsized = if content.len() >= 13 { + Cow::from(format!("{}...", &content[..10])) + } else { + Cow::from(content) + }; + header_text.push_str(&format!( + " [{}: {}] ", + match self.cut { + Cut::Move(_) => "moving", + Cut::Yank(_) => "yanking", + Cut::Empty => unreachable!(), + }, + content_ellipsized + )); + } + Cut::Empty => {} } let (plot, finished_today) = self.last_week_of_done_tasks(); From 2e4906227c0d2013ae824be54f96a838c278c487 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Wed, 22 Sep 2021 19:16:21 +0300 Subject: [PATCH 17/41] Reformat --- src/node.rs | 8 ++++++-- src/pack.rs | 4 +++- src/plot.rs | 8 ++++++-- src/screen.rs | 12 ++++++++---- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/node.rs b/src/node.rs index 2c08179..69c8489 100644 --- a/src/node.rs +++ b/src/node.rs @@ -38,7 +38,9 @@ impl Default for Node { } impl Node { - pub fn toggle_collapsed(&mut self) { self.collapsed = !self.collapsed; } + pub fn toggle_collapsed(&mut self) { + self.collapsed = !self.collapsed; + } pub fn toggle_stricken(&mut self) { if self.stricken { @@ -49,7 +51,9 @@ impl Node { self.stricken = !self.stricken; } - pub fn toggle_hide_stricken(&mut self) { self.hide_stricken = !self.hide_stricken; } + pub fn toggle_hide_stricken(&mut self) { + self.hide_stricken = !self.hide_stricken; + } pub fn new_from(other: &Self) -> Self { Node { diff --git a/src/pack.rs b/src/pack.rs index 32fc0e0..13bd790 100644 --- a/src/pack.rs +++ b/src/pack.rs @@ -80,7 +80,9 @@ impl Pack { ) } - fn is_leaf(&self) -> bool { self.children.is_none() } + fn is_leaf(&self) -> bool { + self.children.is_none() + } fn can_accomodate(&self, dim: Coords) -> bool { let capacity = self.dim(); diff --git a/src/plot.rs b/src/plot.rs index 4b364a4..004c81c 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -1,7 +1,9 @@ use std::cmp; pub fn plot_sparkline(nums_in: Vec) -> String -where T: Into { +where + T: Into, +{ const BARS: [char; 9] = [' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']; let nums: Vec<_> = nums_in.into_iter().map(|n| n.into()).collect(); @@ -20,7 +22,9 @@ where T: Into { } pub fn bounded_count_sparkline(nums_in: Vec, start: T, end: T, bars: usize) -> String -where T: Into { +where + T: Into, +{ if bars == 0 { return String::new(); } diff --git a/src/screen.rs b/src/screen.rs index 299f092..7dc8ad6 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -167,9 +167,11 @@ impl Screen { let mut new_node = Node::new_from(self.nodes.get(&id)?); info!("Made new node"); let new_id = self.new_node_id(); - let new_children = new_node.children.iter().flat_map(|&child_id| { - self.clone_node(child_id, new_id) - }).collect(); + let new_children = new_node + .children + .iter() + .flat_map(|&child_id| self.clone_node(child_id, new_id)) + .collect(); new_node.id = new_id; new_node.children = new_children; new_node.parent_id = new_parent_id; @@ -304,7 +306,9 @@ impl Screen { fn cut_paste(&mut self, yanking: bool) { let can_cut = self.selected.is_some(); - let place = self.selected.map_or(self.drawing_root, |sel| sel.selected_id); + let place = self + .selected + .map_or(self.drawing_root, |sel| sel.selected_id); match self.cut { Cut::Move(cut) => { self.reparent(cut, place); From c3d940afa25d69a01c57e73ba2eed14f25a24b4a Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Wed, 22 Sep 2021 19:26:19 +0300 Subject: [PATCH 18/41] Deal with Clippy lints --- src/bin/void/main.rs | 4 +- src/config.rs | 2 +- src/screen.rs | 114 ++++++++++++++++++++++--------------------- src/tagdb.rs | 4 +- test/screen.rs | 14 +++--- 5 files changed, 71 insertions(+), 67 deletions(-) diff --git a/src/bin/void/main.rs b/src/bin/void/main.rs index c61346a..b27b121 100644 --- a/src/bin/void/main.rs +++ b/src/bin/void/main.rs @@ -16,9 +16,9 @@ fn main() { .value_of("PATH") .map(OsString::from) .or_else(|| { - dirs::home_dir().and_then(|mut h| { + dirs::home_dir().map(|mut h| { h.push(".void.db"); - Some(h.into_os_string()) + h.into_os_string() }) }) .unwrap(); diff --git a/src/config.rs b/src/config.rs index 4f7be6d..6508d86 100644 --- a/src/config.rs +++ b/src/config.rs @@ -293,7 +293,7 @@ impl Config { f.read_to_string(&mut buf)?; let mut config = Config::default(); for (mut line_num, line) in buf.lines().enumerate() { - if line == "" || line.starts_with('#') { + if line.is_empty() || line.starts_with('#') { continue; } if line == "modal" { diff --git a/src/screen.rs b/src/screen.rs index 7dc8ad6..b93ae94 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,7 +1,7 @@ use std::{ self, borrow::Cow, - cmp::{max, min}, + cmp::{max, min, Ordering}, collections::{BTreeMap, BinaryHeap, HashMap, HashSet}, env, fmt::Write as FmtWrite, @@ -95,8 +95,10 @@ pub struct Screen { impl Default for Screen { fn default() -> Screen { - let mut root = Node::default(); - root.content = "home".to_owned(); + let root = Node { + content: "home".to_owned(), + ..Node::default() + }; let mut screen = Screen { autosave_every: 25, config: Config::default(), @@ -445,7 +447,7 @@ impl Screen { .and_then(|c| { if RE.is_match(&*c) { RE.captures_iter(&*c) - .nth(0) + .next() .and_then(|n| n.get(1).unwrap().as_str().parse::().ok()) } else { None @@ -468,7 +470,7 @@ impl Screen { prompt ); self.flush(); - let res = stdin.keys().nth(0).unwrap(); + let res = stdin.keys().next().unwrap(); debug!("read prompt: {:?}", res); print!("{}", style::Reset); res @@ -524,7 +526,7 @@ impl Screen { SearchDirection::Backward => format!("search backwards{}:", last_search_str), }; if let Ok(Some(mut query)) = self.prompt(&*prompt) { - if query == "" { + if query.is_empty() { if let Some((ref last, _)) = self.last_search { query = last.clone(); } else { @@ -540,7 +542,7 @@ impl Screen { if candidates.is_empty() { return; } - candidates.sort(); + candidates.sort_unstable(); let choice = if let Some((_, last_choice)) = self.last_search.take() { let idx = candidates .iter() @@ -908,14 +910,14 @@ impl Screen { node.selected = true; node_id }) - .and_then(|id| { + .map(|id| { self.selected = Some(Selection { selected_id: node_id, inserting: !self.config.modal, }); self.dragging_from = Some(coords); self.dragging_to = Some(coords); - Some(id) + id }) .or_else(|| { trace!("found no node at {:?}", coords); @@ -2023,7 +2025,7 @@ impl Screen { } write!(&mut buf, "{}", pre_meta).unwrap(); write!(&mut buf, "{}", prefix).unwrap(); - if prefix != "" { + if !prefix.is_empty() { // only anchor will have blank prefix if last { write!(&mut buf, "└─").unwrap(); @@ -2051,7 +2053,7 @@ impl Screen { write!(&mut buf, "{}", post_content).unwrap(); } // keep color for selected & tree root Fg - if !node.selected && prefix != "" { + if !node.selected && !prefix.is_empty() { write!(&mut buf, "{}", reset).unwrap(); } @@ -2113,8 +2115,8 @@ impl Screen { let mut prefix = prefix; if last { prefix.push_str(" "); - } else if prefix == "" { - prefix.push_str(" "); + } else if prefix.is_empty() { + prefix.push(' '); } else { prefix.push_str("│ "); } @@ -2147,49 +2149,51 @@ impl Screen { .collect(); trace!("draw_path({:?}, {:?}, {:?})", path, start_dir, dest_dir); print!("{}", color); - if path.len() == 1 { - print!("{} ↺", cursor::Goto(path[0].0, path[0].1)) - } else if path.len() > 1 { - let first = if path[1].1 > path[0].1 { - match start_dir { - Dir::R => '┐', - Dir::L => '┌', - } - } else if path[1].1 < path[0].1 { - match start_dir { - Dir::R => '┘', - Dir::L => '└', - } - } else { - '─' - }; - - print!("{}{}", cursor::Goto(path[0].0, path[0].1), first); - for items in path.windows(3) { - let (p, this, n) = (items[0], items[1], items[2]); - let c = if p.0 == n.0 { - '│' - } else if p.1 == n.1 { - '─' - } else if (this.1 < p.1 && this.0 < n.0) || (this.0 < p.0 && this.1 < n.1) { - '┌' // up+right or left+down - } else if (this.0 > p.0 && this.1 > n.1) || (this.1 > p.1 && this.0 > n.0) { - '┘' // right+up or down+left - } else if (this.0 > p.0 && this.1 < n.1) || (this.1 < p.1 && this.0 > n.0) { - '┐' // right+down or up+left - } else { - '└' // down+right or left+up + match path.len().cmp(&1) { + Ordering::Equal => { + print!("{} ↺", cursor::Goto(path[0].0, path[0].1)) + } + Ordering::Greater => { + let first = match path[1].1.cmp(&path[0].1) { + Ordering::Greater => match start_dir { + Dir::R => '┐', + Dir::L => '┌', + }, + Ordering::Less => match start_dir { + Dir::R => '┘', + Dir::L => '└', + }, + Ordering::Equal => '─', }; - print!("{}{}", cursor::Goto(this.0, this.1), c) + print!("{}{}", cursor::Goto(path[0].0, path[0].1), first); + for items in path.windows(3) { + let (p, this, n) = (items[0], items[1], items[2]); + let c = if p.0 == n.0 { + '│' + } else if p.1 == n.1 { + '─' + } else if (this.1 < p.1 && this.0 < n.0) || (this.0 < p.0 && this.1 < n.1) { + '┌' // up+right or left+down + } else if (this.0 > p.0 && this.1 > n.1) || (this.1 > p.1 && this.0 > n.0) { + '┘' // right+up or down+left + } else if (this.0 > p.0 && this.1 < n.1) || (this.1 < p.1 && this.0 > n.0) { + '┐' // right+down or up+left + } else { + '└' // down+right or left+up + }; + + print!("{}{}", cursor::Goto(this.0, this.1), c) + } + let (end_x, end_y) = (path[path.len() - 1].0, path[path.len() - 1].1); + let end_char = match dest_dir { + Dir::L => '>', + Dir::R => '<', + }; + print!("{}{}", cursor::Goto(end_x, end_y), end_char); } - let (end_x, end_y) = (path[path.len() - 1].0, path[path.len() - 1].1); - let end_char = match dest_dir { - Dir::L => '>', - Dir::R => '<', - }; - print!("{}{}", cursor::Goto(end_x, end_y), end_char); - } + _ => {} + }; print!("{}", color::Fg(color::Reset)); } @@ -2430,7 +2434,7 @@ impl Screen { } let queried_nodes = tagged_children .map(|tc| tc.into_iter().collect()) - .unwrap_or_else(|| vec![]); + .unwrap_or_else(Vec::new); let mut since_opt = None; let mut until_opt = None; @@ -2493,7 +2497,7 @@ impl Screen { let now = now().as_secs(); let buckets = n_opt.cloned().unwrap_or(7); let since = since_opt.unwrap_or_else(|| now - 60 * 60 * 24 * 7); - let until = until_opt.unwrap_or_else(|| now); + let until = until_opt.unwrap_or(now); node.content = match plot.as_str() { "done" => self.plot(queried_nodes, PlotType::Done, buckets, since, until), diff --git a/src/tagdb.rs b/src/tagdb.rs index 21fdf53..31c5a84 100644 --- a/src/tagdb.rs +++ b/src/tagdb.rs @@ -73,8 +73,8 @@ impl TagDB { .tag_to_nodes .get(&tag.to_owned()) .map(|set| set.clone().into_iter().collect()) - .unwrap_or_else(|| vec![]); - res.sort(); + .unwrap_or_else(Vec::new); + res.sort_unstable(); res } } diff --git a/test/screen.rs b/test/screen.rs index 1a357c6..152e340 100644 --- a/test/screen.rs +++ b/test/screen.rs @@ -22,12 +22,12 @@ impl fmt::Debug for Op { } impl Arbitrary for Op { - fn arbitrary(g: &mut G) -> Op { + fn arbitrary(generator: &mut G) -> Op { let (c, u, x, y) = ( - g.sample(Alphanumeric), - g.gen::(), - g.gen::(), - g.gen::(), + generator.sample(Alphanumeric), + generator.gen::(), + generator.gen::(), + generator.gen::(), ); let events = vec![ Event::Key(Key::Char('\n')), @@ -50,7 +50,7 @@ impl Arbitrary for Op { Event::Mouse(MouseEvent::Release(x, y)), ]; Op { - event: events.choose(g).unwrap().clone(), + event: events.choose(generator).unwrap().clone(), } } } @@ -94,7 +94,7 @@ impl Arbitrary for Content { let mut choice = vec![]; for _ in 0..g.gen_range(0, 2) { - let command = commands.choose(g).unwrap().clone(); + let command = commands.choose(g).unwrap(); let mut chars = command.chars().collect(); choice.append(&mut chars); if g.gen_range(0, 10) > 0 { From e7eeece2489b883a05ed751328d8f7307ec952c6 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Wed, 22 Sep 2021 20:03:33 +0300 Subject: [PATCH 19/41] Plot successful tasks in reverse direction --- src/plot.rs | 2 +- src/screen.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plot.rs b/src/plot.rs index 004c81c..6f957f7 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -35,7 +35,7 @@ where let step = (end - start) / bars as i64; let mut counts = vec![0; bars]; - if step == 0 || nums.is_empty() || end <= start { + if step == 0 || nums.is_empty() { return String::from_utf8(vec![b' '; bars]).unwrap(); } diff --git a/src/screen.rs b/src/screen.rs index b93ae94..35f424f 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2390,7 +2390,7 @@ impl Screen { let today_normalized = now / day_in_sec * day_in_sec; let counts_clone = counts.clone(); let finished_today = counts_clone[&today_normalized]; - let week_line: Vec = counts.into_iter().map(|(_, v)| v).collect(); + let week_line: Vec = counts.into_iter().rev().map(|(_, v)| v).collect(); let plot = plot::plot_sparkline(week_line); (plot, finished_today as usize) } @@ -2537,7 +2537,7 @@ impl Screen { }); nodes.append(&mut new); } - let plot = plot::bounded_count_sparkline(nodes, since as i64, until as i64, buckets); + let plot = plot::bounded_count_sparkline(nodes, until as i64, since as i64, buckets); format!("|{}|", plot) } From d88a040b9b03a94979de429e01d3b3bc57862b0a Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Fri, 24 Sep 2021 20:30:04 +0300 Subject: [PATCH 20/41] Really plot sparklines in reverse, instead of clumping everything at the start --- src/plot.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plot.rs b/src/plot.rs index 6f957f7..695ba8b 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -23,12 +23,18 @@ where pub fn bounded_count_sparkline(nums_in: Vec, start: T, end: T, bars: usize) -> String where - T: Into, + T: Into + PartialOrd, { if bars == 0 { return String::new(); } + let (start, end, rev) = if start <= end { + (start, end, false) + } else { + (end, start, true) + }; + let start = start.into(); let end = end.into(); let nums: Vec<_> = nums_in.into_iter().map(|n| n.into()).collect(); @@ -47,5 +53,11 @@ where let idx = (n - start) / step; counts[cmp::min(idx, bars - 1)] += 1; } - plot_sparkline(counts) + + let plot = plot_sparkline(counts); + if rev { + plot.chars().rev().collect() + } else { + plot + } } From 04a540f651a65f3d587cd547254206cec31d2b05 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 25 Sep 2021 20:46:40 +0300 Subject: [PATCH 21/41] Implement deadlines with a nice calendar --- Cargo.lock | 60 +- Cargo.toml | 3 +- include/data_model.proto | 15 +- src/bin/void/main.rs | 6 +- src/meta.rs | 5 +- src/pb/data_model.rs | 2132 +++++++++++++++++++------------------- src/pb/mod.rs | 2 +- src/plot.rs | 4 +- src/screen.rs | 243 ++++- src/serialization.rs | 29 +- 10 files changed, 1384 insertions(+), 1115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 807c0ec..ddbe428 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.15" @@ -94,6 +96,19 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time 0.1.44", + "winapi", +] + [[package]] name = "clap" version = "2.33.3" @@ -215,7 +230,7 @@ checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -260,6 +275,25 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "numtoa" version = "0.1.0" @@ -289,9 +323,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "1.7.5" +version = "2.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ccd6b79ec748412d4f2dfde1a80fa363a67def4062969f8aed3d790a30f28" +checksum = "23129d50f2c9355ced935fce8a08bd706ee2e7ce2b3b33bf61dace0e379ac63a" [[package]] name = "quickcheck" @@ -591,6 +625,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.2.22" @@ -663,6 +708,7 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" name = "voidmap" version = "1.1.5" dependencies = [ + "chrono", "clap", "clippy", "dirs 3.0.1", @@ -676,7 +722,7 @@ dependencies = [ "rand", "regex", "termion", - "time", + "time 0.2.22", "unicode-segmentation", ] @@ -686,6 +732,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasm-bindgen" version = "0.2.68" diff --git a/Cargo.toml b/Cargo.toml index 6248b4c..5ddbdbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,13 +24,14 @@ log = "0.4.11" lazy_static = "1.4.0" time = "0.2.22" getopts = "0.2.21" -protobuf = "1" +protobuf = "2" rand = "0.7.3" libc = "0.2.80" regex = "1.4.2" unicode-segmentation = "1.6.0" clippy = { version = "0.0.302", optional = true } fs2 = "0.4.3" +chrono = "0.4" [dev-dependencies] quickcheck = "0.9.2" diff --git a/include/data_model.proto b/include/data_model.proto index 043d5b6..7f91a39 100644 --- a/include/data_model.proto +++ b/include/data_model.proto @@ -8,8 +8,14 @@ message Tag { } message Gps { - required float lat = 1; - required float lon = 2; + optional float lat = 1; + optional float lon = 2; +} + +message Date { + required uint32 day = 1; + required uint32 month = 2; + required uint32 year = 3; } message Meta { @@ -18,7 +24,8 @@ message Meta { optional uint64 finish_time = 5; required Gps gps = 3; repeated Tag tags = 4; - optional uint64 due = 6; + optional uint64 OLD_due = 6; + optional Date due_date = 7; } message Node { @@ -31,7 +38,7 @@ message Node { required bool hide_stricken = 7; required uint32 x = 8; required uint32 y = 9; - required bool selected = 10; + optional bool selected = 10; required uint64 parent_id = 11; optional string free_text = 12; required bool auto_arrange = 13; diff --git a/src/bin/void/main.rs b/src/bin/void/main.rs index b27b121..c7a8b9b 100644 --- a/src/bin/void/main.rs +++ b/src/bin/void/main.rs @@ -1,6 +1,6 @@ use fs2::FileExt; use std::{ffi::OsString, fs::OpenOptions, io::Read}; -use voidmap::{deserialize_screen, init_screen_log, Config, Screen}; +use voidmap::{deserialize_screen, init_screen_log, Config}; mod cli; @@ -37,10 +37,10 @@ fn main() { .unwrap_or_else(|_| panic!("Another `void` process is using this path already!")); f.read_to_end(&mut data).unwrap(); - let saved_screen = deserialize_screen(data).ok(); + let saved_screen = deserialize_screen(data).expect("invalid screen"); // Initialise the main working screen - let mut screen = saved_screen.unwrap_or_else(Screen::default); + let mut screen = saved_screen/*.unwrap_or_else(Screen::default)*/; screen.work_path = matches .value_of("PATH") diff --git a/src/meta.rs b/src/meta.rs index 37799ec..56dd548 100644 --- a/src/meta.rs +++ b/src/meta.rs @@ -1,13 +1,14 @@ use std::collections::HashMap; use crate::now; +use chrono::{Date, Local}; #[derive(Debug, Clone)] pub struct Meta { pub ctime: u64, pub mtime: u64, pub finish_time: Option, - pub due: Option, + pub due_date: Option>, pub tags: HashMap, } @@ -18,7 +19,7 @@ impl Default for Meta { ctime: now, mtime: now, finish_time: None, - due: None, + due_date: None, tags: HashMap::new(), } } diff --git a/src/pb/data_model.rs b/src/pb/data_model.rs index c50060e..7f36996 100644 --- a/src/pb/data_model.rs +++ b/src/pb/data_model.rs @@ -1,25 +1,27 @@ -// This file is generated. Do not edit +// This file is generated by rust-protobuf 2.25.1. Do not edit // @generated -// https://github.com/Manishearth/rust-clippy/issues/702 +// https://github.com/rust-lang/rust-clippy/issues/702 #![allow(unknown_lints)] -#![allow(bare_trait_objects)] #![allow(clippy::all)] -#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] #![allow(box_pointers)] #![allow(dead_code)] +#![allow(missing_docs)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![allow(trivial_casts)] -#![allow(unsafe_code)] #![allow(unused_imports)] #![allow(unused_results)] +//! Generated file from `include/data_model.proto` -use protobuf::Message as Message_imported_for_functions; -use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; +/// Generated files are compatible only with the same version +/// of protobuf runtime. +// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_1; #[derive(PartialEq,Clone,Default)] pub struct Tag { @@ -27,30 +29,30 @@ pub struct Tag { key: ::protobuf::SingularField<::std::string::String>, value: ::protobuf::SingularField<::std::string::String>, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Tag {} +impl<'a> ::std::default::Default for &'a Tag { + fn default() -> &'a Tag { + ::default_instance() + } +} impl Tag { pub fn new() -> Tag { ::std::default::Default::default() } - pub fn default_instance() -> &'static Tag { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Tag, - }; - unsafe { - instance.get(Tag::new) - } - } - // required string key = 1; + + pub fn get_key(&self) -> &str { + match self.key.as_ref() { + Some(v) => &v, + None => "", + } + } pub fn clear_key(&mut self) { self.key.clear(); } @@ -69,7 +71,7 @@ impl Tag { pub fn mut_key(&mut self) -> &mut ::std::string::String { if self.key.is_none() { self.key.set_default(); - }; + } self.key.as_mut().unwrap() } @@ -78,23 +80,15 @@ impl Tag { self.key.take().unwrap_or_else(|| ::std::string::String::new()) } - pub fn get_key(&self) -> &str { - match self.key.as_ref() { + // required string value = 2; + + + pub fn get_value(&self) -> &str { + match self.value.as_ref() { Some(v) => &v, None => "", } } - - fn get_key_for_reflect(&self) -> &::protobuf::SingularField<::std::string::String> { - &self.key - } - - fn mut_key_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::string::String> { - &mut self.key - } - - // required string value = 2; - pub fn clear_value(&mut self) { self.value.clear(); } @@ -113,7 +107,7 @@ impl Tag { pub fn mut_value(&mut self) -> &mut ::std::string::String { if self.value.is_none() { self.value.set_default(); - }; + } self.value.as_mut().unwrap() } @@ -121,35 +115,20 @@ impl Tag { pub fn take_value(&mut self) -> ::std::string::String { self.value.take().unwrap_or_else(|| ::std::string::String::new()) } - - pub fn get_value(&self) -> &str { - match self.value.as_ref() { - Some(v) => &v, - None => "", - } - } - - fn get_value_for_reflect(&self) -> &::protobuf::SingularField<::std::string::String> { - &self.value - } - - fn mut_value_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::string::String> { - &mut self.value - } } impl ::protobuf::Message for Tag { fn is_initialized(&self) -> bool { if self.key.is_none() { return false; - }; + } if self.value.is_none() { return false; - }; + } true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -171,24 +150,24 @@ impl ::protobuf::Message for Tag { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if let Some(v) = self.key.as_ref() { + if let Some(ref v) = self.key.as_ref() { my_size += ::protobuf::rt::string_size(1, &v); - }; - if let Some(v) = self.value.as_ref() { + } + if let Some(ref v) = self.value.as_ref() { my_size += ::protobuf::rt::string_size(2, &v); - }; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { - if let Some(v) = self.key.as_ref() { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.key.as_ref() { os.write_string(1, &v)?; - }; - if let Some(v) = self.value.as_ref() { + } + if let Some(ref v) = self.value.as_ref() { os.write_string(2, &v)?; - }; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -205,65 +184,69 @@ impl ::protobuf::Message for Tag { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Tag { fn new() -> Tag { Tag::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "key", - Tag::get_key_for_reflect, - Tag::mut_key_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "value", - Tag::get_value_for_reflect, - Tag::mut_value_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Tag", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "key", + |m: &Tag| { &m.key }, + |m: &mut Tag| { &mut m.key }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "value", + |m: &Tag| { &m.value }, + |m: &mut Tag| { &mut m.value }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Tag", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Tag { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Tag::new) } } impl ::protobuf::Clear for Tag { fn clear(&mut self) { - self.clear_key(); - self.clear_value(); + self.key.clear(); + self.value.clear(); self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Tag { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Tag { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } @@ -273,30 +256,27 @@ pub struct Gps { lat: ::std::option::Option, lon: ::std::option::Option, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Gps {} +impl<'a> ::std::default::Default for &'a Gps { + fn default() -> &'a Gps { + ::default_instance() + } +} impl Gps { pub fn new() -> Gps { ::std::default::Default::default() } - pub fn default_instance() -> &'static Gps { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Gps, - }; - unsafe { - instance.get(Gps::new) - } - } + // optional float lat = 1; - // required float lat = 1; + pub fn get_lat(&self) -> f32 { + self.lat.unwrap_or(0.) + } pub fn clear_lat(&mut self) { self.lat = ::std::option::Option::None; } @@ -310,20 +290,12 @@ impl Gps { self.lat = ::std::option::Option::Some(v); } - pub fn get_lat(&self) -> f32 { - self.lat.unwrap_or(0.) - } + // optional float lon = 2; - fn get_lat_for_reflect(&self) -> &::std::option::Option { - &self.lat - } - fn mut_lat_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.lat + pub fn get_lon(&self) -> f32 { + self.lon.unwrap_or(0.) } - - // required float lon = 2; - pub fn clear_lon(&mut self) { self.lon = ::std::option::Option::None; } @@ -336,46 +308,28 @@ impl Gps { pub fn set_lon(&mut self, v: f32) { self.lon = ::std::option::Option::Some(v); } - - pub fn get_lon(&self) -> f32 { - self.lon.unwrap_or(0.) - } - - fn get_lon_for_reflect(&self) -> &::std::option::Option { - &self.lon - } - - fn mut_lon_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.lon - } } impl ::protobuf::Message for Gps { fn is_initialized(&self) -> bool { - if self.lat.is_none() { - return false; - }; - if self.lon.is_none() { - return false; - }; true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { if wire_type != ::protobuf::wire_format::WireTypeFixed32 { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_float()?; self.lat = ::std::option::Option::Some(tmp); }, 2 => { if wire_type != ::protobuf::wire_format::WireTypeFixed32 { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_float()?; self.lon = ::std::option::Option::Some(tmp); }, @@ -393,22 +347,22 @@ impl ::protobuf::Message for Gps { let mut my_size = 0; if let Some(v) = self.lat { my_size += 5; - }; + } if let Some(v) = self.lon { my_size += 5; - }; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.lat { os.write_float(1, v)?; - }; + } if let Some(v) = self.lon { os.write_float(2, v)?; - }; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -425,65 +379,312 @@ impl ::protobuf::Message for Gps { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Gps { fn new() -> Gps { Gps::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeFloat>( - "lat", - Gps::get_lat_for_reflect, - Gps::mut_lat_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeFloat>( - "lon", - Gps::get_lon_for_reflect, - Gps::mut_lon_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Gps", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeFloat>( + "lat", + |m: &Gps| { &m.lat }, + |m: &mut Gps| { &mut m.lat }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeFloat>( + "lon", + |m: &Gps| { &m.lon }, + |m: &mut Gps| { &mut m.lon }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Gps", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Gps { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Gps::new) } } impl ::protobuf::Clear for Gps { fn clear(&mut self) { - self.clear_lat(); - self.clear_lon(); + self.lat = ::std::option::Option::None; + self.lon = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Gps { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Gps { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct Date { + // message fields + day: ::std::option::Option, + month: ::std::option::Option, + year: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a Date { + fn default() -> &'a Date { + ::default_instance() + } +} + +impl Date { + pub fn new() -> Date { + ::std::default::Default::default() + } + + // required uint32 day = 1; + + + pub fn get_day(&self) -> u32 { + self.day.unwrap_or(0) + } + pub fn clear_day(&mut self) { + self.day = ::std::option::Option::None; + } + + pub fn has_day(&self) -> bool { + self.day.is_some() + } + + // Param is passed by value, moved + pub fn set_day(&mut self, v: u32) { + self.day = ::std::option::Option::Some(v); + } + + // required uint32 month = 2; + + + pub fn get_month(&self) -> u32 { + self.month.unwrap_or(0) + } + pub fn clear_month(&mut self) { + self.month = ::std::option::Option::None; + } + + pub fn has_month(&self) -> bool { + self.month.is_some() + } + + // Param is passed by value, moved + pub fn set_month(&mut self, v: u32) { + self.month = ::std::option::Option::Some(v); + } + + // required uint32 year = 3; + + + pub fn get_year(&self) -> u32 { + self.year.unwrap_or(0) + } + pub fn clear_year(&mut self) { + self.year = ::std::option::Option::None; + } + + pub fn has_year(&self) -> bool { + self.year.is_some() + } + + // Param is passed by value, moved + pub fn set_year(&mut self, v: u32) { + self.year = ::std::option::Option::Some(v); + } +} + +impl ::protobuf::Message for Date { + fn is_initialized(&self) -> bool { + if self.day.is_none() { + return false; + } + if self.month.is_none() { + return false; + } + if self.year.is_none() { + return false; + } + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.day = ::std::option::Option::Some(tmp); + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.month = ::std::option::Option::Some(tmp); + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_uint32()?; + self.year = ::std::option::Option::Some(tmp); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(v) = self.day { + my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); + } + if let Some(v) = self.month { + my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); + } + if let Some(v) = self.year { + my_size += ::protobuf::rt::value_size(3, v, ::protobuf::wire_format::WireTypeVarint); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.day { + os.write_uint32(1, v)?; + } + if let Some(v) = self.month { + os.write_uint32(2, v)?; + } + if let Some(v) = self.year { + os.write_uint32(3, v)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> Date { + Date::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "day", + |m: &Date| { &m.day }, + |m: &mut Date| { &mut m.day }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "month", + |m: &Date| { &m.month }, + |m: &mut Date| { &mut m.month }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "year", + |m: &Date| { &m.year }, + |m: &mut Date| { &mut m.year }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Date", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Date { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Date::new) + } +} + +impl ::protobuf::Clear for Date { + fn clear(&mut self) { + self.day = ::std::option::Option::None; + self.month = ::std::option::Option::None; + self.year = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for Date { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Date { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } @@ -493,34 +694,32 @@ pub struct Meta { ctime: ::std::option::Option, mtime: ::std::option::Option, finish_time: ::std::option::Option, - gps: ::protobuf::SingularPtrField, - tags: ::protobuf::RepeatedField, - due: ::std::option::Option, + pub gps: ::protobuf::SingularPtrField, + pub tags: ::protobuf::RepeatedField, + OLD_due: ::std::option::Option, + pub due_date: ::protobuf::SingularPtrField, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Meta {} +impl<'a> ::std::default::Default for &'a Meta { + fn default() -> &'a Meta { + ::default_instance() + } +} impl Meta { pub fn new() -> Meta { ::std::default::Default::default() } - pub fn default_instance() -> &'static Meta { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Meta, - }; - unsafe { - instance.get(Meta::new) - } - } - // required uint64 ctime = 1; + + pub fn get_ctime(&self) -> u64 { + self.ctime.unwrap_or(0) + } pub fn clear_ctime(&mut self) { self.ctime = ::std::option::Option::None; } @@ -534,20 +733,12 @@ impl Meta { self.ctime = ::std::option::Option::Some(v); } - pub fn get_ctime(&self) -> u64 { - self.ctime.unwrap_or(0) - } + // required uint64 mtime = 2; - fn get_ctime_for_reflect(&self) -> &::std::option::Option { - &self.ctime - } - fn mut_ctime_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.ctime + pub fn get_mtime(&self) -> u64 { + self.mtime.unwrap_or(0) } - - // required uint64 mtime = 2; - pub fn clear_mtime(&mut self) { self.mtime = ::std::option::Option::None; } @@ -561,20 +752,12 @@ impl Meta { self.mtime = ::std::option::Option::Some(v); } - pub fn get_mtime(&self) -> u64 { - self.mtime.unwrap_or(0) - } + // optional uint64 finish_time = 5; - fn get_mtime_for_reflect(&self) -> &::std::option::Option { - &self.mtime - } - fn mut_mtime_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.mtime + pub fn get_finish_time(&self) -> u64 { + self.finish_time.unwrap_or(0) } - - // optional uint64 finish_time = 5; - pub fn clear_finish_time(&mut self) { self.finish_time = ::std::option::Option::None; } @@ -588,20 +771,12 @@ impl Meta { self.finish_time = ::std::option::Option::Some(v); } - pub fn get_finish_time(&self) -> u64 { - self.finish_time.unwrap_or(0) - } + // required .void.Gps gps = 3; - fn get_finish_time_for_reflect(&self) -> &::std::option::Option { - &self.finish_time - } - fn mut_finish_time_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.finish_time + pub fn get_gps(&self) -> &Gps { + self.gps.as_ref().unwrap_or_else(|| ::default_instance()) } - - // required .void.Gps gps = 3; - pub fn clear_gps(&mut self) { self.gps.clear(); } @@ -620,7 +795,7 @@ impl Meta { pub fn mut_gps(&mut self) -> &mut Gps { if self.gps.is_none() { self.gps.set_default(); - }; + } self.gps.as_mut().unwrap() } @@ -629,20 +804,12 @@ impl Meta { self.gps.take().unwrap_or_else(|| Gps::new()) } - pub fn get_gps(&self) -> &Gps { - self.gps.as_ref().unwrap_or_else(|| Gps::default_instance()) - } + // repeated .void.Tag tags = 4; - fn get_gps_for_reflect(&self) -> &::protobuf::SingularPtrField { - &self.gps - } - fn mut_gps_for_reflect(&mut self) -> &mut ::protobuf::SingularPtrField { - &mut self.gps + pub fn get_tags(&self) -> &[Tag] { + &self.tags } - - // repeated .void.Tag tags = 4; - pub fn clear_tags(&mut self) { self.tags.clear(); } @@ -662,43 +829,56 @@ impl Meta { ::std::mem::replace(&mut self.tags, ::protobuf::RepeatedField::new()) } - pub fn get_tags(&self) -> &[Tag] { - &self.tags + // optional uint64 OLD_due = 6; + + + pub fn get_OLD_due(&self) -> u64 { + self.OLD_due.unwrap_or(0) + } + pub fn clear_OLD_due(&mut self) { + self.OLD_due = ::std::option::Option::None; } - fn get_tags_for_reflect(&self) -> &::protobuf::RepeatedField { - &self.tags + pub fn has_OLD_due(&self) -> bool { + self.OLD_due.is_some() } - fn mut_tags_for_reflect(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.tags + // Param is passed by value, moved + pub fn set_OLD_due(&mut self, v: u64) { + self.OLD_due = ::std::option::Option::Some(v); } - // optional uint64 due = 6; + // optional .void.Date due_date = 7; - pub fn clear_due(&mut self) { - self.due = ::std::option::Option::None; - } - pub fn has_due(&self) -> bool { - self.due.is_some() + pub fn get_due_date(&self) -> &Date { + self.due_date.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_due_date(&mut self) { + self.due_date.clear(); } - // Param is passed by value, moved - pub fn set_due(&mut self, v: u64) { - self.due = ::std::option::Option::Some(v); + pub fn has_due_date(&self) -> bool { + self.due_date.is_some() } - pub fn get_due(&self) -> u64 { - self.due.unwrap_or(0) + // Param is passed by value, moved + pub fn set_due_date(&mut self, v: Date) { + self.due_date = ::protobuf::SingularPtrField::some(v); } - fn get_due_for_reflect(&self) -> &::std::option::Option { - &self.due + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_due_date(&mut self) -> &mut Date { + if self.due_date.is_none() { + self.due_date.set_default(); + } + self.due_date.as_mut().unwrap() } - fn mut_due_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.due + // Take field + pub fn take_due_date(&mut self) -> Date { + self.due_date.take().unwrap_or_else(|| Date::new()) } } @@ -706,38 +886,53 @@ impl ::protobuf::Message for Meta { fn is_initialized(&self) -> bool { if self.ctime.is_none() { return false; - }; + } if self.mtime.is_none() { return false; - }; + } if self.gps.is_none() { return false; + } + for v in &self.gps { + if !v.is_initialized() { + return false; + } + }; + for v in &self.tags { + if !v.is_initialized() { + return false; + } + }; + for v in &self.due_date { + if !v.is_initialized() { + return false; + } }; true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.ctime = ::std::option::Option::Some(tmp); }, 2 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.mtime = ::std::option::Option::Some(tmp); }, 5 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.finish_time = ::std::option::Option::Some(tmp); }, @@ -750,9 +945,12 @@ impl ::protobuf::Message for Meta { 6 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; - self.due = ::std::option::Option::Some(tmp); + self.OLD_due = ::std::option::Option::Some(tmp); + }, + 7 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.due_date)?; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; @@ -768,52 +966,61 @@ impl ::protobuf::Message for Meta { let mut my_size = 0; if let Some(v) = self.ctime { my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); - }; + } if let Some(v) = self.mtime { my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); - }; + } if let Some(v) = self.finish_time { my_size += ::protobuf::rt::value_size(5, v, ::protobuf::wire_format::WireTypeVarint); - }; - if let Some(v) = self.gps.as_ref() { + } + if let Some(ref v) = self.gps.as_ref() { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }; + } for value in &self.tags { let len = value.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; }; - if let Some(v) = self.due { + if let Some(v) = self.OLD_due { my_size += ::protobuf::rt::value_size(6, v, ::protobuf::wire_format::WireTypeVarint); - }; + } + if let Some(ref v) = self.due_date.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.ctime { os.write_uint64(1, v)?; - }; + } if let Some(v) = self.mtime { os.write_uint64(2, v)?; - }; + } if let Some(v) = self.finish_time { os.write_uint64(5, v)?; - }; - if let Some(v) = self.gps.as_ref() { + } + if let Some(ref v) = self.gps.as_ref() { os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; - }; + } for v in &self.tags { os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; }; - if let Some(v) = self.due { + if let Some(v) = self.OLD_due { os.write_uint64(6, v)?; - }; + } + if let Some(ref v) = self.due_date.as_ref() { + os.write_tag(7, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -830,89 +1037,99 @@ impl ::protobuf::Message for Meta { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Meta { fn new() -> Meta { Meta::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "ctime", - Meta::get_ctime_for_reflect, - Meta::mut_ctime_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "mtime", - Meta::get_mtime_for_reflect, - Meta::mut_mtime_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "finish_time", - Meta::get_finish_time_for_reflect, - Meta::mut_finish_time_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "gps", - Meta::get_gps_for_reflect, - Meta::mut_gps_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "tags", - Meta::get_tags_for_reflect, - Meta::mut_tags_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "due", - Meta::get_due_for_reflect, - Meta::mut_due_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Meta", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "ctime", + |m: &Meta| { &m.ctime }, + |m: &mut Meta| { &mut m.ctime }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "mtime", + |m: &Meta| { &m.mtime }, + |m: &mut Meta| { &mut m.mtime }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "finish_time", + |m: &Meta| { &m.finish_time }, + |m: &mut Meta| { &mut m.finish_time }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "gps", + |m: &Meta| { &m.gps }, + |m: &mut Meta| { &mut m.gps }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "tags", + |m: &Meta| { &m.tags }, + |m: &mut Meta| { &mut m.tags }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "OLD_due", + |m: &Meta| { &m.OLD_due }, + |m: &mut Meta| { &mut m.OLD_due }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "due_date", + |m: &Meta| { &m.due_date }, + |m: &mut Meta| { &mut m.due_date }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Meta", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Meta { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Meta::new) } } impl ::protobuf::Clear for Meta { fn clear(&mut self) { - self.clear_ctime(); - self.clear_mtime(); - self.clear_finish_time(); - self.clear_gps(); - self.clear_tags(); - self.clear_due(); + self.ctime = ::std::option::Option::None; + self.mtime = ::std::option::Option::None; + self.finish_time = ::std::option::Option::None; + self.gps.clear(); + self.tags.clear(); + self.OLD_due = ::std::option::Option::None; + self.due_date.clear(); self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Meta { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Meta { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } @@ -920,9 +1137,9 @@ impl ::protobuf::reflect::ProtobufValue for Meta { pub struct Node { // message fields id: ::std::option::Option, - meta: ::protobuf::SingularPtrField, + pub meta: ::protobuf::SingularPtrField, text: ::protobuf::SingularField<::std::string::String>, - children: ::std::vec::Vec, + pub children: ::std::vec::Vec, collapsed: ::std::option::Option, stricken: ::std::option::Option, hide_stricken: ::std::option::Option, @@ -933,30 +1150,27 @@ pub struct Node { free_text: ::protobuf::SingularField<::std::string::String>, auto_arrange: ::std::option::Option, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Node {} +impl<'a> ::std::default::Default for &'a Node { + fn default() -> &'a Node { + ::default_instance() + } +} impl Node { pub fn new() -> Node { ::std::default::Default::default() } - pub fn default_instance() -> &'static Node { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Node, - }; - unsafe { - instance.get(Node::new) - } - } - // required uint64 id = 1; + + pub fn get_id(&self) -> u64 { + self.id.unwrap_or(0) + } pub fn clear_id(&mut self) { self.id = ::std::option::Option::None; } @@ -970,20 +1184,12 @@ impl Node { self.id = ::std::option::Option::Some(v); } - pub fn get_id(&self) -> u64 { - self.id.unwrap_or(0) - } + // required .void.Meta meta = 2; - fn get_id_for_reflect(&self) -> &::std::option::Option { - &self.id - } - fn mut_id_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.id + pub fn get_meta(&self) -> &Meta { + self.meta.as_ref().unwrap_or_else(|| ::default_instance()) } - - // required .void.Meta meta = 2; - pub fn clear_meta(&mut self) { self.meta.clear(); } @@ -1002,7 +1208,7 @@ impl Node { pub fn mut_meta(&mut self) -> &mut Meta { if self.meta.is_none() { self.meta.set_default(); - }; + } self.meta.as_mut().unwrap() } @@ -1011,20 +1217,15 @@ impl Node { self.meta.take().unwrap_or_else(|| Meta::new()) } - pub fn get_meta(&self) -> &Meta { - self.meta.as_ref().unwrap_or_else(|| Meta::default_instance()) - } + // required string text = 3; - fn get_meta_for_reflect(&self) -> &::protobuf::SingularPtrField { - &self.meta - } - fn mut_meta_for_reflect(&mut self) -> &mut ::protobuf::SingularPtrField { - &mut self.meta + pub fn get_text(&self) -> &str { + match self.text.as_ref() { + Some(v) => &v, + None => "", + } } - - // required string text = 3; - pub fn clear_text(&mut self) { self.text.clear(); } @@ -1043,7 +1244,7 @@ impl Node { pub fn mut_text(&mut self) -> &mut ::std::string::String { if self.text.is_none() { self.text.set_default(); - }; + } self.text.as_mut().unwrap() } @@ -1052,23 +1253,12 @@ impl Node { self.text.take().unwrap_or_else(|| ::std::string::String::new()) } - pub fn get_text(&self) -> &str { - match self.text.as_ref() { - Some(v) => &v, - None => "", - } - } + // repeated uint64 children = 4; - fn get_text_for_reflect(&self) -> &::protobuf::SingularField<::std::string::String> { - &self.text - } - fn mut_text_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::string::String> { - &mut self.text + pub fn get_children(&self) -> &[u64] { + &self.children } - - // repeated uint64 children = 4; - pub fn clear_children(&mut self) { self.children.clear(); } @@ -1088,20 +1278,12 @@ impl Node { ::std::mem::replace(&mut self.children, ::std::vec::Vec::new()) } - pub fn get_children(&self) -> &[u64] { - &self.children - } + // required bool collapsed = 5; - fn get_children_for_reflect(&self) -> &::std::vec::Vec { - &self.children - } - fn mut_children_for_reflect(&mut self) -> &mut ::std::vec::Vec { - &mut self.children + pub fn get_collapsed(&self) -> bool { + self.collapsed.unwrap_or(false) } - - // required bool collapsed = 5; - pub fn clear_collapsed(&mut self) { self.collapsed = ::std::option::Option::None; } @@ -1115,20 +1297,12 @@ impl Node { self.collapsed = ::std::option::Option::Some(v); } - pub fn get_collapsed(&self) -> bool { - self.collapsed.unwrap_or(false) - } + // required bool stricken = 6; - fn get_collapsed_for_reflect(&self) -> &::std::option::Option { - &self.collapsed - } - fn mut_collapsed_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.collapsed + pub fn get_stricken(&self) -> bool { + self.stricken.unwrap_or(false) } - - // required bool stricken = 6; - pub fn clear_stricken(&mut self) { self.stricken = ::std::option::Option::None; } @@ -1142,20 +1316,12 @@ impl Node { self.stricken = ::std::option::Option::Some(v); } - pub fn get_stricken(&self) -> bool { - self.stricken.unwrap_or(false) - } + // required bool hide_stricken = 7; - fn get_stricken_for_reflect(&self) -> &::std::option::Option { - &self.stricken - } - fn mut_stricken_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.stricken + pub fn get_hide_stricken(&self) -> bool { + self.hide_stricken.unwrap_or(false) } - - // required bool hide_stricken = 7; - pub fn clear_hide_stricken(&mut self) { self.hide_stricken = ::std::option::Option::None; } @@ -1169,20 +1335,12 @@ impl Node { self.hide_stricken = ::std::option::Option::Some(v); } - pub fn get_hide_stricken(&self) -> bool { - self.hide_stricken.unwrap_or(false) - } + // required uint32 x = 8; - fn get_hide_stricken_for_reflect(&self) -> &::std::option::Option { - &self.hide_stricken - } - fn mut_hide_stricken_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.hide_stricken + pub fn get_x(&self) -> u32 { + self.x.unwrap_or(0) } - - // required uint32 x = 8; - pub fn clear_x(&mut self) { self.x = ::std::option::Option::None; } @@ -1196,20 +1354,12 @@ impl Node { self.x = ::std::option::Option::Some(v); } - pub fn get_x(&self) -> u32 { - self.x.unwrap_or(0) - } + // required uint32 y = 9; - fn get_x_for_reflect(&self) -> &::std::option::Option { - &self.x - } - fn mut_x_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.x + pub fn get_y(&self) -> u32 { + self.y.unwrap_or(0) } - - // required uint32 y = 9; - pub fn clear_y(&mut self) { self.y = ::std::option::Option::None; } @@ -1218,25 +1368,17 @@ impl Node { self.y.is_some() } - // Param is passed by value, moved - pub fn set_y(&mut self, v: u32) { - self.y = ::std::option::Option::Some(v); - } - - pub fn get_y(&self) -> u32 { - self.y.unwrap_or(0) - } - - fn get_y_for_reflect(&self) -> &::std::option::Option { - &self.y + // Param is passed by value, moved + pub fn set_y(&mut self, v: u32) { + self.y = ::std::option::Option::Some(v); } - fn mut_y_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.y - } + // optional bool selected = 10; - // required bool selected = 10; + pub fn get_selected(&self) -> bool { + self.selected.unwrap_or(false) + } pub fn clear_selected(&mut self) { self.selected = ::std::option::Option::None; } @@ -1250,20 +1392,12 @@ impl Node { self.selected = ::std::option::Option::Some(v); } - pub fn get_selected(&self) -> bool { - self.selected.unwrap_or(false) - } + // required uint64 parent_id = 11; - fn get_selected_for_reflect(&self) -> &::std::option::Option { - &self.selected - } - fn mut_selected_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.selected + pub fn get_parent_id(&self) -> u64 { + self.parent_id.unwrap_or(0) } - - // required uint64 parent_id = 11; - pub fn clear_parent_id(&mut self) { self.parent_id = ::std::option::Option::None; } @@ -1277,20 +1411,15 @@ impl Node { self.parent_id = ::std::option::Option::Some(v); } - pub fn get_parent_id(&self) -> u64 { - self.parent_id.unwrap_or(0) - } + // optional string free_text = 12; - fn get_parent_id_for_reflect(&self) -> &::std::option::Option { - &self.parent_id - } - fn mut_parent_id_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.parent_id + pub fn get_free_text(&self) -> &str { + match self.free_text.as_ref() { + Some(v) => &v, + None => "", + } } - - // optional string free_text = 12; - pub fn clear_free_text(&mut self) { self.free_text.clear(); } @@ -1309,7 +1438,7 @@ impl Node { pub fn mut_free_text(&mut self) -> &mut ::std::string::String { if self.free_text.is_none() { self.free_text.set_default(); - }; + } self.free_text.as_mut().unwrap() } @@ -1318,23 +1447,12 @@ impl Node { self.free_text.take().unwrap_or_else(|| ::std::string::String::new()) } - pub fn get_free_text(&self) -> &str { - match self.free_text.as_ref() { - Some(v) => &v, - None => "", - } - } + // required bool auto_arrange = 13; - fn get_free_text_for_reflect(&self) -> &::protobuf::SingularField<::std::string::String> { - &self.free_text - } - fn mut_free_text_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::string::String> { - &mut self.free_text + pub fn get_auto_arrange(&self) -> bool { + self.auto_arrange.unwrap_or(false) } - - // required bool auto_arrange = 13; - pub fn clear_auto_arrange(&mut self) { self.auto_arrange = ::std::option::Option::None; } @@ -1347,66 +1465,56 @@ impl Node { pub fn set_auto_arrange(&mut self, v: bool) { self.auto_arrange = ::std::option::Option::Some(v); } - - pub fn get_auto_arrange(&self) -> bool { - self.auto_arrange.unwrap_or(false) - } - - fn get_auto_arrange_for_reflect(&self) -> &::std::option::Option { - &self.auto_arrange - } - - fn mut_auto_arrange_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.auto_arrange - } } impl ::protobuf::Message for Node { fn is_initialized(&self) -> bool { if self.id.is_none() { return false; - }; + } if self.meta.is_none() { return false; - }; + } if self.text.is_none() { return false; - }; + } if self.collapsed.is_none() { return false; - }; + } if self.stricken.is_none() { return false; - }; + } if self.hide_stricken.is_none() { return false; - }; + } if self.x.is_none() { return false; - }; + } if self.y.is_none() { return false; - }; - if self.selected.is_none() { - return false; - }; + } if self.parent_id.is_none() { return false; - }; + } if self.auto_arrange.is_none() { return false; + } + for v in &self.meta { + if !v.is_initialized() { + return false; + } }; true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.id = ::std::option::Option::Some(tmp); }, @@ -1422,49 +1530,49 @@ impl ::protobuf::Message for Node { 5 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_bool()?; self.collapsed = ::std::option::Option::Some(tmp); }, 6 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_bool()?; self.stricken = ::std::option::Option::Some(tmp); }, 7 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_bool()?; self.hide_stricken = ::std::option::Option::Some(tmp); }, 8 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint32()?; self.x = ::std::option::Option::Some(tmp); }, 9 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint32()?; self.y = ::std::option::Option::Some(tmp); }, 10 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_bool()?; self.selected = ::std::option::Option::Some(tmp); }, 11 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.parent_id = ::std::option::Option::Some(tmp); }, @@ -1474,7 +1582,7 @@ impl ::protobuf::Message for Node { 13 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_bool()?; self.auto_arrange = ::std::option::Option::Some(tmp); }, @@ -1492,91 +1600,91 @@ impl ::protobuf::Message for Node { let mut my_size = 0; if let Some(v) = self.id { my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); - }; - if let Some(v) = self.meta.as_ref() { + } + if let Some(ref v) = self.meta.as_ref() { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; - }; - if let Some(v) = self.text.as_ref() { + } + if let Some(ref v) = self.text.as_ref() { my_size += ::protobuf::rt::string_size(3, &v); - }; + } for value in &self.children { my_size += ::protobuf::rt::value_size(4, *value, ::protobuf::wire_format::WireTypeVarint); }; if let Some(v) = self.collapsed { my_size += 2; - }; + } if let Some(v) = self.stricken { my_size += 2; - }; + } if let Some(v) = self.hide_stricken { my_size += 2; - }; + } if let Some(v) = self.x { my_size += ::protobuf::rt::value_size(8, v, ::protobuf::wire_format::WireTypeVarint); - }; + } if let Some(v) = self.y { my_size += ::protobuf::rt::value_size(9, v, ::protobuf::wire_format::WireTypeVarint); - }; + } if let Some(v) = self.selected { my_size += 2; - }; + } if let Some(v) = self.parent_id { my_size += ::protobuf::rt::value_size(11, v, ::protobuf::wire_format::WireTypeVarint); - }; - if let Some(v) = self.free_text.as_ref() { + } + if let Some(ref v) = self.free_text.as_ref() { my_size += ::protobuf::rt::string_size(12, &v); - }; + } if let Some(v) = self.auto_arrange { my_size += 2; - }; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.id { os.write_uint64(1, v)?; - }; - if let Some(v) = self.meta.as_ref() { + } + if let Some(ref v) = self.meta.as_ref() { os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; - }; - if let Some(v) = self.text.as_ref() { + } + if let Some(ref v) = self.text.as_ref() { os.write_string(3, &v)?; - }; + } for v in &self.children { os.write_uint64(4, *v)?; }; if let Some(v) = self.collapsed { os.write_bool(5, v)?; - }; + } if let Some(v) = self.stricken { os.write_bool(6, v)?; - }; + } if let Some(v) = self.hide_stricken { os.write_bool(7, v)?; - }; + } if let Some(v) = self.x { os.write_uint32(8, v)?; - }; + } if let Some(v) = self.y { os.write_uint32(9, v)?; - }; + } if let Some(v) = self.selected { os.write_bool(10, v)?; - }; + } if let Some(v) = self.parent_id { os.write_uint64(11, v)?; - }; - if let Some(v) = self.free_text.as_ref() { + } + if let Some(ref v) = self.free_text.as_ref() { os.write_string(12, &v)?; - }; + } if let Some(v) = self.auto_arrange { os.write_bool(13, v)?; - }; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -1593,131 +1701,135 @@ impl ::protobuf::Message for Node { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Node { fn new() -> Node { Node::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "id", - Node::get_id_for_reflect, - Node::mut_id_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "meta", - Node::get_meta_for_reflect, - Node::mut_meta_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "text", - Node::get_text_for_reflect, - Node::mut_text_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_vec_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "children", - Node::get_children_for_reflect, - Node::mut_children_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "collapsed", - Node::get_collapsed_for_reflect, - Node::mut_collapsed_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "stricken", - Node::get_stricken_for_reflect, - Node::mut_stricken_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "hide_stricken", - Node::get_hide_stricken_for_reflect, - Node::mut_hide_stricken_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( - "x", - Node::get_x_for_reflect, - Node::mut_x_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( - "y", - Node::get_y_for_reflect, - Node::mut_y_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "selected", - Node::get_selected_for_reflect, - Node::mut_selected_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "parent_id", - Node::get_parent_id_for_reflect, - Node::mut_parent_id_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "free_text", - Node::get_free_text_for_reflect, - Node::mut_free_text_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( - "auto_arrange", - Node::get_auto_arrange_for_reflect, - Node::mut_auto_arrange_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Node", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "id", + |m: &Node| { &m.id }, + |m: &mut Node| { &mut m.id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "meta", + |m: &Node| { &m.meta }, + |m: &mut Node| { &mut m.meta }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "text", + |m: &Node| { &m.text }, + |m: &mut Node| { &mut m.text }, + )); + fields.push(::protobuf::reflect::accessor::make_vec_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "children", + |m: &Node| { &m.children }, + |m: &mut Node| { &mut m.children }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "collapsed", + |m: &Node| { &m.collapsed }, + |m: &mut Node| { &mut m.collapsed }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "stricken", + |m: &Node| { &m.stricken }, + |m: &mut Node| { &mut m.stricken }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "hide_stricken", + |m: &Node| { &m.hide_stricken }, + |m: &mut Node| { &mut m.hide_stricken }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "x", + |m: &Node| { &m.x }, + |m: &mut Node| { &mut m.x }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint32>( + "y", + |m: &Node| { &m.y }, + |m: &mut Node| { &mut m.y }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "selected", + |m: &Node| { &m.selected }, + |m: &mut Node| { &mut m.selected }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "parent_id", + |m: &Node| { &m.parent_id }, + |m: &mut Node| { &mut m.parent_id }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "free_text", + |m: &Node| { &m.free_text }, + |m: &mut Node| { &mut m.free_text }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "auto_arrange", + |m: &Node| { &m.auto_arrange }, + |m: &mut Node| { &mut m.auto_arrange }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Node", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Node { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Node::new) } } impl ::protobuf::Clear for Node { fn clear(&mut self) { - self.clear_id(); - self.clear_meta(); - self.clear_text(); - self.clear_children(); - self.clear_collapsed(); - self.clear_stricken(); - self.clear_hide_stricken(); - self.clear_x(); - self.clear_y(); - self.clear_selected(); - self.clear_parent_id(); - self.clear_free_text(); - self.clear_auto_arrange(); + self.id = ::std::option::Option::None; + self.meta.clear(); + self.text.clear(); + self.children.clear(); + self.collapsed = ::std::option::Option::None; + self.stricken = ::std::option::Option::None; + self.hide_stricken = ::std::option::Option::None; + self.x = ::std::option::Option::None; + self.y = ::std::option::Option::None; + self.selected = ::std::option::Option::None; + self.parent_id = ::std::option::Option::None; + self.free_text.clear(); + self.auto_arrange = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Node { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Node { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } @@ -1727,30 +1839,27 @@ pub struct Arrow { from_node: ::std::option::Option, to_node: ::std::option::Option, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Arrow {} +impl<'a> ::std::default::Default for &'a Arrow { + fn default() -> &'a Arrow { + ::default_instance() + } +} impl Arrow { pub fn new() -> Arrow { ::std::default::Default::default() } - pub fn default_instance() -> &'static Arrow { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Arrow, - }; - unsafe { - instance.get(Arrow::new) - } - } - // required uint64 from_node = 1; + + pub fn get_from_node(&self) -> u64 { + self.from_node.unwrap_or(0) + } pub fn clear_from_node(&mut self) { self.from_node = ::std::option::Option::None; } @@ -1764,20 +1873,12 @@ impl Arrow { self.from_node = ::std::option::Option::Some(v); } - pub fn get_from_node(&self) -> u64 { - self.from_node.unwrap_or(0) - } + // required uint64 to_node = 2; - fn get_from_node_for_reflect(&self) -> &::std::option::Option { - &self.from_node - } - fn mut_from_node_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.from_node + pub fn get_to_node(&self) -> u64 { + self.to_node.unwrap_or(0) } - - // required uint64 to_node = 2; - pub fn clear_to_node(&mut self) { self.to_node = ::std::option::Option::None; } @@ -1790,46 +1891,34 @@ impl Arrow { pub fn set_to_node(&mut self, v: u64) { self.to_node = ::std::option::Option::Some(v); } - - pub fn get_to_node(&self) -> u64 { - self.to_node.unwrap_or(0) - } - - fn get_to_node_for_reflect(&self) -> &::std::option::Option { - &self.to_node - } - - fn mut_to_node_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.to_node - } } impl ::protobuf::Message for Arrow { fn is_initialized(&self) -> bool { if self.from_node.is_none() { return false; - }; + } if self.to_node.is_none() { return false; - }; + } true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.from_node = ::std::option::Option::Some(tmp); }, 2 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.to_node = ::std::option::Option::Some(tmp); }, @@ -1847,22 +1936,22 @@ impl ::protobuf::Message for Arrow { let mut my_size = 0; if let Some(v) = self.from_node { my_size += ::protobuf::rt::value_size(1, v, ::protobuf::wire_format::WireTypeVarint); - }; + } if let Some(v) = self.to_node { my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); - }; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { if let Some(v) = self.from_node { os.write_uint64(1, v)?; - }; + } if let Some(v) = self.to_node { os.write_uint64(2, v)?; - }; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -1879,99 +1968,100 @@ impl ::protobuf::Message for Arrow { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Arrow { fn new() -> Arrow { Arrow::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "from_node", - Arrow::get_from_node_for_reflect, - Arrow::mut_from_node_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "to_node", - Arrow::get_to_node_for_reflect, - Arrow::mut_to_node_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Arrow", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "from_node", + |m: &Arrow| { &m.from_node }, + |m: &mut Arrow| { &mut m.from_node }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "to_node", + |m: &Arrow| { &m.to_node }, + |m: &mut Arrow| { &mut m.to_node }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Arrow", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Arrow { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Arrow::new) } } impl ::protobuf::Clear for Arrow { fn clear(&mut self) { - self.clear_from_node(); - self.clear_to_node(); + self.from_node = ::std::option::Option::None; + self.to_node = ::std::option::Option::None; self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Arrow { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Arrow { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } #[derive(PartialEq,Clone,Default)] pub struct Screen { // message fields - nodes: ::protobuf::RepeatedField, + pub nodes: ::protobuf::RepeatedField, max_id: ::std::option::Option, - arrows: ::protobuf::RepeatedField, + pub arrows: ::protobuf::RepeatedField, // special fields - unknown_fields: ::protobuf::UnknownFields, - cached_size: ::protobuf::CachedSize, + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, } -// see codegen.rs for the explanation why impl Sync explicitly -unsafe impl ::std::marker::Sync for Screen {} +impl<'a> ::std::default::Default for &'a Screen { + fn default() -> &'a Screen { + ::default_instance() + } +} impl Screen { pub fn new() -> Screen { ::std::default::Default::default() } - pub fn default_instance() -> &'static Screen { - static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const Screen, - }; - unsafe { - instance.get(Screen::new) - } - } - // repeated .void.Node nodes = 1; + + pub fn get_nodes(&self) -> &[Node] { + &self.nodes + } pub fn clear_nodes(&mut self) { self.nodes.clear(); } @@ -1991,20 +2081,12 @@ impl Screen { ::std::mem::replace(&mut self.nodes, ::protobuf::RepeatedField::new()) } - pub fn get_nodes(&self) -> &[Node] { - &self.nodes - } + // required uint64 max_id = 2; - fn get_nodes_for_reflect(&self) -> &::protobuf::RepeatedField { - &self.nodes - } - fn mut_nodes_for_reflect(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.nodes + pub fn get_max_id(&self) -> u64 { + self.max_id.unwrap_or(0) } - - // required uint64 max_id = 2; - pub fn clear_max_id(&mut self) { self.max_id = ::std::option::Option::None; } @@ -2018,20 +2100,12 @@ impl Screen { self.max_id = ::std::option::Option::Some(v); } - pub fn get_max_id(&self) -> u64 { - self.max_id.unwrap_or(0) - } + // repeated .void.Arrow arrows = 3; - fn get_max_id_for_reflect(&self) -> &::std::option::Option { - &self.max_id - } - fn mut_max_id_for_reflect(&mut self) -> &mut ::std::option::Option { - &mut self.max_id + pub fn get_arrows(&self) -> &[Arrow] { + &self.arrows } - - // repeated .void.Arrow arrows = 3; - pub fn clear_arrows(&mut self) { self.arrows.clear(); } @@ -2050,29 +2124,27 @@ impl Screen { pub fn take_arrows(&mut self) -> ::protobuf::RepeatedField { ::std::mem::replace(&mut self.arrows, ::protobuf::RepeatedField::new()) } - - pub fn get_arrows(&self) -> &[Arrow] { - &self.arrows - } - - fn get_arrows_for_reflect(&self) -> &::protobuf::RepeatedField { - &self.arrows - } - - fn mut_arrows_for_reflect(&mut self) -> &mut ::protobuf::RepeatedField { - &mut self.arrows - } } impl ::protobuf::Message for Screen { fn is_initialized(&self) -> bool { if self.max_id.is_none() { return false; + } + for v in &self.nodes { + if !v.is_initialized() { + return false; + } + }; + for v in &self.arrows { + if !v.is_initialized() { + return false; + } }; true } - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { while !is.eof()? { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { @@ -2082,7 +2154,7 @@ impl ::protobuf::Message for Screen { 2 => { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - }; + } let tmp = is.read_uint64()?; self.max_id = ::std::option::Option::Some(tmp); }, @@ -2107,7 +2179,7 @@ impl ::protobuf::Message for Screen { }; if let Some(v) = self.max_id { my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); - }; + } for value in &self.arrows { let len = value.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; @@ -2117,7 +2189,7 @@ impl ::protobuf::Message for Screen { my_size } - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { for v in &self.nodes { os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -2125,7 +2197,7 @@ impl ::protobuf::Message for Screen { }; if let Some(v) = self.max_id { os.write_uint64(2, v)?; - }; + } for v in &self.arrows { os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_raw_varint32(v.get_cached_size())?; @@ -2147,272 +2219,234 @@ impl ::protobuf::Message for Screen { &mut self.unknown_fields } - fn as_any(&self) -> &::std::any::Any { - self as &::std::any::Any + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self } fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - ::protobuf::MessageStatic::descriptor_static(None::) + Self::descriptor_static() } -} -impl ::protobuf::MessageStatic for Screen { fn new() -> Screen { Screen::new() } - fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { - static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, - }; - unsafe { - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "nodes", - Screen::get_nodes_for_reflect, - Screen::mut_nodes_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( - "max_id", - Screen::get_max_id_for_reflect, - Screen::mut_max_id_for_reflect, - )); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( - "arrows", - Screen::get_arrows_for_reflect, - Screen::mut_arrows_for_reflect, - )); - ::protobuf::reflect::MessageDescriptor::new::( - "Screen", - fields, - file_descriptor_proto() - ) - }) - } + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "nodes", + |m: &Screen| { &m.nodes }, + |m: &mut Screen| { &mut m.nodes }, + )); + fields.push(::protobuf::reflect::accessor::make_option_accessor::<_, ::protobuf::types::ProtobufTypeUint64>( + "max_id", + |m: &Screen| { &m.max_id }, + |m: &mut Screen| { &mut m.max_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "arrows", + |m: &Screen| { &m.arrows }, + |m: &mut Screen| { &mut m.arrows }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "Screen", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static Screen { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(Screen::new) } } impl ::protobuf::Clear for Screen { fn clear(&mut self) { - self.clear_nodes(); - self.clear_max_id(); - self.clear_arrows(); + self.nodes.clear(); + self.max_id = ::std::option::Option::None; + self.arrows.clear(); self.unknown_fields.clear(); } } impl ::std::fmt::Debug for Screen { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } impl ::protobuf::reflect::ProtobufValue for Screen { - fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { - ::protobuf::reflect::ProtobufValueRef::Message(self) + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) } } -static file_descriptor_proto_data: &'static [u8] = &[ - 0x0a, 0x18, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x76, 0x6f, 0x69, 0x64, - 0x22, 0x2d, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, - 0x29, 0x0a, 0x03, 0x47, 0x70, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x61, 0x74, 0x18, 0x01, 0x20, - 0x02, 0x28, 0x02, 0x52, 0x03, 0x6c, 0x61, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x02, 0x28, 0x02, 0x52, 0x03, 0x6c, 0x6f, 0x6e, 0x22, 0xa1, 0x01, 0x0a, 0x04, 0x4d, - 0x65, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, - 0x28, 0x04, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, - 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x1b, 0x0a, 0x03, 0x67, 0x70, 0x73, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x09, 0x2e, - 0x76, 0x6f, 0x69, 0x64, 0x2e, 0x47, 0x70, 0x73, 0x52, 0x03, 0x67, 0x70, 0x73, 0x12, 0x1d, 0x0a, - 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x76, 0x6f, - 0x69, 0x64, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, - 0x64, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x64, 0x75, 0x65, 0x22, 0xda, - 0x02, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x02, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, - 0x02, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x76, 0x6f, 0x69, 0x64, 0x2e, 0x4d, 0x65, 0x74, - 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x03, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x04, 0x52, 0x08, 0x63, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x61, - 0x70, 0x73, 0x65, 0x64, 0x18, 0x05, 0x20, 0x02, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6c, 0x6c, - 0x61, 0x70, 0x73, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x65, - 0x6e, 0x18, 0x06, 0x20, 0x02, 0x28, 0x08, 0x52, 0x08, 0x73, 0x74, 0x72, 0x69, 0x63, 0x6b, 0x65, - 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x68, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x63, 0x6b, - 0x65, 0x6e, 0x18, 0x07, 0x20, 0x02, 0x28, 0x08, 0x52, 0x0c, 0x68, 0x69, 0x64, 0x65, 0x53, 0x74, - 0x72, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x08, 0x20, 0x02, 0x28, - 0x0d, 0x52, 0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x09, 0x20, 0x02, 0x28, 0x0d, 0x52, - 0x01, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0a, - 0x20, 0x02, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x1b, - 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x02, 0x28, - 0x04, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x66, - 0x72, 0x65, 0x65, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x66, 0x72, 0x65, 0x65, 0x54, 0x65, 0x78, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, - 0x5f, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x02, 0x28, 0x08, 0x52, 0x0b, - 0x61, 0x75, 0x74, 0x6f, 0x41, 0x72, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x3d, 0x0a, 0x05, 0x41, - 0x72, 0x72, 0x6f, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6e, 0x6f, 0x64, - 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x04, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x02, - 0x28, 0x04, 0x52, 0x06, 0x74, 0x6f, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0x66, 0x0a, 0x06, 0x53, 0x63, - 0x72, 0x65, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x76, 0x6f, 0x69, 0x64, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x02, 0x28, 0x04, 0x52, 0x05, 0x6d, 0x61, 0x78, 0x49, 0x64, 0x12, 0x23, 0x0a, - 0x06, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, - 0x76, 0x6f, 0x69, 0x64, 0x2e, 0x41, 0x72, 0x72, 0x6f, 0x77, 0x52, 0x06, 0x61, 0x72, 0x72, 0x6f, - 0x77, 0x73, 0x4a, 0xb8, 0x10, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x30, 0x01, 0x0a, 0x08, 0x0a, - 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x08, 0x0a, 0x01, 0x02, 0x12, 0x03, 0x02, 0x08, - 0x0c, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x04, 0x00, 0x07, 0x01, 0x0a, 0x0a, 0x0a, - 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x04, 0x08, 0x0b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, - 0x00, 0x12, 0x03, 0x05, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, - 0x03, 0x05, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x05, - 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x01, 0x12, 0x03, 0x05, 0x12, 0x15, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, 0x12, 0x03, 0x05, 0x18, 0x19, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x06, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x00, 0x02, 0x01, 0x04, 0x12, 0x03, 0x06, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, - 0x01, 0x05, 0x12, 0x03, 0x06, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, - 0x12, 0x03, 0x06, 0x12, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, - 0x06, 0x1a, 0x1b, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x01, 0x12, 0x04, 0x09, 0x00, 0x0c, 0x01, 0x0a, - 0x0a, 0x0a, 0x03, 0x04, 0x01, 0x01, 0x12, 0x03, 0x09, 0x08, 0x0b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x01, 0x02, 0x00, 0x12, 0x03, 0x0a, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, - 0x04, 0x12, 0x03, 0x0a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x05, 0x12, - 0x03, 0x0a, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x01, 0x12, 0x03, 0x0a, - 0x11, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0a, 0x17, 0x18, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x01, 0x02, 0x01, 0x12, 0x03, 0x0b, 0x02, 0x19, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x01, 0x02, 0x01, 0x04, 0x12, 0x03, 0x0b, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x01, 0x02, 0x01, 0x05, 0x12, 0x03, 0x0b, 0x0b, 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, - 0x01, 0x01, 0x12, 0x03, 0x0b, 0x11, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x01, 0x02, 0x01, 0x03, - 0x12, 0x03, 0x0b, 0x17, 0x18, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x02, 0x12, 0x04, 0x0e, 0x00, 0x15, - 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x02, 0x01, 0x12, 0x03, 0x0e, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x02, 0x02, 0x00, 0x12, 0x03, 0x0f, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x00, 0x04, 0x12, 0x03, 0x0f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, - 0x05, 0x12, 0x03, 0x0f, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x01, 0x12, - 0x03, 0x0f, 0x12, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x00, 0x03, 0x12, 0x03, 0x0f, - 0x1a, 0x1b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x01, 0x12, 0x03, 0x10, 0x02, 0x1c, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x01, 0x04, 0x12, 0x03, 0x10, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x01, 0x05, 0x12, 0x03, 0x10, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x02, 0x02, 0x01, 0x01, 0x12, 0x03, 0x10, 0x12, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x01, 0x03, 0x12, 0x03, 0x10, 0x1a, 0x1b, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x02, 0x12, - 0x03, 0x11, 0x02, 0x22, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x04, 0x12, 0x03, 0x11, - 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x05, 0x12, 0x03, 0x11, 0x0b, 0x11, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x01, 0x12, 0x03, 0x11, 0x12, 0x1d, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x02, 0x03, 0x12, 0x03, 0x11, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x02, 0x02, 0x03, 0x12, 0x03, 0x12, 0x02, 0x17, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, - 0x03, 0x04, 0x12, 0x03, 0x12, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x06, - 0x12, 0x03, 0x12, 0x0b, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x01, 0x12, 0x03, - 0x12, 0x0f, 0x12, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x03, 0x03, 0x12, 0x03, 0x12, 0x15, - 0x16, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x04, 0x12, 0x03, 0x13, 0x02, 0x18, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x02, 0x02, 0x04, 0x04, 0x12, 0x03, 0x13, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x02, 0x02, 0x04, 0x06, 0x12, 0x03, 0x13, 0x0b, 0x0e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, - 0x02, 0x04, 0x01, 0x12, 0x03, 0x13, 0x0f, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x04, - 0x03, 0x12, 0x03, 0x13, 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x02, 0x02, 0x05, 0x12, 0x03, - 0x14, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x05, 0x04, 0x12, 0x03, 0x14, 0x02, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x05, 0x05, 0x12, 0x03, 0x14, 0x0b, 0x11, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x02, 0x02, 0x05, 0x01, 0x12, 0x03, 0x14, 0x12, 0x15, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x02, 0x02, 0x05, 0x03, 0x12, 0x03, 0x14, 0x18, 0x19, 0x0a, 0x0a, 0x0a, 0x02, 0x04, - 0x03, 0x12, 0x04, 0x17, 0x00, 0x25, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x03, 0x01, 0x12, 0x03, - 0x17, 0x08, 0x0c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x00, 0x12, 0x03, 0x18, 0x02, 0x19, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x04, 0x12, 0x03, 0x18, 0x02, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x00, 0x05, 0x12, 0x03, 0x18, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x00, 0x01, 0x12, 0x03, 0x18, 0x12, 0x14, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x00, 0x03, 0x12, 0x03, 0x18, 0x17, 0x18, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x01, - 0x12, 0x03, 0x19, 0x02, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x04, 0x12, 0x03, - 0x19, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x06, 0x12, 0x03, 0x19, 0x0b, - 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x12, 0x03, 0x19, 0x10, 0x14, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x01, 0x03, 0x12, 0x03, 0x19, 0x17, 0x18, 0x0a, 0x0b, 0x0a, - 0x04, 0x04, 0x03, 0x02, 0x02, 0x12, 0x03, 0x1a, 0x02, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x02, 0x04, 0x12, 0x03, 0x1a, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, - 0x05, 0x12, 0x03, 0x1a, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x12, - 0x03, 0x1a, 0x12, 0x16, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x12, 0x03, 0x1a, - 0x19, 0x1a, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x03, 0x12, 0x03, 0x1b, 0x02, 0x1f, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x03, 0x04, 0x12, 0x03, 0x1b, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x03, 0x02, 0x03, 0x05, 0x12, 0x03, 0x1b, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x03, 0x02, 0x03, 0x01, 0x12, 0x03, 0x1b, 0x12, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x03, 0x03, 0x12, 0x03, 0x1b, 0x1d, 0x1e, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x04, 0x12, - 0x03, 0x1c, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x04, 0x04, 0x12, 0x03, 0x1c, - 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x04, 0x05, 0x12, 0x03, 0x1c, 0x0b, 0x0f, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x04, 0x01, 0x12, 0x03, 0x1c, 0x10, 0x19, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x04, 0x03, 0x12, 0x03, 0x1c, 0x1c, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x03, 0x02, 0x05, 0x12, 0x03, 0x1d, 0x02, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x05, 0x04, 0x12, 0x03, 0x1d, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x05, 0x05, - 0x12, 0x03, 0x1d, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x05, 0x01, 0x12, 0x03, - 0x1d, 0x10, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x05, 0x03, 0x12, 0x03, 0x1d, 0x1b, - 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x06, 0x12, 0x03, 0x1e, 0x02, 0x22, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x06, 0x04, 0x12, 0x03, 0x1e, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x06, 0x05, 0x12, 0x03, 0x1e, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x06, 0x01, 0x12, 0x03, 0x1e, 0x10, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x06, - 0x03, 0x12, 0x03, 0x1e, 0x20, 0x21, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x07, 0x12, 0x03, - 0x1f, 0x02, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x07, 0x04, 0x12, 0x03, 0x1f, 0x02, - 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x07, 0x05, 0x12, 0x03, 0x1f, 0x0b, 0x11, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x07, 0x01, 0x12, 0x03, 0x1f, 0x12, 0x13, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x03, 0x02, 0x07, 0x03, 0x12, 0x03, 0x1f, 0x16, 0x17, 0x0a, 0x0b, 0x0a, 0x04, 0x04, - 0x03, 0x02, 0x08, 0x12, 0x03, 0x20, 0x02, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x08, - 0x04, 0x12, 0x03, 0x20, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x08, 0x05, 0x12, - 0x03, 0x20, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x08, 0x01, 0x12, 0x03, 0x20, - 0x12, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x08, 0x03, 0x12, 0x03, 0x20, 0x16, 0x17, - 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x09, 0x12, 0x03, 0x21, 0x02, 0x1e, 0x0a, 0x0c, 0x0a, - 0x05, 0x04, 0x03, 0x02, 0x09, 0x04, 0x12, 0x03, 0x21, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x03, 0x02, 0x09, 0x05, 0x12, 0x03, 0x21, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, - 0x09, 0x01, 0x12, 0x03, 0x21, 0x10, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x09, 0x03, - 0x12, 0x03, 0x21, 0x1b, 0x1d, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x0a, 0x12, 0x03, 0x22, - 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0a, 0x04, 0x12, 0x03, 0x22, 0x02, 0x0a, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0a, 0x05, 0x12, 0x03, 0x22, 0x0b, 0x11, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0a, 0x01, 0x12, 0x03, 0x22, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x0a, 0x03, 0x12, 0x03, 0x22, 0x1e, 0x20, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x03, - 0x02, 0x0b, 0x12, 0x03, 0x23, 0x02, 0x21, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0b, 0x04, - 0x12, 0x03, 0x23, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0b, 0x05, 0x12, 0x03, - 0x23, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0b, 0x01, 0x12, 0x03, 0x23, 0x12, - 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0b, 0x03, 0x12, 0x03, 0x23, 0x1e, 0x20, 0x0a, - 0x0b, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x0c, 0x12, 0x03, 0x24, 0x02, 0x22, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x03, 0x02, 0x0c, 0x04, 0x12, 0x03, 0x24, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, - 0x02, 0x0c, 0x05, 0x12, 0x03, 0x24, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0c, - 0x01, 0x12, 0x03, 0x24, 0x10, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x03, 0x02, 0x0c, 0x03, 0x12, - 0x03, 0x24, 0x1f, 0x21, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x04, 0x12, 0x04, 0x27, 0x00, 0x2a, 0x01, - 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x04, 0x01, 0x12, 0x03, 0x27, 0x08, 0x0d, 0x0a, 0x0b, 0x0a, 0x04, - 0x04, 0x04, 0x02, 0x00, 0x12, 0x03, 0x28, 0x02, 0x20, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, - 0x00, 0x04, 0x12, 0x03, 0x28, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x05, - 0x12, 0x03, 0x28, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x01, 0x12, 0x03, - 0x28, 0x12, 0x1b, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x00, 0x03, 0x12, 0x03, 0x28, 0x1e, - 0x1f, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x04, 0x02, 0x01, 0x12, 0x03, 0x29, 0x02, 0x1e, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, 0x04, 0x12, 0x03, 0x29, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x04, 0x02, 0x01, 0x05, 0x12, 0x03, 0x29, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, - 0x02, 0x01, 0x01, 0x12, 0x03, 0x29, 0x12, 0x19, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x04, 0x02, 0x01, - 0x03, 0x12, 0x03, 0x29, 0x1c, 0x1d, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x05, 0x12, 0x04, 0x2c, 0x00, - 0x30, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x05, 0x01, 0x12, 0x03, 0x2c, 0x08, 0x0e, 0x0a, 0x0b, - 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x12, 0x03, 0x2d, 0x02, 0x1a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, - 0x05, 0x02, 0x00, 0x04, 0x12, 0x03, 0x2d, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, - 0x00, 0x06, 0x12, 0x03, 0x2d, 0x0b, 0x0f, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x01, - 0x12, 0x03, 0x2d, 0x10, 0x15, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x00, 0x03, 0x12, 0x03, - 0x2d, 0x18, 0x19, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x01, 0x12, 0x03, 0x2e, 0x02, 0x1d, - 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x04, 0x12, 0x03, 0x2e, 0x02, 0x0a, 0x0a, 0x0c, - 0x0a, 0x05, 0x04, 0x05, 0x02, 0x01, 0x05, 0x12, 0x03, 0x2e, 0x0b, 0x11, 0x0a, 0x0c, 0x0a, 0x05, - 0x04, 0x05, 0x02, 0x01, 0x01, 0x12, 0x03, 0x2e, 0x12, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, - 0x02, 0x01, 0x03, 0x12, 0x03, 0x2e, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x05, 0x02, 0x02, - 0x12, 0x03, 0x2f, 0x02, 0x1c, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, 0x04, 0x12, 0x03, - 0x2f, 0x02, 0x0a, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, 0x06, 0x12, 0x03, 0x2f, 0x0b, - 0x10, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, 0x01, 0x12, 0x03, 0x2f, 0x11, 0x17, 0x0a, - 0x0c, 0x0a, 0x05, 0x04, 0x05, 0x02, 0x02, 0x03, 0x12, 0x03, 0x2f, 0x1a, 0x1b, -]; - -static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { - lock: ::protobuf::lazy::ONCE_INIT, - ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, -}; +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x18include/data_model.proto\x12\x04void\"-\n\x03Tag\x12\x10\n\x03key\ + \x18\x01\x20\x02(\tR\x03key\x12\x14\n\x05value\x18\x02\x20\x02(\tR\x05va\ + lue\")\n\x03Gps\x12\x10\n\x03lat\x18\x01\x20\x01(\x02R\x03lat\x12\x10\n\ + \x03lon\x18\x02\x20\x01(\x02R\x03lon\"B\n\x04Date\x12\x10\n\x03day\x18\ + \x01\x20\x02(\rR\x03day\x12\x14\n\x05month\x18\x02\x20\x02(\rR\x05month\ + \x12\x12\n\x04year\x18\x03\x20\x02(\rR\x04year\"\xcf\x01\n\x04Meta\x12\ + \x14\n\x05ctime\x18\x01\x20\x02(\x04R\x05ctime\x12\x14\n\x05mtime\x18\ + \x02\x20\x02(\x04R\x05mtime\x12\x1f\n\x0bfinish_time\x18\x05\x20\x01(\ + \x04R\nfinishTime\x12\x1b\n\x03gps\x18\x03\x20\x02(\x0b2\t.void.GpsR\x03\ + gps\x12\x1d\n\x04tags\x18\x04\x20\x03(\x0b2\t.void.TagR\x04tags\x12\x17\ + \n\x07OLD_due\x18\x06\x20\x01(\x04R\x06OLDDue\x12%\n\x08due_date\x18\x07\ + \x20\x01(\x0b2\n.void.DateR\x07dueDate\"\xda\x02\n\x04Node\x12\x0e\n\x02\ + id\x18\x01\x20\x02(\x04R\x02id\x12\x1e\n\x04meta\x18\x02\x20\x02(\x0b2\n\ + .void.MetaR\x04meta\x12\x12\n\x04text\x18\x03\x20\x02(\tR\x04text\x12\ + \x1a\n\x08children\x18\x04\x20\x03(\x04R\x08children\x12\x1c\n\tcollapse\ + d\x18\x05\x20\x02(\x08R\tcollapsed\x12\x1a\n\x08stricken\x18\x06\x20\x02\ + (\x08R\x08stricken\x12#\n\rhide_stricken\x18\x07\x20\x02(\x08R\x0chideSt\ + ricken\x12\x0c\n\x01x\x18\x08\x20\x02(\rR\x01x\x12\x0c\n\x01y\x18\t\x20\ + \x02(\rR\x01y\x12\x1a\n\x08selected\x18\n\x20\x01(\x08R\x08selected\x12\ + \x1b\n\tparent_id\x18\x0b\x20\x02(\x04R\x08parentId\x12\x1b\n\tfree_text\ + \x18\x0c\x20\x01(\tR\x08freeText\x12!\n\x0cauto_arrange\x18\r\x20\x02(\ + \x08R\x0bautoArrange\"=\n\x05Arrow\x12\x1b\n\tfrom_node\x18\x01\x20\x02(\ + \x04R\x08fromNode\x12\x17\n\x07to_node\x18\x02\x20\x02(\x04R\x06toNode\"\ + f\n\x06Screen\x12\x20\n\x05nodes\x18\x01\x20\x03(\x0b2\n.void.NodeR\x05n\ + odes\x12\x15\n\x06max_id\x18\x02\x20\x02(\x04R\x05maxId\x12#\n\x06arrows\ + \x18\x03\x20\x03(\x0b2\x0b.void.ArrowR\x06arrowsJ\xe4\x12\n\x06\x12\x04\ + \0\07\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\0\ + \r\n\n\n\x02\x04\0\x12\x04\x04\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\ + \x08\x0b\n\x0b\n\x04\x04\0\x02\0\x12\x03\x05\x02\x1a\n\x0c\n\x05\x04\0\ + \x02\0\x04\x12\x03\x05\x02\n\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x05\x0b\ + \x11\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x05\x12\x15\n\x0c\n\x05\x04\0\ + \x02\0\x03\x12\x03\x05\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x06\x02\ + \x1c\n\x0c\n\x05\x04\0\x02\x01\x04\x12\x03\x06\x02\n\n\x0c\n\x05\x04\0\ + \x02\x01\x05\x12\x03\x06\x0b\x11\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\ + \x06\x12\x17\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x06\x1a\x1b\n\n\n\x02\ + \x04\x01\x12\x04\t\0\x0c\x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x0b\n\ + \x0b\n\x04\x04\x01\x02\0\x12\x03\n\x02\x19\n\x0c\n\x05\x04\x01\x02\0\x04\ + \x12\x03\n\x02\n\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x0b\x10\n\x0c\n\ + \x05\x04\x01\x02\0\x01\x12\x03\n\x11\x14\n\x0c\n\x05\x04\x01\x02\0\x03\ + \x12\x03\n\x17\x18\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x02\x19\n\x0c\ + \n\x05\x04\x01\x02\x01\x04\x12\x03\x0b\x02\n\n\x0c\n\x05\x04\x01\x02\x01\ + \x05\x12\x03\x0b\x0b\x10\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x11\ + \x14\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x17\x18\n\n\n\x02\x04\ + \x02\x12\x04\x0e\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x0c\n\ + \x0b\n\x04\x04\x02\x02\0\x12\x03\x0f\x04\x1c\n\x0c\n\x05\x04\x02\x02\0\ + \x04\x12\x03\x0f\x04\x0c\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\r\x13\ + \n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x14\x17\n\x0c\n\x05\x04\x02\ + \x02\0\x03\x12\x03\x0f\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\ + \x04\x1e\n\x0c\n\x05\x04\x02\x02\x01\x04\x12\x03\x10\x04\x0c\n\x0c\n\x05\ + \x04\x02\x02\x01\x05\x12\x03\x10\r\x13\n\x0c\n\x05\x04\x02\x02\x01\x01\ + \x12\x03\x10\x14\x19\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x10\x1c\x1d\ + \n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x11\x04\x1d\n\x0c\n\x05\x04\x02\x02\ + \x02\x04\x12\x03\x11\x04\x0c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\ + \r\x13\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x11\x14\x18\n\x0c\n\x05\ + \x04\x02\x02\x02\x03\x12\x03\x11\x1b\x1c\n\n\n\x02\x04\x03\x12\x04\x14\0\ + \x1c\x01\n\n\n\x03\x04\x03\x01\x12\x03\x14\x08\x0c\n\x0b\n\x04\x04\x03\ + \x02\0\x12\x03\x15\x02\x1c\n\x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x15\x02\ + \n\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x15\x0b\x11\n\x0c\n\x05\x04\x03\ + \x02\0\x01\x12\x03\x15\x12\x17\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x15\ + \x1a\x1b\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x16\x02\x1c\n\x0c\n\x05\x04\ + \x03\x02\x01\x04\x12\x03\x16\x02\n\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\ + \x03\x16\x0b\x11\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x16\x12\x17\n\ + \x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x16\x1a\x1b\n\x0b\n\x04\x04\x03\ + \x02\x02\x12\x03\x17\x02\"\n\x0c\n\x05\x04\x03\x02\x02\x04\x12\x03\x17\ + \x02\n\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x17\x0b\x11\n\x0c\n\x05\ + \x04\x03\x02\x02\x01\x12\x03\x17\x12\x1d\n\x0c\n\x05\x04\x03\x02\x02\x03\ + \x12\x03\x17\x20!\n\x0b\n\x04\x04\x03\x02\x03\x12\x03\x18\x02\x17\n\x0c\ + \n\x05\x04\x03\x02\x03\x04\x12\x03\x18\x02\n\n\x0c\n\x05\x04\x03\x02\x03\ + \x06\x12\x03\x18\x0b\x0e\n\x0c\n\x05\x04\x03\x02\x03\x01\x12\x03\x18\x0f\ + \x12\n\x0c\n\x05\x04\x03\x02\x03\x03\x12\x03\x18\x15\x16\n\x0b\n\x04\x04\ + \x03\x02\x04\x12\x03\x19\x02\x18\n\x0c\n\x05\x04\x03\x02\x04\x04\x12\x03\ + \x19\x02\n\n\x0c\n\x05\x04\x03\x02\x04\x06\x12\x03\x19\x0b\x0e\n\x0c\n\ + \x05\x04\x03\x02\x04\x01\x12\x03\x19\x0f\x13\n\x0c\n\x05\x04\x03\x02\x04\ + \x03\x12\x03\x19\x16\x17\n\x0b\n\x04\x04\x03\x02\x05\x12\x03\x1a\x02\x1e\ + \n\x0c\n\x05\x04\x03\x02\x05\x04\x12\x03\x1a\x02\n\n\x0c\n\x05\x04\x03\ + \x02\x05\x05\x12\x03\x1a\x0b\x11\n\x0c\n\x05\x04\x03\x02\x05\x01\x12\x03\ + \x1a\x12\x19\n\x0c\n\x05\x04\x03\x02\x05\x03\x12\x03\x1a\x1c\x1d\n\x0b\n\ + \x04\x04\x03\x02\x06\x12\x03\x1b\x02\x1d\n\x0c\n\x05\x04\x03\x02\x06\x04\ + \x12\x03\x1b\x02\n\n\x0c\n\x05\x04\x03\x02\x06\x06\x12\x03\x1b\x0b\x0f\n\ + \x0c\n\x05\x04\x03\x02\x06\x01\x12\x03\x1b\x10\x18\n\x0c\n\x05\x04\x03\ + \x02\x06\x03\x12\x03\x1b\x1b\x1c\n\n\n\x02\x04\x04\x12\x04\x1e\0,\x01\n\ + \n\n\x03\x04\x04\x01\x12\x03\x1e\x08\x0c\n\x0b\n\x04\x04\x04\x02\0\x12\ + \x03\x1f\x02\x19\n\x0c\n\x05\x04\x04\x02\0\x04\x12\x03\x1f\x02\n\n\x0c\n\ + \x05\x04\x04\x02\0\x05\x12\x03\x1f\x0b\x11\n\x0c\n\x05\x04\x04\x02\0\x01\ + \x12\x03\x1f\x12\x14\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x1f\x17\x18\n\ + \x0b\n\x04\x04\x04\x02\x01\x12\x03\x20\x02\x19\n\x0c\n\x05\x04\x04\x02\ + \x01\x04\x12\x03\x20\x02\n\n\x0c\n\x05\x04\x04\x02\x01\x06\x12\x03\x20\ + \x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\x20\x10\x14\n\x0c\n\x05\ + \x04\x04\x02\x01\x03\x12\x03\x20\x17\x18\n\x0b\n\x04\x04\x04\x02\x02\x12\ + \x03!\x02\x1b\n\x0c\n\x05\x04\x04\x02\x02\x04\x12\x03!\x02\n\n\x0c\n\x05\ + \x04\x04\x02\x02\x05\x12\x03!\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\x01\ + \x12\x03!\x12\x16\n\x0c\n\x05\x04\x04\x02\x02\x03\x12\x03!\x19\x1a\n\x0b\ + \n\x04\x04\x04\x02\x03\x12\x03\"\x02\x1f\n\x0c\n\x05\x04\x04\x02\x03\x04\ + \x12\x03\"\x02\n\n\x0c\n\x05\x04\x04\x02\x03\x05\x12\x03\"\x0b\x11\n\x0c\ + \n\x05\x04\x04\x02\x03\x01\x12\x03\"\x12\x1a\n\x0c\n\x05\x04\x04\x02\x03\ + \x03\x12\x03\"\x1d\x1e\n\x0b\n\x04\x04\x04\x02\x04\x12\x03#\x02\x1e\n\ + \x0c\n\x05\x04\x04\x02\x04\x04\x12\x03#\x02\n\n\x0c\n\x05\x04\x04\x02\ + \x04\x05\x12\x03#\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x04\x01\x12\x03#\x10\ + \x19\n\x0c\n\x05\x04\x04\x02\x04\x03\x12\x03#\x1c\x1d\n\x0b\n\x04\x04\ + \x04\x02\x05\x12\x03$\x02\x1d\n\x0c\n\x05\x04\x04\x02\x05\x04\x12\x03$\ + \x02\n\n\x0c\n\x05\x04\x04\x02\x05\x05\x12\x03$\x0b\x0f\n\x0c\n\x05\x04\ + \x04\x02\x05\x01\x12\x03$\x10\x18\n\x0c\n\x05\x04\x04\x02\x05\x03\x12\ + \x03$\x1b\x1c\n\x0b\n\x04\x04\x04\x02\x06\x12\x03%\x02\"\n\x0c\n\x05\x04\ + \x04\x02\x06\x04\x12\x03%\x02\n\n\x0c\n\x05\x04\x04\x02\x06\x05\x12\x03%\ + \x0b\x0f\n\x0c\n\x05\x04\x04\x02\x06\x01\x12\x03%\x10\x1d\n\x0c\n\x05\ + \x04\x04\x02\x06\x03\x12\x03%\x20!\n\x0b\n\x04\x04\x04\x02\x07\x12\x03&\ + \x02\x18\n\x0c\n\x05\x04\x04\x02\x07\x04\x12\x03&\x02\n\n\x0c\n\x05\x04\ + \x04\x02\x07\x05\x12\x03&\x0b\x11\n\x0c\n\x05\x04\x04\x02\x07\x01\x12\ + \x03&\x12\x13\n\x0c\n\x05\x04\x04\x02\x07\x03\x12\x03&\x16\x17\n\x0b\n\ + \x04\x04\x04\x02\x08\x12\x03'\x02\x18\n\x0c\n\x05\x04\x04\x02\x08\x04\ + \x12\x03'\x02\n\n\x0c\n\x05\x04\x04\x02\x08\x05\x12\x03'\x0b\x11\n\x0c\n\ + \x05\x04\x04\x02\x08\x01\x12\x03'\x12\x13\n\x0c\n\x05\x04\x04\x02\x08\ + \x03\x12\x03'\x16\x17\n\x0b\n\x04\x04\x04\x02\t\x12\x03(\x02\x1e\n\x0c\n\ + \x05\x04\x04\x02\t\x04\x12\x03(\x02\n\n\x0c\n\x05\x04\x04\x02\t\x05\x12\ + \x03(\x0b\x0f\n\x0c\n\x05\x04\x04\x02\t\x01\x12\x03(\x10\x18\n\x0c\n\x05\ + \x04\x04\x02\t\x03\x12\x03(\x1b\x1d\n\x0b\n\x04\x04\x04\x02\n\x12\x03)\ + \x02!\n\x0c\n\x05\x04\x04\x02\n\x04\x12\x03)\x02\n\n\x0c\n\x05\x04\x04\ + \x02\n\x05\x12\x03)\x0b\x11\n\x0c\n\x05\x04\x04\x02\n\x01\x12\x03)\x12\ + \x1b\n\x0c\n\x05\x04\x04\x02\n\x03\x12\x03)\x1e\x20\n\x0b\n\x04\x04\x04\ + \x02\x0b\x12\x03*\x02!\n\x0c\n\x05\x04\x04\x02\x0b\x04\x12\x03*\x02\n\n\ + \x0c\n\x05\x04\x04\x02\x0b\x05\x12\x03*\x0b\x11\n\x0c\n\x05\x04\x04\x02\ + \x0b\x01\x12\x03*\x12\x1b\n\x0c\n\x05\x04\x04\x02\x0b\x03\x12\x03*\x1e\ + \x20\n\x0b\n\x04\x04\x04\x02\x0c\x12\x03+\x02\"\n\x0c\n\x05\x04\x04\x02\ + \x0c\x04\x12\x03+\x02\n\n\x0c\n\x05\x04\x04\x02\x0c\x05\x12\x03+\x0b\x0f\ + \n\x0c\n\x05\x04\x04\x02\x0c\x01\x12\x03+\x10\x1c\n\x0c\n\x05\x04\x04\ + \x02\x0c\x03\x12\x03+\x1f!\n\n\n\x02\x04\x05\x12\x04.\01\x01\n\n\n\x03\ + \x04\x05\x01\x12\x03.\x08\r\n\x0b\n\x04\x04\x05\x02\0\x12\x03/\x02\x20\n\ + \x0c\n\x05\x04\x05\x02\0\x04\x12\x03/\x02\n\n\x0c\n\x05\x04\x05\x02\0\ + \x05\x12\x03/\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03/\x12\x1b\n\ + \x0c\n\x05\x04\x05\x02\0\x03\x12\x03/\x1e\x1f\n\x0b\n\x04\x04\x05\x02\ + \x01\x12\x030\x02\x1e\n\x0c\n\x05\x04\x05\x02\x01\x04\x12\x030\x02\n\n\ + \x0c\n\x05\x04\x05\x02\x01\x05\x12\x030\x0b\x11\n\x0c\n\x05\x04\x05\x02\ + \x01\x01\x12\x030\x12\x19\n\x0c\n\x05\x04\x05\x02\x01\x03\x12\x030\x1c\ + \x1d\n\n\n\x02\x04\x06\x12\x043\07\x01\n\n\n\x03\x04\x06\x01\x12\x033\ + \x08\x0e\n\x0b\n\x04\x04\x06\x02\0\x12\x034\x02\x1a\n\x0c\n\x05\x04\x06\ + \x02\0\x04\x12\x034\x02\n\n\x0c\n\x05\x04\x06\x02\0\x06\x12\x034\x0b\x0f\ + \n\x0c\n\x05\x04\x06\x02\0\x01\x12\x034\x10\x15\n\x0c\n\x05\x04\x06\x02\ + \0\x03\x12\x034\x18\x19\n\x0b\n\x04\x04\x06\x02\x01\x12\x035\x02\x1d\n\ + \x0c\n\x05\x04\x06\x02\x01\x04\x12\x035\x02\n\n\x0c\n\x05\x04\x06\x02\ + \x01\x05\x12\x035\x0b\x11\n\x0c\n\x05\x04\x06\x02\x01\x01\x12\x035\x12\ + \x18\n\x0c\n\x05\x04\x06\x02\x01\x03\x12\x035\x1b\x1c\n\x0b\n\x04\x04\ + \x06\x02\x02\x12\x036\x02\x1c\n\x0c\n\x05\x04\x06\x02\x02\x04\x12\x036\ + \x02\n\n\x0c\n\x05\x04\x06\x02\x02\x06\x12\x036\x0b\x10\n\x0c\n\x05\x04\ + \x06\x02\x02\x01\x12\x036\x11\x17\n\x0c\n\x05\x04\x06\x02\x02\x03\x12\ + \x036\x1a\x1b\ +"; + +static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { - ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() } pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { - unsafe { - file_descriptor_proto_lazy.get(|| { - parse_descriptor_proto() - }) - } + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) } diff --git a/src/pb/mod.rs b/src/pb/mod.rs index 1e7cf76..87bc616 100644 --- a/src/pb/mod.rs +++ b/src/pb/mod.rs @@ -1,3 +1,3 @@ mod data_model; -pub use self::data_model::{Arrow, Gps, Meta, Node, Screen, Tag}; +pub use self::data_model::{Arrow, Date, Gps, Meta, Node, Screen, Tag}; diff --git a/src/plot.rs b/src/plot.rs index 695ba8b..72f8223 100644 --- a/src/plot.rs +++ b/src/plot.rs @@ -1,11 +1,11 @@ use std::cmp; +pub const BARS: [char; 9] = [' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']; + pub fn plot_sparkline(nums_in: Vec) -> String where T: Into, { - const BARS: [char; 9] = [' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']; - let nums: Vec<_> = nums_in.into_iter().map(|n| n.into()).collect(); let max = nums.iter().max().unwrap(); diff --git a/src/screen.rs b/src/screen.rs index 35f424f..003c447 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -19,6 +19,7 @@ use termion::{ style, terminal_size, }; +use chrono::{Date, Datelike, Local, NaiveDate, TimeZone, Weekday}; use rand::{self, Rng}; use regex::Regex; use unicode_segmentation::UnicodeSegmentation; @@ -56,6 +57,7 @@ pub struct Screen { // non-pub members are ephemeral drawing_root: NodeID, show_logs: bool, + show_calendar: bool, selected: Option, cut: Cut, drawing_arrow: Option, @@ -110,6 +112,7 @@ impl Default for Screen { lookup: HashMap::new(), drawn_at: HashMap::new(), show_logs: false, + show_calendar: true, drawing_root: 0, stdout: None, dragging_from: None, @@ -165,9 +168,7 @@ impl Screen { } fn clone_node(&mut self, id: NodeID, new_parent_id: NodeID) -> Option { - info!("Try new node"); let mut new_node = Node::new_from(self.nodes.get(&id)?); - info!("Made new node"); let new_id = self.new_node_id(); let new_children = new_node .children @@ -179,7 +180,6 @@ impl Screen { new_node.parent_id = new_parent_id; self.nodes.insert(new_id, new_node); - info!("Inserted new node"); Some(new_id) } @@ -325,9 +325,7 @@ impl Screen { self.with_node_mut_no_meta(place, |parent_nd| { parent_nd.children.push(new_id); }); - } else { - info!("Yank failed somewhere"); - }; + } self.cut = Cut::Empty; } Cut::Empty if yanking && can_cut => { @@ -537,8 +535,8 @@ impl Screen { self.last_search.take(); } - let mut f = |n: &Node| n.content.find(&*query).map(|idx| (idx, n.id)); - let mut candidates = self.recursive_child_filter_map(self.drawing_root, &mut f); + let mut f = |n: &Node, _: ()| (n.content.find(&*query).map(|idx| (idx, n.id)), ()); + let mut candidates = self.recursive_child_filter_map(self.drawing_root, (), &mut f); if candidates.is_empty() { return; } @@ -770,19 +768,26 @@ impl Screen { } } - pub fn recursive_child_filter_map(&self, node_id: NodeID, filter_map: &mut F) -> Vec + pub fn recursive_child_filter_map( + &self, + node_id: NodeID, + context: C, + filter_map: &mut F, + ) -> Vec where - F: FnMut(&Node) -> Option, + F: FnMut(&Node, C) -> (Option, C), + C: Copy, { trace!("recursive_child_filter_map({}, F...)", node_id); let mut ret = vec![]; if let Some(node) = self.nodes.get(&node_id) { - if let Some(b) = filter_map(node) { + let (filtered, context) = filter_map(node, context); + if let Some(b) = filtered { ret.push(b); } for &child_id in &node.children { - ret.append(&mut self.recursive_child_filter_map(child_id, filter_map)); + ret.append(&mut self.recursive_child_filter_map(child_id, context, filter_map)); } } else { debug!("queried for node {} but it is not in self.nodes", node_id); @@ -836,7 +841,7 @@ impl Screen { fn unselect(&mut self) -> Option { trace!("unselect()"); lazy_static! { - static ref RE_DATE: Regex = Regex::new(r"\[(\S+)\]").unwrap(); + static ref RE_DATE: Regex = Regex::new(r"\[(\d{2}\.\d{2}\.\d{4})\]").unwrap(); } if let Some(Selection { selected_id, .. }) = self.selected { // nuke node if it's empty and has no children @@ -853,18 +858,22 @@ impl Screen { self.with_node_mut_no_meta(selected_id, |n| { // if parseable date, change date + let mut due_date_set = false; if let Some(date) = re_matches::(&RE_DATE, &*n.content).get(0) { - if let Some(date) = dateparse(date.clone()) { - n.content = RE_DATE.replace(&*n.content, "").trim_end().to_owned(); + if let Ok(date) = NaiveDate::parse_from_str(date, "%d.%m.%Y") { + let date = Local.from_local_date(&date).unwrap(); if n.meta.finish_time.is_some() { - n.meta.finish_time = Some(date); + n.meta.finish_time = Some(date.and_hms(0, 0, 0).timestamp() as u64); } else { - let now_in_s = now().as_secs(); - let future_date = now_in_s + (now_in_s - date); - n.meta.due = Some(future_date); + n.meta.due_date = Some(date); + due_date_set = true; } } } + + if !due_date_set { + n.meta.due_date = None; + } }); } self.selected.take().map(|s| s.selected_id) @@ -1030,8 +1039,6 @@ impl Screen { for (num_events, c) in stdin.events().enumerate() { let evt = c.unwrap(); - self.dims = terminal_size().unwrap(); - let should_break = !self.handle_event(evt); self.draw(); @@ -1843,6 +1850,147 @@ impl Screen { } } + fn reserve_and_draw_calendar(&mut self) { + if !self.show_calendar { + return; + } + const CALENDAR_WIDTH: u16 = 1 + // vertical line + 4 + // week numbers + padding + 3*7; // days + if self.dims.0 < CALENDAR_WIDTH { + return; + } + self.dims.0 -= CALENDAR_WIDTH; + + let today = Local::today(); + let mut date = today.with_day(1).unwrap(); + let mut line = 2; + let max_line = self.dims.1; + 'make_month: loop { + if line > max_line { + break; + } + + let (month, year) = (date.month(), date.year()); + let month_assigned_days = self.recursive_child_filter_map( + self.drawing_root, + None, + &mut |nd: &Node, default_date: Option>| { + let date = nd.meta.due_date.or(default_date); + if let Some(assigned) = date { + if assigned.year() == year && assigned.month() == month { + (Some(assigned.day0()), date) + } else { + (None, date) + } + } else { + (None, None) + } + }, + ); + let mut counts_by_day = [0usize; 31]; + for day in month_assigned_days { + counts_by_day[day as usize] += 1; + } + + let month_header = format!( + "{}│{}{:^width$}{}", + cursor::Goto(self.dims.0, line), + style::Bold, + date.format("%B %Y").to_string(), + style::Reset, + width = (CALENDAR_WIDTH - 1) as usize, + ); + + println!("{}", month_header); + line += 1; + if line > max_line { + break; + } + + let weekday_header = format!( + "{}│ │ M T W T F S S", + cursor::Goto(self.dims.0, line) + ); + println!("{}", weekday_header); + line += 1; + if line > max_line { + break; + } + + let week_header = format!( + "{}│{:3}│{}│ │", + cursor::Goto(self.dims.0, line), + date.iso_week().week(), + cursor::Goto(self.dims.0, line + 1), + ); + print!("{}", week_header); + + loop { + if line > max_line { + break 'make_month; + } + + let offset_x = self.dims.0 + 5 + date.weekday().num_days_from_monday() as u16 * 3; + let day_label = format!( + "{}{}{:3}{}", + cursor::Goto(offset_x, line), + if today == date { + &style::Bold as &dyn std::fmt::Display + } else { + &style::Reset as &dyn std::fmt::Display + }, + date.day(), + style::Reset, + ); + print!("{}", day_label); + + if line + 1 < max_line { + let assigned = counts_by_day[date.day0() as usize]; + if assigned > 0 { + let day_assigned_tasks_label = format!( + "{}{}{:3}{}", + cursor::Goto(offset_x, line + 1), + style::Italic, + assigned, + style::Reset, + ); + print!("{}", day_assigned_tasks_label); + } + } + + let prev_month = date.month(); + date = date.succ(); + + if prev_month != date.month() { + break; + } + + if date.weekday() == Weekday::Mon { + line += 2; + if line > max_line { + break 'make_month; + } + + let week_header = format!( + "{}│{:3}│{}│ │", + cursor::Goto(self.dims.0, line), + date.iso_week().week(), + cursor::Goto(self.dims.0, line + 1), + ); + print!("{}", week_header); + } + } + line += 2; + if line > max_line { + break; + } + + println!("{}│", cursor::Goto(self.dims.0, line)); + line += 1; + } + } + // * // * // *┌──┐ @@ -1864,6 +2012,9 @@ impl Screen { self.lowest_drawn = 0; print!("{}", clear::All); + self.dims = terminal_size().unwrap(); + self.reserve_and_draw_calendar(); + // print visible nodes self.draw_children_of_root(); @@ -2364,18 +2515,19 @@ impl Screen { let now = now().as_secs(); let day_in_sec = 60 * 60 * 24; let last_week = now - (day_in_sec * 7); - let tasks_finished_in_last_week = self.recursive_child_filter_map(0, &mut |n: &Node| { - let f = n.meta.finish_time; - if let Some(t) = f { - if t > last_week { - Some(t) + let tasks_finished_in_last_week = + self.recursive_child_filter_map(0, (), &mut |n: &Node, _: ()| { + let f = n.meta.finish_time; + if let Some(t) = f { + if t > last_week { + (Some(t), ()) + } else { + (None, ()) + } } else { - None + (None, ()) } - } else { - None - } - }); + }); let mut counts = BTreeMap::new(); for d in 0..7 { let t = now - (d * day_in_sec); @@ -2518,23 +2670,24 @@ impl Screen { ) -> String { let mut nodes = vec![]; for &c in &queried_nodes { - let mut new = self.recursive_child_filter_map(c, &mut |n: &Node| match kind { - PlotType::Done => { - if let Some(ft) = n.meta.finish_time { - if ft >= since { - return Some(ft as i64); + let mut new = + self.recursive_child_filter_map(c, (), &mut |n: &Node, _: ()| match kind { + PlotType::Done => { + if let Some(ft) = n.meta.finish_time { + if ft >= since { + return (Some(ft as i64), ()); + } } + (None, ()) } - None - } - PlotType::New => { - if n.meta.ctime >= since { - Some(n.meta.ctime as i64) - } else { - None + PlotType::New => { + if n.meta.ctime >= since { + (Some(n.meta.ctime as i64), ()) + } else { + (None, ()) + } } - } - }); + }); nodes.append(&mut new); } let plot = plot::bounded_count_sparkline(nodes, until as i64, since as i64, buckets); diff --git a/src/serialization.rs b/src/serialization.rs index fe34bee..b86a7b5 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -1,3 +1,4 @@ +use chrono::{Datelike, Local, TimeZone}; use protobuf::{self, Message}; use crate::{pb, random_fg_color, Meta, Node, Screen}; @@ -25,6 +26,14 @@ pub fn serialize_screen(screen: &Screen) -> Vec { screen_pb.write_to_bytes().unwrap() } +fn serialize_date(date: chrono::Date) -> pb::Date { + let mut date_pb = pb::Date::default(); + date_pb.set_day(date.day()); + date_pb.set_month(date.month()); + date_pb.set_year(date.year() as u32); + date_pb +} + fn serialize_meta(meta: &Meta) -> pb::Meta { let mut meta_pb = pb::Meta::default(); meta_pb.set_gps(pb::Gps::default()); @@ -33,6 +42,9 @@ fn serialize_meta(meta: &Meta) -> pb::Meta { if let Some(finish_time) = meta.finish_time { meta_pb.set_finish_time(finish_time); } + if let Some(due_date) = meta.due_date { + meta_pb.set_due_date(serialize_date(due_date)); + } let mut tags = vec![]; for (tagk, tagv) in &meta.tags { let mut tag = pb::Tag::default(); @@ -53,6 +65,7 @@ fn serialize_node(node: &Node) -> pb::Node { node_pb.set_stricken(node.stricken); node_pb.set_hide_stricken(node.hide_stricken); node_pb.set_parent_id(node.parent_id); + node_pb.set_selected(node.selected); node_pb.set_x(u32::from(node.rooted_coords.0)); node_pb.set_y(u32::from(node.rooted_coords.1)); node_pb.set_meta(serialize_meta(&node.meta)); @@ -63,6 +76,14 @@ fn serialize_node(node: &Node) -> pb::Node { node_pb } +fn deserialize_date(date_pb: &pb::Date) -> chrono::Date { + let day = date_pb.get_day(); + let month = date_pb.get_month(); + let year = date_pb.get_year(); + + Local.ymd(year as i32, month, day) +} + fn deserialize_meta(meta_pb: &pb::Meta) -> Meta { Meta { ctime: meta_pb.get_ctime(), @@ -72,8 +93,8 @@ fn deserialize_meta(meta_pb: &pb::Meta) -> Meta { } else { None }, - due: if meta_pb.has_due() { - Some(meta_pb.get_due()) + due_date: if meta_pb.has_due_date() { + Some(deserialize_date(meta_pb.get_due_date())) } else { None }, @@ -91,7 +112,7 @@ fn deserialize_node(node_pb: &pb::Node) -> Node { rooted_coords: (node_pb.get_x() as u16, node_pb.get_y() as u16), content: node_pb.get_text().to_owned(), children: node_pb.get_children().to_vec(), - selected: node_pb.get_selected(), + selected: false, // Don't actually load this... collapsed: node_pb.get_collapsed(), stricken: node_pb.get_stricken(), hide_stricken: node_pb.get_hide_stricken(), @@ -108,7 +129,7 @@ fn deserialize_node(node_pb: &pb::Node) -> Node { } pub fn deserialize_screen(data: Vec) -> Result { - let screen_pb: pb::Screen = protobuf::parse_from_bytes(&*data)?; + let screen_pb: pb::Screen = Message::parse_from_bytes(&*data)?; let mut screen = Screen::default(); screen.max_id = screen_pb.get_max_id(); screen.nodes = screen_pb From d6abf5d12409400d54be9678cec27bf4114108a9 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 25 Sep 2021 21:47:24 +0300 Subject: [PATCH 22/41] Implement mysterious fix for header rendering --- src/screen.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 003c447..44ee622 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1863,8 +1863,10 @@ impl Screen { self.dims.0 -= CALENDAR_WIDTH; let today = Local::today(); - let mut date = today.with_day(1).unwrap(); - let mut line = 2; + let mut date = today + .with_day(max(1, today.day() - today.weekday().num_days_from_monday())) + .unwrap(); + let mut line = 3; let max_line = self.dims.1; 'make_month: loop { if line > max_line { @@ -1878,7 +1880,11 @@ impl Screen { &mut |nd: &Node, default_date: Option>| { let date = nd.meta.due_date.or(default_date); if let Some(assigned) = date { - if assigned.year() == year && assigned.month() == month { + if !nd.stricken + && nd.children.is_empty() + && assigned.year() == year + && assigned.month() == month + { (Some(assigned.day0()), date) } else { (None, date) @@ -2013,16 +2019,17 @@ impl Screen { print!("{}", clear::All); self.dims = terminal_size().unwrap(); - self.reserve_and_draw_calendar(); - - // print visible nodes - self.draw_children_of_root(); // TODO figure out why header doesn't get shown // when a root node is NOT drawn at 1,1 // (this only happens when draw_header() is above // the call to draw_children_of_root()... + self.draw_header(); + self.reserve_and_draw_calendar(); + + // print visible nodes + self.draw_children_of_root(); // print logs if self.show_logs && self.dims.0 > 4 && self.dims.1 > 7 { @@ -2348,7 +2355,7 @@ impl Screen { print!("{}", color::Fg(color::Reset)); } - fn draw_header(&self) { + fn draw_header(&mut self) { trace!("draw_header()"); let mut header_text = self .with_node(self.drawing_root, |node| node.content.clone()) @@ -2389,7 +2396,7 @@ impl Screen { if self.dims.0 > header_text.len() as u16 && self.dims.1 > 1 { let mut sep = format!( "{}{}{}{}", - cursor::Goto(0, 1), + cursor::Goto(1, 1), style::Invert, header_text, style::Reset @@ -2398,7 +2405,7 @@ impl Screen { for _ in 0..(max(self.dims.0 as usize, text_len) - text_len) { sep.push('█'); } - println!("{}", sep); + print!("{}", sep); } } From 78894a866d36078ed0824a118951832a06879824 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 26 Sep 2021 10:51:26 +0300 Subject: [PATCH 23/41] Automatically expand node when creating a child --- src/screen.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/screen.rs b/src/screen.rs index 44ee622..fcfc51d 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1116,6 +1116,7 @@ impl Screen { self.with_node_mut_no_meta(node_id, |node| node.parent_id = selected_id); let added = self.with_node_mut_no_meta(selected_id, |selected| { selected.children.push(node_id); + selected.collapsed = false; }); if added.is_some() { self.select_node_ensure_inserting(node_id); From 0d326c65cc1d14aa654bfab2f31029e10b2fee02 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 26 Sep 2021 11:20:56 +0300 Subject: [PATCH 24/41] When reordering nodes, skip invisible ones --- src/screen.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index fcfc51d..f96c1c0 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1525,15 +1525,38 @@ impl Screen { // principle: don't modify things that are above the visible scope return; } - self.with_node_mut_no_meta(parent_id, |parent| { + + if let Some((swap_from, swap_to)) = self.with_node(parent_id, |parent| { let idx = parent .children .iter() .position(|&e| e == selected_id) .unwrap(); + let to = max(idx, 1) - 1; - parent.children.swap(idx, to); - }); + let hide_stricken = parent.hide_stricken; + if !hide_stricken { + (idx, to) + } else { + ( + idx, + parent.children[..idx] + .iter() + .enumerate() + .rfind(|(_, child_id)| { + self.with_node(**child_id, |child| child.stricken) == Some(false) + }) + .map(|(child_idx, _)| child_idx) + .unwrap_or(0), + ) + } + }) { + self.with_node_mut_no_meta(parent_id, |parent| { + for i in (swap_to..swap_from).rev() { + parent.children.swap(i, i + 1); + } + }); + } } } @@ -1548,18 +1571,45 @@ impl Screen { // principle: don't modify things that are above the visible scope return; } - self.with_node_mut_no_meta(parent_id, |parent| { + + if let Some((swap_from, swap_to)) = self.with_node(parent_id, |parent| { let idx = parent .children .iter() .position(|&e| e == selected_id) .unwrap(); + let len = parent.children.len(); - if len > 1 { - let to = min(idx, len - 2) + 1; - parent.children.swap(idx, to); + if len <= 1 { + return (idx, 1); } - }); + + let to = min(idx, len - 2) + 1; + let hide_stricken = parent.hide_stricken; + if !hide_stricken { + (idx, to) + } else { + ( + idx, + parent + .children + .iter() + .enumerate() + .skip(idx + 1) + .find(|(_, child_id)| { + self.with_node(**child_id, |child| child.stricken) == Some(false) + }) + .map(|(child_idx, _)| child_idx) + .unwrap_or(len - 1), + ) + } + }) { + self.with_node_mut_no_meta(parent_id, |parent| { + for i in swap_from..swap_to { + parent.children.swap(i, i + 1); + } + }); + } } } From 53b085f1083272acaea28a12ddc4b98a02006744 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 26 Sep 2021 11:50:10 +0300 Subject: [PATCH 25/41] When deleting a node, make a new selection --- src/screen.rs | 55 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index f96c1c0..51d19d0 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -975,21 +975,52 @@ impl Screen { fn delete_selected(&mut self, reselect: bool) { trace!("delete_selected()"); if let Some(Selection { selected_id, .. }) = self.selected.take() { - let (_, height) = self.drawable_subtree_dims(selected_id).unwrap(); - let coords = self.drawn_at.remove(&selected_id); + self.drawn_at.remove(&selected_id); // remove ref from parent if let Some(parent_id) = self.parent(selected_id) { trace!("deleting node {} from parent {}", selected_id, parent_id); - self.with_node_mut_no_meta(parent_id, |p| p.children.retain(|c| c != &selected_id)) + let self_pos = self + .with_node_mut_no_meta(parent_id, |p| { + let self_pos = p + .children + .iter() + .enumerate() + .find(|(_, id)| **id == selected_id) + .unwrap() + .0; + p.children.remove(self_pos); + self_pos + }) .unwrap(); - } - // remove children - self.delete_recursive(selected_id); - if let Some((x, y)) = coords { if reselect { - self.click_select((x, y + height)); + let next_selection = self + .with_node(parent_id, |p| { + if p.children.is_empty() { + parent_id + } else if !p.hide_stricken { + p.children[min(self_pos, p.children.len() - 1)] + } else { + let forward_search = + p.children.iter().copied().skip(self_pos).find(|id| { + self.with_node(*id, |sibling| !sibling.stricken) + == Some(true) + }); + forward_search + .or_else(|| { + p.children.iter().copied().take(self_pos).rfind(|id| { + self.with_node(*id, |sibling| !sibling.stricken) + == Some(true) + }) + }) + .unwrap_or(parent_id) + } + }) + .unwrap(); + self.select_node(next_selection); } } + // remove children + self.delete_recursive(selected_id); self.undo_stack.push(selected_id); } } @@ -1452,14 +1483,6 @@ impl Screen { } } - fn click_select(&mut self, coords: Coords) -> Option { - trace!("click_select({:?})", coords); - let result = self.try_select(coords); - self.dragging_from.take(); - self.dragging_to.take(); - result - } - fn scroll_up(&mut self) { self.view_y = max(self.view_y, self.dims.1 / 2) - self.dims.1 / 2; self.unselect(); From df9dadf4ca467e46bfae6a2a8412eb835ff623cd Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sun, 26 Sep 2021 12:04:38 +0300 Subject: [PATCH 26/41] When striking or deleting a node, a nearby sibling or parent is selected instead --- src/screen.rs | 72 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 51d19d0..044a003 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -944,6 +944,23 @@ impl Screen { trace!("toggle_stricken()"); if let Some(Selection { selected_id, .. }) = self.selected { self.with_node_mut(selected_id, |node| node.toggle_stricken()); + if let Some(parent_id) = self.parent(selected_id) { + if let Some(child_pos) = self.with_node(parent_id, |p| { + p.children + .iter() + .copied() + .enumerate() + .find(|(_, id)| *id == selected_id) + .unwrap() + .0 + }) { + if let Some(new_selection) = + self.find_near_sibling_or_parent(parent_id, child_pos) + { + self.select_node(new_selection); + } + } + } } } @@ -972,6 +989,30 @@ impl Screen { } } + fn find_near_sibling_or_parent(&self, parent_id: NodeID, child_pos: usize) -> Option { + self.with_node(parent_id, |p| { + if p.children.is_empty() { + parent_id + } else if !p.hide_stricken { + p.children[min(child_pos, p.children.len() - 1)] + } else { + let forward_search = p + .children + .iter() + .copied() + .skip(child_pos) + .find(|id| self.with_node(*id, |sibling| !sibling.stricken) == Some(true)); + forward_search + .or_else(|| { + p.children.iter().copied().take(child_pos).rfind(|id| { + self.with_node(*id, |sibling| !sibling.stricken) == Some(true) + }) + }) + .unwrap_or(parent_id) + } + }) + } + fn delete_selected(&mut self, reselect: bool) { trace!("delete_selected()"); if let Some(Selection { selected_id, .. }) = self.selected.take() { @@ -979,7 +1020,7 @@ impl Screen { // remove ref from parent if let Some(parent_id) = self.parent(selected_id) { trace!("deleting node {} from parent {}", selected_id, parent_id); - let self_pos = self + let child_pos = self .with_node_mut_no_meta(parent_id, |p| { let self_pos = p .children @@ -993,30 +1034,11 @@ impl Screen { }) .unwrap(); if reselect { - let next_selection = self - .with_node(parent_id, |p| { - if p.children.is_empty() { - parent_id - } else if !p.hide_stricken { - p.children[min(self_pos, p.children.len() - 1)] - } else { - let forward_search = - p.children.iter().copied().skip(self_pos).find(|id| { - self.with_node(*id, |sibling| !sibling.stricken) - == Some(true) - }); - forward_search - .or_else(|| { - p.children.iter().copied().take(self_pos).rfind(|id| { - self.with_node(*id, |sibling| !sibling.stricken) - == Some(true) - }) - }) - .unwrap_or(parent_id) - } - }) - .unwrap(); - self.select_node(next_selection); + if let Some(next_selection) = + self.find_near_sibling_or_parent(parent_id, child_pos) + { + self.select_node(next_selection); + } } } // remove children From 4c3ba3977ca7d1c45e1a6ab6615a3df07242dd0d Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 30 Sep 2021 20:39:24 +0300 Subject: [PATCH 27/41] In calendar, don't count nodes whose parent has been stricken --- src/screen.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/screen.rs b/src/screen.rs index 044a003..3acd39d 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1982,8 +1982,10 @@ impl Screen { && assigned.month() == month { (Some(assigned.day0()), date) - } else { + } else if !nd.stricken { (None, date) + } else { + (None, None) } } else { (None, None) From 822828611b413d532f34291a8561445762d8e766 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 2 Oct 2021 15:11:56 +0300 Subject: [PATCH 28/41] Fix underflow at start of month when finding Monday --- src/screen.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/screen.rs b/src/screen.rs index 3acd39d..1c30065 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1960,7 +1960,10 @@ impl Screen { let today = Local::today(); let mut date = today - .with_day(max(1, today.day() - today.weekday().num_days_from_monday())) + .with_day(max( + 1i32, + today.day() as i32 - today.weekday().num_days_from_monday() as i32, + ) as u32) .unwrap(); let mut line = 3; let max_line = self.dims.1; From 34838f088022e2ca69441779834934acd7c33829 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 2 Oct 2021 15:18:15 +0300 Subject: [PATCH 29/41] Stop overriding done-time based on date in node --- src/screen.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 1c30065..27de96f 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -862,12 +862,8 @@ impl Screen { if let Some(date) = re_matches::(&RE_DATE, &*n.content).get(0) { if let Ok(date) = NaiveDate::parse_from_str(date, "%d.%m.%Y") { let date = Local.from_local_date(&date).unwrap(); - if n.meta.finish_time.is_some() { - n.meta.finish_time = Some(date.and_hms(0, 0, 0).timestamp() as u64); - } else { - n.meta.due_date = Some(date); - due_date_set = true; - } + n.meta.due_date = Some(date); + due_date_set = true; } } From 202c42640cb82061c299f7b9ae738109558c5052 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 2 Oct 2021 15:55:13 +0300 Subject: [PATCH 30/41] Allow attaching URLs to node metadata --- include/data_model.proto | 1 + src/config.rs | 5 + src/node.rs | 2 + src/pb/data_model.rs | 305 +++++++++++++++++++++++---------------- src/screen.rs | 61 ++++++-- src/serialization.rs | 8 + 6 files changed, 244 insertions(+), 138 deletions(-) diff --git a/include/data_model.proto b/include/data_model.proto index 7f91a39..75287f3 100644 --- a/include/data_model.proto +++ b/include/data_model.proto @@ -42,6 +42,7 @@ message Node { required uint64 parent_id = 11; optional string free_text = 12; required bool auto_arrange = 13; + optional string url = 14; } message Arrow { diff --git a/src/config.rs b/src/config.rs index 6508d86..a744ae9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -183,6 +183,7 @@ pub struct Config { pub collapsed: String, pub hide_stricken: String, pub free_text: String, + pub url: String, } impl Default for Config { @@ -235,6 +236,7 @@ impl Default for Config { collapsed: "⊞".to_owned(), hide_stricken: "⚔".to_owned(), free_text: "✏".to_owned(), + url: "".to_owned(), } } } @@ -329,6 +331,9 @@ impl Config { ("free_text", p) => { config.free_text = p.to_owned(); } + ("url", p) => { + config.url = p.to_owned(); + } (raw_action, raw_key) => { let key_opt = to_key(raw_key.to_owned()); let action_opt = to_action(raw_action.to_owned()); diff --git a/src/node.rs b/src/node.rs index 69c8489..50a3946 100644 --- a/src/node.rs +++ b/src/node.rs @@ -15,6 +15,7 @@ pub struct Node { pub free_text: Option, pub color: String, pub auto_arrange: bool, + pub url: Option, } impl Default for Node { @@ -31,6 +32,7 @@ impl Default for Node { hide_stricken: false, meta: Meta::default(), free_text: None, + url: None, color: random_fg_color(), auto_arrange: true, } diff --git a/src/pb/data_model.rs b/src/pb/data_model.rs index 7f36996..d343ad2 100644 --- a/src/pb/data_model.rs +++ b/src/pb/data_model.rs @@ -1149,6 +1149,7 @@ pub struct Node { parent_id: ::std::option::Option, free_text: ::protobuf::SingularField<::std::string::String>, auto_arrange: ::std::option::Option, + url: ::protobuf::SingularField<::std::string::String>, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -1465,6 +1466,42 @@ impl Node { pub fn set_auto_arrange(&mut self, v: bool) { self.auto_arrange = ::std::option::Option::Some(v); } + + // optional string url = 14; + + + pub fn get_url(&self) -> &str { + match self.url.as_ref() { + Some(v) => &v, + None => "", + } + } + pub fn clear_url(&mut self) { + self.url.clear(); + } + + pub fn has_url(&self) -> bool { + self.url.is_some() + } + + // Param is passed by value, moved + pub fn set_url(&mut self, v: ::std::string::String) { + self.url = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_url(&mut self) -> &mut ::std::string::String { + if self.url.is_none() { + self.url.set_default(); + } + self.url.as_mut().unwrap() + } + + // Take field + pub fn take_url(&mut self) -> ::std::string::String { + self.url.take().unwrap_or_else(|| ::std::string::String::new()) + } } impl ::protobuf::Message for Node { @@ -1586,6 +1623,9 @@ impl ::protobuf::Message for Node { let tmp = is.read_bool()?; self.auto_arrange = ::std::option::Option::Some(tmp); }, + 14 => { + ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.url)?; + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -1638,6 +1678,9 @@ impl ::protobuf::Message for Node { if let Some(v) = self.auto_arrange { my_size += 2; } + if let Some(ref v) = self.url.as_ref() { + my_size += ::protobuf::rt::string_size(14, &v); + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -1685,6 +1728,9 @@ impl ::protobuf::Message for Node { if let Some(v) = self.auto_arrange { os.write_bool(13, v)?; } + if let Some(ref v) = self.url.as_ref() { + os.write_string(14, &v)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -1788,6 +1834,11 @@ impl ::protobuf::Message for Node { |m: &Node| { &m.auto_arrange }, |m: &mut Node| { &mut m.auto_arrange }, )); + fields.push(::protobuf::reflect::accessor::make_singular_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "url", + |m: &Node| { &m.url }, + |m: &mut Node| { &mut m.url }, + )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "Node", fields, @@ -1817,6 +1868,7 @@ impl ::protobuf::Clear for Node { self.parent_id = ::std::option::Option::None; self.free_text.clear(); self.auto_arrange = ::std::option::Option::None; + self.url.clear(); self.unknown_fields.clear(); } } @@ -2303,7 +2355,7 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x04R\nfinishTime\x12\x1b\n\x03gps\x18\x03\x20\x02(\x0b2\t.void.GpsR\x03\ gps\x12\x1d\n\x04tags\x18\x04\x20\x03(\x0b2\t.void.TagR\x04tags\x12\x17\ \n\x07OLD_due\x18\x06\x20\x01(\x04R\x06OLDDue\x12%\n\x08due_date\x18\x07\ - \x20\x01(\x0b2\n.void.DateR\x07dueDate\"\xda\x02\n\x04Node\x12\x0e\n\x02\ + \x20\x01(\x0b2\n.void.DateR\x07dueDate\"\xec\x02\n\x04Node\x12\x0e\n\x02\ id\x18\x01\x20\x02(\x04R\x02id\x12\x1e\n\x04meta\x18\x02\x20\x02(\x0b2\n\ .void.MetaR\x04meta\x12\x12\n\x04text\x18\x03\x20\x02(\tR\x04text\x12\ \x1a\n\x08children\x18\x04\x20\x03(\x04R\x08children\x12\x1c\n\tcollapse\ @@ -2313,130 +2365,133 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x02(\rR\x01y\x12\x1a\n\x08selected\x18\n\x20\x01(\x08R\x08selected\x12\ \x1b\n\tparent_id\x18\x0b\x20\x02(\x04R\x08parentId\x12\x1b\n\tfree_text\ \x18\x0c\x20\x01(\tR\x08freeText\x12!\n\x0cauto_arrange\x18\r\x20\x02(\ - \x08R\x0bautoArrange\"=\n\x05Arrow\x12\x1b\n\tfrom_node\x18\x01\x20\x02(\ - \x04R\x08fromNode\x12\x17\n\x07to_node\x18\x02\x20\x02(\x04R\x06toNode\"\ - f\n\x06Screen\x12\x20\n\x05nodes\x18\x01\x20\x03(\x0b2\n.void.NodeR\x05n\ - odes\x12\x15\n\x06max_id\x18\x02\x20\x02(\x04R\x05maxId\x12#\n\x06arrows\ - \x18\x03\x20\x03(\x0b2\x0b.void.ArrowR\x06arrowsJ\xe4\x12\n\x06\x12\x04\ - \0\07\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\0\ - \r\n\n\n\x02\x04\0\x12\x04\x04\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\ - \x08\x0b\n\x0b\n\x04\x04\0\x02\0\x12\x03\x05\x02\x1a\n\x0c\n\x05\x04\0\ - \x02\0\x04\x12\x03\x05\x02\n\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x05\x0b\ - \x11\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x05\x12\x15\n\x0c\n\x05\x04\0\ - \x02\0\x03\x12\x03\x05\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x06\x02\ - \x1c\n\x0c\n\x05\x04\0\x02\x01\x04\x12\x03\x06\x02\n\n\x0c\n\x05\x04\0\ - \x02\x01\x05\x12\x03\x06\x0b\x11\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\ - \x06\x12\x17\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x06\x1a\x1b\n\n\n\x02\ - \x04\x01\x12\x04\t\0\x0c\x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x0b\n\ - \x0b\n\x04\x04\x01\x02\0\x12\x03\n\x02\x19\n\x0c\n\x05\x04\x01\x02\0\x04\ - \x12\x03\n\x02\n\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x0b\x10\n\x0c\n\ - \x05\x04\x01\x02\0\x01\x12\x03\n\x11\x14\n\x0c\n\x05\x04\x01\x02\0\x03\ - \x12\x03\n\x17\x18\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x02\x19\n\x0c\ - \n\x05\x04\x01\x02\x01\x04\x12\x03\x0b\x02\n\n\x0c\n\x05\x04\x01\x02\x01\ - \x05\x12\x03\x0b\x0b\x10\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x11\ - \x14\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x17\x18\n\n\n\x02\x04\ - \x02\x12\x04\x0e\0\x12\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x0c\n\ - \x0b\n\x04\x04\x02\x02\0\x12\x03\x0f\x04\x1c\n\x0c\n\x05\x04\x02\x02\0\ - \x04\x12\x03\x0f\x04\x0c\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\r\x13\ - \n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0f\x14\x17\n\x0c\n\x05\x04\x02\ - \x02\0\x03\x12\x03\x0f\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\ - \x04\x1e\n\x0c\n\x05\x04\x02\x02\x01\x04\x12\x03\x10\x04\x0c\n\x0c\n\x05\ - \x04\x02\x02\x01\x05\x12\x03\x10\r\x13\n\x0c\n\x05\x04\x02\x02\x01\x01\ - \x12\x03\x10\x14\x19\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x10\x1c\x1d\ - \n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x11\x04\x1d\n\x0c\n\x05\x04\x02\x02\ - \x02\x04\x12\x03\x11\x04\x0c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\ - \r\x13\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x11\x14\x18\n\x0c\n\x05\ - \x04\x02\x02\x02\x03\x12\x03\x11\x1b\x1c\n\n\n\x02\x04\x03\x12\x04\x14\0\ - \x1c\x01\n\n\n\x03\x04\x03\x01\x12\x03\x14\x08\x0c\n\x0b\n\x04\x04\x03\ - \x02\0\x12\x03\x15\x02\x1c\n\x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x15\x02\ - \n\n\x0c\n\x05\x04\x03\x02\0\x05\x12\x03\x15\x0b\x11\n\x0c\n\x05\x04\x03\ - \x02\0\x01\x12\x03\x15\x12\x17\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x15\ - \x1a\x1b\n\x0b\n\x04\x04\x03\x02\x01\x12\x03\x16\x02\x1c\n\x0c\n\x05\x04\ - \x03\x02\x01\x04\x12\x03\x16\x02\n\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\ - \x03\x16\x0b\x11\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x16\x12\x17\n\ - \x0c\n\x05\x04\x03\x02\x01\x03\x12\x03\x16\x1a\x1b\n\x0b\n\x04\x04\x03\ - \x02\x02\x12\x03\x17\x02\"\n\x0c\n\x05\x04\x03\x02\x02\x04\x12\x03\x17\ - \x02\n\n\x0c\n\x05\x04\x03\x02\x02\x05\x12\x03\x17\x0b\x11\n\x0c\n\x05\ - \x04\x03\x02\x02\x01\x12\x03\x17\x12\x1d\n\x0c\n\x05\x04\x03\x02\x02\x03\ - \x12\x03\x17\x20!\n\x0b\n\x04\x04\x03\x02\x03\x12\x03\x18\x02\x17\n\x0c\ - \n\x05\x04\x03\x02\x03\x04\x12\x03\x18\x02\n\n\x0c\n\x05\x04\x03\x02\x03\ - \x06\x12\x03\x18\x0b\x0e\n\x0c\n\x05\x04\x03\x02\x03\x01\x12\x03\x18\x0f\ - \x12\n\x0c\n\x05\x04\x03\x02\x03\x03\x12\x03\x18\x15\x16\n\x0b\n\x04\x04\ - \x03\x02\x04\x12\x03\x19\x02\x18\n\x0c\n\x05\x04\x03\x02\x04\x04\x12\x03\ - \x19\x02\n\n\x0c\n\x05\x04\x03\x02\x04\x06\x12\x03\x19\x0b\x0e\n\x0c\n\ - \x05\x04\x03\x02\x04\x01\x12\x03\x19\x0f\x13\n\x0c\n\x05\x04\x03\x02\x04\ - \x03\x12\x03\x19\x16\x17\n\x0b\n\x04\x04\x03\x02\x05\x12\x03\x1a\x02\x1e\ - \n\x0c\n\x05\x04\x03\x02\x05\x04\x12\x03\x1a\x02\n\n\x0c\n\x05\x04\x03\ - \x02\x05\x05\x12\x03\x1a\x0b\x11\n\x0c\n\x05\x04\x03\x02\x05\x01\x12\x03\ - \x1a\x12\x19\n\x0c\n\x05\x04\x03\x02\x05\x03\x12\x03\x1a\x1c\x1d\n\x0b\n\ - \x04\x04\x03\x02\x06\x12\x03\x1b\x02\x1d\n\x0c\n\x05\x04\x03\x02\x06\x04\ - \x12\x03\x1b\x02\n\n\x0c\n\x05\x04\x03\x02\x06\x06\x12\x03\x1b\x0b\x0f\n\ - \x0c\n\x05\x04\x03\x02\x06\x01\x12\x03\x1b\x10\x18\n\x0c\n\x05\x04\x03\ - \x02\x06\x03\x12\x03\x1b\x1b\x1c\n\n\n\x02\x04\x04\x12\x04\x1e\0,\x01\n\ - \n\n\x03\x04\x04\x01\x12\x03\x1e\x08\x0c\n\x0b\n\x04\x04\x04\x02\0\x12\ - \x03\x1f\x02\x19\n\x0c\n\x05\x04\x04\x02\0\x04\x12\x03\x1f\x02\n\n\x0c\n\ - \x05\x04\x04\x02\0\x05\x12\x03\x1f\x0b\x11\n\x0c\n\x05\x04\x04\x02\0\x01\ - \x12\x03\x1f\x12\x14\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x1f\x17\x18\n\ - \x0b\n\x04\x04\x04\x02\x01\x12\x03\x20\x02\x19\n\x0c\n\x05\x04\x04\x02\ - \x01\x04\x12\x03\x20\x02\n\n\x0c\n\x05\x04\x04\x02\x01\x06\x12\x03\x20\ - \x0b\x0f\n\x0c\n\x05\x04\x04\x02\x01\x01\x12\x03\x20\x10\x14\n\x0c\n\x05\ - \x04\x04\x02\x01\x03\x12\x03\x20\x17\x18\n\x0b\n\x04\x04\x04\x02\x02\x12\ - \x03!\x02\x1b\n\x0c\n\x05\x04\x04\x02\x02\x04\x12\x03!\x02\n\n\x0c\n\x05\ - \x04\x04\x02\x02\x05\x12\x03!\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\x01\ - \x12\x03!\x12\x16\n\x0c\n\x05\x04\x04\x02\x02\x03\x12\x03!\x19\x1a\n\x0b\ - \n\x04\x04\x04\x02\x03\x12\x03\"\x02\x1f\n\x0c\n\x05\x04\x04\x02\x03\x04\ - \x12\x03\"\x02\n\n\x0c\n\x05\x04\x04\x02\x03\x05\x12\x03\"\x0b\x11\n\x0c\ - \n\x05\x04\x04\x02\x03\x01\x12\x03\"\x12\x1a\n\x0c\n\x05\x04\x04\x02\x03\ - \x03\x12\x03\"\x1d\x1e\n\x0b\n\x04\x04\x04\x02\x04\x12\x03#\x02\x1e\n\ - \x0c\n\x05\x04\x04\x02\x04\x04\x12\x03#\x02\n\n\x0c\n\x05\x04\x04\x02\ - \x04\x05\x12\x03#\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x04\x01\x12\x03#\x10\ - \x19\n\x0c\n\x05\x04\x04\x02\x04\x03\x12\x03#\x1c\x1d\n\x0b\n\x04\x04\ - \x04\x02\x05\x12\x03$\x02\x1d\n\x0c\n\x05\x04\x04\x02\x05\x04\x12\x03$\ - \x02\n\n\x0c\n\x05\x04\x04\x02\x05\x05\x12\x03$\x0b\x0f\n\x0c\n\x05\x04\ - \x04\x02\x05\x01\x12\x03$\x10\x18\n\x0c\n\x05\x04\x04\x02\x05\x03\x12\ - \x03$\x1b\x1c\n\x0b\n\x04\x04\x04\x02\x06\x12\x03%\x02\"\n\x0c\n\x05\x04\ - \x04\x02\x06\x04\x12\x03%\x02\n\n\x0c\n\x05\x04\x04\x02\x06\x05\x12\x03%\ - \x0b\x0f\n\x0c\n\x05\x04\x04\x02\x06\x01\x12\x03%\x10\x1d\n\x0c\n\x05\ - \x04\x04\x02\x06\x03\x12\x03%\x20!\n\x0b\n\x04\x04\x04\x02\x07\x12\x03&\ - \x02\x18\n\x0c\n\x05\x04\x04\x02\x07\x04\x12\x03&\x02\n\n\x0c\n\x05\x04\ - \x04\x02\x07\x05\x12\x03&\x0b\x11\n\x0c\n\x05\x04\x04\x02\x07\x01\x12\ - \x03&\x12\x13\n\x0c\n\x05\x04\x04\x02\x07\x03\x12\x03&\x16\x17\n\x0b\n\ - \x04\x04\x04\x02\x08\x12\x03'\x02\x18\n\x0c\n\x05\x04\x04\x02\x08\x04\ - \x12\x03'\x02\n\n\x0c\n\x05\x04\x04\x02\x08\x05\x12\x03'\x0b\x11\n\x0c\n\ - \x05\x04\x04\x02\x08\x01\x12\x03'\x12\x13\n\x0c\n\x05\x04\x04\x02\x08\ - \x03\x12\x03'\x16\x17\n\x0b\n\x04\x04\x04\x02\t\x12\x03(\x02\x1e\n\x0c\n\ - \x05\x04\x04\x02\t\x04\x12\x03(\x02\n\n\x0c\n\x05\x04\x04\x02\t\x05\x12\ - \x03(\x0b\x0f\n\x0c\n\x05\x04\x04\x02\t\x01\x12\x03(\x10\x18\n\x0c\n\x05\ - \x04\x04\x02\t\x03\x12\x03(\x1b\x1d\n\x0b\n\x04\x04\x04\x02\n\x12\x03)\ - \x02!\n\x0c\n\x05\x04\x04\x02\n\x04\x12\x03)\x02\n\n\x0c\n\x05\x04\x04\ - \x02\n\x05\x12\x03)\x0b\x11\n\x0c\n\x05\x04\x04\x02\n\x01\x12\x03)\x12\ - \x1b\n\x0c\n\x05\x04\x04\x02\n\x03\x12\x03)\x1e\x20\n\x0b\n\x04\x04\x04\ - \x02\x0b\x12\x03*\x02!\n\x0c\n\x05\x04\x04\x02\x0b\x04\x12\x03*\x02\n\n\ - \x0c\n\x05\x04\x04\x02\x0b\x05\x12\x03*\x0b\x11\n\x0c\n\x05\x04\x04\x02\ - \x0b\x01\x12\x03*\x12\x1b\n\x0c\n\x05\x04\x04\x02\x0b\x03\x12\x03*\x1e\ - \x20\n\x0b\n\x04\x04\x04\x02\x0c\x12\x03+\x02\"\n\x0c\n\x05\x04\x04\x02\ - \x0c\x04\x12\x03+\x02\n\n\x0c\n\x05\x04\x04\x02\x0c\x05\x12\x03+\x0b\x0f\ - \n\x0c\n\x05\x04\x04\x02\x0c\x01\x12\x03+\x10\x1c\n\x0c\n\x05\x04\x04\ - \x02\x0c\x03\x12\x03+\x1f!\n\n\n\x02\x04\x05\x12\x04.\01\x01\n\n\n\x03\ - \x04\x05\x01\x12\x03.\x08\r\n\x0b\n\x04\x04\x05\x02\0\x12\x03/\x02\x20\n\ - \x0c\n\x05\x04\x05\x02\0\x04\x12\x03/\x02\n\n\x0c\n\x05\x04\x05\x02\0\ - \x05\x12\x03/\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03/\x12\x1b\n\ - \x0c\n\x05\x04\x05\x02\0\x03\x12\x03/\x1e\x1f\n\x0b\n\x04\x04\x05\x02\ - \x01\x12\x030\x02\x1e\n\x0c\n\x05\x04\x05\x02\x01\x04\x12\x030\x02\n\n\ - \x0c\n\x05\x04\x05\x02\x01\x05\x12\x030\x0b\x11\n\x0c\n\x05\x04\x05\x02\ - \x01\x01\x12\x030\x12\x19\n\x0c\n\x05\x04\x05\x02\x01\x03\x12\x030\x1c\ - \x1d\n\n\n\x02\x04\x06\x12\x043\07\x01\n\n\n\x03\x04\x06\x01\x12\x033\ - \x08\x0e\n\x0b\n\x04\x04\x06\x02\0\x12\x034\x02\x1a\n\x0c\n\x05\x04\x06\ - \x02\0\x04\x12\x034\x02\n\n\x0c\n\x05\x04\x06\x02\0\x06\x12\x034\x0b\x0f\ - \n\x0c\n\x05\x04\x06\x02\0\x01\x12\x034\x10\x15\n\x0c\n\x05\x04\x06\x02\ - \0\x03\x12\x034\x18\x19\n\x0b\n\x04\x04\x06\x02\x01\x12\x035\x02\x1d\n\ - \x0c\n\x05\x04\x06\x02\x01\x04\x12\x035\x02\n\n\x0c\n\x05\x04\x06\x02\ - \x01\x05\x12\x035\x0b\x11\n\x0c\n\x05\x04\x06\x02\x01\x01\x12\x035\x12\ - \x18\n\x0c\n\x05\x04\x06\x02\x01\x03\x12\x035\x1b\x1c\n\x0b\n\x04\x04\ - \x06\x02\x02\x12\x036\x02\x1c\n\x0c\n\x05\x04\x06\x02\x02\x04\x12\x036\ - \x02\n\n\x0c\n\x05\x04\x06\x02\x02\x06\x12\x036\x0b\x10\n\x0c\n\x05\x04\ - \x06\x02\x02\x01\x12\x036\x11\x17\n\x0c\n\x05\x04\x06\x02\x02\x03\x12\ - \x036\x1a\x1b\ + \x08R\x0bautoArrange\x12\x10\n\x03url\x18\x0e\x20\x01(\tR\x03url\"=\n\ + \x05Arrow\x12\x1b\n\tfrom_node\x18\x01\x20\x02(\x04R\x08fromNode\x12\x17\ + \n\x07to_node\x18\x02\x20\x02(\x04R\x06toNode\"f\n\x06Screen\x12\x20\n\ + \x05nodes\x18\x01\x20\x03(\x0b2\n.void.NodeR\x05nodes\x12\x15\n\x06max_i\ + d\x18\x02\x20\x02(\x04R\x05maxId\x12#\n\x06arrows\x18\x03\x20\x03(\x0b2\ + \x0b.void.ArrowR\x06arrowsJ\xa9\x13\n\x06\x12\x04\0\08\x01\n\x08\n\x01\ + \x0c\x12\x03\0\0\x12\n\x08\n\x01\x02\x12\x03\x02\0\r\n\n\n\x02\x04\0\x12\ + \x04\x04\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x04\x08\x0b\n\x0b\n\x04\ + \x04\0\x02\0\x12\x03\x05\x02\x1a\n\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x05\ + \x02\n\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x05\x0b\x11\n\x0c\n\x05\x04\0\ + \x02\0\x01\x12\x03\x05\x12\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x05\ + \x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x06\x02\x1c\n\x0c\n\x05\x04\0\ + \x02\x01\x04\x12\x03\x06\x02\n\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x06\ + \x0b\x11\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x06\x12\x17\n\x0c\n\x05\ + \x04\0\x02\x01\x03\x12\x03\x06\x1a\x1b\n\n\n\x02\x04\x01\x12\x04\t\0\x0c\ + \x01\n\n\n\x03\x04\x01\x01\x12\x03\t\x08\x0b\n\x0b\n\x04\x04\x01\x02\0\ + \x12\x03\n\x02\x19\n\x0c\n\x05\x04\x01\x02\0\x04\x12\x03\n\x02\n\n\x0c\n\ + \x05\x04\x01\x02\0\x05\x12\x03\n\x0b\x10\n\x0c\n\x05\x04\x01\x02\0\x01\ + \x12\x03\n\x11\x14\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x17\x18\n\x0b\ + \n\x04\x04\x01\x02\x01\x12\x03\x0b\x02\x19\n\x0c\n\x05\x04\x01\x02\x01\ + \x04\x12\x03\x0b\x02\n\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x0b\x0b\ + \x10\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x11\x14\n\x0c\n\x05\x04\ + \x01\x02\x01\x03\x12\x03\x0b\x17\x18\n\n\n\x02\x04\x02\x12\x04\x0e\0\x12\ + \x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x0c\n\x0b\n\x04\x04\x02\x02\0\ + \x12\x03\x0f\x04\x1c\n\x0c\n\x05\x04\x02\x02\0\x04\x12\x03\x0f\x04\x0c\n\ + \x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0f\r\x13\n\x0c\n\x05\x04\x02\x02\0\ + \x01\x12\x03\x0f\x14\x17\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0f\x1a\ + \x1b\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x10\x04\x1e\n\x0c\n\x05\x04\x02\ + \x02\x01\x04\x12\x03\x10\x04\x0c\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\ + \x10\r\x13\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x10\x14\x19\n\x0c\n\ + \x05\x04\x02\x02\x01\x03\x12\x03\x10\x1c\x1d\n\x0b\n\x04\x04\x02\x02\x02\ + \x12\x03\x11\x04\x1d\n\x0c\n\x05\x04\x02\x02\x02\x04\x12\x03\x11\x04\x0c\ + \n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\x11\r\x13\n\x0c\n\x05\x04\x02\ + \x02\x02\x01\x12\x03\x11\x14\x18\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\ + \x11\x1b\x1c\n\n\n\x02\x04\x03\x12\x04\x14\0\x1c\x01\n\n\n\x03\x04\x03\ + \x01\x12\x03\x14\x08\x0c\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x15\x02\x1c\n\ + \x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x15\x02\n\n\x0c\n\x05\x04\x03\x02\0\ + \x05\x12\x03\x15\x0b\x11\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x15\x12\ + \x17\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x15\x1a\x1b\n\x0b\n\x04\x04\ + \x03\x02\x01\x12\x03\x16\x02\x1c\n\x0c\n\x05\x04\x03\x02\x01\x04\x12\x03\ + \x16\x02\n\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\x03\x16\x0b\x11\n\x0c\n\ + \x05\x04\x03\x02\x01\x01\x12\x03\x16\x12\x17\n\x0c\n\x05\x04\x03\x02\x01\ + \x03\x12\x03\x16\x1a\x1b\n\x0b\n\x04\x04\x03\x02\x02\x12\x03\x17\x02\"\n\ + \x0c\n\x05\x04\x03\x02\x02\x04\x12\x03\x17\x02\n\n\x0c\n\x05\x04\x03\x02\ + \x02\x05\x12\x03\x17\x0b\x11\n\x0c\n\x05\x04\x03\x02\x02\x01\x12\x03\x17\ + \x12\x1d\n\x0c\n\x05\x04\x03\x02\x02\x03\x12\x03\x17\x20!\n\x0b\n\x04\ + \x04\x03\x02\x03\x12\x03\x18\x02\x17\n\x0c\n\x05\x04\x03\x02\x03\x04\x12\ + \x03\x18\x02\n\n\x0c\n\x05\x04\x03\x02\x03\x06\x12\x03\x18\x0b\x0e\n\x0c\ + \n\x05\x04\x03\x02\x03\x01\x12\x03\x18\x0f\x12\n\x0c\n\x05\x04\x03\x02\ + \x03\x03\x12\x03\x18\x15\x16\n\x0b\n\x04\x04\x03\x02\x04\x12\x03\x19\x02\ + \x18\n\x0c\n\x05\x04\x03\x02\x04\x04\x12\x03\x19\x02\n\n\x0c\n\x05\x04\ + \x03\x02\x04\x06\x12\x03\x19\x0b\x0e\n\x0c\n\x05\x04\x03\x02\x04\x01\x12\ + \x03\x19\x0f\x13\n\x0c\n\x05\x04\x03\x02\x04\x03\x12\x03\x19\x16\x17\n\ + \x0b\n\x04\x04\x03\x02\x05\x12\x03\x1a\x02\x1e\n\x0c\n\x05\x04\x03\x02\ + \x05\x04\x12\x03\x1a\x02\n\n\x0c\n\x05\x04\x03\x02\x05\x05\x12\x03\x1a\ + \x0b\x11\n\x0c\n\x05\x04\x03\x02\x05\x01\x12\x03\x1a\x12\x19\n\x0c\n\x05\ + \x04\x03\x02\x05\x03\x12\x03\x1a\x1c\x1d\n\x0b\n\x04\x04\x03\x02\x06\x12\ + \x03\x1b\x02\x1d\n\x0c\n\x05\x04\x03\x02\x06\x04\x12\x03\x1b\x02\n\n\x0c\ + \n\x05\x04\x03\x02\x06\x06\x12\x03\x1b\x0b\x0f\n\x0c\n\x05\x04\x03\x02\ + \x06\x01\x12\x03\x1b\x10\x18\n\x0c\n\x05\x04\x03\x02\x06\x03\x12\x03\x1b\ + \x1b\x1c\n\n\n\x02\x04\x04\x12\x04\x1e\0-\x01\n\n\n\x03\x04\x04\x01\x12\ + \x03\x1e\x08\x0c\n\x0b\n\x04\x04\x04\x02\0\x12\x03\x1f\x02\x19\n\x0c\n\ + \x05\x04\x04\x02\0\x04\x12\x03\x1f\x02\n\n\x0c\n\x05\x04\x04\x02\0\x05\ + \x12\x03\x1f\x0b\x11\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\x1f\x12\x14\n\ + \x0c\n\x05\x04\x04\x02\0\x03\x12\x03\x1f\x17\x18\n\x0b\n\x04\x04\x04\x02\ + \x01\x12\x03\x20\x02\x19\n\x0c\n\x05\x04\x04\x02\x01\x04\x12\x03\x20\x02\ + \n\n\x0c\n\x05\x04\x04\x02\x01\x06\x12\x03\x20\x0b\x0f\n\x0c\n\x05\x04\ + \x04\x02\x01\x01\x12\x03\x20\x10\x14\n\x0c\n\x05\x04\x04\x02\x01\x03\x12\ + \x03\x20\x17\x18\n\x0b\n\x04\x04\x04\x02\x02\x12\x03!\x02\x1b\n\x0c\n\ + \x05\x04\x04\x02\x02\x04\x12\x03!\x02\n\n\x0c\n\x05\x04\x04\x02\x02\x05\ + \x12\x03!\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\x01\x12\x03!\x12\x16\n\x0c\ + \n\x05\x04\x04\x02\x02\x03\x12\x03!\x19\x1a\n\x0b\n\x04\x04\x04\x02\x03\ + \x12\x03\"\x02\x1f\n\x0c\n\x05\x04\x04\x02\x03\x04\x12\x03\"\x02\n\n\x0c\ + \n\x05\x04\x04\x02\x03\x05\x12\x03\"\x0b\x11\n\x0c\n\x05\x04\x04\x02\x03\ + \x01\x12\x03\"\x12\x1a\n\x0c\n\x05\x04\x04\x02\x03\x03\x12\x03\"\x1d\x1e\ + \n\x0b\n\x04\x04\x04\x02\x04\x12\x03#\x02\x1e\n\x0c\n\x05\x04\x04\x02\ + \x04\x04\x12\x03#\x02\n\n\x0c\n\x05\x04\x04\x02\x04\x05\x12\x03#\x0b\x0f\ + \n\x0c\n\x05\x04\x04\x02\x04\x01\x12\x03#\x10\x19\n\x0c\n\x05\x04\x04\ + \x02\x04\x03\x12\x03#\x1c\x1d\n\x0b\n\x04\x04\x04\x02\x05\x12\x03$\x02\ + \x1d\n\x0c\n\x05\x04\x04\x02\x05\x04\x12\x03$\x02\n\n\x0c\n\x05\x04\x04\ + \x02\x05\x05\x12\x03$\x0b\x0f\n\x0c\n\x05\x04\x04\x02\x05\x01\x12\x03$\ + \x10\x18\n\x0c\n\x05\x04\x04\x02\x05\x03\x12\x03$\x1b\x1c\n\x0b\n\x04\ + \x04\x04\x02\x06\x12\x03%\x02\"\n\x0c\n\x05\x04\x04\x02\x06\x04\x12\x03%\ + \x02\n\n\x0c\n\x05\x04\x04\x02\x06\x05\x12\x03%\x0b\x0f\n\x0c\n\x05\x04\ + \x04\x02\x06\x01\x12\x03%\x10\x1d\n\x0c\n\x05\x04\x04\x02\x06\x03\x12\ + \x03%\x20!\n\x0b\n\x04\x04\x04\x02\x07\x12\x03&\x02\x18\n\x0c\n\x05\x04\ + \x04\x02\x07\x04\x12\x03&\x02\n\n\x0c\n\x05\x04\x04\x02\x07\x05\x12\x03&\ + \x0b\x11\n\x0c\n\x05\x04\x04\x02\x07\x01\x12\x03&\x12\x13\n\x0c\n\x05\ + \x04\x04\x02\x07\x03\x12\x03&\x16\x17\n\x0b\n\x04\x04\x04\x02\x08\x12\ + \x03'\x02\x18\n\x0c\n\x05\x04\x04\x02\x08\x04\x12\x03'\x02\n\n\x0c\n\x05\ + \x04\x04\x02\x08\x05\x12\x03'\x0b\x11\n\x0c\n\x05\x04\x04\x02\x08\x01\ + \x12\x03'\x12\x13\n\x0c\n\x05\x04\x04\x02\x08\x03\x12\x03'\x16\x17\n\x0b\ + \n\x04\x04\x04\x02\t\x12\x03(\x02\x1e\n\x0c\n\x05\x04\x04\x02\t\x04\x12\ + \x03(\x02\n\n\x0c\n\x05\x04\x04\x02\t\x05\x12\x03(\x0b\x0f\n\x0c\n\x05\ + \x04\x04\x02\t\x01\x12\x03(\x10\x18\n\x0c\n\x05\x04\x04\x02\t\x03\x12\ + \x03(\x1b\x1d\n\x0b\n\x04\x04\x04\x02\n\x12\x03)\x02!\n\x0c\n\x05\x04\ + \x04\x02\n\x04\x12\x03)\x02\n\n\x0c\n\x05\x04\x04\x02\n\x05\x12\x03)\x0b\ + \x11\n\x0c\n\x05\x04\x04\x02\n\x01\x12\x03)\x12\x1b\n\x0c\n\x05\x04\x04\ + \x02\n\x03\x12\x03)\x1e\x20\n\x0b\n\x04\x04\x04\x02\x0b\x12\x03*\x02!\n\ + \x0c\n\x05\x04\x04\x02\x0b\x04\x12\x03*\x02\n\n\x0c\n\x05\x04\x04\x02\ + \x0b\x05\x12\x03*\x0b\x11\n\x0c\n\x05\x04\x04\x02\x0b\x01\x12\x03*\x12\ + \x1b\n\x0c\n\x05\x04\x04\x02\x0b\x03\x12\x03*\x1e\x20\n\x0b\n\x04\x04\ + \x04\x02\x0c\x12\x03+\x02\"\n\x0c\n\x05\x04\x04\x02\x0c\x04\x12\x03+\x02\ + \n\n\x0c\n\x05\x04\x04\x02\x0c\x05\x12\x03+\x0b\x0f\n\x0c\n\x05\x04\x04\ + \x02\x0c\x01\x12\x03+\x10\x1c\n\x0c\n\x05\x04\x04\x02\x0c\x03\x12\x03+\ + \x1f!\n\x0b\n\x04\x04\x04\x02\r\x12\x03,\x02\x1b\n\x0c\n\x05\x04\x04\x02\ + \r\x04\x12\x03,\x02\n\n\x0c\n\x05\x04\x04\x02\r\x05\x12\x03,\x0b\x11\n\ + \x0c\n\x05\x04\x04\x02\r\x01\x12\x03,\x12\x15\n\x0c\n\x05\x04\x04\x02\r\ + \x03\x12\x03,\x18\x1a\n\n\n\x02\x04\x05\x12\x04/\02\x01\n\n\n\x03\x04\ + \x05\x01\x12\x03/\x08\r\n\x0b\n\x04\x04\x05\x02\0\x12\x030\x02\x20\n\x0c\ + \n\x05\x04\x05\x02\0\x04\x12\x030\x02\n\n\x0c\n\x05\x04\x05\x02\0\x05\ + \x12\x030\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x01\x12\x030\x12\x1b\n\x0c\n\ + \x05\x04\x05\x02\0\x03\x12\x030\x1e\x1f\n\x0b\n\x04\x04\x05\x02\x01\x12\ + \x031\x02\x1e\n\x0c\n\x05\x04\x05\x02\x01\x04\x12\x031\x02\n\n\x0c\n\x05\ + \x04\x05\x02\x01\x05\x12\x031\x0b\x11\n\x0c\n\x05\x04\x05\x02\x01\x01\ + \x12\x031\x12\x19\n\x0c\n\x05\x04\x05\x02\x01\x03\x12\x031\x1c\x1d\n\n\n\ + \x02\x04\x06\x12\x044\08\x01\n\n\n\x03\x04\x06\x01\x12\x034\x08\x0e\n\ + \x0b\n\x04\x04\x06\x02\0\x12\x035\x02\x1a\n\x0c\n\x05\x04\x06\x02\0\x04\ + \x12\x035\x02\n\n\x0c\n\x05\x04\x06\x02\0\x06\x12\x035\x0b\x0f\n\x0c\n\ + \x05\x04\x06\x02\0\x01\x12\x035\x10\x15\n\x0c\n\x05\x04\x06\x02\0\x03\ + \x12\x035\x18\x19\n\x0b\n\x04\x04\x06\x02\x01\x12\x036\x02\x1d\n\x0c\n\ + \x05\x04\x06\x02\x01\x04\x12\x036\x02\n\n\x0c\n\x05\x04\x06\x02\x01\x05\ + \x12\x036\x0b\x11\n\x0c\n\x05\x04\x06\x02\x01\x01\x12\x036\x12\x18\n\x0c\ + \n\x05\x04\x06\x02\x01\x03\x12\x036\x1b\x1c\n\x0b\n\x04\x04\x06\x02\x02\ + \x12\x037\x02\x1c\n\x0c\n\x05\x04\x06\x02\x02\x04\x12\x037\x02\n\n\x0c\n\ + \x05\x04\x06\x02\x02\x06\x12\x037\x0b\x10\n\x0c\n\x05\x04\x06\x02\x02\ + \x01\x12\x037\x11\x17\n\x0c\n\x05\x04\x06\x02\x02\x03\x12\x037\x1a\x1b\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/src/screen.rs b/src/screen.rs index 27de96f..1821f2b 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -642,24 +642,23 @@ impl Screen { }; let Selection { selected_id, .. } = self.selected.unwrap(); - let content_opt = self.with_node(selected_id, |n| n.content.clone()); + let content_opt = self.with_node(selected_id, |n| (n.url.clone(), n.content.clone())); if content_opt.is_none() { error!("tried to exec deleted node"); return; } + let (url, content) = content_opt.unwrap(); // remove any tags from the exec // except for those that are escaped as ## - let content = RE_TAG - .replace_all(&content_opt.unwrap(), "$1") - .replace("##", "#"); + let content = RE_TAG.replace_all(&content, "$1").replace("##", "#"); info!("executing command: {}", content); if content.is_empty() { error!("cannot execute empty command"); } else if content.starts_with("txt:") { self.exec_text_editor(selected_id); - } else if content.starts_with("http") { + } else if let Some(url) = url { #[cfg(any(target_os = "macos",))] let default_open_cmd = "open"; #[cfg(target_os = "linux")] @@ -668,9 +667,9 @@ impl Screen { let default_open_cmd = "start"; let browser = env::var("BROWSER").unwrap_or_else(|_| default_open_cmd.to_owned()); - let cmd = process::Command::new(browser).arg(&content).spawn(); + let cmd = process::Command::new(browser).arg(&url).spawn(); if cmd.is_err() { - error!("command failed to start: {}", &content); + error!("url command failed to start: {}", &url); } } else { let shell = env::var("SHELL").unwrap_or_else(|_| "bash".to_owned()); @@ -810,7 +809,24 @@ impl Screen { let raw_node_opt = self.with_node(node_id, |n| n.clone()); if let Some(raw_node) = raw_node_opt { let node = self.format_node(&raw_node); - let width = 2 + (3 * depth as u16) + node.content.len() as u16; + let mut width = 2 + (3 * depth as u16) + node.content.len() as u16; + + if node.hide_stricken { + width += 1; + } + if node.free_text.is_some() { + width += 1; + } + if node.stricken { + width += 1; + } + if node.url.is_some() { + width += 1; + } + if node.collapsed { + width += 1; + } + let mut ret = vec![width]; let hide_stricken = self.with_node(node_id, |n| n.hide_stricken).unwrap(); if !node.collapsed { @@ -842,6 +858,7 @@ impl Screen { trace!("unselect()"); lazy_static! { static ref RE_DATE: Regex = Regex::new(r"\[(\d{2}\.\d{2}\.\d{4})\]").unwrap(); + static ref RE_URL: Regex = Regex::new(r"#url=(.*)$").unwrap(); } if let Some(Selection { selected_id, .. }) = self.selected { // nuke node if it's empty and has no children @@ -856,6 +873,7 @@ impl Screen { return None; } + let mut invalidate_cache = false; self.with_node_mut_no_meta(selected_id, |n| { // if parseable date, change date let mut due_date_set = false; @@ -867,10 +885,23 @@ impl Screen { } } + if let Some(url) = re_matches::(&RE_URL, &*n.content).get(0) { + n.content = RE_URL.replace(&*n.content, "").trim_end().to_owned(); + invalidate_cache = true; + if url.is_empty() { + n.url = None; + } else { + n.url = Some(url.to_owned()); + } + } + if !due_date_set { n.meta.due_date = None; } }); + if invalidate_cache { + self.grapheme_cache.remove(&selected_id); + } } self.selected.take().map(|s| s.selected_id) } @@ -2290,14 +2321,18 @@ impl Screen { } if node.stricken { buf.write_str(&self.config.stricken).unwrap(); - } else if node.collapsed { + } + if node.collapsed { buf.write_str(&self.config.collapsed).unwrap(); - } else if node.hide_stricken { + } + if node.hide_stricken { buf.write_str(&self.config.hide_stricken).unwrap(); - } else if node.free_text.is_some() { + } + if node.free_text.is_some() { buf.write_str(&self.config.free_text).unwrap(); - } else { - write!(&mut buf, " ").unwrap(); + } + if node.url.is_some() { + buf.write_str(&self.config.url).unwrap(); } write!(&mut buf, "{}", node.content).unwrap(); diff --git a/src/serialization.rs b/src/serialization.rs index b86a7b5..b113304 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -73,6 +73,9 @@ fn serialize_node(node: &Node) -> pb::Node { if let Some(ref free_text) = node.free_text { node_pb.set_free_text(free_text.to_owned()); } + if let Some(ref url) = node.url { + node_pb.set_url(url.to_owned()); + } node_pb } @@ -123,6 +126,11 @@ fn deserialize_node(node_pb: &pb::Node) -> Node { } else { None }, + url: if node_pb.has_url() { + Some(node_pb.get_url().to_owned()) + } else { + None + }, color: random_fg_color(), auto_arrange: node_pb.get_auto_arrange(), } From 9719d4420fbe59049f8903fe8de2bf0eb1606fb1 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Mon, 4 Oct 2021 12:09:05 +0300 Subject: [PATCH 31/41] Stop showing browser command output --- src/screen.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/screen.rs b/src/screen.rs index 1821f2b..2171241 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -667,7 +667,11 @@ impl Screen { let default_open_cmd = "start"; let browser = env::var("BROWSER").unwrap_or_else(|_| default_open_cmd.to_owned()); - let cmd = process::Command::new(browser).arg(&url).spawn(); + let cmd = process::Command::new(browser) + .arg(&url) + .stdout(process::Stdio::null()) + .stderr(process::Stdio::null()) + .spawn(); if cmd.is_err() { error!("url command failed to start: {}", &url); } From 11ca168ef7c1b5d8614c2d563cb7f949df6f81d1 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Fri, 15 Oct 2021 16:40:29 +0300 Subject: [PATCH 32/41] Accept 1-based indexing for terminal size --- src/screen.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 2171241..2c0797c 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -462,7 +462,7 @@ impl Screen { let stdin: Box = Box::new(stdin()); print!( "{}{}{}{}", - cursor::Goto(0, self.dims.1), + cursor::Goto(1, self.dims.1), style::Invert, clear::AfterCursor, prompt @@ -484,7 +484,7 @@ impl Screen { print!( "{}{}{}{}{}", style::Invert, - cursor::Goto(0, self.dims.1), + cursor::Goto(1, self.dims.1), clear::AfterCursor, prompt, cursor::Show @@ -2120,7 +2120,7 @@ impl Screen { } } line += 2; - if line > max_line { + if line >= max_line { break; } @@ -2167,7 +2167,7 @@ impl Screen { if self.show_logs && self.dims.0 > 4 && self.dims.1 > 7 { let mut sep = format!( "{}{}logs{}", - cursor::Goto(0, self.dims.1 - 6), + cursor::Goto(1, self.dims.1 - 6), style::Invert, style::Reset ); @@ -2309,6 +2309,9 @@ impl Screen { // only actually print it if we're in-view if let Some((x, y)) = self.internal_to_screen_xy(internal_coords) { + if x < 1 || y < 1 { + warn!("drawn at {} {}", x, y); + } write!(pre_meta, "{}{}", cursor::Goto(x, y), color).unwrap(); if node.selected && !(self.config.modal && self.is_insert_mode()) { write!(&mut pre_meta, "{}", style::Invert).unwrap(); From 23c7d112c3178cd39492f668397ec38df1a6023a Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Sat, 16 Oct 2021 15:34:03 +0300 Subject: [PATCH 33/41] Display date on header line --- src/screen.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/screen.rs b/src/screen.rs index 2c0797c..275dd15 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2532,6 +2532,9 @@ impl Screen { header_text.push_str(&*plot_line); + let date = Local::today(); + header_text.push_str(&format!(" {}", date.format("%-d.%-m.%Y"))); + if self.dims.0 > header_text.len() as u16 && self.dims.1 > 1 { let mut sep = format!( "{}{}{}{}", From 6d69544fa065a86baa59e6cb9cf17a32096f37d0 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 28 Oct 2021 22:13:28 +0300 Subject: [PATCH 34/41] Don't count stricken subtrees for calendar --- src/screen.rs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 275dd15..6dcbb22 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -535,7 +535,8 @@ impl Screen { self.last_search.take(); } - let mut f = |n: &Node, _: ()| (n.content.find(&*query).map(|idx| (idx, n.id)), ()); + let mut f = + |n: &Node, _: ()| (n.content.find(&*query).map(|idx| (idx, n.id)), (), true); let mut candidates = self.recursive_child_filter_map(self.drawing_root, (), &mut f); if candidates.is_empty() { return; @@ -778,19 +779,21 @@ impl Screen { filter_map: &mut F, ) -> Vec where - F: FnMut(&Node, C) -> (Option, C), + F: FnMut(&Node, C) -> (Option, C, bool), C: Copy, { trace!("recursive_child_filter_map({}, F...)", node_id); let mut ret = vec![]; if let Some(node) = self.nodes.get(&node_id) { - let (filtered, context) = filter_map(node, context); + let (filtered, context, walk) = filter_map(node, context); if let Some(b) = filtered { ret.push(b); } - for &child_id in &node.children { - ret.append(&mut self.recursive_child_filter_map(child_id, context, filter_map)); + if walk { + for &child_id in &node.children { + ret.append(&mut self.recursive_child_filter_map(child_id, context, filter_map)); + } } } else { debug!("queried for node {} but it is not in self.nodes", node_id); @@ -2015,14 +2018,14 @@ impl Screen { && assigned.year() == year && assigned.month() == month { - (Some(assigned.day0()), date) + (Some(assigned.day0()), date, false) } else if !nd.stricken { - (None, date) + (None, date, true) } else { - (None, None) + (None, None, false) } } else { - (None, None) + (None, None, !nd.stricken) } }, ); @@ -2669,12 +2672,12 @@ impl Screen { let f = n.meta.finish_time; if let Some(t) = f { if t > last_week { - (Some(t), ()) + (Some(t), (), true) } else { - (None, ()) + (None, (), true) } } else { - (None, ()) + (None, (), true) } }); let mut counts = BTreeMap::new(); @@ -2824,16 +2827,16 @@ impl Screen { PlotType::Done => { if let Some(ft) = n.meta.finish_time { if ft >= since { - return (Some(ft as i64), ()); + return (Some(ft as i64), (), true); } } - (None, ()) + (None, (), true) } PlotType::New => { if n.meta.ctime >= since { - (Some(n.meta.ctime as i64), ()) + (Some(n.meta.ctime as i64), (), true) } else { - (None, ()) + (None, (), true) } } }); From 7d7bcb77cf43ec900df029d154216335995e88fa Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 4 Nov 2021 19:17:59 +0200 Subject: [PATCH 35/41] Don't overflow when there are too many assigned tasks --- src/screen.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/screen.rs b/src/screen.rs index 6dcbb22..6a07f73 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2088,7 +2088,7 @@ impl Screen { if line + 1 < max_line { let assigned = counts_by_day[date.day0() as usize]; - if assigned > 0 { + if assigned > 0 && assigned < 100 { let day_assigned_tasks_label = format!( "{}{}{:3}{}", cursor::Goto(offset_x, line + 1), @@ -2097,6 +2097,15 @@ impl Screen { style::Reset, ); print!("{}", day_assigned_tasks_label); + } else if assigned > 0 { + let day_assigned_tasks_label = format!( + "{}{}{:3}{}", + cursor::Goto(offset_x, line + 1), + style::Italic, + "?!", + style::Reset, + ); + print!("{}", day_assigned_tasks_label); } } From 16d78d79bd15a71c387203b0cc0303f382063583 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Thu, 11 Nov 2021 10:30:17 +0200 Subject: [PATCH 36/41] Prevent done tasks being counted twice, when actual tasks are counted in subtress --- src/screen.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 6a07f73..40e49e6 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2680,7 +2680,12 @@ impl Screen { self.recursive_child_filter_map(0, (), &mut |n: &Node, _: ()| { let f = n.meta.finish_time; if let Some(t) = f { - if t > last_week { + if t > last_week + && !n + .children + .iter() + .any(|ch| self.with_node(*ch, |sub_n| sub_n.stricken).unwrap()) + { (Some(t), (), true) } else { (None, (), true) @@ -2835,7 +2840,12 @@ impl Screen { self.recursive_child_filter_map(c, (), &mut |n: &Node, _: ()| match kind { PlotType::Done => { if let Some(ft) = n.meta.finish_time { - if ft >= since { + if ft >= since + && !n + .children + .iter() + .any(|ch| self.with_node(*ch, |sub_n| sub_n.stricken).unwrap()) + { return (Some(ft as i64), (), true); } } From fb8afca887d27a47fd1c2ce6667f454038861dd4 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Mon, 27 Dec 2021 16:07:09 +0200 Subject: [PATCH 37/41] Fix Unicode boundary issue in statusline drawing --- src/screen.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index 40e49e6..787bd7e 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2521,8 +2521,9 @@ impl Screen { match self.cut { Cut::Move(id) | Cut::Yank(id) => { let content = &self.nodes.get(&id).unwrap().content; - let content_ellipsized = if content.len() >= 13 { - Cow::from(format!("{}...", &content[..10])) + let restricted_chars = content.chars().take(10).collect::(); + let content_ellipsized = if restricted_chars.len() < content.len() { + Cow::from(format!("{}...", &restricted_chars)) } else { Cow::from(content) }; From 64eadd0aed3f7b6b7a807722cb3ef3a652a25a95 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Tue, 8 Feb 2022 10:45:22 +0200 Subject: [PATCH 38/41] Reap background processes --- src/config.rs | 22 ++++++++-------- src/screen.rs | 69 +++++++++++++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/config.rs b/src/config.rs index a744ae9..9d571ff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -57,7 +57,7 @@ impl fmt::Display for Action { match self { Action::LeftClick(..) | Action::RightClick(..) | Action::Release(..) => { write!(f, "Other action") - } + }, Action::Arrow => write!(f, "Start or end arrow"), Action::AutoArrange => write!(f, "Toggle automatic arrangement"), Action::Char(c) => write!(f, "Input character {}", c), @@ -321,19 +321,19 @@ impl Config { match (option, param) { ("stricken", p) => { config.stricken = p.to_owned(); - } + }, ("collapsed", p) => { config.collapsed = p.to_owned(); - } + }, ("hide_stricken", p) => { config.hide_stricken = p.to_owned(); - } + }, ("free_text", p) => { config.free_text = p.to_owned(); - } + }, ("url", p) => { config.url = p.to_owned(); - } + }, (raw_action, raw_key) => { let key_opt = to_key(raw_key.to_owned()); let action_opt = to_action(raw_action.to_owned()); @@ -348,7 +348,7 @@ impl Config { let action = action_opt.unwrap(); config.config.insert(key, action); - } + }, } } @@ -364,10 +364,10 @@ impl Config { } else { Some(Action::Char(c)) } - } + }, Event::Mouse(MouseEvent::Press(MouseButton::Right, x, y)) => { Some(Action::RightClick(x, y)) - } + }, Event::Mouse(MouseEvent::Press(_, x, y)) => Some(Action::LeftClick(x, y)), Event::Mouse(MouseEvent::Release(x, y)) => Some(Action::Release(x, y)), Event::Mouse(MouseEvent::Hold(..)) => None, @@ -377,11 +377,11 @@ impl Config { warn!("Weird event {:?}", other); } lookup - } + }, other => { warn!("Unknown event received: {:?}", other); None - } + }, } } } diff --git a/src/screen.rs b/src/screen.rs index 787bd7e..975848a 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -222,24 +222,24 @@ impl Screen { Action::LeftClick(x, y) => { let internal_coords = self.screen_to_internal_xy((x, y)); self.click_screen(internal_coords) - } + }, Action::RightClick(..) => { self.pop_focus(); - } + }, Action::Release(x, y) => { let internal_coords = self.screen_to_internal_xy((x, y)); self.release(internal_coords) - } + }, Action::Char('/') => { self.search_forward(); - } + }, Action::Char('?') => { self.search_backward(); - } + }, Action::Char(c) if !self.config.modal => { self.prefix_jump_to(c.to_string()); - } - Action::Char(_) => {} + }, + Action::Char(_) => {}, Action::Help => self.help(), Action::Insert => { if let Some(sel) = self.selected.as_mut() { @@ -247,7 +247,7 @@ impl Screen { self.grapheme_cache.remove(&sel.selected_id); sel.inserting = true } - } + }, Action::UnselectRet if self.config.modal && self.selected.map(|s| s.inserting) == Some(true) => @@ -257,10 +257,10 @@ impl Screen { self.grapheme_cache.remove(&sel.selected_id); sel.inserting = false } - } + }, Action::UnselectRet => { self.unselect(); - } + }, Action::ScrollUp => self.scroll_up(), Action::ScrollDown => self.scroll_down(), Action::DeleteSelected => self.delete_selected(true), @@ -269,7 +269,7 @@ impl Screen { Action::SelectLeft => self.select_left(), Action::SelectRight => self.select_right(), Action::EraseChar if self.is_insert_mode() => self.backspace(), - Action::EraseChar => {} + Action::EraseChar => {}, Action::CreateSibling => self.create_sibling(), Action::CreateChild => self.create_child(), Action::CreateFreeNode => self.create_free_node(), @@ -315,7 +315,7 @@ impl Screen { Cut::Move(cut) => { self.reparent(cut, place); self.cut = Cut::Empty; - } + }, Cut::Yank(cut) => { if self.is_parent(cut, place) { warn!("Can't copy a node into itself"); @@ -327,14 +327,14 @@ impl Screen { }); } self.cut = Cut::Empty; - } + }, Cut::Empty if yanking && can_cut => { self.cut = Cut::Yank(place); - } + }, Cut::Empty if can_cut => { self.cut = Cut::Move(place); - } - Cut::Empty => {} + }, + Cut::Empty => {}, } } @@ -655,10 +655,12 @@ impl Screen { let content = RE_TAG.replace_all(&content, "$1").replace("##", "#"); info!("executing command: {}", content); - if content.is_empty() { + let handle = if content.is_empty() { error!("cannot execute empty command"); + None } else if content.starts_with("txt:") { self.exec_text_editor(selected_id); + None } else if let Some(url) = url { #[cfg(any(target_os = "macos",))] let default_open_cmd = "open"; @@ -673,15 +675,24 @@ impl Screen { .stdout(process::Stdio::null()) .stderr(process::Stdio::null()) .spawn(); - if cmd.is_err() { - error!("url command failed to start: {}", &url); - } + Some(cmd) } else { let shell = env::var("SHELL").unwrap_or_else(|_| "bash".to_owned()); let cmd = process::Command::new(shell).arg("-c").arg(&content).spawn(); - if cmd.is_err() { + Some(cmd) + }; + match handle { + Some(Err(_)) => { error!("command failed to start: {}", &content); - } + }, + Some(Ok(mut child)) => { + std::thread::spawn(move || { + if matches!(child.wait(), Err(..)) { + error!("command failed to finish: {}", &content); + } + }); + }, + None => {}, } } @@ -2461,7 +2472,7 @@ impl Screen { match path.len().cmp(&1) { Ordering::Equal => { print!("{} ↺", cursor::Goto(path[0].0, path[0].1)) - } + }, Ordering::Greater => { let first = match path[1].1.cmp(&path[0].1) { Ordering::Greater => match start_dir { @@ -2500,8 +2511,8 @@ impl Screen { Dir::R => '<', }; print!("{}{}", cursor::Goto(end_x, end_y), end_char); - } - _ => {} + }, + _ => {}, }; print!("{}", color::Fg(color::Reset)); } @@ -2536,8 +2547,8 @@ impl Screen { }, content_ellipsized )); - } - Cut::Empty => {} + }, + Cut::Empty => {}, } let (plot, finished_today) = self.last_week_of_done_tasks(); @@ -2851,14 +2862,14 @@ impl Screen { } } (None, (), true) - } + }, PlotType::New => { if n.meta.ctime >= since { (Some(n.meta.ctime as i64), (), true) } else { (None, (), true) } - } + }, }); nodes.append(&mut new); } From 78091f9b1fcbd510a43f711e333836f10545f0c4 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Tue, 8 Feb 2022 13:05:23 +0200 Subject: [PATCH 39/41] Implement selecting first and last sibling, undoing completion marking --- src/config.rs | 16 ++++++++++---- src/screen.rs | 58 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/config.rs b/src/config.rs index 9d571ff..741ad6d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,11 +44,13 @@ pub enum Action { RaiseSelected, LowerSelected, Search, - UndoDelete, + Undo, Help, SelectParent, SelectNextSibling, SelectPrevSibling, + SelectFirstSibling, + SelectLastSibling, Insert, } @@ -83,6 +85,8 @@ impl fmt::Display for Action { Action::ScrollUp => write!(f, "Scroll view up"), Action::Search => write!(f, "Search for node"), Action::SelectDown => write!(f, "Select next node down"), + Action::SelectFirstSibling => write!(f, "Select first sibling"), + Action::SelectLastSibling => write!(f, "Select last sibling"), Action::SelectLeft => write!(f, "Select next node left"), Action::SelectNextSibling => write!(f, "Select next sibling"), Action::SelectParent => write!(f, "Select parent node"), @@ -93,7 +97,7 @@ impl fmt::Display for Action { Action::ToggleCompleted => write!(f, "Toggle completed"), Action::ToggleHideCompleted => write!(f, "Toggle hiding of completed tasks"), Action::ToggleShowLogs => write!(f, "Toggle log"), - Action::UndoDelete => write!(f, "Undo deletion"), + Action::Undo => write!(f, "Undo deletion/toggling completed"), Action::UnselectRet => write!(f, "Unselect node / leave insert mode"), Action::YankPasteNode => write!(f, "Yank node"), } @@ -133,11 +137,13 @@ fn to_action(input: String) -> Option { "raise_selected" => Some(Action::RaiseSelected), "lower_selected" => Some(Action::LowerSelected), "search" => Some(Action::Search), - "undo_delete" => Some(Action::UndoDelete), + "undo" => Some(Action::Undo), "help" => Some(Action::Help), "select_parent" => Some(Action::SelectParent), "select_next_sibling" => Some(Action::SelectNextSibling), "select_prev_sibling" => Some(Action::SelectPrevSibling), + "select_first_sibling" => Some(Action::SelectFirstSibling), + "select_last_sibling" => Some(Action::SelectLastSibling), "insert" => Some(Action::Insert), _ => None, } @@ -222,12 +228,14 @@ impl Default for Config { (Ctrl('g'), Action::RaiseSelected), (Ctrl('d'), Action::LowerSelected), (Ctrl('u'), Action::Search), - (Ctrl('z'), Action::UndoDelete), + (Ctrl('z'), Action::Undo), (Ctrl('?'), Action::Help), (Alt('P'), Action::SelectParent), (Alt('y'), Action::MovePasteNode), (Alt('n'), Action::SelectNextSibling), (Alt('p'), Action::SelectPrevSibling), + (Alt('k'), Action::SelectFirstSibling), + (Alt('j'), Action::SelectLastSibling), ] .into_iter() .collect(), diff --git a/src/screen.rs b/src/screen.rs index 975848a..4c41582 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -42,6 +42,12 @@ enum Cut { Empty, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum UndoNode { + Delete(NodeID), + ToggleStricken(NodeID), +} + pub struct Screen { pub max_id: u64, pub nodes: HashMap, @@ -74,7 +80,7 @@ pub struct Screen { last_search: Option<(String, NodeID)>, // undo info - undo_stack: Vec, + undo_stack: Vec, // needs to be separate, as recursive deletion of nodes causes ordering issues undo_nodes: HashMap, @@ -277,7 +283,7 @@ impl Screen { Action::DrillDown => self.drill_down(), Action::PopUp => self.pop_focus(), Action::PrefixJump => self.prefix_jump_prompt(), - Action::ToggleCompleted => self.toggle_stricken(), + Action::ToggleCompleted => self.toggle_stricken(true), Action::ToggleHideCompleted => self.toggle_hide_stricken(), Action::Arrow => self.add_or_remove_arrow(), Action::AutoArrange => self.toggle_auto_arrange(), @@ -292,10 +298,12 @@ impl Screen { Action::RaiseSelected => self.raise_selected(), Action::LowerSelected => self.lower_selected(), Action::Search => self.search_forward(), - Action::UndoDelete => self.undo_delete(), + Action::Undo => self.undo(), Action::SelectParent => self.select_parent(), Action::SelectNextSibling => self.select_next_sibling(), Action::SelectPrevSibling => self.select_prev_sibling(), + Action::SelectFirstSibling => self.select_first_sibling(), + Action::SelectLastSibling => self.select_last_sibling(), }, None => warn!("received unknown input"), } @@ -985,9 +993,12 @@ impl Screen { None } - fn toggle_stricken(&mut self) { + fn toggle_stricken(&mut self, make_undo: bool) { trace!("toggle_stricken()"); if let Some(Selection { selected_id, .. }) = self.selected { + if make_undo { + self.undo_stack.push(UndoNode::ToggleStricken(selected_id)); + } self.with_node_mut(selected_id, |node| node.toggle_stricken()); if let Some(parent_id) = self.parent(selected_id) { if let Some(child_pos) = self.with_node(parent_id, |p| { @@ -1088,14 +1099,21 @@ impl Screen { } // remove children self.delete_recursive(selected_id); - self.undo_stack.push(selected_id); + self.undo_stack.push(UndoNode::Delete(selected_id)); } } - fn undo_delete(&mut self) { - if let Some(node_id) = self.undo_stack.pop() { - self.recursive_restore(node_id).unwrap(); - self.select_node(node_id); + fn undo(&mut self) { + match self.undo_stack.pop() { + Some(UndoNode::Delete(node_id)) => { + self.recursive_restore(node_id).unwrap(); + self.select_node(node_id); + }, + Some(UndoNode::ToggleStricken(node_id)) => { + self.select_node(node_id); + self.toggle_stricken(false); + }, + None => {}, } } @@ -1498,6 +1516,28 @@ impl Screen { } } + fn select_first_sibling(&mut self) { + if let Some(Selection { selected_id, .. }) = self.selected { + if let Some(parent_id) = self.parent(selected_id) { + if let Some(parent) = self.nodes.get(&parent_id) { + let choose = *parent.children.first().unwrap(); + self.select_node(choose); + } + } + } + } + + fn select_last_sibling(&mut self) { + if let Some(Selection { selected_id, .. }) = self.selected { + if let Some(parent_id) = self.parent(selected_id) { + if let Some(parent) = self.nodes.get(&parent_id) { + let choose = *parent.children.last().unwrap(); + self.select_node(choose); + } + } + } + } + fn select_next_sibling(&mut self) { self.select_neighbor(SearchDirection::Forward); } From 1226d962aa1f9069ace491d4edc0d5e08031ea82 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Tue, 8 Feb 2022 13:28:27 +0200 Subject: [PATCH 40/41] Implement universal file locking --- Cargo.lock | 18 ++++++++++++++++++ Cargo.toml | 1 + src/bin/void/main.rs | 45 ++++++++++++++++++++++++++++++++++++++------ src/screen.rs | 12 ++++++------ src/tagdb.rs | 10 +--------- 5 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddbe428..9f22535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,6 +242,17 @@ dependencies = [ "libc", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "itoa" version = "0.4.6" @@ -269,6 +280,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "memchr" version = "2.3.4" @@ -714,6 +731,7 @@ dependencies = [ "dirs 3.0.1", "fs2", "getopts", + "hostname", "lazy_static", "libc", "log", diff --git a/Cargo.toml b/Cargo.toml index 5ddbdbb..9aea4bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ unicode-segmentation = "1.6.0" clippy = { version = "0.0.302", optional = true } fs2 = "0.4.3" chrono = "0.4" +hostname = "0.3.1" [dev-dependencies] quickcheck = "0.9.2" diff --git a/src/bin/void/main.rs b/src/bin/void/main.rs index c7a8b9b..9ba983b 100644 --- a/src/bin/void/main.rs +++ b/src/bin/void/main.rs @@ -1,9 +1,21 @@ -use fs2::FileExt; -use std::{ffi::OsString, fs::OpenOptions, io::Read}; +use std::{ + ffi::OsString, + fs::OpenOptions, + io::{Read, Write}, + path::PathBuf, +}; use voidmap::{deserialize_screen, init_screen_log, Config}; mod cli; +struct DeleteOnDrop(PathBuf); + +impl Drop for DeleteOnDrop { + fn drop(&mut self) { + std::fs::remove_file(&self.0).expect("failed to kill lockfile") + } +} + fn main() { // Initialise the CLI parser let app = cli::create(); @@ -25,6 +37,30 @@ fn main() { // load from file if present let mut data = vec![]; + let mut lock_path = PathBuf::new(); + lock_path.push(&path); + let mut file_name = lock_path + .file_name() + .expect("a filename for the db is needed") + .to_owned(); + file_name.push(".lock"); + lock_path.set_file_name(file_name); + + let mut lock_file = OpenOptions::new() + .write(true) + .create_new(true) + .open(&lock_path) + .expect("failed to lock db - is another process using it?"); + write!( + lock_file, + "{}::{}", + hostname::get().unwrap().to_string_lossy(), + std::process::id() + ) + .unwrap(); + lock_file.sync_all().unwrap(); + let guard = DeleteOnDrop(lock_path); + let mut f = OpenOptions::new() .write(true) .read(true) @@ -32,10 +68,6 @@ fn main() { .open(&path) .unwrap(); - // exclusively lock the file - f.try_lock_exclusive() - .unwrap_or_else(|_| panic!("Another `void` process is using this path already!")); - f.read_to_end(&mut data).unwrap(); let saved_screen = deserialize_screen(data).expect("invalid screen"); @@ -58,4 +90,5 @@ fn main() { screen.config = config; screen.run(); + drop(guard); } diff --git a/src/screen.rs b/src/screen.rs index 4c41582..f58634c 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -190,28 +190,28 @@ impl Screen { Some(new_id) } - pub fn with_node(&self, k: NodeID, mut f: F) -> Option + pub fn with_node(&self, k: NodeID, f: F) -> Option where F: FnMut(&Node) -> B, { - self.nodes.get(&k).map(|node| f(node)) + self.nodes.get(&k).map(f) } fn with_node_mut(&mut self, k: NodeID, mut f: F) -> Option where F: FnMut(&mut Node) -> B, { - self.nodes.get_mut(&k).map(|mut node| { + self.nodes.get_mut(&k).map(|node| { node.meta.bump_mtime(); - f(&mut node) + f(node) }) } - fn with_node_mut_no_meta(&mut self, k: NodeID, mut f: F) -> Option + fn with_node_mut_no_meta(&mut self, k: NodeID, f: F) -> Option where F: FnMut(&mut Node) -> B, { - self.nodes.get_mut(&k).map(|mut node| f(&mut node)) + self.nodes.get_mut(&k).map(f) } // return of false signals to the caller that we are done in this view diff --git a/src/tagdb.rs b/src/tagdb.rs index 31c5a84..c3795e4 100644 --- a/src/tagdb.rs +++ b/src/tagdb.rs @@ -4,20 +4,12 @@ use regex::Regex; use crate::{re_matches, NodeID}; +#[derive(Default)] pub struct TagDB { node_to_tags: HashMap>, tag_to_nodes: HashMap>, } -impl Default for TagDB { - fn default() -> TagDB { - TagDB { - node_to_tags: HashMap::new(), - tag_to_nodes: HashMap::new(), - } - } -} - impl TagDB { pub fn reindex(&mut self, node: NodeID, text: String) { lazy_static! { From f075f5e4236d5e0ac034c1e350e9e1109fa29671 Mon Sep 17 00:00:00 2001 From: Aleksi Hannula Date: Tue, 15 Feb 2022 15:59:11 +0200 Subject: [PATCH 41/41] Reroute all stdout writes through buffer to avoid flickering --- src/screen.rs | 147 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 45 deletions(-) diff --git a/src/screen.rs b/src/screen.rs index f58634c..ae53fa1 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,12 +1,13 @@ use std::{ self, borrow::Cow, + cell::{RefCell, RefMut}, cmp::{max, min, Ordering}, collections::{BTreeMap, BinaryHeap, HashMap, HashSet}, env, fmt::Write as FmtWrite, fs::{remove_file, rename, File, OpenOptions}, - io::{self, stdin, stdout, Error, ErrorKind, Read, Seek, SeekFrom, Stdout, Write}, + io::{self, stdin, stdout, BufWriter, Error, ErrorKind, Read, Seek, SeekFrom, Stdout, Write}, process, }; @@ -71,7 +72,7 @@ pub struct Screen { drawn_at: HashMap, dragging_from: Option, dragging_to: Option, - stdout: Option>>>, + stdout: Option>>>>>, lowest_drawn: u16, // where we start drawing from view_y: u16, @@ -144,11 +145,34 @@ impl Default for Screen { } } +macro_rules! write { + ($stdout:expr, $($arg:tt)*) => { + { + let out = ::std::format!($($arg)*); + ::std::write!($stdout, "{}", out) + } + }; +} + +macro_rules! writeln { + ($stdout:expr, $($arg:tt)*) => { + { + let out = ::std::format!($($arg)*); + ::std::writeln!($stdout, "{}", out) + } + }; +} + impl Screen { + fn assume_stdout(&self) -> RefMut<'_, impl Write> { + self.stdout.as_ref().unwrap().borrow_mut() + } + fn help(&mut self) { self.cleanup(); self.start_raw_mode(); - println!( + writeln!( + self.assume_stdout(), "{}{}{}", cursor::Goto(1, 1), clear::All, @@ -468,7 +492,8 @@ impl Screen { } let stdin: Box = Box::new(stdin()); - print!( + write!( + self.assume_stdout(), "{}{}{}{}", cursor::Goto(1, self.dims.1), style::Invert, @@ -478,7 +503,7 @@ impl Screen { self.flush(); let res = stdin.keys().next().unwrap(); debug!("read prompt: {:?}", res); - print!("{}", style::Reset); + write!(self.assume_stdout(), "{}", style::Reset); res } @@ -489,7 +514,8 @@ impl Screen { } let mut stdin: Box = Box::new(stdin()); - print!( + write!( + self.assume_stdout(), "{}{}{}{}{}", style::Invert, cursor::Goto(1, self.dims.1), @@ -501,7 +527,7 @@ impl Screen { let res = stdin.read_line(); self.start_raw_mode(); debug!("read prompt: {:?}", res); - print!("{}", style::Reset); + write!(self.assume_stdout(), "{}", style::Reset); res } @@ -600,13 +626,19 @@ impl Screen { chars.split("").skip(1).zip(nodes.into_iter()).collect(); // clear the prompt - print!("{}{}", cursor::Goto(1, self.dims.1), clear::AfterCursor); + write!( + self.assume_stdout(), + "{}{}", + cursor::Goto(1, self.dims.1), + clear::AfterCursor + ); // print the hilighted char at each choice for (&c, &node_id) in &mapping { let &coords = self.drawn_at(node_id).unwrap(); let (x, y) = self.internal_to_screen_xy(coords).unwrap(); - print!( + write!( + self.assume_stdout(), "{}{}{}{}", cursor::Goto(x, y), style::Invert, @@ -875,7 +907,7 @@ impl Screen { pub fn flush(&mut self) { trace!("flush()"); if let Some(mut s) = self.stdout.take() { - s.flush().unwrap(); + s.get_mut().flush().unwrap(); self.stdout = Some(s); } } @@ -1179,7 +1211,7 @@ impl Screen { } } trace!("leaving stdin.events() loop"); - print!("{}{}", cursor::Goto(1, 1), clear::All); + write!(self.assume_stdout(), "{}{}", cursor::Goto(1, 1), clear::All); } fn toggle_collapsed(&mut self) { @@ -1966,15 +1998,17 @@ impl Screen { pub fn cleanup(&mut self) { trace!("cleanup()"); - print!("{}", cursor::Show); - self.stdout.take().unwrap().flush().unwrap(); + write!(self.assume_stdout(), "{}", cursor::Show); + self.stdout.take().unwrap().get_mut().flush().unwrap(); } pub fn start_raw_mode(&mut self) { if self.stdout.is_none() { - self.stdout = Some(MouseTerminal::from( - AlternateScreen::from(stdout()).into_raw_mode().unwrap(), - )); + self.stdout = Some(RefCell::new(MouseTerminal::from( + AlternateScreen::from(BufWriter::with_capacity(8192 * 1024, stdout())) + .into_raw_mode() + .unwrap(), + ))); } } @@ -2050,10 +2084,10 @@ impl Screen { today.day() as i32 - today.weekday().num_days_from_monday() as i32, ) as u32) .unwrap(); - let mut line = 3; + let mut line = 2; let max_line = self.dims.1; 'make_month: loop { - if line > max_line { + if line >= max_line { break; } @@ -2094,9 +2128,9 @@ impl Screen { width = (CALENDAR_WIDTH - 1) as usize, ); - println!("{}", month_header); + writeln!(self.assume_stdout(), "{}", month_header); line += 1; - if line > max_line { + if line >= max_line { break; } @@ -2104,9 +2138,9 @@ impl Screen { "{}│ │ M T W T F S S", cursor::Goto(self.dims.0, line) ); - println!("{}", weekday_header); + writeln!(self.assume_stdout(), "{}", weekday_header); line += 1; - if line > max_line { + if line >= max_line { break; } @@ -2116,10 +2150,10 @@ impl Screen { date.iso_week().week(), cursor::Goto(self.dims.0, line + 1), ); - print!("{}", week_header); + write!(self.assume_stdout(), "{}", week_header); loop { - if line > max_line { + if line >= max_line { break 'make_month; } @@ -2135,7 +2169,7 @@ impl Screen { date.day(), style::Reset, ); - print!("{}", day_label); + write!(self.assume_stdout(), "{}", day_label); if line + 1 < max_line { let assigned = counts_by_day[date.day0() as usize]; @@ -2147,7 +2181,7 @@ impl Screen { assigned, style::Reset, ); - print!("{}", day_assigned_tasks_label); + write!(self.assume_stdout(), "{}", day_assigned_tasks_label); } else if assigned > 0 { let day_assigned_tasks_label = format!( "{}{}{:3}{}", @@ -2156,7 +2190,7 @@ impl Screen { "?!", style::Reset, ); - print!("{}", day_assigned_tasks_label); + write!(self.assume_stdout(), "{}", day_assigned_tasks_label); } } @@ -2169,7 +2203,7 @@ impl Screen { if date.weekday() == Weekday::Mon { line += 2; - if line > max_line { + if line >= max_line { break 'make_month; } @@ -2179,7 +2213,7 @@ impl Screen { date.iso_week().week(), cursor::Goto(self.dims.0, line + 1), ); - print!("{}", week_header); + write!(self.assume_stdout(), "{}", week_header); } } line += 2; @@ -2187,7 +2221,7 @@ impl Screen { break; } - println!("{}│", cursor::Goto(self.dims.0, line)); + writeln!(self.assume_stdout(), "{}│", cursor::Goto(self.dims.0, line)); line += 1; } } @@ -2211,7 +2245,7 @@ impl Screen { self.lookup.clear(); self.drawn_at.clear(); self.lowest_drawn = 0; - print!("{}", clear::All); + write!(self.assume_stdout(), "{}", clear::All); self.dims = terminal_size().unwrap(); @@ -2237,12 +2271,16 @@ impl Screen { for _ in 0..self.dims.0 - 4 { sep.push('█'); } - println!("{}", sep); + writeln!(self.assume_stdout(), "{}", sep); { let logs = logging::read_logs(); for msg in logs.iter().rev() { let line_width = min(msg.len(), self.dims.0 as usize); - println!("\r{}", msg[..line_width as usize].to_owned()); + writeln!( + self.assume_stdout(), + "\r{}", + msg[..line_width as usize].to_owned() + ); } } } @@ -2279,7 +2317,7 @@ impl Screen { self.draw_scrollbar(); } - print!("{}", cursor::Hide); + write!(self.assume_stdout(), "{}", cursor::Hide); self.flush(); // let after = time::get_time(); @@ -2287,7 +2325,7 @@ impl Screen { // debug!("draw time: {}", after - before); } - fn draw_scrollbar(&self) { + fn draw_scrollbar(&mut self) { let bar_height = max(self.dims.1, 1) - 1; let normalized_lowest = f64::from(max(self.lowest_drawn, 1)); let fraction_viewable = f64::from(self.dims.1) / normalized_lowest; @@ -2299,9 +2337,9 @@ impl Screen { for (i, y) in (2..bar_height + 2).enumerate() { if i >= shade_start && i < shade_end { - print!("{}┃", cursor::Goto(self.dims.0, y)); + write!(self.assume_stdout(), "{}┃", cursor::Goto(self.dims.0, y)); } else { - print!("{}│", cursor::Goto(self.dims.0, y)); + write!(self.assume_stdout(), "{}│", cursor::Goto(self.dims.0, y)); } } } @@ -2443,7 +2481,7 @@ impl Screen { buf.push('…'); } - print!("{}{}", buf, style::Reset); + write!(self.assume_stdout(), "{}{}", buf, style::Reset); } let visible_graphemes = self @@ -2508,10 +2546,14 @@ impl Screen { .filter_map(|&c| self.internal_to_screen_xy(c)) .collect(); trace!("draw_path({:?}, {:?}, {:?})", path, start_dir, dest_dir); - print!("{}", color); + write!(self.assume_stdout(), "{}", color); match path.len().cmp(&1) { Ordering::Equal => { - print!("{} ↺", cursor::Goto(path[0].0, path[0].1)) + write!( + self.assume_stdout(), + "{} ↺", + cursor::Goto(path[0].0, path[0].1) + ); }, Ordering::Greater => { let first = match path[1].1.cmp(&path[0].1) { @@ -2526,7 +2568,12 @@ impl Screen { Ordering::Equal => '─', }; - print!("{}{}", cursor::Goto(path[0].0, path[0].1), first); + write!( + self.assume_stdout(), + "{}{}", + cursor::Goto(path[0].0, path[0].1), + first + ); for items in path.windows(3) { let (p, this, n) = (items[0], items[1], items[2]); let c = if p.0 == n.0 { @@ -2543,18 +2590,28 @@ impl Screen { '└' // down+right or left+up }; - print!("{}{}", cursor::Goto(this.0, this.1), c) + write!( + self.assume_stdout(), + "{}{}", + cursor::Goto(this.0, this.1), + c + ); } let (end_x, end_y) = (path[path.len() - 1].0, path[path.len() - 1].1); let end_char = match dest_dir { Dir::L => '>', Dir::R => '<', }; - print!("{}{}", cursor::Goto(end_x, end_y), end_char); + write!( + self.assume_stdout(), + "{}{}", + cursor::Goto(end_x, end_y), + end_char + ); }, _ => {}, }; - print!("{}", color::Fg(color::Reset)); + write!(self.assume_stdout(), "{}", color::Fg(color::Reset)); } fn draw_header(&mut self) { @@ -2611,7 +2668,7 @@ impl Screen { for _ in 0..(max(self.dims.0 as usize, text_len) - text_len) { sep.push('█'); } - print!("{}", sep); + write!(self.assume_stdout(), "{}", sep); } }