nncli

NextCloud Notes Command Line Interface
git clone git://git.danielmoch.com/nncli.git
Log | Files | Refs | LICENSE

commit f55b72f55fcc5dd1d4ada25f2b246c33c0a1887a
parent 5af3cd7bd53c2c0940f5bef7534960a634a1a2f8
Author: Daniel Moch <daniel@danielmoch.com>
Date:   Sat, 28 Jul 2018 20:49:26 -0400

Delete note working

Diffstat:
MREADME.md | 70++++++++++++++++++++++++++++++----------------------------------------
Mnnotes_cli/config.py | 44++++++++++++++++----------------------------
Mnnotes_cli/nextcloud_note.py | 22+++++++++++-----------
Mnnotes_cli/nncli.py | 261++++++++++++++++++-------------------------------------------------------------
Mnnotes_cli/notes_db.py | 190+++++++++++++++++++++++++++++++++----------------------------------------------
Mnnotes_cli/utils.py | 86++++++++++++++++++++-----------------------------------------------------------
Mnnotes_cli/view_note.py | 74+++++++++++++-------------------------------------------------------------
Mnnotes_cli/view_titles.py | 10+++++-----
Mtodo.txt | 4++--
9 files changed, 239 insertions(+), 522 deletions(-)

diff --git a/README.md b/README.md @@ -42,18 +42,17 @@ Check your OS distribution for installation packages. - full two-way sync with NextCloud Notes performed dynamically in the background - all actions logged and easily reviewed - - list note titles (configurable format w/ title, date, flags, tags, + - list note titles (configurable format w/ title, date, flags, category, keys, etc) - - sort notes by date, alpha by title, tags, pinned on top + - sort notes by date, alpha by title, category, favorite on top - search for notes using a Google style search pattern or Regular Expression - view note contents and meta data - - view and restore previous versions of notes - pipe note contents to external command - create and edit notes (using your editor) - - edit note tags - - trash/untrash notes - - pin/unpin notes + - edit note category + - delete notes + - favorite/unfavorite notes - vi-like keybinds (fully configurable) - Colors! (fully configurable) * Command Line (scripting) @@ -66,9 +65,9 @@ Check your OS distribution for installation packages. - create a new note (via stdin or editor) - import a note with raw json data (stdin or editor) - edit a note (via editor) - - trash/untrash a note - - pin/unpin a note - - view and edit note tags + - delete a note + - favorite/unfavorite a note + - view and edit note category ### HowTo @@ -91,12 +90,11 @@ Check your OS distribution for installation packages. note in JSON format ('-' JSON from stdin) export - export a note in JSON format (specified by <key>) dump - dump a note (specified by <key>) edit - edit a - note (specified by <key>) < trash | untrash > - trash/untrash - a note (specified by <key>) < pin | unpin > - pin/unpin a - - retrieve the tags from a note (specified by <key>) tag set <tags> - - set the tags for a note (specified by <key>) tag add <tags> - - add tags to a note (specified by <key>) tag rm <tags> - - remove tags from a note (specified by <key>) ``` + note (specified by <key>) delete - delete + a note (specified by <key>) < favorite | unfavorite > - favorite/unfavorite a + - retrieve the category from a note (specified by <key>) cat set <category> + - set the category for a note (specified by <key>) + cat rm - remove category from a note (specified by <key>) ``` #### Configuration @@ -157,11 +155,11 @@ supported for dynamically building the title string. Each of these formatting tags supports a width specifier (decimal) and a left justification (-) like that supported by printf: -``` %F - flags (fixed 5 char width) X - needs sync T - trashed - * - pinned S - published/shared m - tags %D - date +``` %F - flags (fixed 5 char width) X - needs sync + * - favorited m - tags %D - date %N - title ``` -The default note title format pushes the note tags to the far right of +The default note title format pushes the note category to the far right of the terminal and left justifies the note title after the date and flags: ``` cfg_format_note_title = '[%D] %F %-N %T' ``` @@ -188,7 +186,7 @@ A Google style search string is a group of tokens (separated by spaces) with an implied *AND* between each token. This style search is case insensitive. For example: -``` /tag:tag1 tag:tag2 word1 "word2 word3" tag:tag3 ``` +``` /category:category1 category:category2 word1 "word2 word3" category:category3 ``` Regular expression searching also supports the use of flags (currently only case-insensitive) by adding a final forward slash followed by the @@ -209,11 +207,9 @@ flags. The following example will do a case-insensitive search for nncli can import notes from raw json data (via stdin or editor). For example: -``` echo '{"tags":["testing","new"],"content":"New note!"}' | nncli -import - ``` +``` echo '{"category":"testing","content":"New note!"}' | nncli import - ``` -Allowed fields are `content`, `tags`, `systemtags`, `modified`, -`createdate`, and `deleted`. +Allowed fields are `content`, `category`, `favorite`, and `modified` ### Exporting @@ -230,27 +226,21 @@ Note that nncli still stores all the notes data in the directory specified by `cfg_db_path`, so for easy backups, it may be easier/quicker to simply backup this entire directory. -### Tags +### Category -Note tags can be modified directly from the command line. Example: +Note category can be modified directly from the command line. Example: -``` # Retrieve note tags, as one comma-separated string (e.g. -"tag1,tag2") nncli -k somekeyid tag get # Returns -"tag1,tag2" +``` # Retrieve note category (e.g. "category1") +nncli -k somekeyid cat get +# Returns "category1" -# Add a tag to a note, if it doesn't already have it nncli -k somekeyid -tag add "tag3" # Now tagged as "tag1,tag2,tag3" - -# Remove a tag from a note nncli -k somekeyid tag rm "tag2" # -Now tagged as "tag1,tag3" - -# Overwrite all of the tags for a note nncli -k somekeyid tag set -"tag2,tag4" # Now tagged as "tag2,tag4" ``` - -Note that in SimpleNote, tags are case-insensitive, so "TAG2", "tag2", -and "tAg2" are interpreted as the same and will all be converted to -lowercase. +# Add a category to a note, overwriting any existing one +nncli -k somekeyid cat set "category3" +# Now tagged as "category3" +# Remove a category from a note +nncli -k somekeyid cat rm +# Note now has no category ### Tricks diff --git a/nnotes_cli/config.py b/nnotes_cli/config.py @@ -56,9 +56,9 @@ def __init__(self, custom_file=None): 'cfg_nn_username' : '', 'cfg_nn_password' : '', 'cfg_db_path' : self.cache_home, - 'cfg_search_tags' : 'yes', # with regex searches + 'cfg_search_categories' : 'yes', # with regex searches 'cfg_sort_mode' : 'date', # 'alpha' or 'date' - 'cfg_pinned_ontop' : 'yes', + 'cfg_favorite_ontop' : 'yes', 'cfg_tabstop' : '4', 'cfg_format_strftime' : '%Y/%m/%d', 'cfg_format_note_title' : '[%D] %F %-N %T', @@ -96,12 +96,6 @@ def __init__(self, custom_file=None): 'kb_tabstop2' : '2', 'kb_tabstop4' : '4', 'kb_tabstop8' : '8', - 'kb_prev_version' : '<', - 'kb_next_version' : '>', - 'kb_diff_version' : 'D', - 'kb_restore_version' : 'R', - 'kb_latest_version' : 'L', - 'kb_select_version' : '#', 'kb_search_gstyle' : '/', 'kb_search_regex' : 'meta /', 'kb_search_prev_gstyle' : '?', @@ -111,10 +105,10 @@ def __init__(self, custom_file=None): 'kb_clear_search' : 'A', 'kb_sort_date' : 'd', 'kb_sort_alpha' : 'a', - 'kb_sort_tags' : 'ctrl t', - 'kb_note_trash' : 'T', - 'kb_note_pin' : 'p', - 'kb_note_tags' : 't', + 'kb_sort_categories' : 'ctrl t', + 'kb_note_delete' : 'D', + 'kb_note_favorite' : 'p', + 'kb_note_category' : 't', 'kb_copy_note_text' : 'y', 'clr_default_fg' : 'default', @@ -141,8 +135,8 @@ def __init__(self, custom_file=None): '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_category_fg' : 'dark red', + 'clr_note_category_bg' : 'default', 'clr_note_content_fg' : 'default', 'clr_note_content_bg' : 'default', 'clr_note_content_focus_fg' : 'white', @@ -196,9 +190,9 @@ def __init__(self, custom_file=None): self.configs['nn_password'] = [ nn_password, 'NextCloud Password' ] self.configs['nn_host'] = [ cp.get(cfg_sec, 'cfg_nn_host', raw=True), 'NextCloud server hostname' ] self.configs['db_path'] = [ cp.get(cfg_sec, 'cfg_db_path'), 'Note storage path' ] - self.configs['search_tags'] = [ cp.get(cfg_sec, 'cfg_search_tags'), 'Search tags as well' ] + self.configs['search_categories'] = [ cp.get(cfg_sec, 'cfg_search_categories'), 'Search categories as well' ] self.configs['sort_mode'] = [ cp.get(cfg_sec, 'cfg_sort_mode'), 'Sort mode' ] - self.configs['pinned_ontop'] = [ cp.get(cfg_sec, 'cfg_pinned_ontop'), 'Pinned at top of list' ] + self.configs['favorite_ontop'] = [ cp.get(cfg_sec, 'cfg_favorite_ontop'), 'Favorite at top of list' ] self.configs['tabstop'] = [ cp.get(cfg_sec, 'cfg_tabstop'), 'Tabstop spaces' ] self.configs['format_strftime'] = [ cp.get(cfg_sec, 'cfg_format_strftime', raw=True), 'Date strftime format' ] self.configs['format_note_title'] = [ cp.get(cfg_sec, 'cfg_format_note_title', raw=True), 'Note title format' ] @@ -236,12 +230,6 @@ def __init__(self, custom_file=None): 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['diff_version'] = [ cp.get(cfg_sec, 'kb_diff_version'), [ 'notes' ], 'Diff version of note' ] - self.keybinds['restore_version'] = [ cp.get(cfg_sec, 'kb_restore_version'), [ 'notes' ], 'Restore version of note' ] - self.keybinds['latest_version'] = [ cp.get(cfg_sec, 'kb_latest_version'), [ 'notes' ], 'View latest version' ] - self.keybinds['select_version'] = [ cp.get(cfg_sec, 'kb_select_version'), [ 'notes' ], 'Select version' ] self.keybinds['search_gstyle'] = [ cp.get(cfg_sec, 'kb_search_gstyle'), [ 'titles', 'notes' ], 'Search using gstyle' ] self.keybinds['search_prev_gstyle'] = [ cp.get(cfg_sec, 'kb_search_prev_gstyle'), [ 'notes' ], 'Search backwards using gstyle' ] self.keybinds['search_regex'] = [ cp.get(cfg_sec, 'kb_search_regex'), [ 'titles', 'notes' ], 'Search using regex' ] @@ -251,10 +239,10 @@ def __init__(self, custom_file=None): self.keybinds['clear_search'] = [ cp.get(cfg_sec, 'kb_clear_search'), [ 'titles' ], 'Show all notes' ] self.keybinds['sort_date'] = [ cp.get(cfg_sec, 'kb_sort_date'), [ 'titles' ], 'Sort notes by date' ] self.keybinds['sort_alpha'] = [ cp.get(cfg_sec, 'kb_sort_alpha'), [ 'titles' ], 'Sort notes by alpha' ] - self.keybinds['sort_tags'] = [ cp.get(cfg_sec, 'kb_sort_tags'), [ 'titles' ], 'Sort notes by tags' ] - self.keybinds['note_trash'] = [ cp.get(cfg_sec, 'kb_note_trash'), [ 'titles', 'notes' ], 'Trash a note' ] - self.keybinds['note_pin'] = [ cp.get(cfg_sec, 'kb_note_pin'), [ 'titles', 'notes' ], 'Pin note' ] - self.keybinds['note_tags'] = [ cp.get(cfg_sec, 'kb_note_tags'), [ 'titles', 'notes' ], 'Edit note tags' ] + self.keybinds['sort_categories'] = [ cp.get(cfg_sec, 'kb_sort_categories'), [ 'titles' ], 'Sort notes by categories' ] + self.keybinds['note_delete'] = [ cp.get(cfg_sec,'kb_note_delete'), [ 'titles', 'notes' ], 'Delete a note' ] + self.keybinds['note_favorite'] = [ cp.get(cfg_sec, 'kb_note_favorite'), [ 'titles', 'notes' ], 'Favorite note' ] + self.keybinds['note_category'] = [ cp.get(cfg_sec, 'kb_note_category'), [ 'titles', 'notes' ], 'Edit note category' ] self.keybinds['copy_note_text'] = [ cp.get(cfg_sec, 'kb_copy_note_text'), [ 'notes' ], 'Copy line (xsel/pbcopy)' ] self.colors = collections.OrderedDict() @@ -282,8 +270,8 @@ def __init__(self, custom_file=None): self.colors['note_date_bg'] = [ cp.get(cfg_sec, 'clr_note_date_bg'), 'Note date bg' ] self.colors['note_flags_fg'] = [ cp.get(cfg_sec, 'clr_note_flags_fg'), 'Note flags fg' ] self.colors['note_flags_bg'] = [ cp.get(cfg_sec, 'clr_note_flags_bg'), 'Note flags bg' ] - self.colors['note_tags_fg'] = [ cp.get(cfg_sec, 'clr_note_tags_fg'), 'Note tags fg' ] - self.colors['note_tags_bg'] = [ cp.get(cfg_sec, 'clr_note_tags_bg'), 'Note tags bg' ] + self.colors['note_category_fg'] = [ cp.get(cfg_sec, 'clr_note_category_fg'), 'Note category fg' ] + self.colors['note_category_bg'] = [ cp.get(cfg_sec, 'clr_note_category_bg'), 'Note category bg' ] self.colors['note_content_fg'] = [ cp.get(cfg_sec, 'clr_note_content_fg'), 'Note content fg' ] 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' ] diff --git a/nnotes_cli/nextcloud_note.py b/nnotes_cli/nextcloud_note.py @@ -107,9 +107,9 @@ def get_note(self, noteid): # # use UTF-8 encoding # note["content"] = note["content"].encode('utf-8') - # # For early versions of notes, tags not always available - # if "tags" in note: - # note["tags"] = [t.encode('utf-8') for t in note["tags"]] + # # For early versions of notes, category is not always available + # if "category" in note: + # note["category"] = [t.encode('utf-8') for t in note["category"]] #logging.debug('RESPONSE OK: ' + str(note)) return note, 0 @@ -194,12 +194,12 @@ def get_note_list(self, category=None): The function can be passed optional arguments to limit the date range of the list returned and/or limit the list to notes - containing a certain tag. If omitted a list of all notes + containing a certain category. If omitted a list of all notes is returned. Arguments: - - category=None list of tags as string: return notes that have - at least one of these tags + - category=None category as string: return notes tagged to + this category Returns: A tuple `(notes, status)` @@ -244,11 +244,11 @@ def get_note_list(self, category=None): return note_list, status - def delete_note(self, note_id): + def delete_note(self, note): """ method to permanently delete a note Arguments: - - note_id (string): key of the note to trash + - note_id (string): key of the note to delete Returns: A tuple `(note, status)` @@ -257,11 +257,11 @@ def delete_note(self, note_id): - status (int): 0 on sucesss and -1 otherwise """ - # notes have to be trashed before deletion - url = '{}/{}'.format(self.api_url, str(note_id)) + url = '{}/{}'.format(self.api_url, str(note['id'])) + logurl = '{}/{}'.format(self.sanitized_url, str(note['id'])) try: - #logging.debug('REQUEST DELETE: ' + self.DATA_URL+params) + logging.debug('REQUEST DELETE: ' + logurl) res = requests.delete(url) res.raise_for_status() self.status = 'online' diff --git a/nnotes_cli/nncli.py b/nnotes_cli/nncli.py @@ -342,13 +342,11 @@ def gui_switch_frame_body(self, new_view, save_current_view=True): self.last_view.append(self.gui_body_get()) self.gui_body_set(new_view) - def trash_note_callback(self, key, yes): - if not yes: + def delete_note_callback(self, key, delete): + if not delete: return - - # toggle the deleted flag note = self.ndb.get_note(key) - self.ndb.set_note_deleted(key, 0 if note['deleted'] else 1) + self.ndb.set_note_deleted(key, True) if self.gui_body_get().__class__ == view_titles.ViewTitles: self.view_titles.update_note_title() @@ -356,19 +354,6 @@ def trash_note_callback(self, key, yes): self.gui_update_status_bar() self.ndb.sync_worker_go() - def restore_note_callback(self, key, yes): - if not yes: - return - - # restore the contents of the old_note - self.log('Restoring version v{0} (key={1})'. - format(self.view_note.old_note['version'], key)) - self.ndb.set_note_content(key, self.view_note.old_note['content']) - - self.view_note.update_note_view() - self.gui_update_status_bar() - self.ndb.sync_worker_go() - def gui_yes_no_input(self, args, yes_no): self.gui_footer_input_clear() self.gui_body_focus() @@ -389,31 +374,17 @@ def gui_search_input(self, args, search_string): self.view_titles.update_note_list(search_string, args[0], sort_mode=self.current_sort_mode) self.gui_body_set(self.view_titles) - def gui_version_input(self, args, version): + def gui_category_input(self, args, category): self.gui_footer_input_clear() self.gui_body_focus() self.master_frame.keypress = self.gui_frame_keypress - if version: - try: - # verify input is a number - int(version) - except ValueError as e: - self.log('ERROR: Invalid version value') - return - self.view_note.update_note_view(version=version) - self.gui_update_status_bar() - - def gui_tags_input(self, args, tags): - self.gui_footer_input_clear() - self.gui_body_focus() - self.master_frame.keypress = self.gui_frame_keypress - if tags != None: + if category != None: if self.gui_body_get().__class__ == view_titles.ViewTitles: note = self.view_titles.note_list[self.view_titles.focus_position].note else: # self.gui_body_get().__class__ == view_note.ViewNote: note = self.view_note.note - self.ndb.set_note_tags(note['localkey'], tags) + self.ndb.set_note_category(note['localkey'], category) if self.gui_body_get().__class__ == view_titles.ViewTitles: self.view_titles.update_note_title() @@ -574,76 +545,6 @@ def gui_frame_keypress(self, size, key): self.view_titles.note_list[self.view_titles.focus_position].note['localkey']) self.gui_switch_frame_body(self.view_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 - - version = diff + (self.view_note.old_note['version'] - if self.view_note.old_note else - self.view_note.note['version']) - - lb.update_note_view(version=version) - - elif key == self.config.get_keybind('diff_version'): - if self.gui_body_get().__class__ != view_note.ViewNote: - return key - - if not self.view_note.old_note: - self.log('Already at latest version (key={0})'. - format(self.view_note.key)) - return None - - self.gui_clear() - self.exec_diff_on_note(self.view_note.note, - self.view_note.old_note) - self.gui_reset() - - elif key == self.config.get_keybind('restore_version'): - if self.gui_body_get().__class__ != view_note.ViewNote: - return key - - if not self.view_note.old_note: - self.log('Already at latest version (key={0})'. - format(self.view_note.key)) - return None - - self.gui_footer_input_set( - urwid.AttrMap( - user_input.UserInput( - self.config, - 'Restore v{0} (y/n): '.format(self.view_note.old_note['version']), - '', - self.gui_yes_no_input, - [ self.restore_note_callback, self.view_note.key ]), - 'user_input_bar')) - self.gui_footer_focus_input() - self.master_frame.keypress = self.gui_footer_input_get().keypress - - elif key == self.config.get_keybind('latest_version'): - if self.gui_body_get().__class__ != view_note.ViewNote: - return key - - lb.update_note_view(version=None) - - elif key == self.config.get_keybind('select_version'): - if self.gui_body_get().__class__ != view_note.ViewNote: - return key - - self.gui_footer_input_set( - urwid.AttrMap( - user_input.UserInput( - self.config, - key, - '', - self.gui_version_input, - None), - 'user_input_bar')) - self.gui_footer_focus_input() - self.master_frame.keypress = self.gui_footer_input_get().keypress - elif key == self.config.get_keybind('status'): if self.status_bar == 'yes': self.status_bar = 'no' @@ -742,7 +643,8 @@ def gui_frame_keypress(self, size, key): self.gui_footer_focus_input() self.master_frame.keypress = self.gui_footer_input_get().keypress - elif key == self.config.get_keybind('note_trash'): + elif key == self.config.get_keybind('note_delete'): + logging.debug('Delete key pressed') if self.gui_body_get().__class__ != view_titles.ViewTitles and \ self.gui_body_get().__class__ != view_note.ViewNote: return key @@ -758,15 +660,15 @@ def gui_frame_keypress(self, size, key): urwid.AttrMap( user_input.UserInput( self.config, - '{0} (y/n): '.format('Untrash' if note['deleted'] else 'Trash'), + 'Delete (y/n): ', '', self.gui_yes_no_input, - [ self.trash_note_callback, note['localkey'] ]), + [ self.delete_note_callback, note['localkey'] ]), 'user_input_bar')) self.gui_footer_focus_input() self.master_frame.keypress = self.gui_footer_input_get().keypress - elif key == self.config.get_keybind('note_pin'): + elif key == self.config.get_keybind('note_favorite'): if self.gui_body_get().__class__ != view_titles.ViewTitles and \ self.gui_body_get().__class__ != view_note.ViewNote: return key @@ -778,19 +680,18 @@ def gui_frame_keypress(self, size, key): else: # self.gui_body_get().__class__ == view_note.ViewNote: note = lb.note - pin = 1 - if 'systemtags' in note: - if 'pinned' in note['systemtags']: pin = 0 - else: pin = 1 + favorite = 1 + if 'favorite' in note: favorite = 0 + else: favorite = 1 - self.ndb.set_note_pinned(note['localkey'], pin) + self.ndb.set_note_favorite(note['localkey'], favorite) if self.gui_body_get().__class__ == view_titles.ViewTitles: lb.update_note_title() self.ndb.sync_worker_go() - elif key == self.config.get_keybind('note_tags'): + elif key == self.config.get_keybind('note_category'): if self.gui_body_get().__class__ != view_titles.ViewTitles and \ self.gui_body_get().__class__ != view_note.ViewNote: return key @@ -806,9 +707,9 @@ def gui_frame_keypress(self, size, key): urwid.AttrMap( user_input.UserInput( self.config, - 'Tags: ', - '%s' % ','.join(note['tags']), - self.gui_tags_input, + 'Category: ', + '%s' % ','.join(note['category']), + self.gui_category_input, None), 'user_input_bar')) self.gui_footer_focus_input() @@ -885,12 +786,12 @@ def gui_frame_keypress(self, size, key): self.current_sort_mode = 'alpha' self.view_titles.sort_note_list('alpha') - elif key == self.config.get_keybind('sort_tags'): + elif key == self.config.get_keybind('sort_categories'): if self.gui_body_get().__class__ != view_titles.ViewTitles: return key - self.current_sort_mode = 'tags' - self.view_titles.sort_note_list('tags') + self.current_sort_mode = 'categories' + self.view_titles.sort_note_list('categories') elif key == self.config.get_keybind('copy_note_text'): if self.gui_body_get().__class__ != view_note.ViewNote: @@ -1005,9 +906,9 @@ def gui(self, key): ('note_flags', self.config.get_color('note_flags_fg'), self.config.get_color('note_flags_bg') ), - ('note_tags', - self.config.get_color('note_tags_fg'), - self.config.get_color('note_tags_bg') ), + ('note_category', + self.config.get_color('note_category_fg'), + self.config.get_color('note_category_bg') ), ('note_content', self.config.get_color('note_content_fg'), self.config.get_color('note_content_bg') ), @@ -1078,19 +979,14 @@ def cli_note_dump(self, key): mod_time = time.strftime('%a, %d %b %Y %H:%M:%S', t) title = utils.get_note_title(note) flags = utils.get_note_flags(note) - tags = utils.get_note_tags(note) + category = utils.get_note_category(note) print(sep) print(('| {:<' + str(w) + '} |').format((' Title: ' + title)[:w])) print(('| {:<' + str(w) + '} |').format((' Key: ' + note.get('id', 'Localkey: {}'.format(note.get('localkey'))))[:w])) print(('| {:<' + str(w) + '} |').format((' Date: ' + mod_time)[:w])) - print(('| {:<' + str(w) + '} |').format((' Tags: ' + tags)[:w])) - print(('| {:<' + str(w) + '} |').format((' Version: v' + str(note.get('version', 0)))[:w])) + print(('| {:<' + str(w) + '} |').format((' Category: ' + category)[:w])) print(('| {:<' + str(w) + '} |').format((' Flags: [' + flags + ']')[:w])) - if utils.note_published(note) and 'publishkey' in note: - print(('| {:<' + str(w) + '} |').format(('Published: http://simp.ly/publish/' + note['publishkey'])[:w])) - else: - print(('| {:<' + str(w) + '} |').format(('Published: n/a')[:w])) print(sep) print((note['content'])) @@ -1180,85 +1076,56 @@ def cli_note_edit(self, key): else: self.log('Note unchanged') - def cli_note_trash(self, key, trash): + def cli_note_delete(self, key, delete): note = self.ndb.get_note(key) if not note: self.log('ERROR: Key does not exist') return - self.ndb.set_note_deleted(key, trash) + self.ndb.set_note_deleted(key, delete) self.sync_notes() - def cli_note_pin(self, key, pin): + def cli_note_favorite(self, key, favorite): note = self.ndb.get_note(key) if not note: self.log('ERROR: Key does not exist') return - self.ndb.set_note_pinned(key, pin) + self.ndb.set_note_favorite(key, favorite) self.sync_notes() - def cli_note_tags_get(self, key): + def cli_note_category_get(self, key): note = self.ndb.get_note(key) if not note: self.log('ERROR: Key does not exist') return - tags = utils.get_note_tags(note) - return tags + category = utils.get_note_category(note) + return category - def cli_note_tags_set(self, key, tags): + def cli_note_category_set(self, key, category): note = self.ndb.get_note(key) if not note: self.log('Error: Key does not exist') return - self.ndb.set_note_tags(key, tags.lower()) + self.ndb.set_note_category(key, category.lower()) self.sync_notes() - def cli_note_tags_add(self, key, new_tags): - - note = self.ndb.get_note(key) - if not note: - self.log('Error: Key does not exist') - return - - # Add tag only if it isn't already there - old_tags = self.cli_note_tags_get(key) - if old_tags: - old_tag_list = old_tags.lower().split(',') - new_tag_list = new_tags.lower().split(',') - tag_list = old_tag_list - for tag in new_tag_list: - if tag not in tag_list: - tag_list.append(tag) - tags = ','.join(tag_list) - else: - tags = new_tags - - self.cli_note_tags_set(key, tags) - - def cli_note_tags_rm(self, key, rm_tags): + def cli_note_category_rm(self, key): note = self.ndb.get_note(key) if not note: self.log('Error: Key does not exist') return - old_tags = self.cli_note_tags_get(key) - if old_tags: - old_tag_list = old_tags.lower().split(',') - rm_tag_list = rm_tags.lower().split(',') - tag_list = old_tag_list - for tag in rm_tag_list: - if tag in tag_list: - tag_list.remove(tag) - tags = ','.join(tag_list) - self.cli_note_tags_set(key, tags) + old_category = self.cli_note_category_get(key) + if old_category: + self.cli_note_category_set(key, None) def SIGINT_handler(signum, frame): print('\nSignal caught, bye!') @@ -1292,12 +1159,11 @@ def usage(): export - export a note in JSON format (specified by <key>) dump - dump a note (specified by <key>) edit - edit a note (specified by <key>) - < trash | untrash > - trash/untrash a note (specified by <key>) - < pin | unpin > - pin/unpin a note (specified by <key>) - tag get - retrieve the tags from a note (specified by <key>) - tag set <tags> - set the tags for a note (specified by <key>) - tag add <tags> - add tags to a note (specified by <key>) - tag rm <tags> - remove tags from a note (specified by <key>) + delete - delete a note (specified by <key>) + < favorite | unfavorite > - favorite/unfavorite a note (specified by <key>) + cat get - retrieve the category from a note (specified by <key>) + cat set <category> - set the category for a note (specified by <key>) + cat rm - remove category from a note (specified by <key>) ''') sys.exit(0) @@ -1399,58 +1265,51 @@ def nncli_start(sync=sync, verbose=verbose, config=config): sn = nncli_start() sn.cli_note_edit(key) - elif args[0] == 'trash' or args[0] == 'untrash': + elif args[0] == 'delete': if not key: usage() sn = nncli_start() - sn.cli_note_trash(key, 1 if args[0] == 'trash' else 0) + sn.cli_note_delete(key, True) - elif args[0] == 'pin' or args[0] == 'unpin': + elif args[0] == 'favorite' or args[0] == 'unfavorite': if not key: usage() sn = nncli_start() - sn.cli_note_pin(key, 1 if args[0] == 'pin' else 0) + sn.cli_note_favorite(key, 1 if args[0] == 'favorite' else 0) - # Tag API - elif args[0] == 'tag': + # Category API + elif args[0] == 'cat': if not key: usage() nargs = len(args) - correct_get = (args[1] == 'get' and nargs == 2) - correct_other = (args[1] in ['set', 'add', 'rm'] and nargs == 3) - if not (correct_get or correct_other): + correct_other = (args[1] in ['get', 'rm'] and nargs == 2) + correct_set = (args[1] == 'set' and nargs == 3) + if not (correct_set or correct_other): usage() if args[1] == 'get': sn = nncli_start() - tags = sn.cli_note_tags_get(key) - if tags: - print(tags) + category = sn.cli_note_category_get(key) + if category: + print(category) elif args[1] == 'set': - tags = args[2] - sn = nncli_start() - sn.cli_note_tags_set(key, tags) - - elif args[1] == 'add': - - new_tags = args[2] + category = args[2] sn = nncli_start() - sn.cli_note_tags_add(key, new_tags) + sn.cli_note_category_set(key, category) elif args[1] == 'rm': - rm_tags = args[2] sn = nncli_start() - sn.cli_note_tags_rm(key, rm_tags) + sn.cli_note_category_rm(key) else: usage() diff --git a/nnotes_cli/notes_db.py b/nnotes_cli/notes_db.py @@ -100,18 +100,19 @@ def __init__(self, config, log, update_view): def filtered_notes_sort(self, filtered_notes, sort_mode='date'): if sort_mode == 'date': - if self.config.get_config('pinned_ontop') == 'yes': - filtered_notes.sort(key=utils.sort_by_modify_date_pinned, reverse=True) + if self.config.get_config('favorite_ontop') == 'yes': + filtered_notes.sort(key=utils.sort_by_modify_date_favorite, reverse=True) else: filtered_notes.sort(key=lambda o: -float(o.note.get('modified', 0))) elif sort_mode == 'alpha': - if self.config.get_config('pinned_ontop') == 'yes': - filtered_notes.sort(key=utils.sort_by_title_pinned) + if self.config.get_config('favorite_ontop') == 'yes': + filtered_notes.sort(key=utils.sort_by_title_favorite) else: filtered_notes.sort(key=lambda o: utils.get_note_title(o.note)) - elif sort_mode == 'tags': - pinned = self.config.get_config('pinned_ontop') - utils.sort_notes_by_tags(filtered_notes, pinned_ontop=pinned) + elif sort_mode == 'categories': + favorite = self.config.get_config('favorite_ontop') + utils.sort_notes_by_categories(filtered_notes, \ + favorite_ontop=favorite) def filter_notes(self, search_string=None, search_mode='gstyle', sort_mode='date'): """Return list of notes filtered with search string. @@ -137,34 +138,35 @@ def filter_notes(self, search_string=None, search_mode='gstyle', sort_mode='date return filtered_notes, match_regexp, active_notes - def _helper_gstyle_tagmatch(self, tag_pats, note): + def _helper_gstyle_categorymatch(self, cat_pats, note): # Returns: - # 2 = match - no tag patterns specified - # 1 = match - all tag patterns match a tag on this note - # 0 = no match - note has no tags or not all tag patterns match + # 2 = match - no category patterns specified + # 1 = match - all category patterns match a category on this + # note + # 0 = no match - note has no category or not all category patterns match - if not tag_pats: - # match because no tag patterns were specified + if not cat_pats: + # match because no category patterns were specified return 2 - note_tags = note.get('tags') + note_category = note.get('category') - if not note_tags: - # tag patterns specified but note has no tags, so no match + if not note_category: + # category patterns specified but note has no categories, so no match return 0 - # for each tag_pat, we have to find a matching tag + # for each cat_pat, we have to find a matching category # .lower() used for case-insensitive search - tag_pats_matched = 0 - for tp in tag_pats: + cat_pats_matched = 0 + for tp in cat_pats: tp = tp.lower() - for t in note_tags: + for t in note_category: if tp in t.lower(): - tag_pats_matched += 1 + cat_pats_matched += 1 break - if tag_pats_matched == len(tag_pats): - # all tag patterns specified matched a tag on this note + if cat_pats_matched == len(cat_pats): + # all category patterns specified matched a category on this note return 1 # note doesn't match @@ -189,42 +191,31 @@ def _helper_gstyle_wordmatch(self, word_pats, content): def filter_notes_gstyle(self, search_string=None): filtered_notes = [] - - # total number of notes, excluding deleted - # if tag:trash then counts deleted as well active_notes = 0 if not search_string: for k in self.notes: n = self.notes[k] - if n.get('deleted'): - continue active_notes += 1 - filtered_notes.append(utils.KeyValueObject(key=k, note=n, tagfound=0)) + filtered_notes.append(utils.KeyValueObject(key=k, note=n, catfound=0)) return filtered_notes, [], active_notes - # group0: tag:([^\s]+) + # group0: category:([^\s]+) # group1: multiple words in quotes # group2: single words - # example result for: 'tag:tag1 tag:tag2 word1 "word2 word3" tag:tag3' - # [ ('tag1', '', ''), - # ('tag2', '', ''), + # example result for: 'category:category1 category:category2 word1 "word2 word3" category:category3' + # [ ('category1', '', ''), + # ('category2', '', ''), # ('', '', 'word1'), # ('', 'word2 word3', ''), - # ('tag3', '', '') ] + # ('category3', '', '') ] - groups = re.findall('tag:([^\s]+)|"([^"]+)"|([^\s]+)', search_string) + groups = re.findall('category:([^\s]+)|"([^"]+)"|([^\s]+)', search_string) all_pats = [[] for _ in range(3)] - search_trash = False - for g in groups: - if g[0] == 'trash': - groups.remove(g) - search_trash = True - - # we end up with [[tag_pats],[multi_word_pats],[single_word_pats]] + # we end up with [[cat_pats],[multi_word_pats],[single_word_pats]] for g in groups: for i in range(3): if g[i]: all_pats[i].append(g[i]) @@ -232,31 +223,19 @@ def filter_notes_gstyle(self, search_string=None): for k in self.notes: n = self.notes[k] - if not search_trash and n.get('deleted'): - continue - active_notes += 1 - if search_trash and len(groups) == 0: - # simple search of only 'tag:trash' to get all trashed notes - if n.get('deleted'): - filtered_notes.append( - utils.KeyValueObject(key=k, - note=n, - tagfound=1)) - continue - - tagmatch = self._helper_gstyle_tagmatch(all_pats[0], n) + catmatch = self._helper_gstyle_catmatch(all_pats[0], n) word_pats = all_pats[1] + all_pats[2] - if tagmatch and \ + if catmatch and \ self._helper_gstyle_wordmatch(word_pats, n.get('content')): # we have a note that can go through! filtered_notes.append( utils.KeyValueObject(key=k, note=n, - tagfound=1 if tagmatch == 1 else 0)) + catfound=1 if catmatch == 1 else 0)) return filtered_notes, '|'.join(all_pats[1] + all_pats[2]), active_notes @@ -276,21 +255,21 @@ def filter_notes_regex(self, search_string=None): active_notes += 1 if not sspat: - filtered_notes.append(utils.KeyValueObject(key=k, note=n, tagfound=0)) + filtered_notes.append(utils.KeyValueObject(key=k, note=n, catfound=0)) continue - if self.config.get_config('search_tags') == 'yes': - tag_matched = False - for t in n.get('tags'): + if self.config.get_config('search_categories') == 'yes': + cat_matched = False + for t in n.get('category'): if sspat.search(t): - tag_matched = True - filtered_notes.append(utils.KeyValueObject(key=k, note=n, tagfound=1)) + cat_matched = True + filtered_notes.append(utils.KeyValueObject(key=k, note=n, catfound=1)) break - if tag_matched: + if cat_matched: continue if sspat.search(n.get('content')): - filtered_notes.append(utils.KeyValueObject(key=k, note=n, tagfound=0)) + filtered_notes.append(utils.KeyValueObject(key=k, note=n, catfound=0)) match_regexp = search_string if sspat else '' return filtered_notes, match_regexp, active_notes @@ -317,30 +296,23 @@ def import_note(self, note): 'category' : note.get('category', None), 'savedate' : 0, # never been written to disc 'syncdate' : 0, # never been synced with server - 'favorite' : False + 'favorite' : False, + 'deleted' : False } # sanity check all note values if not isinstance(new_note['content'], str): raise ValueError('"content" must be a string') - if not new_note['deleted'] in (0, 1): - raise ValueError('"deleted" must be 0 or 1') for n in (new_note['modified']): if not 0 <= n <= timestamp: raise ValueError('date fields must be real') - if not isinstance(new_note['tags'], list): - raise ValueError('"tags" must be an array') - for tag in new_note['tags']: - if not isinstance(tag, str): - raise ValueError('items in the "tags" array must be strings') + if not isinstance(new_note['category'], str): + raise ValueError('"category" must be an string') - if not isinstance(new_note['systemtags'], list): - raise ValueError('"systemtags" must be an array') - for tag in new_note['systemtags']: - if not isinstance(tag, str): - raise ValueError('items in the "systemtags" array must be strings') + if not isinstance(new_note['favorite'], bool): + raise ValueError('"favorite" must be a boolean') self.notes[new_key] = new_note @@ -363,7 +335,8 @@ def create_note(self, content): 'category' : None, 'savedate' : 0, # never been written to disc 'syncdate' : 0, # never been synced with server - 'favorite' : False + 'favorite' : False, + 'deleted' : False } self.notes[new_key] = new_note @@ -373,11 +346,11 @@ def create_note(self, content): def get_note(self, key): return self.notes[key] - def get_note_systemtags(self, key): - return self.notes[key].get('systemtags') + def get_note_favorite(self, key): + return self.notes[key].get('favorite') - def get_note_tags(self, key): - return self.notes[key].get('tags') + def get_note_category(self, key): + return self.notes[key].get('category') def get_note_content(self, key): return self.notes[key].get('content') @@ -390,12 +363,12 @@ def flag_what_changed(self, note, what_changed): def set_note_deleted(self, key, deleted): n = self.notes[key] - if (not n['deleted'] and deleted) or \ - (n['deleted'] and not deleted): + old_deleted = n['deleted'] if 'deleted' in n else 0 + if old_deleted != deleted: n['deleted'] = deleted n['modified'] = int(time.time()) self.flag_what_changed(n, 'deleted') - self.log('Note {0} (key={1})'.format('trashed' if deleted else 'untrashed', key)) + self.log('Note marked for deletion (key={0})'.format(key)) def set_note_content(self, key, content): n = self.notes[key] @@ -406,30 +379,25 @@ def set_note_content(self, key, content): self.flag_what_changed(n, 'content') self.log('Note content updated (key={0})'.format(key)) - def set_note_tags(self, key, tags): + def set_note_category(self, key, category): n = self.notes[key] - old_tags = n.get('tags') - tags = utils.sanitise_tags(tags) - if tags != old_tags: - n['tags'] = tags + old_category = n.get('category') + if category != old_category: + n['category'] = category n['modified'] = int(time.time()) - self.flag_what_changed(n, 'tags') - self.log('Note tags updated (key={0})'.format(key)) + self.flag_what_changed(n, 'category') + self.log('Note category updated (key={0})'.format(key)) - def set_note_pinned(self, key, pinned): + def set_note_favorite(self, key, favorite): n = self.notes[key] - old_pinned = utils.note_pinned(n) - if pinned != old_pinned: - if 'systemtags' not in n: - n['systemtags'] = [] - systemtags = n['systemtags'] - if pinned: - systemtags.append('pinned') - else: - systemtags.remove('pinned') + old_favorite = utils.note_favorite(n) + if favorite != old_favorite: + n['favorite'] = favorite n['modified'] = int(time.time()) - self.flag_what_changed(n, 'systemtags') - self.log('Note {0} (key={1})'.format('pinned' if pinned else 'unpinned', key)) + self.flag_what_changed(n, 'favorite') + self.log('Note {0} (key={1})'. \ + format('favorite' if favorited else \ + 'unfavorited', key)) def helper_key_to_fname(self, k): return os.path.join(self.config.get_config('db_path'), str(k)) + '.json' @@ -507,6 +475,7 @@ def sync_notes(self, server_sync=True, full_sync=True): del cn['minversion'] del cn['syncdate'] del cn['savedate'] + del cn['deleted'] if 'what_changed' in cn: if 'category' not in cn['what_changed']: @@ -517,7 +486,10 @@ def sync_notes(self, server_sync=True, full_sync=True): del cn['content'] del cn['what_changed'] - uret = self.note.update_note(cn) + if n['deleted']: + uret = self.note.delete_note(cn) + else: + uret = self.note.update_note(cn) if uret[1] == 0: # success # if this is a new note our local key is not valid anymore @@ -577,6 +549,7 @@ def sync_notes(self, server_sync=True, full_sync=True): local_updates[k] = True self.notes[k]['syncdate'] = now self.notes[k]['localkey'] = k + self.notes[k]['deleted'] = False self.log('Synced newer note from server (key={0})'.format(k)) else: @@ -590,6 +563,7 @@ def sync_notes(self, server_sync=True, full_sync=True): local_updates[k] = True self.notes[k]['syncdate'] = now self.notes[k]['localkey'] = k + self.notes[k]['deleted'] = False self.log('Synced new note from server (key={0})'.format(k)) else: @@ -632,10 +606,6 @@ def sync_notes(self, server_sync=True, full_sync=True): return sync_errors - def get_note_version(self, key, version): - gret = self.note.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/nnotes_cli/utils.py b/nnotes_cli/utils.py @@ -31,9 +31,6 @@ import datetime, random, re -# first line with non-whitespace should be the title -note_title_re = re.compile('\s*(.*)\n?') - def generate_random_key(): """Generate random 30 digit (15 byte) hex string. @@ -41,36 +38,28 @@ def generate_random_key(): """ return '%030x' % (random.randrange(256**15),) -def get_note_tags(note): - if 'tags' in note: - tags = '%s' % ','.join(note['tags']) - if 'deleted' in note and note['deleted']: - if tags: tags += ',trash' - else: tags = 'trash' +def get_note_category(note): + if 'category' in note: + category = note['category'] if note['category'] is not None else '' else: - tags = '' - return tags + category = '' + return category # Returns a fixed length string: # 'X' - needs sync -# 'T' - trashed -# '*' - pinned -# 'S' - published/shared +# '*' - favorite def get_note_flags(note): flags = '' flags += 'X' if float(note['modified']) > float(note['syncdate']) else ' ' - flags += 'T' if 'deleted' in note and note['deleted'] else ' ' - if 'systemtags' in note: - flags += '*' if 'pinned' in note['systemtags'] else ' ' - flags += 'S' if 'published' in note['systemtags'] else ' ' + if 'favorite' in note: + flags += '*' if note['favorite'] else ' ' else: - flags += ' ' + flags += ' ' return flags def get_note_title(note): - mo = note_title_re.match(note.get('content', '')) - if mo: - return mo.groups()[0] + if 'title' in note: + return note['title'] else: return '' @@ -121,53 +110,22 @@ def human_date(timestamp): # not today or this year, so we do "Dec 11, 2011" return '%s %d, %d' % (dt.strftime('%b'), dt.day, dt.year) -def note_published(n): - asystags = n.get('systemtags', 0) - if not asystags: - return 0 - return 1 if 'published' in asystags else 0 - -def note_pinned(n): - asystags = n.get('systemtags', 0) - if not asystags: - return 0 - return 1 if 'pinned' in asystags else 0 - -# TODO: NextCloud notes doesn't have a concept of tags, but it does -# allow assignment of notes to a single category. Refactor to take this -# into account -tags_illegal_chars = re.compile(r'[\s]') -def sanitise_tags(tags): - """ - Given a string containing comma-separated tags, sanitise and return a list of string tags. - - The NextCloud API doesn't allow for spaces, so we strip those out. - - @param tags: Comma-separated tags, one string. - @returns: List of strings. - """ - # hack out all kinds of whitespace, then split on , - # if you run into more illegal characters (NextCloud does not want to sync them) - # add them to the regular expression above. - illegals_removed = tags_illegal_chars.sub('', tags) - if len(illegals_removed) == 0: - # special case for empty string '' - # split turns that into [''], which is not valid - return [] - +def note_favorite(n): + if 'favorite' in n: + return n['favorite'] else: - return illegals_removed.split(',') + return False -def sort_by_title_pinned(a): - return (not note_pinned(a.note), get_note_title(a.note)) +def sort_by_title_favorite(a): + return (not note_favorite(a.note), get_note_title(a.note)) -def sort_notes_by_tags(notes, pinned_ontop=False): - notes.sort(key=lambda i: (pinned_ontop and not note_pinned(i.note), - i.note.get('tags'), +def sort_notes_by_categories(notes, favorite_ontop=False): + notes.sort(key=lambda i: (favorite_ontop and not note_favorite(i.note), + i.note.get('category'), get_note_title(i.note))) -def sort_by_modify_date_pinned(a): - if note_pinned(a.note): +def sort_by_modify_date_favorite(a): + if note_favorite(a.note): return 100.0 * float(a.note.get('modified', 0)) else: return float(a.note.get('modified', 0)) diff --git a/nnotes_cli/view_note.py b/nnotes_cli/view_note.py @@ -50,30 +50,6 @@ def update_note_view(self, key=None, version=None): self.note = self.ndb.get_note(self.key) self.old_note = None - if self.key and version: - # verify version is within range - if int(version) <= 0 or int(version) >= self.note['version'] + 1: - self.log('Version v{0} is unavailable (key={1})'. - format(version, self.key)) - return - - if (not version and self.old_note) or \ - (self.key and version and version == self.note['version']): - self.log('Displaying latest version v{0} of note (key={1})'. - format(self.note['version'], self.key)) - self.old_note = None - elif self.key and version: - # get a previous version of the note - self.log('Fetching version v{0} of note (key={1})'. - format(version, self.key)) - version_note = self.ndb.get_note_version(self.key, version) - if not version_note: - self.log('Failed to get version v{0} of note (key={1})'. - format(version, self.key)) - # don't do anything, keep current note/version - else: - self.old_note = version_note - self.body[:] = \ urwid.SimpleFocusListWalker(self.get_note_content_as_list()) if not self.search_string: @@ -131,16 +107,10 @@ def get_status_bar(self): cur = self.focus_position total = len(self.body.positions()) - if self.old_note: - t = time.localtime(float(self.old_note['versiondate'])) - title = utils.get_note_title(self.old_note) - version = self.old_note['version'] - else: - t = time.localtime(float(self.note['modified'])) - title = utils.get_note_title(self.note) - flags = utils.get_note_flags(self.note) - tags = utils.get_note_tags(self.note) - version = self.note.get('version', 0) + t = time.localtime(float(self.note['modified'])) + title = utils.get_note_title(self.note) + flags = utils.get_note_flags(self.note) + category = utils.get_note_category(self.note) mod_time = time.strftime('Date: %a, %d %b %Y %H:%M:%S', t) @@ -164,37 +134,19 @@ def get_status_bar(self): wrap='clip'), 'status_bar') - if self.old_note: - status_tags_flags = \ - ('pack', urwid.AttrMap(urwid.Text('[OLD:v' + - str(version) + - ']'), - 'status_bar')) - else: - status_tags_flags = \ - ('pack', urwid.AttrMap(urwid.Text('[' + - tags + - '] [v' + - str(version) + - '] [' + - flags + - ']'), - 'status_bar')) + status_category_flags = \ + ('pack', urwid.AttrMap(urwid.Text('[' + + category + + '] [' + + flags + + ']'), + 'status_bar')) pile_top = urwid.Columns([ status_title, status_key_index ]) - pile_bottom = urwid.Columns([ status_date, status_tags_flags ]) + pile_bottom = urwid.Columns([ status_date, status_category_flags ]) - if self.old_note or \ - not (utils.note_published(self.note) and 'publishkey' in self.note): - return urwid.AttrMap(urwid.Pile([ pile_top, pile_bottom ]), - 'status_bar') - - pile_publish = \ - urwid.AttrMap(urwid.Text('Published: http://simp.ly/publish/' + - self.note['publishkey']), - 'status_bar') return \ - urwid.AttrMap(urwid.Pile([ pile_top, pile_bottom, pile_publish ]), + urwid.AttrMap(urwid.Pile([ pile_top, pile_bottom ]), 'status_bar') def copy_note_text(self): diff --git a/nnotes_cli/view_titles.py b/nnotes_cli/view_titles.py @@ -41,7 +41,7 @@ def format_title(self, note): supported by printf. %F -- flags - %T -- tags + %T -- category %D -- date %N -- note title """ @@ -50,7 +50,7 @@ def format_title(self, note): mod_time = time.strftime(self.config.get_config('format_strftime'), t) title = utils.get_note_title(note) flags = utils.get_note_flags(note) - tags = utils.get_note_tags(note) + category = utils.get_note_category(note) # get the age of the note dt = datetime.datetime.fromtimestamp(time.mktime(t)) @@ -91,10 +91,10 @@ def recursive_format(title_format): wrap='clip'), 'note_date')) elif fmt.group(4) == 'T': - m = (width, urwid.AttrMap(urwid.Text(tags, + m = (width, urwid.AttrMap(urwid.Text(category, align=align, wrap='clip'), - 'note_tags')) + 'note_category')) elif fmt.group(4) == 'N': if note_age == 'd': attr = 'note_title_day' elif note_age == 'w': attr = 'note_title_week' @@ -135,7 +135,7 @@ def get_note_title(self, note): 'note_title_ancient' : 'note_focus', 'note_date' : 'note_focus', 'note_flags' : 'note_focus', - 'note_tags' : 'note_focus' }) + 'note_categories' : 'note_focus' }) def get_note_titles(self): lines = [] diff --git a/todo.txt b/todo.txt @@ -1,2 +1,2 @@ -1. Trash->Delete -2. Pin->Favorite +1. Pin->Favorite +2. Tags->Category