commit 84ab7c29061f8b67bed5d18a518ea5117e06dfdd
parent 99d614d8b700c4860f410ab0726a033ea6f3d99e
Author: Eric Davis <edavis@insanum.com>
Date: Mon, 14 Jul 2014 22:14:17 -0700
new keybind command for viewing the previous/next version of a note
non-latest version note content views have their own color scheme
fixed some minor crashes dues to key errors
Diffstat:
M | config.py | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | notes_db.py | | | 4 | ++++ |
M | sncli.py | | | 55 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | utils.py | | | 13 | ++++++++----- |
M | view_note.py | | | 50 | ++++++++++++++++++++++++++++++++++---------------- |
5 files changed, 160 insertions(+), 68 deletions(-)
diff --git a/config.py b/config.py
@@ -46,6 +46,9 @@ def __init__(self):
'kb_tabstop2' : '2',
'kb_tabstop4' : '4',
'kb_tabstop8' : '8',
+ 'kb_prev_version' : '<',
+ 'kb_next_version' : '>',
+ 'kb_latest_version' : 'L',
'kb_search_gstyle' : '/',
'kb_search_regex' : 'meta /',
'kb_clear_search' : 'A',
@@ -56,46 +59,50 @@ def __init__(self):
'kb_note_markdown' : 'm',
'kb_note_tags' : 't',
- 'clr_default_fg' : 'default',
- 'clr_default_bg' : 'default',
- 'clr_status_bar_fg' : 'dark gray',
- 'clr_status_bar_bg' : 'light gray',
- 'clr_log_fg' : 'dark gray',
- 'clr_log_bg' : 'light gray',
- 'clr_search_bar_fg' : 'white',
- 'clr_search_bar_bg' : 'light red',
- 'clr_note_focus_fg' : 'white',
- 'clr_note_focus_bg' : 'light red',
- 'clr_note_title_day_fg' : 'light red',
- 'clr_note_title_day_bg' : 'default',
- 'clr_note_title_week_fg' : 'light green',
- 'clr_note_title_week_bg' : 'default',
- 'clr_note_title_month_fg' : 'brown',
- 'clr_note_title_month_bg' : 'default',
- 'clr_note_title_year_fg' : 'light blue',
- 'clr_note_title_year_bg' : 'default',
- 'clr_note_title_ancient_fg' : 'light blue',
- 'clr_note_title_ancient_bg' : 'default',
- 'clr_note_date_fg' : 'dark blue',
- 'clr_note_date_bg' : 'default',
- 'clr_note_flags_fg' : 'dark magenta',
- 'clr_note_flags_bg' : 'default',
- 'clr_note_tags_fg' : 'dark red',
- 'clr_note_tags_bg' : 'default',
- 'clr_note_content_fg' : 'default',
- 'clr_note_content_bg' : 'default',
- 'clr_note_content_focus_fg' : 'white',
- 'clr_note_content_focus_bg' : 'light red',
- 'clr_help_focus_fg' : 'white',
- 'clr_help_focus_bg' : 'light red',
- 'clr_help_header_fg' : 'dark blue',
- 'clr_help_header_bg' : 'default',
- 'clr_help_config_fg' : 'dark green',
- 'clr_help_config_bg' : 'default',
- 'clr_help_value_fg' : 'dark red',
- 'clr_help_value_bg' : 'default',
- 'clr_help_descr_fg' : 'default',
- 'clr_help_descr_bg' : 'default'
+ 'clr_default_fg' : 'default',
+ 'clr_default_bg' : 'default',
+ 'clr_status_bar_fg' : 'dark gray',
+ 'clr_status_bar_bg' : 'light gray',
+ 'clr_log_fg' : 'dark gray',
+ 'clr_log_bg' : 'light gray',
+ 'clr_search_bar_fg' : 'white',
+ 'clr_search_bar_bg' : 'light red',
+ 'clr_note_focus_fg' : 'white',
+ 'clr_note_focus_bg' : 'light red',
+ 'clr_note_title_day_fg' : 'light red',
+ 'clr_note_title_day_bg' : 'default',
+ 'clr_note_title_week_fg' : 'light green',
+ 'clr_note_title_week_bg' : 'default',
+ 'clr_note_title_month_fg' : 'brown',
+ 'clr_note_title_month_bg' : 'default',
+ 'clr_note_title_year_fg' : 'light blue',
+ 'clr_note_title_year_bg' : 'default',
+ 'clr_note_title_ancient_fg' : 'light blue',
+ 'clr_note_title_ancient_bg' : 'default',
+ 'clr_note_date_fg' : 'dark blue',
+ 'clr_note_date_bg' : 'default',
+ 'clr_note_flags_fg' : 'dark magenta',
+ 'clr_note_flags_bg' : 'default',
+ 'clr_note_tags_fg' : 'dark red',
+ 'clr_note_tags_bg' : 'default',
+ 'clr_note_content_fg' : 'default',
+ 'clr_note_content_bg' : 'default',
+ 'clr_note_content_focus_fg' : 'white',
+ 'clr_note_content_focus_bg' : 'light red',
+ 'clr_note_content_old_fg' : 'yellow',
+ 'clr_note_content_old_bg' : 'dark gray',
+ 'clr_note_content_old_focus_fg' : 'white',
+ 'clr_note_content_old_focus_bg' : 'light red',
+ 'clr_help_focus_fg' : 'white',
+ 'clr_help_focus_bg' : 'light red',
+ 'clr_help_header_fg' : 'dark blue',
+ 'clr_help_header_bg' : 'default',
+ 'clr_help_config_fg' : 'dark green',
+ 'clr_help_config_bg' : 'default',
+ 'clr_help_value_fg' : 'dark red',
+ 'clr_help_value_bg' : 'default',
+ 'clr_help_descr_fg' : 'default',
+ 'clr_help_descr_bg' : 'default'
}
cp = ConfigParser.SafeConfigParser(defaults)
@@ -134,7 +141,7 @@ def __init__(self):
self.keybinds['page_down'] = [ cp.get(cfg_sec, 'kb_page_down'), [ 'common' ], 'Page down' ]
self.keybinds['page_up'] = [ cp.get(cfg_sec, 'kb_page_up'), [ 'common' ], 'Page up' ]
self.keybinds['half_page_down'] = [ cp.get(cfg_sec, 'kb_half_page_down'), [ 'common' ], 'Half page down' ]
- self.keybinds['half_page_up'] = [ cp.get(cfg_sec, 'kb_half_page_up'), [ 'common' ], 'Half page up' ]
+ self.keybinds['half_page_up'] = [ cp.get(cfg_sec, 'kb_half_page_up'), [ 'common' ], 'Half page up' ]
self.keybinds['bottom'] = [ cp.get(cfg_sec, 'kb_bottom'), [ 'common' ], 'Goto bottom' ]
self.keybinds['top'] = [ cp.get(cfg_sec, 'kb_top'), [ 'common' ], 'Goto top' ]
self.keybinds['status'] = [ cp.get(cfg_sec, 'kb_status'), [ 'common' ], 'Toggle status bar' ]
@@ -144,11 +151,14 @@ def __init__(self):
self.keybinds['view_note'] = [ cp.get(cfg_sec, 'kb_view_note'), [ 'titles' ], 'View note' ]
self.keybinds['view_note_ext'] = [ cp.get(cfg_sec, 'kb_view_note_ext'), [ 'titles', 'notes' ], 'View note with pager' ]
self.keybinds['pipe_note'] = [ cp.get(cfg_sec, 'kb_pipe_note'), [ 'titles', 'notes' ], 'Pipe note contents' ]
- self.keybinds['view_next_note'] = [ cp.get(cfg_sec, 'kb_view_next_note'), [ 'notes' ], 'View next note' ]
- self.keybinds['view_prev_note'] = [ cp.get(cfg_sec, 'kb_view_prev_note'), [ 'notes' ], 'View previous note' ]
- self.keybinds['tabstop2'] = [ cp.get(cfg_sec, 'kb_tabstop2'), [ 'notes' ], 'View with tabstop=2' ]
- self.keybinds['tabstop4'] = [ cp.get(cfg_sec, 'kb_tabstop4'), [ 'notes' ], 'View with tabstop=4' ]
- self.keybinds['tabstop8'] = [ cp.get(cfg_sec, 'kb_tabstop8'), [ 'notes' ], 'View with tabstop=8' ]
+ self.keybinds['view_next_note'] = [ cp.get(cfg_sec, 'kb_view_next_note'), [ 'notes' ], 'View next note' ]
+ self.keybinds['view_prev_note'] = [ cp.get(cfg_sec, 'kb_view_prev_note'), [ 'notes' ], 'View previous note' ]
+ self.keybinds['tabstop2'] = [ cp.get(cfg_sec, 'kb_tabstop2'), [ 'notes' ], 'View with tabstop=2' ]
+ self.keybinds['tabstop4'] = [ cp.get(cfg_sec, 'kb_tabstop4'), [ 'notes' ], 'View with tabstop=4' ]
+ self.keybinds['tabstop8'] = [ cp.get(cfg_sec, 'kb_tabstop8'), [ 'notes' ], 'View with tabstop=8' ]
+ self.keybinds['prev_version'] = [ cp.get(cfg_sec, 'kb_prev_version'), [ 'notes' ], 'View previous version' ]
+ self.keybinds['next_version'] = [ cp.get(cfg_sec, 'kb_next_version'), [ 'notes' ], 'View next version' ]
+ self.keybinds['latest_version'] = [ cp.get(cfg_sec, 'kb_latest_version'), [ 'notes' ], 'View latest version' ]
self.keybinds['search_gstyle'] = [ cp.get(cfg_sec, 'kb_search_gstyle'), [ 'titles' ], 'Search using gstyle' ]
self.keybinds['search_regex'] = [ cp.get(cfg_sec, 'kb_search_regex'), [ 'titles' ], 'Search using regex' ]
self.keybinds['clear_search'] = [ cp.get(cfg_sec, 'kb_clear_search'), [ 'titles' ], 'Show all notes' ]
@@ -190,6 +200,10 @@ def __init__(self):
self.colors['note_content_bg'] = [ cp.get(cfg_sec, 'clr_note_content_bg'), 'Note content bg' ]
self.colors['note_content_focus_fg'] = [ cp.get(cfg_sec, 'clr_note_content_focus_fg'), 'Note content focus fg' ]
self.colors['note_content_focus_bg'] = [ cp.get(cfg_sec, 'clr_note_content_focus_bg'), 'Note content focus bg' ]
+ self.colors['note_content_old_fg'] = [ cp.get(cfg_sec, 'clr_note_content_old_fg'), 'Old note content fg' ]
+ self.colors['note_content_old_bg'] = [ cp.get(cfg_sec, 'clr_note_content_old_bg'), 'Old note content bg' ]
+ self.colors['note_content_old_focus_fg'] = [ cp.get(cfg_sec, 'clr_note_content_old_focus_fg'), 'Old note content focus fg' ]
+ self.colors['note_content_old_focus_bg'] = [ cp.get(cfg_sec, 'clr_note_content_old_focus_bg'), 'Old note content focus bg' ]
self.colors['help_focus_fg'] = [ cp.get(cfg_sec, 'clr_help_focus_fg'), 'Help focus fg' ]
self.colors['help_focus_bg'] = [ cp.get(cfg_sec, 'clr_help_focus_bg'), 'Help focus bg' ]
self.colors['help_header_fg'] = [ cp.get(cfg_sec, 'clr_help_header_fg'), 'Help header fg' ]
diff --git a/notes_db.py b/notes_db.py
@@ -565,6 +565,10 @@ def sync_notes(self, server_sync=True, full_sync=True):
return sync_errors
+ def get_note_version(self, key, version):
+ gret = self.simplenote.get_note(key, version)
+ return gret[0] if gret[1] == 0 else None
+
def get_note_status(self, key):
n = self.notes[key]
o = utils.KeyValueObject(saved=False, synced=False, modified=False)
diff --git a/sncli.py b/sncli.py
@@ -205,7 +205,7 @@ def gui_update_view(self):
self.view_titles.focus_note(cur_key)
if self.gui_body_get().__class__ == view_note.ViewNote:
- self.view_note.update_note(self.view_note.note['key'])
+ self.view_note.update_note(self.view_note.note)
self.gui_update_status_bar()
@@ -398,6 +398,53 @@ def gui_frame_keypress(self, size, key):
self.view_titles.note_list[self.view_titles.focus_position].note['key'])
self.gui_switch_frame_body(self.view_note)
+ elif key == self.config.get_keybind('latest_version'):
+ if self.gui_body_get().__class__ != view_note.ViewNote:
+ return key
+
+ self.view_note.old_note_version = None
+ self.view_note.old_note = None
+
+ lb.update_note()
+
+ elif key == self.config.get_keybind('prev_version') or \
+ key == self.config.get_keybind('next_version'):
+ if self.gui_body_get().__class__ != view_note.ViewNote:
+ return key
+
+ diff = -1 if key == self.config.get_keybind('prev_version') \
+ else 1
+ limit = 0 if key == self.config.get_keybind('prev_version') \
+ else self.view_note.note['version'] + 1
+
+ if not self.view_note.old_note_version:
+ next_note_version = self.view_note.note['version'] + diff
+ else:
+ next_note_version = self.view_note.old_note_version + diff
+
+ if next_note_version == limit:
+ self.log(u'Version v{0} is unavailable (key={1})'.
+ format(next_note_version, self.view_note.key))
+ return None
+
+ self.log(u'Fetching version v{0} of note (key={1})'.
+ format(next_note_version, self.view_note.key))
+ next_note = self.ndb.get_note_version(self.view_note.key, next_note_version)
+
+ if not next_note:
+ self.log(u'Failed to get version v{0} of note (key={1})'.
+ format(next_note_version, self.view_note.key))
+ return None
+
+ if next_note_version != self.view_note.note['version']:
+ self.view_note.old_note_version = next_note_version
+ self.view_note.old_note = next_note
+ else:
+ self.view_note.old_note_version = None
+ self.view_note.old_note = None
+
+ lb.update_note()
+
elif key == self.config.get_keybind('status'):
if self.status_bar == 'yes':
self.status_bar = 'no'
@@ -717,6 +764,12 @@ def gui(self, key):
('note_content_focus',
self.config.get_color('note_content_focus_fg'),
self.config.get_color('note_content_focus_bg') ),
+ ('note_content_old',
+ self.config.get_color('note_content_old_fg'),
+ self.config.get_color('note_content_old_bg') ),
+ ('note_content_old_focus',
+ self.config.get_color('note_content_old_focus_fg'),
+ self.config.get_color('note_content_old_focus_bg') ),
('help_focus',
self.config.get_color('help_focus_fg'),
self.config.get_color('help_focus_bg') ),
diff --git a/utils.py b/utils.py
@@ -15,15 +15,18 @@ def generate_random_key():
return '%030x' % (random.randrange(256**15),)
def get_note_tags(note):
- tags = '%s' % ','.join(note['tags'])
- if note['deleted']:
- if tags: tags += u',trash'
- else: tags = u'trash'
+ if 'tags' in note:
+ tags = '%s' % ','.join(note['tags'])
+ if 'deleted' in note and note['deleted']:
+ if tags: tags += u',trash'
+ else: tags = u'trash'
+ else:
+ tags = u''
return tags
def get_note_flags(note):
flags = ''
- flags += u'T' if note['deleted'] else u' '
+ flags += u'T' if 'deleted' in note and note['deleted'] else u' '
if 'systemtags' in note:
flags += u'*' if 'pinned' in note['systemtags'] else u' '
flags += u'S' if 'published' in note['systemtags'] else u' '
diff --git a/view_note.py b/view_note.py
@@ -8,6 +8,9 @@ def __init__(self, config, args):
self.config = config
self.ndb = args['ndb']
self.key = args['key']
+ self.log = args['log']
+ self.old_note_version = None
+ self.old_note = None
self.note = self.ndb.get_note(self.key) if self.key else None
self.tabstop = int(self.config.get_config('tabstop'))
super(ViewNote, self).__init__(
@@ -17,17 +20,25 @@ def get_note_content_as_list(self):
lines = []
if not self.key:
return lines
- for l in self.note['content'].split('\n'):
- lines.append(
- urwid.AttrMap(urwid.Text(l.replace('\t', ' ' * self.tabstop)),
- 'note_content',
- 'note_content_focus'))
+ if self.old_note:
+ for l in self.old_note['content'].split('\n'):
+ lines.append(
+ urwid.AttrMap(urwid.Text(l.replace('\t', ' ' * self.tabstop)),
+ 'note_content_old',
+ 'note_content_old_focus'))
+ else:
+ for l in self.note['content'].split('\n'):
+ lines.append(
+ urwid.AttrMap(urwid.Text(l.replace('\t', ' ' * self.tabstop)),
+ 'note_content',
+ 'note_content_focus'))
lines.append(urwid.AttrMap(urwid.Divider(u'-'), 'default'))
return lines
- def update_note(self, key):
- self.key = key
- self.note = self.ndb.get_note(self.key) if self.key else None
+ def update_note(self, key=None):
+ if key:
+ self.key = key
+ self.note = self.ndb.get_note(self.key) if self.key else None
self.body[:] = \
urwid.SimpleFocusListWalker(self.get_note_content_as_list())
self.focus_position = 0
@@ -44,11 +55,18 @@ def get_status_bar(self):
cur = self.focus_position
total = len(self.body.positions())
- t = time.localtime(float(self.note['modifydate']))
+ if self.old_note:
+ tnote = self.old_note
+ t = time.localtime(float(tnote['versiondate']))
+ else:
+ tnote = self.note
+ t = time.localtime(float(tnote['modifydate']))
+
mod_time = time.strftime(u'Date: %a, %d %b %Y %H:%M:%S', t)
- title = utils.get_note_title(self.note)
- flags = utils.get_note_flags(self.note)
- tags = utils.get_note_tags(self.note)
+ title = utils.get_note_title(tnote)
+ flags = utils.get_note_flags(tnote)
+ tags = utils.get_note_tags(tnote)
+ version = tnote['version']
status_title = \
urwid.AttrMap(urwid.Text(u'Title: ' +
@@ -57,7 +75,7 @@ def get_status_bar(self):
'status_bar')
status_key_index = \
('pack', urwid.AttrMap(urwid.Text(u' [' +
- self.note['key'] +
+ self.key +
u'] ' +
str(cur + 1) +
u'/' +
@@ -71,7 +89,7 @@ def get_status_bar(self):
('pack', urwid.AttrMap(urwid.Text(u'[' +
tags +
u'] [v' +
- str(self.note['version']) +
+ str(version) +
u'] [' +
flags +
u']'),
@@ -79,10 +97,10 @@ def get_status_bar(self):
pile_top = urwid.Columns([ status_title, status_key_index ])
pile_bottom = urwid.Columns([ status_date, status_tags_flags ])
- if utils.note_published(self.note) and 'publishkey' in self.note:
+ if utils.note_published(tnote) and 'publishkey' in tnote:
pile_publish = \
urwid.AttrMap(urwid.Text(u'Published: http://simp.ly/publish/' +
- self.note['publishkey']),
+ tnote['publishkey']),
'status_bar')
return \
urwid.AttrMap(urwid.Pile([ pile_top, pile_bottom, pile_publish ]),