From 051cb8189e6ebc2021463a6fdd8e8588ea11e5fb Mon Sep 17 00:00:00 2001 From: Corentin Girard Date: Wed, 2 Jun 2021 22:18:01 +0200 Subject: [PATCH 1/4] Remove usage of click._compat https://github.com/pallets/click/issues/1721 --- google_keep_tasks/cli.py | 3 +-- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/google_keep_tasks/cli.py b/google_keep_tasks/cli.py index 1173e88..ca44536 100644 --- a/google_keep_tasks/cli.py +++ b/google_keep_tasks/cli.py @@ -1,5 +1,4 @@ import click -from click._compat import iteritems def choices_prompt(text, choices, default_choice): @@ -32,7 +31,7 @@ def make_formatter(self): class GkeepGroup(click.Group): def make_context(self, info_name, args, parent=None, **extra): - for key, value in iteritems(self.context_settings): + for key, value in self.context_settings.items(): if key not in extra: extra[key] = value ctx = GkeepContext(self, info_name=info_name, parent=parent, **extra) diff --git a/requirements.txt b/requirements.txt index 6ff73b9..a7fccfc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ gkeepapi>=0.10.6 -click \ No newline at end of file +click>=8.0.0 \ No newline at end of file From 4d7ced4640ae910c34078c2415eeae358154aedf Mon Sep 17 00:00:00 2001 From: Corentin Girard Date: Wed, 2 Jun 2021 22:18:43 +0200 Subject: [PATCH 2/4] Use default editor to edit a note --- google_keep_tasks/notes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/google_keep_tasks/notes.py b/google_keep_tasks/notes.py index e482b36..7ec5689 100644 --- a/google_keep_tasks/notes.py +++ b/google_keep_tasks/notes.py @@ -19,6 +19,8 @@ } COLOR_NAMES = [color.name.lower() for color in gkeepapi.node.ColorValue] +placeholder = '__placeholder__' + def get_color(color): if not color: @@ -199,7 +201,7 @@ def get_note(ctx, **kwargs): @notes.command('edit', options_metavar='[options]') @click.option('--title', default=None, required=False, metavar='', help='Change the note title') -@click.option('--text', default=None, required=False, metavar='', +@click.option('--text', default=None, required=False, is_flag=False, flag_value=placeholder, metavar='[new_note_content]', help='Change the note text') @click.option('--filter-id', default=None, required=False, metavar='', help='Filter by id note. This is the preferred way to ensure editing the correct note') @@ -231,6 +233,8 @@ def edit_note(ctx, title, text, color, labels, archived, pinned, filter_id, filt if not note: click.echo('The note was not found', err=True) sys.exit(2) + if text == placeholder: + text = click.edit(note.text).strip() updated = {} boolean_nullables = ['archived', 'pinned'] # 3 state params for param in ['title', 'text', 'color', 'labels'] + boolean_nullables: From 1ffcbac58400c9540f4c4b10bd0f461dc574f5a1 Mon Sep 17 00:00:00 2001 From: Corentin Girard Date: Sat, 5 Jun 2021 16:54:30 +0200 Subject: [PATCH 3/4] Support notes with checkboxes --- google_keep_tasks/notes.py | 89 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/google_keep_tasks/notes.py b/google_keep_tasks/notes.py index 7ec5689..dc0a67e 100644 --- a/google_keep_tasks/notes.py +++ b/google_keep_tasks/notes.py @@ -2,6 +2,9 @@ import click import gkeepapi import sys +import re + +from gkeepapi.node import List from google_keep_tasks.cli import GkeepGroup from google_keep_tasks.exceptions import InvalidColor @@ -73,6 +76,21 @@ def query_params(keep, **kwargs): set(x.labels.all()) == set(labels) if labels is not None else None])) return kwargs +def format_note_item(item): + return u'%s%s %s' % ( + ' ' if item.indented else '', + u'- [x]' if item.checked else u'- [ ]', + item.text + ) + +def format_note(note): + if not isinstance(note, List): + return note.text + text = "" + for item in note.items: + text += "%s | %s\n" % (item.id.ljust(30), format_note_item(item)) + return text + def print_note(note): params = COLORS.get(note.color, {}) @@ -82,15 +100,74 @@ def print_note(note): click.echo(click.style('"' * len(note_id), **params)) if note.title: click.echo(click.style(note.title, bold=True)) - click.echo(note.text) + click.echo('-' * len(note_id)) + click.echo(format_note(note)) + click.echo('-' * len(note_id)) if note.labels: - click.echo() click.echo(' '.join(click.style('[{}]'.format(label.name), underline=True, bold=True) for label in note.labels.all())) click.echo(click.style('"' * len(note_id), **params)) click.echo('\n') +def edit_note_checkboxes(note): + text = click.edit(format_note(note)).strip() + lines = text.split("\n") + regex = re.compile(r"([\w.]*) *\| ( *)- \[(x| )\] (.*)") + + last_old_note = 'top' + current_items = [] + for line in lines: + id, indent, check_mark, content = regex.match(line).groups() + found = list(filter(lambda item: item.id == id, note.items)) + old_note = found[0] if len(found) > 0 else None + indented = len(indent) > 1 + checked = check_mark == 'x' + current_items.append({ + 'id': id, + 'previous': last_old_note, + 'old': old_note, + 'indented': indented, + 'checked': checked, + 'content': content + }) + last_old_note = old_note + + # Deletion + for item in note.items: + if item.id not in [parts['id'] for parts in current_items]: + item.delete() + + last_added = None + for parts in current_items: + previous = parts['previous'] if parts['previous'] != None else last_added + + # Addition + if parts['old'] == None: + sort = int(previous.sort) - 1 if previous != None and previous != 'top' else gkeepapi.node.NewListItemPlacementValue.Top + added = note.add(parts['content'], parts['checked'], sort) + if parts['indented']: + previous.indent(added) + last_added = added + + # Modification + else: + if parts['old'].indented and not parts['indented']: + if previous != None: + previous.dedent(parts['old']) + if not parts['old'].indented and parts['indented']: + if previous != None: + previous.indent(parts['old']) + + if parts['old'].checked and not parts['checked']: + parts['old'].checked = False + if not parts['old'].checked and parts['checked']: + parts['old'].checked = True + + if parts['old'].text != parts['content']: + parts['old'].text = parts['content'] + + def get_note_instance(keep, id=None, **kwargs): if id: note = keep.get(id) @@ -234,7 +311,11 @@ def edit_note(ctx, title, text, color, labels, archived, pinned, filter_id, filt click.echo('The note was not found', err=True) sys.exit(2) if text == placeholder: - text = click.edit(note.text).strip() + if isinstance(note, List): + edit_note_checkboxes(note) + text = None + else: + text = click.edit(note.text).strip() updated = {} boolean_nullables = ['archived', 'pinned'] # 3 state params for param in ['title', 'text', 'color', 'labels'] + boolean_nullables: @@ -275,4 +356,4 @@ def delete_note(ctx, **kwargs): click.echo('Note with title "{}" deleted.'.format(note.title)) else: click.echo('The note was not found', err=True) - sys.exit(2) + sys.exit(2) \ No newline at end of file From 2f7a7a9a5fadb6404c259a9800563dea4c3bdf52 Mon Sep 17 00:00:00 2001 From: Corentin Girard Date: Sat, 5 Jun 2021 16:54:54 +0200 Subject: [PATCH 4/4] Add prints --- google_keep_tasks/notes.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/google_keep_tasks/notes.py b/google_keep_tasks/notes.py index dc0a67e..ab7a557 100644 --- a/google_keep_tasks/notes.py +++ b/google_keep_tasks/notes.py @@ -137,6 +137,7 @@ def edit_note_checkboxes(note): for item in note.items: if item.id not in [parts['id'] for parts in current_items]: item.delete() + print('Deleted "%s"' % item.text) last_added = None for parts in current_items: @@ -149,23 +150,30 @@ def edit_note_checkboxes(note): if parts['indented']: previous.indent(added) last_added = added + print('Added "%s"' % parts['content']) # Modification else: + updated = False if parts['old'].indented and not parts['indented']: if previous != None: previous.dedent(parts['old']) + updated = True if not parts['old'].indented and parts['indented']: if previous != None: previous.indent(parts['old']) - + updated = True if parts['old'].checked and not parts['checked']: parts['old'].checked = False + updated = True if not parts['old'].checked and parts['checked']: parts['old'].checked = True - + updated = True if parts['old'].text != parts['content']: parts['old'].text = parts['content'] + updated = True + if updated: + print('Updated "%s"' % parts['content']) def get_note_instance(keep, id=None, **kwargs):