# This file exists within 'dob':
#
# https://github.com/hotoffthehamster/dob
#
# Copyright © 2018-2020 Landon Bouma, 2015-2016 Eric Goller. All rights reserved.
#
# 'dob' is free software: you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# 'dob' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You can find the GNU General Public License reprinted in the file titled 'LICENSE',
# or visit <http://www.gnu.org/licenses/>.
from gettext import gettext as _
import click_hotoffthehamster as click
from dob_bright.crud.fact_dressed import FactDressed
from dob_bright.crud.interrogate import ask_edit_with_editor
from dob_bright.termio import dob_in_user_exit, dob_in_user_warning
from dob_prompt.prompters.triple_prompter import ask_user_for_edits
from .save_backedup import prompt_and_save_backedup
from .simple_prompts import mend_facts_confirm_and_save_maybe
__all__ = ('edit_fact_by_pk', )
[docs]def edit_fact_by_pk(
controller,
key,
use_carousel=True,
edit_text=False,
edit_meta=False,
):
""""""
def _edit_fact_by_pk():
old_fact = fact_from_key(key)
if old_fact is None:
return warn_nothing_found(key)
unedited = old_fact.copy() if old_fact else None
# Pre-run Awesome Prompt and/or $EDITOR.
# Then run the Interactive Editor Carousel, the star
# of the show; or show the $EDITOR if nothing else done.
# FIXME/2019-11-23: (lb): add_fact does $EDITOR, then Awesome.
# - Which way is best? Make if configurable!!
if edit_meta:
_prompter = ask_user_for_edits( # noqa: F841
controller,
# MAYBE: rename old_fact
# fact=edit_fact,
fact=old_fact,
always_ask=True,
# (lb): If we leave restrict_edit alone, the prompter will
# prompt for act@gory, then tags, and description (show editor).
# Otherwise, we could just ask for, e.g., act@gory, say:
# restrict_edit='actegory',
)
# FIXME: Missing diff with old Fact to see if edited (and tell user)
# and missing save Fact.
if edit_text:
_prompter = ask_user_for_edits( # noqa: F841
controller,
# MAYBE: rename old_fact
# fact=edit_fact,
fact=old_fact,
always_ask=True,
restrict_edit='description',
)
# FIXME: Missing diff with old Fact to see if edited (and tell user)
# and missing save Fact.
if use_carousel:
edited_facts = edit_old_fact(old_fact)
elif not edit_meta and not edit_text:
edited_facts = edit_old_factoid(old_fact)
elif old_fact != unedited:
# So @post_processor get proper list of edited facts,
# we have to check if really edited.
edited_facts = [old_fact]
else:
edited_facts = []
return edited_facts
def fact_from_key(key):
if key > 0:
return fact_from_key_pk(key)
return fact_from_key_relative_or_new(key)
def fact_from_key_relative_or_new(key):
old_fact = fact_from_key_relative(key)
if old_fact or key > 0:
return old_fact
return FactDressed.new_gap_fact(start=controller.now)
def fact_from_key_pk(key):
try:
old_fact = controller.facts.get(pk=key)
return old_fact
except KeyError:
dob_in_user_exit(
_("No fact found with ID “{0}”.").format(key)
)
def fact_from_key_relative(key):
offset = -1 - key
old_facts = controller.facts.get_all(
sort_cols=('start',),
sort_orders=('desc',),
limit=1,
offset=offset,
deleted=False,
)
return old_facts[0] if old_facts else None
def warn_nothing_found(key):
if key > 0:
msg = _('No Fact found with ID “{}”.'.format(key))
else:
msg = _('There are not that many Facts.')
dob_in_user_warning(msg)
return None
# ***
def edit_old_fact(old_fact):
saved_facts = prompt_and_save_backedup(
controller,
edit_facts=[old_fact],
# (lb): The whole point on dob-edit is to fire up the Carousel.
use_carousel=True,
# MEH/2019-02-01: (lb) Support --yes or --dry on dob-edit?
yes=False,
dry=False,
)
return saved_facts
# ***
def edit_old_factoid(old_fact):
raw_fact = editor_interact(old_fact)
time_hint = fact_time_hint(old_fact)
new_fact = new_fact_from_factoid(raw_fact, old_fact, time_hint)
echo_edited_fact(new_fact, old_fact)
new_and_edited = confirm_and_save(new_fact, time_hint)
return new_and_edited
def editor_interact(old_fact):
"""Presents user with their EDITOR displaying the Factoid text.
"""
# So that the user can edit act@gory and tags, and not solely
# the description, marshal the Fact to a factoid string and
# let the user edit that.
old_raw_fact = old_fact.friendly_str(
shellify=False,
description_sep='\n\n',
localize=True,
colorful=False,
show_elapsed=False,
)
# MAYBE/2020-01-28: Give user option of using dob-prompt to edit
# act@gory and tags, then the description, e.g., something like
# this?:
#
# # MAYBE/2019-11-23: Call ask_user_for_edits instead?
# What happens on active Fact that has body?
# __prompter = ask_user_for_edits(
# controller,
# fact=old_fact,
# always_ask=True,
# restrict_edit='description',
# )
new_raw_fact = ask_edit_with_editor(controller, old_fact, old_raw_fact)
if old_raw_fact == new_raw_fact:
dob_in_user_exit(
_("Nothing changed! New Fact same as the old Fact.")
)
return new_raw_fact
def fact_time_hint(old_fact):
if old_fact.start and old_fact.end:
time_hint = 'verify_both'
else:
assert old_fact.start
time_hint = 'verify_start'
return time_hint
def new_fact_from_factoid(raw_fact, old_fact, time_hint):
# NOTE: Parser expects Iterable of input parts.
new_fact, __err = old_fact.create_from_factoid(
(raw_fact,),
time_hint=time_hint, # Either 'verify_both' or 'verify_start'.
lenient=True,
)
# FIXME/2018-06-10: (lb): Do we care about the error?
# (lb): Start with the PK of the old fact. On save/update, the
# store will see that the fact already exists, so it'll make a
# new copy of the fact (with a new ID), and mark the old fact
# 'deleted' (thereby acting like a Wiki -- never delete!).
new_fact.pk = old_fact.pk
return new_fact
def echo_edited_fact(new_fact, old_fact):
if new_fact == old_fact:
dob_in_user_exit(
_("Nothing changed! New Fact same as old Fact.")
)
click.echo('An edited fact!: {}'.format(str(new_fact)))
click.echo('\nThe diff!\n')
click.echo(old_fact.friendly_diff(new_fact))
def confirm_and_save(new_fact, time_hint):
new_and_edited = mend_facts_confirm_and_save_maybe(
controller,
new_fact,
time_hint,
other_edits={},
yes=False,
dry=False,
)
return new_and_edited
# ***
return _edit_fact_by_pk()