mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 16:48:31 +02:00
DayOne support for --edit
This commit is contained in:
parent
ca6b16a5a1
commit
0e637d26d0
3 changed files with 113 additions and 21 deletions
|
@ -9,8 +9,8 @@ class Entry:
|
|||
def __init__(self, journal, date=None, title="", body="", starred=False):
|
||||
self.journal = journal # Reference to journal mainly to access it's config
|
||||
self.date = date or datetime.now()
|
||||
self.title = title.strip()
|
||||
self.body = body.strip()
|
||||
self.title = title.strip("\n ")
|
||||
self.body = body.strip("\n ")
|
||||
self.tags = self.parse_tags()
|
||||
self.starred = starred
|
||||
self.modified = False
|
||||
|
@ -68,6 +68,18 @@ class Entry:
|
|||
def __repr__(self):
|
||||
return "<Entry '{0}' on {1}>".format(self.title.strip(), self.date.strftime("%Y-%m-%d %H:%M"))
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Entry) \
|
||||
or self.title.strip() != other.title.strip() \
|
||||
or self.body.strip() != other.body.strip() \
|
||||
or self.date != other.date \
|
||||
or self.starred != other.starred:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'title': self.title.strip(),
|
||||
|
|
103
jrnl/Journal.py
103
jrnl/Journal.py
|
@ -50,9 +50,7 @@ class Journal(object):
|
|||
self.search_tags = None # Store tags we're highlighting
|
||||
self.name = name
|
||||
|
||||
journal_txt = self.open()
|
||||
self.entries = self.parse(journal_txt)
|
||||
self.sort()
|
||||
self.open()
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of entries"""
|
||||
|
@ -119,9 +117,10 @@ class Journal(object):
|
|||
else:
|
||||
with codecs.open(filename, "r", "utf-8") as f:
|
||||
journal = f.read()
|
||||
return journal
|
||||
self.entries = self._parse(journal)
|
||||
self.sort()
|
||||
|
||||
def parse(self, journal):
|
||||
def _parse(self, journal_txt):
|
||||
"""Parses a journal that's stored in a string and returns a list of entries"""
|
||||
|
||||
# Entries start with a line that looks like 'date title' - let's figure out how
|
||||
|
@ -132,7 +131,7 @@ class Journal(object):
|
|||
entries = []
|
||||
current_entry = None
|
||||
|
||||
for line in journal.splitlines():
|
||||
for line in journal_txt.splitlines():
|
||||
try:
|
||||
# try to parse line as date => new entry begins
|
||||
line = line.strip()
|
||||
|
@ -309,20 +308,30 @@ class Journal(object):
|
|||
self.sort()
|
||||
return entry
|
||||
|
||||
def editable_str(self):
|
||||
"""Turns the journal into a string of entries that can be edited
|
||||
manually and later be parsed with eslf.parse_editable_str."""
|
||||
return u"\n".join([e.__unicode__() for e in self.entries])
|
||||
|
||||
def parse_editable_str(self, edited):
|
||||
"""Parses the output of self.editable_str and updates it's entries."""
|
||||
mod_entries = self._parse(edited)
|
||||
# Match those entries that can be found in self.entries and set
|
||||
# these to modified, so we can get a count of how many entries got
|
||||
# modified and how many got deleted later.
|
||||
for entry in mod_entries:
|
||||
entry.modified = not any(entry == old_entry for old_entry in self.entries)
|
||||
self.entries = mod_entries
|
||||
|
||||
class DayOne(Journal):
|
||||
"""A special Journal handling DayOne files"""
|
||||
def __init__(self, **kwargs):
|
||||
self.entries = []
|
||||
self._deleted_entries = []
|
||||
super(DayOne, self).__init__(**kwargs)
|
||||
|
||||
def open(self):
|
||||
files = [os.path.join(self.config['journal'], "entries", f) for f in os.listdir(os.path.join(self.config['journal'], "entries"))]
|
||||
return files
|
||||
|
||||
def parse(self, filenames):
|
||||
"""Instead of parsing a string into an entry, this method will take a list
|
||||
of filenames, interpret each as a plist file and create a new entry from that."""
|
||||
filenames = [os.path.join(self.config['journal'], "entries", f) for f in os.listdir(os.path.join(self.config['journal'], "entries"))]
|
||||
self.entries = []
|
||||
for filename in filenames:
|
||||
with open(filename, 'rb') as plist_entry:
|
||||
|
@ -340,6 +349,7 @@ class DayOne(Journal):
|
|||
entry.uuid = dict_entry["UUID"]
|
||||
entry.tags = dict_entry.get("Tags", [])
|
||||
self.entries.append(entry)
|
||||
self.sort()
|
||||
|
||||
def write(self):
|
||||
"""Writes only the entries that have been modified into plist files."""
|
||||
|
@ -358,3 +368,72 @@ class DayOne(Journal):
|
|||
'Tags': [tag.strip(self.config['tagsymbols']) for tag in entry.tags]
|
||||
}
|
||||
plistlib.writePlist(entry_plist, filename)
|
||||
for entry in self._deleted_entries:
|
||||
print "DELETING", entry.uuid, entry.title
|
||||
filename = os.path.join(self.config['journal'], "entries", entry.uuid+".doentry")
|
||||
os.remove(filename)
|
||||
|
||||
def editable_str(self):
|
||||
"""Turns the journal into a string of entries that can be edited
|
||||
manually and later be parsed with eslf.parse_editable_str."""
|
||||
return u"\n".join(["# {0}\n{1}".format(e.uuid, e.__unicode__()) for e in self.entries])
|
||||
|
||||
def parse_editable_str(self, edited):
|
||||
"""Parses the output of self.editable_str and updates it's entries."""
|
||||
# Method: create a new list of entries from the edited text, then match
|
||||
# UUIDs of the new entries against self.entries, updating the entries
|
||||
# if the edited entries differ, and deleting entries from self.entries
|
||||
# if they don't show up in the edited entries anymore.
|
||||
date_length = len(datetime.today().strftime(self.config['timeformat']))
|
||||
|
||||
# Initialise our current entry
|
||||
entries = []
|
||||
current_entry = None
|
||||
|
||||
for line in edited.splitlines():
|
||||
# try to parse line as UUID => new entry begins
|
||||
line = line.strip()
|
||||
m = re.match("# *([a-f0-9]+) *$", line.lower())
|
||||
if m:
|
||||
if current_entry:
|
||||
entries.append(current_entry)
|
||||
current_entry = Entry.Entry(self)
|
||||
current_entry.modified = False
|
||||
current_entry.uuid = m.group(1).lower()
|
||||
else:
|
||||
try:
|
||||
new_date = datetime.strptime(line[:date_length], self.config['timeformat'])
|
||||
if line.endswith("*"):
|
||||
current_entry.starred = True
|
||||
line = line[:-1]
|
||||
current_entry.title = line[date_length+1:]
|
||||
current_entry.date = new_date
|
||||
except ValueError:
|
||||
if current_entry:
|
||||
current_entry.body += line + "\n"
|
||||
|
||||
# Append last entry
|
||||
if current_entry:
|
||||
entries.append(current_entry)
|
||||
|
||||
# Now, update our current entries if they changed
|
||||
for entry in entries:
|
||||
entry.parse_tags()
|
||||
matched_entries = [e for e in self.entries if e.uuid.lower() == entry.uuid]
|
||||
if matched_entries:
|
||||
# This entry is an existing entry
|
||||
match = matched_entries[0]
|
||||
if match != entry:
|
||||
self.entries.remove(match)
|
||||
entry.modified = True
|
||||
self.entries.append(entry)
|
||||
else:
|
||||
# This entry seems to be new... save it.
|
||||
entry.modified = True
|
||||
self.entries.append(entry)
|
||||
# Remove deleted entries
|
||||
edited_uuids = [e.uuid for e in entries]
|
||||
self._deleted_entries = [e for e in self.entries if e.uuid not in edited_uuids]
|
||||
self.entries[:] = [e for e in self.entries if e.uuid in edited_uuids]
|
||||
return entries
|
||||
|
||||
|
|
15
jrnl/cli.py
15
jrnl/cli.py
|
@ -219,14 +219,15 @@ def run(manual_args=None):
|
|||
other_entries = [e for e in old_entries if e not in journal.entries]
|
||||
# Edit
|
||||
old_num_entries = len(journal)
|
||||
template = u"\n".join([e.__unicode__() for e in journal.entries])
|
||||
edited = util.get_text_from_editor(config, template)
|
||||
journal.entries = journal.parse(edited)
|
||||
edited = util.get_text_from_editor(config, journal.editable_str())
|
||||
journal.parse_editable_str(edited)
|
||||
num_deleted = old_num_entries - len(journal)
|
||||
if num_deleted:
|
||||
util.prompt("[Deleted {0} entries]".format(num_deleted))
|
||||
else:
|
||||
util.prompt("[Edited {0} entries]".format(len(journal)))
|
||||
num_edited = len([e for e in journal.entries if e.modified])
|
||||
prompts = []
|
||||
if num_deleted: prompts.append("{0} entries deleted".format(num_deleted))
|
||||
if num_edited: prompts.append("{0} entries modified".format(num_edited))
|
||||
if prompts:
|
||||
util.prompt("[{0}]".format(", ".join(prompts).capitalize()))
|
||||
journal.entries += other_entries
|
||||
journal.write()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue