mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 08:38:32 +02:00
Merge pull request #347 from MinchinWeb/2.0-rc1-markdown-export-fix
2.0 rc1 markdown export fix
This commit is contained in:
commit
0d1b381bd1
12 changed files with 225 additions and 16 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -50,3 +50,6 @@ docs/_themes/jrnl/static/less/3L.less
|
|||
|
||||
# export testing director
|
||||
exp/
|
||||
|
||||
_extras/
|
||||
*.sublime-*
|
||||
|
|
11
features/data/configs/markdown-headings-335.yaml
Normal file
11
features/data/configs/markdown-headings-335.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
default_hour: 9
|
||||
default_minute: 0
|
||||
editor: ''
|
||||
encrypt: false
|
||||
highlight: true
|
||||
journals:
|
||||
default: features/journals/markdown-headings-335.journal
|
||||
linewrap: 80
|
||||
password: ''
|
||||
tagsymbols: '@'
|
||||
timeformat: '%Y-%m-%d %H:%M'
|
42
features/data/journals/markdown-headings-335.journal
Normal file
42
features/data/journals/markdown-headings-335.journal
Normal file
|
@ -0,0 +1,42 @@
|
|||
[2015-04-14 13:23] Heading Test
|
||||
|
||||
H1-1
|
||||
=
|
||||
|
||||
H1-2
|
||||
===
|
||||
|
||||
H1-3
|
||||
============================
|
||||
|
||||
H2-1
|
||||
-
|
||||
|
||||
H2-2
|
||||
---
|
||||
|
||||
H2-3
|
||||
----------------------------------
|
||||
|
||||
Horizontal Rules (ignore)
|
||||
|
||||
---
|
||||
|
||||
===
|
||||
|
||||
# ATX H1
|
||||
|
||||
## ATX H2
|
||||
|
||||
### ATX H3
|
||||
|
||||
#### ATX H4
|
||||
|
||||
##### ATX H5
|
||||
|
||||
###### ATX H6
|
||||
|
||||
Stuff
|
||||
|
||||
More stuff
|
||||
more stuff again
|
|
@ -26,3 +26,52 @@ Feature: Exporting a Journal
|
|||
Then we should get no error
|
||||
and the output should be parsable as json
|
||||
and the json output should contain entries.0.uuid = "4BB1F46946AD439996C9B59DE7C4DDC1"
|
||||
|
||||
Scenario: Increasing Headings on Markdown export
|
||||
Given we use the config "markdown-headings-335.yaml"
|
||||
When we run "jrnl --export markdown"
|
||||
Then the output should be
|
||||
"""
|
||||
2015
|
||||
====
|
||||
|
||||
April
|
||||
-----
|
||||
|
||||
### 2015-04-14 13:23 Heading Test
|
||||
|
||||
#### H1-1
|
||||
|
||||
#### H1-2
|
||||
|
||||
#### H1-3
|
||||
|
||||
##### H2-1
|
||||
|
||||
##### H2-2
|
||||
|
||||
##### H2-3
|
||||
|
||||
Horizontal Rules (ignore)
|
||||
|
||||
---
|
||||
|
||||
===
|
||||
|
||||
#### ATX H1
|
||||
|
||||
##### ATX H2
|
||||
|
||||
###### ATX H3
|
||||
|
||||
####### ATX H4
|
||||
|
||||
######## ATX H5
|
||||
|
||||
######### ATX H6
|
||||
|
||||
Stuff
|
||||
|
||||
More stuff
|
||||
more stuff again
|
||||
"""
|
||||
|
|
|
@ -271,6 +271,3 @@ def run(manual_args=None):
|
|||
journal.entries += other_entries
|
||||
journal.sort()
|
||||
journal.write()
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
|
|
|
@ -8,6 +8,7 @@ import importlib
|
|||
|
||||
|
||||
class PluginMeta(type):
|
||||
|
||||
def __init__(cls, name, bases, attrs):
|
||||
"""Called when a Plugin derived class is imported"""
|
||||
if not hasattr(cls, 'PLUGINS'):
|
||||
|
|
|
@ -1,33 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
from .text_exporter import TextExporter
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
class MarkdownExporter(TextExporter):
|
||||
"""This Exporter can convert entries and journals into json."""
|
||||
"""This Exporter can convert entries and journals into Markdown."""
|
||||
names = ["md", "markdown"]
|
||||
extension = "md"
|
||||
|
||||
@classmethod
|
||||
def export_entry(cls, entry):
|
||||
def export_entry(cls, entry, to_multifile=True):
|
||||
"""Returns a markdown representation of a single entry."""
|
||||
date_str = entry.date.strftime(entry.journal.config['timeformat'])
|
||||
body_wrapper = "\n" if entry.body else ""
|
||||
body = body_wrapper + entry.body
|
||||
|
||||
if to_multifile is True:
|
||||
heading = '#'
|
||||
else:
|
||||
heading = '###'
|
||||
|
||||
'''Increase heading levels in body text'''
|
||||
newbody = ''
|
||||
previous_line = ''
|
||||
warn_on_heading_level = False
|
||||
for line in body.splitlines(True):
|
||||
if re.match(r"#+ ", line):
|
||||
"""ATX style headings"""
|
||||
newbody = newbody + previous_line + heading + line
|
||||
if re.match(r"#######+ ", heading + line):
|
||||
warn_on_heading_level = True
|
||||
line = ''
|
||||
elif re.match(r"=+$", line) and not re.match(r"^$", previous_line):
|
||||
"""Setext style H1"""
|
||||
newbody = newbody + heading + "# " + previous_line
|
||||
line = ''
|
||||
elif re.match(r"-+$", line) and not re.match(r"^$", previous_line):
|
||||
"""Setext style H2"""
|
||||
newbody = newbody + heading + "## " + previous_line
|
||||
line = ''
|
||||
else:
|
||||
newbody = newbody + previous_line
|
||||
previous_line = line
|
||||
newbody = newbody + previous_line # add very last line
|
||||
|
||||
if warn_on_heading_level is True:
|
||||
print("{}WARNING{}: Headings increased past H6 on export - {} {}".format("\033[33m", "\033[0m", date_str, entry.title), file=sys.stderr)
|
||||
|
||||
return "{md} {date} {title} {body} {space}".format(
|
||||
md="###",
|
||||
md=heading,
|
||||
date=date_str,
|
||||
title=entry.title,
|
||||
body=body,
|
||||
body=newbody,
|
||||
space=""
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def export_journal(cls, journal):
|
||||
"""Returns a json representation of an entire journal."""
|
||||
"""Returns a Markdown representation of an entire journal."""
|
||||
out = []
|
||||
year, month = -1, -1
|
||||
for e in journal.entries:
|
||||
|
@ -39,6 +73,6 @@ class MarkdownExporter(TextExporter):
|
|||
month = e.date.month
|
||||
out.append(e.date.strftime("%B"))
|
||||
out.append('-' * len(e.date.strftime("%B")) + "\n")
|
||||
out.append(cls.export_entry(e))
|
||||
out.append(cls.export_entry(e, False))
|
||||
result = "\n".join(out)
|
||||
return result
|
||||
|
|
|
@ -7,18 +7,18 @@ from .util import get_tags_count
|
|||
|
||||
|
||||
class TagExporter(TextExporter):
|
||||
"""This Exporter can convert entries and journals into json."""
|
||||
"""This Exporter can lists the tags for entries and journals, exported as a plain text file."""
|
||||
names = ["tags"]
|
||||
extension = "tags"
|
||||
|
||||
@classmethod
|
||||
def export_entry(cls, entry):
|
||||
"""Returns a markdown representation of a single entry."""
|
||||
"""Returns a list of tags for a single entry."""
|
||||
return ", ".join(entry.tags)
|
||||
|
||||
@classmethod
|
||||
def export_journal(cls, journal):
|
||||
"""Returns a json representation of an entire journal."""
|
||||
"""Returns a list of tags and their frequency for an entire journal."""
|
||||
tag_counts = get_tags_count(journal)
|
||||
result = ""
|
||||
if not tag_counts:
|
||||
|
|
|
@ -56,7 +56,7 @@ class TextExporter(BaseExporter):
|
|||
representation as unicode if output is None."""
|
||||
if output and os.path.isdir(output): # multiple files
|
||||
return cls.write_files(journal, output)
|
||||
elif output:
|
||||
elif output: # single file
|
||||
return cls.write_file(journal, output)
|
||||
else:
|
||||
return cls.export_journal(journal)
|
||||
|
|
70
jrnl/plugins/yaml_exporter.py
Normal file
70
jrnl/plugins/yaml_exporter.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
from .text_exporter import TextExporter
|
||||
import re
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
|
||||
class MarkdownExporter(TextExporter):
|
||||
"""This Exporter can convert entries and journals into Markdown with YAML front matter."""
|
||||
names = ["yaml"]
|
||||
extension = "md"
|
||||
|
||||
@classmethod
|
||||
def export_entry(cls, entry, to_multifile=True):
|
||||
"""Returns a markdown representation of a single entry, with YAML front matter."""
|
||||
if to_multifile is False:
|
||||
print("{}ERROR{}: YAML export must be to individual files. Please specify a directory to export to.".format("\033[31m", "\033[0m", file=sys.stderr))
|
||||
return
|
||||
|
||||
date_str = entry.date.strftime(entry.journal.config['timeformat'])
|
||||
body_wrapper = "\n" if entry.body else ""
|
||||
body = body_wrapper + entry.body
|
||||
|
||||
'''Increase heading levels in body text'''
|
||||
newbody = ''
|
||||
heading = '###'
|
||||
previous_line = ''
|
||||
warn_on_heading_level = False
|
||||
for line in entry.body.splitlines(True):
|
||||
if re.match(r"#+ ", line):
|
||||
"""ATX style headings"""
|
||||
newbody = newbody + previous_line + heading + line
|
||||
if re.match(r"#######+ ", heading + line):
|
||||
warn_on_heading_level = True
|
||||
line = ''
|
||||
elif re.match(r"=+$", line) and not re.match(r"^$", previous_line):
|
||||
"""Setext style H1"""
|
||||
newbody = newbody + heading + "# " + previous_line
|
||||
line = ''
|
||||
elif re.match(r"-+$", line) and not re.match(r"^$", previous_line):
|
||||
"""Setext style H2"""
|
||||
newbody = newbody + heading + "## " + previous_line
|
||||
line = ''
|
||||
else:
|
||||
newbody = newbody + previous_line
|
||||
previous_line = line
|
||||
newbody = newbody + previous_line # add very last line
|
||||
|
||||
if warn_on_heading_level is True:
|
||||
print("{}WARNING{}: Headings increased past H6 on export - {} {}".format("\033[33m", "\033[0m", date_str, entry.title), file=sys.stderr)
|
||||
|
||||
# top = yaml.dump(entry)
|
||||
|
||||
return "title: {title}\ndate: {date}\nstared: {stared}\ntags: {tags}\n{body} {space}".format(
|
||||
date=date_str,
|
||||
title=entry.title,
|
||||
stared=entry.starred,
|
||||
tags=', '.join([tag[1:] for tag in entry.tags]),
|
||||
body=newbody,
|
||||
space=""
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def export_journal(cls, journal):
|
||||
"""Returns an error, as YAML export requires a directory as a target."""
|
||||
print("{}ERROR{}: YAML export must be to individual files. Please specify a directory to export to.".format("\033[31m", "\033[0m", file=sys.stderr))
|
||||
return
|
|
@ -146,6 +146,8 @@ def slugify(string):
|
|||
"""
|
||||
string = u(string)
|
||||
ascii_string = str(unicodedata.normalize('NFKD', string).encode('ascii', 'ignore'))
|
||||
if PY3:
|
||||
ascii_string = ascii_string[1:] # removed the leading 'b'
|
||||
no_punctuation = re.sub(r'[^\w\s-]', '', ascii_string).strip().lower()
|
||||
slug = re.sub(r'[-\s]+', '-', no_punctuation)
|
||||
return u(slug)
|
||||
|
|
4
setup.py
4
setup.py
|
@ -78,12 +78,12 @@ setup(
|
|||
name="jrnl",
|
||||
version=get_version(),
|
||||
description="A command line journal application that stores your journal in a plain text file",
|
||||
packages=['jrnl'],
|
||||
packages=['jrnl', 'jrnl.plugins'],
|
||||
install_requires=[
|
||||
"parsedatetime>=1.2",
|
||||
"pytz>=2013b",
|
||||
"six>=1.7.4",
|
||||
"cryptography==0.8.1",
|
||||
"cryptography>=0.8.1",
|
||||
"tzlocal>=1.1",
|
||||
"pyyaml>=3.11",
|
||||
"keyring>=3.3",
|
||||
|
|
Loading…
Add table
Reference in a new issue