mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-08-26 12:46:08 +00:00
doc: wikiparser: Preserve spaces during parsing and generation
- Matches the original XML more accurately and simplifies some parsing. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
aa27037c71
commit
d760ee004f
@ -166,10 +166,7 @@ class Paragraph(Element):
|
|||||||
xml = ''
|
xml = ''
|
||||||
|
|
||||||
for item_xml in items_xml:
|
for item_xml in items_xml:
|
||||||
if item_xml[0] in '.,:;-_!?':
|
xml += item_xml
|
||||||
xml += item_xml
|
|
||||||
else:
|
|
||||||
xml += ' ' + item_xml
|
|
||||||
|
|
||||||
return f'<para>{xml}</para>'
|
return f'<para>{xml}</para>'
|
||||||
|
|
||||||
@ -555,7 +552,6 @@ def split_formatted(text, delimiter, end_delimiter=None):
|
|||||||
Return (formatted_text, remaining_text) if it is found.
|
Return (formatted_text, remaining_text) if it is found.
|
||||||
Return (None, text) otherwise.
|
Return (None, text) otherwise.
|
||||||
"""
|
"""
|
||||||
text = text.strip()
|
|
||||||
end_delimiter = end_delimiter or delimiter
|
end_delimiter = end_delimiter or delimiter
|
||||||
content = None
|
content = None
|
||||||
if text.startswith(delimiter):
|
if text.startswith(delimiter):
|
||||||
@ -698,7 +694,6 @@ def parse_text(line, context=None, parse_links=True):
|
|||||||
content = re.split(r"''|`|{{|__|\[\[", line)[0]
|
content = re.split(r"''|`|{{|__|\[\[", line)[0]
|
||||||
if content:
|
if content:
|
||||||
line = line.replace(content, '', 1)
|
line = line.replace(content, '', 1)
|
||||||
content = content.strip()
|
|
||||||
result += parse_plain_text(content, parse_links=parse_links)
|
result += parse_plain_text(content, parse_links=parse_links)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -711,7 +706,6 @@ def parse_plain_text(content, parse_links=True):
|
|||||||
"""Parse a line or plain text and generate plain text and URL objects."""
|
"""Parse a line or plain text and generate plain text and URL objects."""
|
||||||
result = []
|
result = []
|
||||||
while content:
|
while content:
|
||||||
content = content.strip()
|
|
||||||
wiki_link_match = re.search(
|
wiki_link_match = re.search(
|
||||||
r'(?: |^)([A-Z][a-z0-9]+([A-Z][a-z0-9]+)+)(?: |$)', content)
|
r'(?: |^)([A-Z][a-z0-9]+([A-Z][a-z0-9]+)+)(?: |$)', content)
|
||||||
link_match = re.search(r'(https?://[^<> ]+[^<> .:\(\)])', content)
|
link_match = re.search(r'(https?://[^<> ]+[^<> .:\(\)])', content)
|
||||||
@ -737,9 +731,6 @@ def parse_plain_text(content, parse_links=True):
|
|||||||
# Replace occurrences of !WikiText with WikiText
|
# Replace occurrences of !WikiText with WikiText
|
||||||
text = re.sub(r'([^A-Za-z]|^)!', r'\g<1>', text)
|
text = re.sub(r'([^A-Za-z]|^)!', r'\g<1>', text)
|
||||||
|
|
||||||
# Gobble multiple spaces
|
|
||||||
text = re.sub(r' +', r' ', text)
|
|
||||||
|
|
||||||
result.append(PlainText(text))
|
result.append(PlainText(text))
|
||||||
|
|
||||||
if end:
|
if end:
|
||||||
@ -755,8 +746,8 @@ def parse_table_row(line, context=None):
|
|||||||
row_cells = re.split(r'\|\|', line)[1:-1]
|
row_cells = re.split(r'\|\|', line)[1:-1]
|
||||||
row_items = []
|
row_items = []
|
||||||
for cell in row_cells:
|
for cell in row_cells:
|
||||||
content = cell.strip()
|
content = cell
|
||||||
if content:
|
if content.strip():
|
||||||
# remove <tablestyle=...> that was already processed
|
# remove <tablestyle=...> that was already processed
|
||||||
content = re.sub('<tablestyle=[^>]+>', '', content)
|
content = re.sub('<tablestyle=[^>]+>', '', content)
|
||||||
align = None
|
align = None
|
||||||
@ -804,8 +795,21 @@ def parse_list(list_data, context=None):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
content = list_data.pop(0)[2]
|
content = list_data.pop(0)[2]
|
||||||
|
new_content = ''
|
||||||
|
in_code_block = False
|
||||||
|
for line in content.splitlines(True):
|
||||||
|
if line.startswith(' ' * current_level) and not in_code_block:
|
||||||
|
line = line[current_level:]
|
||||||
|
|
||||||
|
if line.strip().startswith('{{{'):
|
||||||
|
in_code_block = True
|
||||||
|
elif line.strip().startswith('}}}'):
|
||||||
|
in_code_block = False
|
||||||
|
|
||||||
|
new_content += line
|
||||||
|
|
||||||
parsed_list.add_item(
|
parsed_list.add_item(
|
||||||
ListItem(parse_wiki(content, context),
|
ListItem(parse_wiki(new_content, context),
|
||||||
override_marker=override_marker))
|
override_marker=override_marker))
|
||||||
|
|
||||||
return parsed_list, list_data
|
return parsed_list, list_data
|
||||||
@ -885,91 +889,94 @@ def parse_wiki(text, context=None, begin_marker=None, end_marker=None):
|
|||||||
[Heading(5, 'heading 5th level')]
|
[Heading(5, 'heading 5th level')]
|
||||||
|
|
||||||
>>> parse_wiki('plain text')
|
>>> parse_wiki('plain text')
|
||||||
[Paragraph([PlainText('plain text')])]
|
[Paragraph([PlainText('plain text ')])]
|
||||||
>>> parse_wiki(' plain multispaced text ')
|
>>> parse_wiki(' plain multispaced text ')
|
||||||
[Paragraph([PlainText('plain multispaced text')])]
|
[Paragraph([PlainText(' plain multispaced text ')])]
|
||||||
>>> parse_wiki('https://freedombox.org')
|
>>> parse_wiki('https://freedombox.org')
|
||||||
[Paragraph([Url('https://freedombox.org')])]
|
[Paragraph([Url('https://freedombox.org'), PlainText(' ')])]
|
||||||
>>> parse_wiki("''italic''")
|
>>> parse_wiki("''italic''")
|
||||||
[Paragraph([ItalicText('italic')])]
|
[Paragraph([ItalicText('italic'), PlainText(' ')])]
|
||||||
>>> parse_wiki("'''bold'''")
|
>>> parse_wiki("'''bold'''")
|
||||||
[Paragraph([BoldText('bold')])]
|
[Paragraph([BoldText('bold'), PlainText(' ')])]
|
||||||
>>> parse_wiki("normal text followed by '''bold text'''")
|
>>> parse_wiki("normal text followed by '''bold text'''")
|
||||||
[Paragraph([PlainText('normal text followed by'), BoldText('bold text')])]
|
[Paragraph([PlainText('normal text followed by '), BoldText('bold text'), \
|
||||||
|
PlainText(' ')])]
|
||||||
>>> parse_wiki('`monospace`')
|
>>> parse_wiki('`monospace`')
|
||||||
[Paragraph([MonospaceText('monospace')])]
|
[Paragraph([MonospaceText('monospace'), PlainText(' ')])]
|
||||||
>>> parse_wiki('{{{code}}}')
|
>>> parse_wiki('{{{code}}}')
|
||||||
[Paragraph([CodeText('code')])]
|
[Paragraph([CodeText('code'), PlainText(' ')])]
|
||||||
>>> parse_wiki('__underline__')
|
>>> parse_wiki('__underline__')
|
||||||
[Paragraph([UnderlineText('underline')])]
|
[Paragraph([UnderlineText('underline'), PlainText(' ')])]
|
||||||
>>> parse_wiki('~-smaller text-~')
|
>>> parse_wiki('~-smaller text-~')
|
||||||
[Paragraph([SmallerTextWarning(), PlainText('smaller text')])]
|
[Paragraph([SmallerTextWarning(), PlainText('smaller text ')])]
|
||||||
>>> parse_wiki('!FreedomBox')
|
>>> parse_wiki('!FreedomBox')
|
||||||
[Paragraph([PlainText('FreedomBox')])]
|
[Paragraph([PlainText('FreedomBox ')])]
|
||||||
>>> parse_wiki('making a point!')
|
>>> parse_wiki('making a point!')
|
||||||
[Paragraph([PlainText('making a point!')])]
|
[Paragraph([PlainText('making a point! ')])]
|
||||||
>>> parse_wiki('Back to [[FreedomBox/Manual|manual]] page.')
|
>>> parse_wiki('Back to [[FreedomBox/Manual|manual]] page.')
|
||||||
[Paragraph([PlainText('Back to'), Link('FreedomBox/Manual', \
|
[Paragraph([PlainText('Back to '), Link('FreedomBox/Manual', \
|
||||||
[PlainText('manual')]), PlainText('page.')])]
|
[PlainText('manual')]), PlainText(' page. ')])]
|
||||||
>>> parse_wiki('[[attachment:Searx.webm|Searx installation and first steps\
|
>>> parse_wiki('[[attachment:Searx.webm|Searx installation and first steps\
|
||||||
|&do=get]]')
|
|&do=get]]')
|
||||||
[Paragraph([Link('attachment:Searx.webm', \
|
[Paragraph([Link('attachment:Searx.webm', \
|
||||||
[PlainText('Searx installation and first steps')], '&do=get')])]
|
[PlainText('Searx installation and first steps')], '&do=get'), \
|
||||||
|
PlainText(' ')])]
|
||||||
>>> parse_wiki('[[https://onionshare.org/|Onionshare]]')
|
>>> parse_wiki('[[https://onionshare.org/|Onionshare]]')
|
||||||
[Paragraph([Link('https://onionshare.org/', [PlainText('Onionshare')])])]
|
[Paragraph([Link('https://onionshare.org/', [PlainText('Onionshare')]), \
|
||||||
|
PlainText(' ')])]
|
||||||
|
|
||||||
>>> parse_wiki('/!\\\\')
|
>>> parse_wiki('/!\\\\')
|
||||||
[Paragraph([EmbeddedAttachment('icons/alert.png', \
|
[Paragraph([EmbeddedAttachment('icons/alert.png', \
|
||||||
[PlainText('icons/alert.png')], 'height=20')])]
|
[PlainText('icons/alert.png')], 'height=20'), PlainText(' ')])]
|
||||||
>>> parse_wiki('(./)')
|
>>> parse_wiki('(./)')
|
||||||
[Paragraph([EmbeddedAttachment('icons/checkmark.png', \
|
[Paragraph([EmbeddedAttachment('icons/checkmark.png', \
|
||||||
[PlainText('icons/checkmark.png')], 'height=20')])]
|
[PlainText('icons/checkmark.png')], 'height=20'), PlainText(' ')])]
|
||||||
>>> parse_wiki('{X}')
|
>>> parse_wiki('{X}')
|
||||||
[Paragraph([EmbeddedAttachment('icons/icon-error.png', \
|
[Paragraph([EmbeddedAttachment('icons/icon-error.png', \
|
||||||
[PlainText('icons/icon-error.png')], 'height=20')])]
|
[PlainText('icons/icon-error.png')], 'height=20'), PlainText(' ')])]
|
||||||
>>> parse_wiki('{i}')
|
>>> parse_wiki('{i}')
|
||||||
[Paragraph([EmbeddedAttachment('icons/icon-info.png', \
|
[Paragraph([EmbeddedAttachment('icons/icon-info.png', \
|
||||||
[PlainText('icons/icon-info.png')], 'height=20')])]
|
[PlainText('icons/icon-info.png')], 'height=20'), PlainText(' ')])]
|
||||||
>>> parse_wiki('{o}')
|
>>> parse_wiki('{o}')
|
||||||
[Paragraph([EmbeddedAttachment('icons/star_off.png', \
|
[Paragraph([EmbeddedAttachment('icons/star_off.png', \
|
||||||
[PlainText('icons/star_off.png')], 'height=20')])]
|
[PlainText('icons/star_off.png')], 'height=20'), PlainText(' ')])]
|
||||||
>>> parse_wiki('{*}')
|
>>> parse_wiki('{*}')
|
||||||
[Paragraph([EmbeddedAttachment('icons/star_on.png', \
|
[Paragraph([EmbeddedAttachment('icons/star_on.png', \
|
||||||
[PlainText('icons/star_on.png')], 'height=20')])]
|
[PlainText('icons/star_on.png')], 'height=20'), PlainText(' ')])]
|
||||||
|
|
||||||
>>> parse_wiki('{{attachment:cockpit-enable.png}}')
|
>>> parse_wiki('{{attachment:cockpit-enable.png}}')
|
||||||
[Paragraph([EmbeddedAttachment('cockpit-enable.png', \
|
[Paragraph([EmbeddedAttachment('cockpit-enable.png', \
|
||||||
[PlainText('cockpit-enable.png')])])]
|
[PlainText('cockpit-enable.png')]), PlainText(' ')])]
|
||||||
>>> parse_wiki('{{attachment:Backups_Step1_v49.png|Backups: Step 1|\
|
>>> parse_wiki('{{attachment:Backups_Step1_v49.png|Backups: Step 1|\
|
||||||
width=800}}')
|
width=800}}')
|
||||||
[Paragraph([EmbeddedAttachment('Backups_Step1_v49.png', \
|
[Paragraph([EmbeddedAttachment('Backups_Step1_v49.png', \
|
||||||
[PlainText('Backups: Step 1')], 'width=800')])]
|
[PlainText('Backups: Step 1')], 'width=800'), PlainText(' ')])]
|
||||||
|
|
||||||
>>> parse_wiki(' * single item')
|
>>> parse_wiki(' * single item')
|
||||||
[List('bulleted', [ListItem([Paragraph([PlainText('single item')])])])]
|
[List('bulleted', [ListItem([Paragraph([PlainText('single item ')])])])]
|
||||||
>>> parse_wiki(' * first item\\n * second item')
|
>>> parse_wiki(' * first item\\n * second item')
|
||||||
[List('bulleted', [ListItem([Paragraph([PlainText('first item')])]), \
|
[List('bulleted', [ListItem([Paragraph([PlainText('first item ')])]), \
|
||||||
ListItem([Paragraph([PlainText('second item')])])])]
|
ListItem([Paragraph([PlainText('second item ')])])])]
|
||||||
>>> parse_wiki('text to introduce\\n * a list')
|
>>> parse_wiki('text to introduce\\n * a list')
|
||||||
[Paragraph([PlainText('text to introduce')]), \
|
[Paragraph([PlainText('text to introduce ')]), \
|
||||||
List('bulleted', [ListItem([Paragraph([PlainText('a list')])])])]
|
List('bulleted', [ListItem([Paragraph([PlainText('a list ')])])])]
|
||||||
>>> parse_wiki(' . first item\\n . second item')
|
>>> parse_wiki(' . first item\\n . second item')
|
||||||
[List('plain', [ListItem([Paragraph([PlainText('first item')])]), \
|
[List('plain', [ListItem([Paragraph([PlainText('first item ')])]), \
|
||||||
ListItem([Paragraph([PlainText('second item')])])])]
|
ListItem([Paragraph([PlainText('second item ')])])])]
|
||||||
>>> parse_wiki(' * item 1\\n * item 1.1')
|
>>> parse_wiki(' * item 1\\n * item 1.1')
|
||||||
[List('bulleted', [ListItem([Paragraph([PlainText('item 1')]), \
|
[List('bulleted', [ListItem([Paragraph([PlainText('item 1 ')]), \
|
||||||
List('bulleted', [ListItem([Paragraph([PlainText('item 1.1')])])])])])]
|
List('bulleted', [ListItem([Paragraph([PlainText('item 1.1 ')])])])])])]
|
||||||
>>> parse_wiki(' 1. item 1\\n 1. item 1.1')
|
>>> parse_wiki(' 1. item 1\\n 1. item 1.1')
|
||||||
[List('numbered', [ListItem([Paragraph([PlainText('item 1')]), \
|
[List('numbered', [ListItem([Paragraph([PlainText('item 1 ')]), \
|
||||||
List('numbered', [ListItem([Paragraph([PlainText('item 1.1')])])])])])]
|
List('numbered', [ListItem([Paragraph([PlainText('item 1.1 ')])])])])])]
|
||||||
>>> parse_wiki(' * single,\\n multiline item')
|
>>> parse_wiki(' * single,\\n multiline item')
|
||||||
[List('bulleted', \
|
[List('bulleted', \
|
||||||
[ListItem([Paragraph([PlainText('single,'), \
|
[ListItem([Paragraph([PlainText('single, '), \
|
||||||
PlainText('multiline item')])])])]
|
PlainText('multiline item ')])])])]
|
||||||
>>> parse_wiki(' * single,\\n \\n multipara item')
|
>>> parse_wiki(' * single,\\n \\n multipara item')
|
||||||
[List('bulleted', \
|
[List('bulleted', \
|
||||||
[ListItem([Paragraph([PlainText('single,')]), \
|
[ListItem([Paragraph([PlainText('single, ')]), \
|
||||||
Paragraph([PlainText('multipara item')])])])]
|
Paragraph([PlainText('multipara item ')])])])]
|
||||||
|
|
||||||
>>> parse_wiki('----')
|
>>> parse_wiki('----')
|
||||||
[HorizontalRule(4)]
|
[HorizontalRule(4)]
|
||||||
@ -980,9 +987,9 @@ Paragraph([PlainText('multipara item')])])])]
|
|||||||
[Table([TableRow([TableItem([Paragraph([BoldText('A')])]), \
|
[Table([TableRow([TableItem([Paragraph([BoldText('A')])]), \
|
||||||
TableItem([Paragraph([BoldText('B')])]), \
|
TableItem([Paragraph([BoldText('B')])]), \
|
||||||
TableItem([Paragraph([BoldText('C')])])]), \
|
TableItem([Paragraph([BoldText('C')])])]), \
|
||||||
TableRow([TableItem([Paragraph([PlainText('1')])]), \
|
TableRow([TableItem([Paragraph([PlainText('1 ')])]), \
|
||||||
TableItem([Paragraph([PlainText('2')])]), \
|
TableItem([Paragraph([PlainText('2 ')])]), \
|
||||||
TableItem([Paragraph([PlainText('3')])])])])]
|
TableItem([Paragraph([PlainText('3 ')])])])])]
|
||||||
|
|
||||||
>>> parse_wiki("||<tablestyle='border:1px solid black;width: 80%'>A||")
|
>>> parse_wiki("||<tablestyle='border:1px solid black;width: 80%'>A||")
|
||||||
[Table([TableRow([TableItem([Paragraph([PlainText('A')])])])], \
|
[Table([TableRow([TableItem([Paragraph([PlainText('A')])])])], \
|
||||||
@ -1020,52 +1027,53 @@ from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>')
|
|||||||
|
|
||||||
>>> parse_wiki('a\\n\\n## END_INCLUDE\\n\\nb', \
|
>>> parse_wiki('a\\n\\n## END_INCLUDE\\n\\nb', \
|
||||||
None, None, '## END_INCLUDE')
|
None, None, '## END_INCLUDE')
|
||||||
[Paragraph([PlainText('a')])]
|
[Paragraph([PlainText('a ')])]
|
||||||
>>> parse_wiki('a\\n\\n## BEGIN_INCLUDE\\n\\nb' \
|
>>> parse_wiki('a\\n\\n## BEGIN_INCLUDE\\n\\nb' \
|
||||||
'\\n\\n## END_INCLUDE\\n\\nc', \
|
'\\n\\n## END_INCLUDE\\n\\nc', \
|
||||||
None, '## BEGIN_INCLUDE', '## END_INCLUDE')
|
None, '## BEGIN_INCLUDE', '## END_INCLUDE')
|
||||||
[Paragraph([PlainText('b')])]
|
[Paragraph([PlainText('b ')])]
|
||||||
|
|
||||||
>>> parse_wiki('a<<BR>>\\nb')
|
>>> parse_wiki('a<<BR>>\\nb')
|
||||||
[Paragraph([PlainText('a')]), Paragraph([PlainText('b')])]
|
[Paragraph([PlainText('a')]), Paragraph([PlainText('b ')])]
|
||||||
>>> parse_wiki('{{{#!wiki caution\\n\\nOnce some other app is set as the \
|
>>> parse_wiki('{{{#!wiki caution\\n\\nOnce some other app is set as the \
|
||||||
home page, you can only navigate to the !FreedomBox Service (Plinth) by \
|
home page, you can only navigate to the !FreedomBox Service (Plinth) by \
|
||||||
typing https://myfreedombox.rocks/plinth/ into the browser. <<BR>>\\n\
|
typing https://myfreedombox.rocks/plinth/ into the browser. <<BR>>\\n\
|
||||||
''/freedombox'' can also be used as an alias to ''/plinth''\\n}}}')
|
''/freedombox'' can also be used as an alias to ''/plinth''\\n}}}')
|
||||||
[Admonition('caution', [Paragraph([PlainText('Once some other app is set \
|
[Admonition('caution', [Paragraph([PlainText('Once some other app is set \
|
||||||
as the home page, you can only navigate to the FreedomBox Service (Plinth) by \
|
as the home page, you can only navigate to the FreedomBox Service (Plinth) by \
|
||||||
typing '), Url('https://myfreedombox.rocks/plinth/'), PlainText('into the \
|
typing '), Url('https://myfreedombox.rocks/plinth/'), PlainText(' into the \
|
||||||
browser.')]), Paragraph([PlainText('/freedombox can also be used as an alias \
|
browser. ')]), Paragraph([PlainText('/freedombox can also be used as an alias \
|
||||||
to /plinth')])])]
|
to /plinth')])])]
|
||||||
|
|
||||||
>>> parse_wiki('{{{\\nmulti-line\\n\
|
>>> parse_wiki('{{{\\nmulti-line\\n\
|
||||||
preformatted text (source code)\\n}}}''')
|
preformatted text (source code)\\n}}}''')
|
||||||
[CodeText('multi-line\\npreformatted text (source code)')]
|
[CodeText('multi-line\\npreformatted text (source code)')]
|
||||||
>>> parse_wiki('text to introduce {{{ a singleliner}}}')
|
>>> parse_wiki('text to introduce {{{ a singleliner}}}')
|
||||||
[Paragraph([PlainText('text to introduce'), CodeText(' a singleliner')])]
|
[Paragraph([PlainText('text to introduce '), CodeText(' a singleliner'),\
|
||||||
>>> parse_wiki('text to introduce \\n{{{\\n a multiliner\\nstarting at\
|
PlainText(' ')])]
|
||||||
|
>>> parse_wiki('text to introduce\\n{{{\\n a multiliner\\nstarting at\
|
||||||
\\n different indents.\\n}}}')
|
\\n different indents.\\n}}}')
|
||||||
[Paragraph([PlainText('text to introduce')]), \
|
[Paragraph([PlainText('text to introduce ')]), \
|
||||||
CodeText(' a multiliner\\nstarting at\\n different indents.')]
|
CodeText(' a multiliner\\nstarting at\\n different indents.')]
|
||||||
>>> parse_wiki('Blah, blah:\\n {{{\\nmulti-line\\nformatted text\\n\
|
>>> parse_wiki('Blah, blah:\\n {{{\\nmulti-line\\nformatted text\\n\
|
||||||
starting at col #1\\n}}}')
|
starting at col #1\\n}}}')
|
||||||
[Paragraph([PlainText('Blah, blah:')]), \
|
[Paragraph([PlainText('Blah, blah: ')]), \
|
||||||
CodeText('multi-line\\nformatted text\\nstarting at col #1')]
|
CodeText('multi-line\\nformatted text\\nstarting at col #1')]
|
||||||
>>> parse_wiki(' * Blah, blah:\\n {{{\\nmulti-line\\nformatted text\
|
>>> parse_wiki(' * Blah, blah:\\n {{{\\nmulti-line\\nformatted text\
|
||||||
\\nstarting at col #1\\n}}}')
|
\\nstarting at col #1\\n}}}')
|
||||||
[List('bulleted', \
|
[List('bulleted', \
|
||||||
[ListItem([Paragraph([PlainText('Blah, blah:')]), \
|
[ListItem([Paragraph([PlainText('Blah, blah: ')]), \
|
||||||
CodeText('multi-line\\nformatted text\\nstarting at col #1')])])]
|
CodeText('multi-line\\nformatted text\\nstarting at col #1')])])]
|
||||||
>>> parse_wiki(' {{{\\n nmap -p 80 --open -sV 192.168.0.0/24 \
|
>>> parse_wiki(' {{{\\n nmap -p 80 --open -sV 192.168.0.0/24 \
|
||||||
(replace the ip/netmask with the one the router uses)\\n }}}\\n In \
|
(replace the ip/netmask with the one the router uses)\\n }}}\\n In \
|
||||||
most cases you can look at your current IP address, and change the last \
|
most cases you can look at your current IP address, and change the last \
|
||||||
digits with zero to find your home network, like so: XXX.XXX.XXX.0/24')
|
digits with zero to find your home network, like so: XXX.XXX.XXX.0/24')
|
||||||
[CodeText(' nmap -p 80 --open -sV 192.168.0.0/24 (replace the \
|
[CodeText(' nmap -p 80 --open -sV 192.168.0.0/24 (replace the \
|
||||||
ip/netmask with the one the router uses)'), Paragraph([PlainText('In \
|
ip/netmask with the one the router uses)'), Paragraph([PlainText(' In \
|
||||||
most cases you can look at your current IP address, and change the last \
|
most cases you can look at your current IP address, and change the last \
|
||||||
digits with zero to find your home network, like so: XXX.XXX.XXX.0/24')])]
|
digits with zero to find your home network, like so: XXX.XXX.XXX.0/24 ')])]
|
||||||
>>> parse_wiki('text to introduce \\n----\\n<<TableOfContents()>>')
|
>>> parse_wiki('text to introduce\\n----\\n<<TableOfContents()>>')
|
||||||
[Paragraph([PlainText('text to introduce')]), \
|
[Paragraph([PlainText('text to introduce ')]), \
|
||||||
HorizontalRule(4), TableOfContents()]
|
HorizontalRule(4), TableOfContents()]
|
||||||
|
|
||||||
>>> parse_wiki(' If this command shows an error such as ''new key but \
|
>>> parse_wiki(' If this command shows an error such as ''new key but \
|
||||||
@ -1074,69 +1082,69 @@ the keys:\\n {{{\\n$ gpg --keyserver keys.gnupg.net --recv-keys \
|
|||||||
BCBEBD57A11F70B23782BC5736C361440C9BC971\\n$ gpg --keyserver keys.gnupg.net \
|
BCBEBD57A11F70B23782BC5736C361440C9BC971\\n$ gpg --keyserver keys.gnupg.net \
|
||||||
--recv-keys 7D6ADB750F91085589484BE677C0C75E7B650808\\n$ gpg --keyserver \
|
--recv-keys 7D6ADB750F91085589484BE677C0C75E7B650808\\n$ gpg --keyserver \
|
||||||
keys.gnupg.net --recv-keys 013D86D8BA32EAB4A6691BF85D4153D6FE188FC8\\n }}}')
|
keys.gnupg.net --recv-keys 013D86D8BA32EAB4A6691BF85D4153D6FE188FC8\\n }}}')
|
||||||
[Paragraph([PlainText('If this command shows an error such as new key but \
|
[Paragraph([PlainText(' If this command shows an error such as new key \
|
||||||
contains no user ID - skipped, then use a different keyserver to download the \
|
but contains no user ID - skipped, then use a different keyserver to download \
|
||||||
keys:')]), CodeText('$ gpg --keyserver keys.gnupg.net --recv-keys \
|
the keys: ')]), CodeText('$ gpg --keyserver keys.gnupg.net --recv-keys \
|
||||||
BCBEBD57A11F70B23782BC5736C361440C9BC971\\n$ gpg --keyserver keys.gnupg.net \
|
BCBEBD57A11F70B23782BC5736C361440C9BC971\\n$ gpg --keyserver keys.gnupg.net \
|
||||||
--recv-keys 7D6ADB750F91085589484BE677C0C75E7B650808\\n$ gpg --keyserver \
|
--recv-keys 7D6ADB750F91085589484BE677C0C75E7B650808\\n$ gpg --keyserver \
|
||||||
keys.gnupg.net --recv-keys 013D86D8BA32EAB4A6691BF85D4153D6FE188FC8')]
|
keys.gnupg.net --recv-keys 013D86D8BA32EAB4A6691BF85D4153D6FE188FC8')]
|
||||||
|
|
||||||
>>> parse_wiki('User documentation:\\n * List of \
|
>>> parse_wiki('User documentation:\\n * List of \
|
||||||
[[FreedomBox/Features|applications]] offered by !FreedomBox.')
|
[[FreedomBox/Features|applications]] offered by !FreedomBox.')
|
||||||
[Paragraph([PlainText('User documentation:')]), List('bulleted', \
|
[Paragraph([PlainText('User documentation: ')]), List('bulleted', \
|
||||||
[ListItem([Paragraph([PlainText('List of'), Link('FreedomBox/Features', \
|
[ListItem([Paragraph([PlainText('List of '), Link('FreedomBox/Features', \
|
||||||
[PlainText('applications')]), PlainText('offered by FreedomBox.')])])])]
|
[PlainText('applications')]), PlainText(' offered by FreedomBox. ')])])])]
|
||||||
|
|
||||||
>>> parse_wiki('\
|
>>> parse_wiki('\
|
||||||
* Within !FreedomBox Service (Plinth)\\n\
|
* Within !FreedomBox Service (Plinth)\\n\
|
||||||
1. select ''Apps''\\n\
|
1. select ''Apps''\\n\
|
||||||
2. go to ''Radicale (Calendar and Addressbook)'' and \\n\
|
2. go to ''Radicale (Calendar and Addressbook)'' and\\n\
|
||||||
3. install the application. After the installation is complete, make sure \
|
3. install the application. After the installation is complete, make sure \
|
||||||
the application is marked "enabled" in the !FreedomBox interface. Enabling \
|
the application is marked "enabled" in the !FreedomBox interface. Enabling \
|
||||||
the application launches the Radicale CalDAV/CardDAV server. \\n\
|
the application launches the Radicale CalDAV/CardDAV server.\\n\
|
||||||
4. define the access rights:\\n\
|
4. define the access rights:\\n\
|
||||||
* Only the owner of a calendar/addressbook can view or make changes\\n\
|
* Only the owner of a calendar/addressbook can view or make changes\\n\
|
||||||
* Any user can view any calendar/addressbook, but only the owner can make \
|
* Any user can view any calendar/addressbook, but only the owner can make \
|
||||||
changes\\n\
|
changes\\n\
|
||||||
* Any user can view or make changes to any calendar/addressbook')
|
* Any user can view or make changes to any calendar/addressbook')
|
||||||
[List('bulleted', [\
|
[List('bulleted', [\
|
||||||
ListItem([Paragraph([PlainText('Within FreedomBox Service (Plinth)')]), \
|
ListItem([Paragraph([PlainText('Within FreedomBox Service (Plinth) ')]), \
|
||||||
List('numbered', [ListItem([Paragraph([PlainText('select Apps')])]), \
|
List('numbered', [ListItem([Paragraph([PlainText('select Apps ')])]), \
|
||||||
ListItem([Paragraph([PlainText('go to Radicale (Calendar and Addressbook) \
|
ListItem([Paragraph([PlainText('go to Radicale (Calendar and Addressbook) \
|
||||||
and')])]), \
|
and ')])]), \
|
||||||
ListItem([Paragraph([PlainText('install the application. After the \
|
ListItem([Paragraph([PlainText('install the application. After the \
|
||||||
installation is complete, make sure the application is marked "enabled" in \
|
installation is complete, make sure the application is marked "enabled" in \
|
||||||
the FreedomBox interface. Enabling the application launches the Radicale \
|
the FreedomBox interface. Enabling the application launches the Radicale \
|
||||||
CalDAV/CardDAV server.')])]), \
|
CalDAV/CardDAV server. ')])]), \
|
||||||
ListItem([Paragraph([PlainText('define the access rights:')]), \
|
ListItem([Paragraph([PlainText('define the access rights: ')]), \
|
||||||
List('bulleted', [ListItem([Paragraph([PlainText('Only the owner of a \
|
List('bulleted', [ListItem([Paragraph([PlainText('Only the owner of a \
|
||||||
calendar/addressbook can view or make changes')])]), \
|
calendar/addressbook can view or make changes ')])]), \
|
||||||
ListItem([Paragraph([PlainText('Any user can view any calendar/addressbook, \
|
ListItem([Paragraph([PlainText('Any user can view any calendar/addressbook, \
|
||||||
but only the owner can make changes')])]), \
|
but only the owner can make changes ')])]), \
|
||||||
ListItem([Paragraph([PlainText('Any user can view or make changes to any \
|
ListItem([Paragraph([PlainText('Any user can view or make changes to any \
|
||||||
calendar/addressbook')])])])])])])])]
|
calendar/addressbook ')])])])])])])])]
|
||||||
|
|
||||||
>>> parse_wiki('[[attachment:freedombox-screenshot-home.png|\
|
>>> parse_wiki('[[attachment:freedombox-screenshot-home.png|\
|
||||||
{{attachment:freedombox-screenshot-home.png|Home Page|width=300}}]]')
|
{{attachment:freedombox-screenshot-home.png|Home Page|width=300}}]]')
|
||||||
[Paragraph([Link('attachment:freedombox-screenshot-home.png', \
|
[Paragraph([Link('attachment:freedombox-screenshot-home.png', \
|
||||||
[EmbeddedAttachment('freedombox-screenshot-home.png', \
|
[EmbeddedAttachment('freedombox-screenshot-home.png', \
|
||||||
[PlainText('Home Page')], 'width=300')])])]
|
[PlainText('Home Page')], 'width=300')]), PlainText(' ')])]
|
||||||
|
|
||||||
>>> parse_wiki(" * New wiki and manual content licence: \
|
>>> parse_wiki(" * New wiki and manual content licence: \
|
||||||
''[[https://creativecommons.org/licenses/by-sa/4.0/|Creative Commons \
|
''[[https://creativecommons.org/licenses/by-sa/4.0/|Creative Commons \
|
||||||
Attribution-ShareAlike 4.0 International]]'' (from June 13rd 2016).")
|
Attribution-ShareAlike 4.0 International]]'' (from June 13rd 2016).")
|
||||||
[List('bulleted', [ListItem([Paragraph([PlainText('New wiki and manual \
|
[List('bulleted', [ListItem([Paragraph([PlainText('New wiki and manual \
|
||||||
content licence:'), Link('https://creativecommons.org/licenses/by-sa/4.0/', \
|
content licence: '), Link('https://creativecommons.org/licenses/by-sa/4.0/', \
|
||||||
[ItalicText('Creative Commons Attribution-ShareAlike 4.0 International')]), \
|
[ItalicText('Creative Commons Attribution-ShareAlike 4.0 International')]), \
|
||||||
PlainText('(from June 13rd 2016).')])])])]
|
PlainText(' (from June 13rd 2016). ')])])])]
|
||||||
|
|
||||||
>>> parse_wiki('An alternative to downloading these images is to \
|
>>> parse_wiki('An alternative to downloading these images is to \
|
||||||
[[InstallingDebianOn/TI/BeagleBone|install Debian]] on the !BeagleBone and \
|
[[InstallingDebianOn/TI/BeagleBone|install Debian]] on the !BeagleBone and \
|
||||||
then [[FreedomBox/Hardware/Debian|install FreedomBox]] on it.')
|
then [[FreedomBox/Hardware/Debian|install FreedomBox]] on it.')
|
||||||
[Paragraph([PlainText('An alternative to downloading these images is to'),\
|
[Paragraph([PlainText('An alternative to downloading these images is to ')\
|
||||||
Link('InstallingDebianOn/TI/BeagleBone', [PlainText('install Debian')]), \
|
, Link('InstallingDebianOn/TI/BeagleBone', [PlainText('install Debian')]), \
|
||||||
PlainText('on the BeagleBone and then'), Link('FreedomBox/Hardware/Debian', \
|
PlainText(' on the BeagleBone and then '), Link('FreedomBox/Hardware/Debian', \
|
||||||
[PlainText('install FreedomBox')]), PlainText('on it.')])]
|
[PlainText('install FreedomBox')]), PlainText(' on it. ')])]
|
||||||
|
|
||||||
>>> parse_wiki("'''Synchronizing contacts'''\\n 1. Click on the hamburger \
|
>>> parse_wiki("'''Synchronizing contacts'''\\n 1. Click on the hamburger \
|
||||||
menus of CalDAV and CardDAV and select either \\"Refresh ...\\" in case of \
|
menus of CalDAV and CardDAV and select either \\"Refresh ...\\" in case of \
|
||||||
@ -1144,13 +1152,14 @@ existing accounts or \\"Create ...\\" in case of new accounts (see the second \
|
|||||||
screenshot below).\\n 1. Check the checkboxes for the address books and \
|
screenshot below).\\n 1. Check the checkboxes for the address books and \
|
||||||
calendars you want to synchronize and click on the sync button in the header. \
|
calendars you want to synchronize and click on the sync button in the header. \
|
||||||
(see the third screenshot below)")
|
(see the third screenshot below)")
|
||||||
[Paragraph([BoldText('Synchronizing contacts')]), List('numbered', \
|
[Paragraph([BoldText('Synchronizing contacts'), PlainText(' ')]), \
|
||||||
|
List('numbered', \
|
||||||
[ListItem([Paragraph([PlainText('Click on the hamburger menus of CalDAV and \
|
[ListItem([Paragraph([PlainText('Click on the hamburger menus of CalDAV and \
|
||||||
CardDAV and select either "Refresh ..." in case of existing accounts or \
|
CardDAV and select either "Refresh ..." in case of existing accounts or \
|
||||||
"Create ..." in case of new accounts (see the second screenshot below).')])]),\
|
"Create ..." in case of new accounts (see the second screenshot below). ')])]),\
|
||||||
ListItem([Paragraph([PlainText('Check the checkboxes for the address books \
|
ListItem([Paragraph([PlainText('Check the checkboxes for the address books \
|
||||||
and calendars you want to synchronize and click on the sync button in the \
|
and calendars you want to synchronize and click on the sync button in the \
|
||||||
header. (see the third screenshot below)')])])])]
|
header. (see the third screenshot below) ')])])])]
|
||||||
|
|
||||||
>>> parse_wiki("After Roundcube is installed, it can be accessed at \
|
>>> parse_wiki("After Roundcube is installed, it can be accessed at \
|
||||||
{{{https://<your freedombox>/roundcube}}}. Enter your username and password. \
|
{{{https://<your freedombox>/roundcube}}}. Enter your username and password. \
|
||||||
@ -1164,19 +1173,19 @@ the IMAP server. Using encrypted connection to your IMAP server is strongly \
|
|||||||
recommended. To do this, prepend 'imaps://' at the beginning of your IMAP \
|
recommended. To do this, prepend 'imaps://' at the beginning of your IMAP \
|
||||||
server address. For example, ''imaps://imap.example.org''.")
|
server address. For example, ''imaps://imap.example.org''.")
|
||||||
[Paragraph([PlainText('After Roundcube is installed, it can be accessed \
|
[Paragraph([PlainText('After Roundcube is installed, it can be accessed \
|
||||||
at'), CodeText('https://<your freedombox>/roundcube'), PlainText('. Enter \
|
at '), CodeText('https://<your freedombox>/roundcube'), PlainText('. Enter \
|
||||||
your username and password. The username for many mail services will be the \
|
your username and password. The username for many mail services will be the \
|
||||||
full email address such as'), ItalicText('exampleuser@example.org'), \
|
full email address such as '), ItalicText('exampleuser@example.org'), \
|
||||||
PlainText('and not just the username like'), ItalicText('exampleuser'), \
|
PlainText(' and not just the username like '), ItalicText('exampleuser'), \
|
||||||
PlainText(". Enter the address of your email service's IMAP server address in \
|
PlainText(". Enter the address of your email service's IMAP server address in \
|
||||||
the"), ItalicText('Server'), PlainText('field. You can try providing your \
|
the "), ItalicText('Server'), PlainText(' field. You can try providing your \
|
||||||
domain name here such as'), ItalicText('example.org'), PlainText('for email \
|
domain name here such as '), ItalicText('example.org'), PlainText(' for email \
|
||||||
address'), ItalicText('exampleuser@example.org'), PlainText("and if this does \
|
address '), ItalicText('exampleuser@example.org'), PlainText(" and if this \
|
||||||
not work, consult your email provider's documentation for the address of the \
|
does not work, consult your email provider's documentation for the address \
|
||||||
IMAP server. Using encrypted connection to your IMAP server is strongly \
|
of the IMAP server. Using encrypted connection to your IMAP server is \
|
||||||
recommended. To do this, prepend 'imaps://' at the beginning of your IMAP \
|
strongly recommended. To do this, prepend 'imaps://' at the beginning of \
|
||||||
server address. For example,"), ItalicText('imaps://imap.example.org'), \
|
your IMAP server address. For example, "), \
|
||||||
PlainText('.')])]
|
ItalicText('imaps://imap.example.org'), PlainText('. ')])]
|
||||||
|
|
||||||
>>> parse_wiki('Tor Browser is the recommended way to browse the web \
|
>>> parse_wiki('Tor Browser is the recommended way to browse the web \
|
||||||
using Tor. You can download the Tor Browser from \
|
using Tor. You can download the Tor Browser from \
|
||||||
@ -1184,19 +1193,19 @@ https://www.torproject.org/projects/torbrowser.html and follow the \
|
|||||||
instructions on that site to install and run it.')
|
instructions on that site to install and run it.')
|
||||||
[Paragraph([PlainText('Tor Browser is the recommended way to browse the \
|
[Paragraph([PlainText('Tor Browser is the recommended way to browse the \
|
||||||
web using Tor. You can download the Tor Browser from '), Url('\
|
web using Tor. You can download the Tor Browser from '), Url('\
|
||||||
https://www.torproject.org/projects/torbrowser.html'), PlainText('and follow \
|
https://www.torproject.org/projects/torbrowser.html'), PlainText(' and follow \
|
||||||
the instructions on that site to install and run it.')])]
|
the instructions on that site to install and run it. ')])]
|
||||||
|
|
||||||
>>> parse_wiki('After installation a web page becomes available on \
|
>>> parse_wiki('After installation a web page becomes available on \
|
||||||
https://<your-freedombox>/_minidlna.')
|
https://<your-freedombox>/_minidlna.')
|
||||||
[Paragraph([PlainText('After installation a web page becomes available on \
|
[Paragraph([PlainText('After installation a web page becomes available on \
|
||||||
https://<your-freedombox>/_minidlna.')])]
|
https://<your-freedombox>/_minidlna. ')])]
|
||||||
|
|
||||||
>>> parse_wiki('or http://10.42.0.1/.')
|
>>> parse_wiki('or http://10.42.0.1/.')
|
||||||
[Paragraph([PlainText('or '), Url('http://10.42.0.1/'), PlainText('.')])]
|
[Paragraph([PlainText('or '), Url('http://10.42.0.1/'), PlainText('. ')])]
|
||||||
|
|
||||||
>>> parse_wiki('or http://10.42.0.1/:')
|
>>> parse_wiki('or http://10.42.0.1/:')
|
||||||
[Paragraph([PlainText('or '), Url('http://10.42.0.1/'), PlainText(':')])]
|
[Paragraph([PlainText('or '), Url('http://10.42.0.1/'), PlainText(': ')])]
|
||||||
|
|
||||||
>>> parse_wiki('||<style="text-align: center;"> [[FreedomBox/Hardware/\
|
>>> parse_wiki('||<style="text-align: center;"> [[FreedomBox/Hardware/\
|
||||||
A20-OLinuXino-Lime2|{{attachment:a20-olinuxino-lime2_thumb.jpg|A20 OLinuXino \
|
A20-OLinuXino-Lime2|{{attachment:a20-olinuxino-lime2_thumb.jpg|A20 OLinuXino \
|
||||||
@ -1207,18 +1216,23 @@ MICRO|width=235,height=132}}]]<<BR>> [[FreedomBox/Hardware/A20-OLinuXino-MICRO\
|
|||||||
|A20 OLinuXino MICRO]] ||<style="text-align: center;"> [[FreedomBox/Hardware/\
|
|A20 OLinuXino MICRO]] ||<style="text-align: center;"> [[FreedomBox/Hardware/\
|
||||||
APU|{{attachment:apu1d_thumb.jpg|PC Engines APU|width=235,height=157}}]]<<BR>>\
|
APU|{{attachment:apu1d_thumb.jpg|PC Engines APU|width=235,height=157}}]]<<BR>>\
|
||||||
[[FreedomBox/Hardware/APU|PC Engines APU]] ||')
|
[[FreedomBox/Hardware/APU|PC Engines APU]] ||')
|
||||||
[Table([TableRow([TableItem([Paragraph([Link('FreedomBox/Hardware/\
|
[Table([TableRow([TableItem([Paragraph([PlainText(' '), \
|
||||||
A20-OLinuXino-Lime2', [EmbeddedAttachment('a20-olinuxino-lime2_thumb.jpg', [\
|
Link('FreedomBox/Hardware/A20-OLinuXino-Lime2', \
|
||||||
PlainText('A20 OLinuXino Lime2')], 'width=235,height=159')])]), Paragraph([\
|
[EmbeddedAttachment('a20-olinuxino-lime2_thumb.jpg', \
|
||||||
Link('FreedomBox/Hardware/A20-OLinuXino-Lime2', [PlainText('A20 OLinuXino \
|
[PlainText('A20 OLinuXino Lime2')], 'width=235,height=159')])]), \
|
||||||
Lime2')])])], 'center'), TableItem([Paragraph([Link('FreedomBox/Hardware/\
|
Paragraph([PlainText(' '), Link('FreedomBox/Hardware/A20-OLinuXino-Lime2', \
|
||||||
A20-OLinuXino-MICRO', [EmbeddedAttachment('a20-olinuxino-micro_thumb.jpg', [\
|
[PlainText('A20 OLinuXino Lime2')]), PlainText(' ')])], 'center'), \
|
||||||
PlainText('A20 OLinuXino MICRO')], 'width=235,height=132')])]), Paragraph([\
|
TableItem([Paragraph([PlainText(' '), \
|
||||||
Link('FreedomBox/Hardware/A20-OLinuXino-MICRO', [PlainText('A20 OLinuXino \
|
Link('FreedomBox/Hardware/A20-OLinuXino-MICRO', \
|
||||||
MICRO')])])], 'center'), TableItem([Paragraph([Link('FreedomBox/Hardware/\
|
[EmbeddedAttachment('a20-olinuxino-micro_thumb.jpg', \
|
||||||
APU', [EmbeddedAttachment('apu1d_thumb.jpg', [PlainText('PC Engines APU')], \
|
[PlainText('A20 OLinuXino MICRO')], 'width=235,height=132')])]), \
|
||||||
'width=235,height=157')])]), Paragraph([Link('FreedomBox/Hardware/APU', [\
|
Paragraph([PlainText(' '), Link('FreedomBox/Hardware/A20-OLinuXino-MICRO', \
|
||||||
PlainText('PC Engines APU')])])], 'center')])])]
|
[PlainText('A20 OLinuXino MICRO')]), PlainText(' ')])], 'center'), \
|
||||||
|
TableItem([Paragraph([PlainText(' '), Link('FreedomBox/Hardware/APU', \
|
||||||
|
[EmbeddedAttachment('apu1d_thumb.jpg', [PlainText('PC Engines APU')], \
|
||||||
|
'width=235,height=157')])]), Paragraph([PlainText(' '), \
|
||||||
|
Link('FreedomBox/Hardware/APU', [PlainText('PC Engines APU')]), \
|
||||||
|
PlainText(' ')])], 'center')])])]
|
||||||
|
|
||||||
>>> parse_wiki(" 1. When created, go to the virtual machine's Settings -> \
|
>>> parse_wiki(" 1. When created, go to the virtual machine's Settings -> \
|
||||||
[Network] -> [Adapter 1]->[Attached to:] and choose the network type your \
|
[Network] -> [Adapter 1]->[Attached to:] and choose the network type your \
|
||||||
@ -1228,14 +1242,14 @@ that this exposes the !FreedomBox's services to your entire local network.")
|
|||||||
[List('numbered', [ListItem([Paragraph([PlainText("When created, go to \
|
[List('numbered', [ListItem([Paragraph([PlainText("When created, go to \
|
||||||
the virtual machine's Settings -> [Network] -> [Adapter 1]->[Attached to:] \
|
the virtual machine's Settings -> [Network] -> [Adapter 1]->[Attached to:] \
|
||||||
and choose the network type your want the machine to use according to the \
|
and choose the network type your want the machine to use according to the \
|
||||||
explanation in Network Configuration below. The recommended type is the"), \
|
explanation in Network Configuration below. The recommended type is the "), \
|
||||||
ItalicText('Bridged adapter'), PlainText("option, but be aware that this \
|
ItalicText('Bridged adapter'), PlainText(" option, but be aware that this \
|
||||||
exposes the FreedomBox's services to your entire local network.")])])])]
|
exposes the FreedomBox's services to your entire local network. ")])])])]
|
||||||
|
|
||||||
>>> parse_wiki('After logging in, you can become root with the command \
|
>>> parse_wiki('After logging in, you can become root with the command \
|
||||||
`sudo su`.\\n \\n=== Build Image ===')
|
`sudo su`.\\n \\n=== Build Image ===')
|
||||||
[Paragraph([PlainText('After logging in, you can become root with the \
|
[Paragraph([PlainText('After logging in, you can become root with the \
|
||||||
command'), MonospaceText('sudo su'), PlainText('.')]), \
|
command '), MonospaceText('sudo su'), PlainText('. ')]), \
|
||||||
Heading(3, 'Build Image')]
|
Heading(3, 'Build Image')]
|
||||||
|
|
||||||
>>> parse_wiki('Quassel Core will be initialized too.\\n\\n\
|
>>> parse_wiki('Quassel Core will be initialized too.\\n\\n\
|
||||||
@ -1246,15 +1260,16 @@ width=394}}\\n\
|
|||||||
1. Click the `Add` button to launch `Add Core Account` dialog.\\n\
|
1. Click the `Add` button to launch `Add Core Account` dialog.\\n\
|
||||||
')
|
')
|
||||||
[Paragraph(\
|
[Paragraph(\
|
||||||
[PlainText('Quassel Core will be initialized too.')]), \
|
[PlainText('Quassel Core will be initialized too. ')]), \
|
||||||
List('numbered', \
|
List('numbered', \
|
||||||
[ListItem([Paragraph([PlainText('Launch Quassel Client. You will be greeted \
|
[ListItem([Paragraph([PlainText('Launch Quassel Client. You will be greeted \
|
||||||
with a wizard to'), MonospaceText('Connect to Core'), PlainText('.')]), \
|
with a wizard to '), MonospaceText('Connect to Core'), PlainText('. ')]), \
|
||||||
Paragraph([EmbeddedAttachment('quassel-client-1-connect-to-core.png', \
|
Paragraph([PlainText(' '), \
|
||||||
[PlainText('Connect to Core')], 'width=394')])]), \
|
EmbeddedAttachment('quassel-client-1-connect-to-core.png', \
|
||||||
ListItem([Paragraph([PlainText('Click the'), MonospaceText('Add'), \
|
[PlainText('Connect to Core')], 'width=394'), PlainText(' ')])]), \
|
||||||
PlainText('button to launch'), MonospaceText('Add Core Account'), \
|
ListItem([Paragraph([PlainText('Click the '), MonospaceText('Add'), \
|
||||||
PlainText('dialog.')])])])]
|
PlainText(' button to launch '), MonospaceText('Add Core Account'), \
|
||||||
|
PlainText(' dialog. ')])])])]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
elements = []
|
elements = []
|
||||||
@ -1264,7 +1279,7 @@ PlainText('dialog.')])])])]
|
|||||||
if begin_marker:
|
if begin_marker:
|
||||||
removed_lines = []
|
removed_lines = []
|
||||||
while lines:
|
while lines:
|
||||||
line = lines.pop(0).strip()
|
line = lines.pop(0)
|
||||||
removed_lines.append(line)
|
removed_lines.append(line)
|
||||||
if line.startswith(begin_marker):
|
if line.startswith(begin_marker):
|
||||||
break
|
break
|
||||||
@ -1375,9 +1390,10 @@ PlainText('dialog.')])])])]
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
next_list_item += '\n' + line
|
next_list_item += '\n' + line
|
||||||
elif candidate.strip().startswith('{{'):
|
elif (candidate.strip().startswith('{{')
|
||||||
|
and next_list_item[-1] != '\n'):
|
||||||
# Add line break before inline image
|
# Add line break before inline image
|
||||||
next_list_item += '<<BR>>\n' + lines.pop(0)
|
next_list_item += ' <<BR>>\n' + lines.pop(0)
|
||||||
else:
|
else:
|
||||||
next_list_item += '\n' + lines.pop(0)
|
next_list_item += '\n' + lines.pop(0)
|
||||||
|
|
||||||
@ -1396,7 +1412,7 @@ PlainText('dialog.')])])])]
|
|||||||
list_type = ListType.BULLETED
|
list_type = ListType.BULLETED
|
||||||
else:
|
else:
|
||||||
list_type = ListType.NUMBERED
|
list_type = ListType.NUMBERED
|
||||||
content = line.lstrip(match.group(2) + ' ')
|
content = ' ' * indent + line.lstrip(match.group(2) + ' ')
|
||||||
list_data.append((list_type, indent, content))
|
list_data.append((list_type, indent, content))
|
||||||
|
|
||||||
new_list, _ = parse_list(list_data, context)
|
new_list, _ = parse_list(list_data, context)
|
||||||
@ -1457,13 +1473,17 @@ PlainText('dialog.')])])])]
|
|||||||
if line.strip():
|
if line.strip():
|
||||||
texts = []
|
texts = []
|
||||||
br = '<<BR>>'
|
br = '<<BR>>'
|
||||||
texts.extend(parse_text(line.rstrip(br), context))
|
space_line = line.rstrip(br) if br in line else line + ' '
|
||||||
|
texts.extend(parse_text(space_line, context))
|
||||||
if br not in line:
|
if br not in line:
|
||||||
# Collect text until next empty line is reached.
|
# Collect text until next empty line is reached.
|
||||||
while lines and lines[0].strip():
|
while lines and lines[0].strip():
|
||||||
if end_marker and lines[0].strip().startswith(end_marker):
|
if end_marker and lines[0].strip().startswith(end_marker):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if br in line:
|
||||||
|
break
|
||||||
|
|
||||||
# If any of the syntax that ends a paragraph
|
# If any of the syntax that ends a paragraph
|
||||||
paragraph_breakers = ['{{{', '##', '----', '||']
|
paragraph_breakers = ['{{{', '##', '----', '||']
|
||||||
if any([
|
if any([
|
||||||
@ -1476,7 +1496,8 @@ PlainText('dialog.')])])])]
|
|||||||
break
|
break
|
||||||
|
|
||||||
line = lines.pop(0)
|
line = lines.pop(0)
|
||||||
texts.extend(parse_text(line.rstrip(br), context))
|
space_line = line.rstrip(br) if br in line else line + ' '
|
||||||
|
texts.extend(parse_text(space_line, context))
|
||||||
|
|
||||||
elements.append(Paragraph(texts))
|
elements.append(Paragraph(texts))
|
||||||
|
|
||||||
@ -1492,13 +1513,13 @@ def generate_inner_docbook(parsed_wiki, context=None):
|
|||||||
>>> generate_inner_docbook([\
|
>>> generate_inner_docbook([\
|
||||||
Heading(1, 'heading 1st level'), \
|
Heading(1, 'heading 1st level'), \
|
||||||
Heading(2, 'heading 2nd level'), \
|
Heading(2, 'heading 2nd level'), \
|
||||||
Paragraph([PlainText('plain text')]), \
|
Paragraph([PlainText('plain text ')]), \
|
||||||
Heading(3, 'heading 3rd level'), \
|
Heading(3, 'heading 3rd level'), \
|
||||||
Heading(2, 'heading 2nd level'), \
|
Heading(2, 'heading 2nd level'), \
|
||||||
])
|
])
|
||||||
'<section><title>heading 1st level</title>\
|
'<section><title>heading 1st level</title>\
|
||||||
<section><title>heading 2nd level</title>\
|
<section><title>heading 2nd level</title>\
|
||||||
<para>plain text</para>\
|
<para>plain text </para>\
|
||||||
<section><title>heading 3rd level</title>\
|
<section><title>heading 3rd level</title>\
|
||||||
</section></section>\
|
</section></section>\
|
||||||
<section><title>heading 2nd level</title>\
|
<section><title>heading 2nd level</title>\
|
||||||
@ -1507,8 +1528,8 @@ Heading(2, 'heading 2nd level'), \
|
|||||||
>>> generate_inner_docbook([Heading(1, 'Date & Time')])
|
>>> generate_inner_docbook([Heading(1, 'Date & Time')])
|
||||||
'<section><title>Date & Time</title></section>'
|
'<section><title>Date & Time</title></section>'
|
||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([PlainText('plain text')])])
|
>>> generate_inner_docbook([Paragraph([PlainText('plain text ')])])
|
||||||
'<para>plain text</para>'
|
'<para>plain text </para>'
|
||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([Url('https://freedombox.org')])])
|
>>> generate_inner_docbook([Paragraph([Url('https://freedombox.org')])])
|
||||||
'<para><ulink url="https://freedombox.org"/></para>'
|
'<para><ulink url="https://freedombox.org"/></para>'
|
||||||
@ -1520,7 +1541,7 @@ Heading(2, 'heading 2nd level'), \
|
|||||||
'<para><emphasis role="strong">bold</emphasis></para>'
|
'<para><emphasis role="strong">bold</emphasis></para>'
|
||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([\
|
>>> generate_inner_docbook([Paragraph([\
|
||||||
PlainText('normal text followed by'), BoldText('bold text')])])
|
PlainText('normal text followed by '), BoldText('bold text')])])
|
||||||
'<para>normal text followed by \
|
'<para>normal text followed by \
|
||||||
<emphasis role="strong">bold text</emphasis></para>'
|
<emphasis role="strong">bold text</emphasis></para>'
|
||||||
|
|
||||||
@ -1639,9 +1660,9 @@ Url('http://example.com')])])
|
|||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([\
|
>>> generate_inner_docbook([Paragraph([\
|
||||||
PlainText('User documentation:')]), \
|
PlainText('User documentation:')]), \
|
||||||
List('bulleted', [ListItem([Paragraph([PlainText('List of'), \
|
List('bulleted', [ListItem([Paragraph([PlainText('List of '), \
|
||||||
Link('FreedomBox/Features', [PlainText('applications')]), \
|
Link('FreedomBox/Features', [PlainText('applications')]), \
|
||||||
PlainText('offered by FreedomBox.')])])])])
|
PlainText(' offered by FreedomBox.')])])])])
|
||||||
'<para>User documentation:</para><itemizedlist><listitem><para>List of \
|
'<para>User documentation:</para><itemizedlist><listitem><para>List of \
|
||||||
<ulink url="https://wiki.debian.org/FreedomBox/Features#">applications\
|
<ulink url="https://wiki.debian.org/FreedomBox/Features#">applications\
|
||||||
</ulink> offered by FreedomBox.</para></listitem></itemizedlist>'
|
</ulink> offered by FreedomBox.</para></listitem></itemizedlist>'
|
||||||
@ -1650,52 +1671,52 @@ PlainText('offered by FreedomBox.')])])])])
|
|||||||
ListItem([Paragraph([PlainText('Within FreedomBox Service (Plinth)')]), \
|
ListItem([Paragraph([PlainText('Within FreedomBox Service (Plinth)')]), \
|
||||||
List('numbered', [ListItem([Paragraph([PlainText('select Apps')])]), \
|
List('numbered', [ListItem([Paragraph([PlainText('select Apps')])]), \
|
||||||
ListItem([Paragraph([PlainText('go to Radicale (Calendar and Addressbook) \
|
ListItem([Paragraph([PlainText('go to Radicale (Calendar and Addressbook) \
|
||||||
and')])]), \
|
and ')])]), \
|
||||||
ListItem([Paragraph([PlainText('install the application. After the \
|
ListItem([Paragraph([PlainText('install the application. After the \
|
||||||
installation is complete, make sure the application is marked "enabled" in \
|
installation is complete, make sure the application is marked "enabled" in \
|
||||||
the FreedomBox interface. Enabling the application launches the Radicale \
|
the FreedomBox interface. Enabling the application launches the Radicale \
|
||||||
CalDAV/CardDAV server.')])]), \
|
CalDAV/CardDAV server. ')])]), \
|
||||||
ListItem([Paragraph([PlainText('define the access rights:')]), \
|
ListItem([Paragraph([PlainText('define the access rights: ')]), \
|
||||||
List('bulleted', [ListItem([Paragraph([PlainText('Only the owner of a \
|
List('bulleted', [ListItem([Paragraph([PlainText('Only the owner of a \
|
||||||
calendar/addressbook can view or make changes')])]), \
|
calendar/addressbook can view or make changes ')])]), \
|
||||||
ListItem([Paragraph([PlainText('Any user can view any calendar/addressbook, \
|
ListItem([Paragraph([PlainText('Any user can view any calendar/addressbook, \
|
||||||
but only the owner can make changes')])]), \
|
but only the owner can make changes ')])]), \
|
||||||
ListItem([Paragraph([PlainText('Any user can view or make changes to any \
|
ListItem([Paragraph([PlainText('Any user can view or make changes to any \
|
||||||
calendar/addressbook')])])])])])])])])
|
calendar/addressbook ')])])])])])])])])
|
||||||
'<itemizedlist>\
|
'<itemizedlist>\
|
||||||
<listitem><para>Within FreedomBox Service (Plinth)</para> \
|
<listitem><para>Within FreedomBox Service (Plinth)</para> \
|
||||||
<orderedlist numeration="arabic">\
|
<orderedlist numeration="arabic">\
|
||||||
<listitem><para>select Apps</para></listitem>\
|
<listitem><para>select Apps</para></listitem>\
|
||||||
<listitem><para>go to Radicale (Calendar and Addressbook) and</para>\
|
<listitem><para>go to Radicale (Calendar and Addressbook) and </para>\
|
||||||
</listitem>\
|
</listitem>\
|
||||||
<listitem><para>install the application. After the installation is complete, \
|
<listitem><para>install the application. After the installation is complete, \
|
||||||
make sure the application is marked "enabled" in the FreedomBox interface. \
|
make sure the application is marked "enabled" in the FreedomBox interface. \
|
||||||
Enabling the application launches the Radicale CalDAV/CardDAV server.</para>\
|
Enabling the application launches the Radicale CalDAV/CardDAV server. </para>\
|
||||||
</listitem>\
|
</listitem>\
|
||||||
<listitem><para>define the access rights:</para> \
|
<listitem><para>define the access rights: </para> \
|
||||||
<itemizedlist>\
|
<itemizedlist>\
|
||||||
<listitem><para>Only the owner of a calendar/addressbook can view or make \
|
<listitem><para>Only the owner of a calendar/addressbook can view or make \
|
||||||
changes</para></listitem>\
|
changes </para></listitem>\
|
||||||
<listitem><para>Any user can view any calendar/addressbook, but only the \
|
<listitem><para>Any user can view any calendar/addressbook, but only the \
|
||||||
owner can make changes</para></listitem>\
|
owner can make changes </para></listitem>\
|
||||||
<listitem><para>Any user can view or make changes to any calendar/addressbook\
|
<listitem><para>Any user can view or make changes to any calendar/addressbook \
|
||||||
</para></listitem></itemizedlist>\
|
</para></listitem></itemizedlist>\
|
||||||
</listitem></orderedlist>\
|
</listitem></orderedlist>\
|
||||||
</listitem></itemizedlist>'
|
</listitem></itemizedlist>'
|
||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([PlainText('An alternative to \
|
>>> generate_inner_docbook([Paragraph([PlainText('An alternative to \
|
||||||
downloading these images is to'), Link('InstallingDebianOn/TI/BeagleBone', \
|
downloading these images is to '), Link('InstallingDebianOn/TI/BeagleBone', \
|
||||||
[PlainText('install Debian')]), PlainText('on the BeagleBone and then'), \
|
[PlainText(' install Debian')]), PlainText(' on the BeagleBone and then '), \
|
||||||
Link('FreedomBox/Hardware/Debian', [PlainText('install FreedomBox')]), \
|
Link('FreedomBox/Hardware/Debian', [PlainText('install FreedomBox')]), \
|
||||||
PlainText('on it.')])])
|
PlainText(' on it. ')])])
|
||||||
'<para>An alternative to downloading these images is to \
|
'<para>An alternative to downloading these images is to \
|
||||||
<ulink url="https://wiki.debian.org/InstallingDebianOn/TI/BeagleBone#">\
|
<ulink url="https://wiki.debian.org/InstallingDebianOn/TI/BeagleBone#">\
|
||||||
install Debian</ulink> on the BeagleBone and then \
|
install Debian</ulink> on the BeagleBone and then \
|
||||||
<ulink url="https://wiki.debian.org/FreedomBox/Hardware/Debian#">install \
|
<ulink url="https://wiki.debian.org/FreedomBox/Hardware/Debian#">install \
|
||||||
FreedomBox</ulink> on it.</para>'
|
FreedomBox</ulink> on it. </para>'
|
||||||
|
|
||||||
>>> generate_inner_docbook([Paragraph([PlainText('After Roundcube is \
|
>>> generate_inner_docbook([Paragraph([PlainText('After Roundcube is \
|
||||||
installed, it can be accessed at'), CodeText('https://<your freedombox>\
|
installed, it can be accessed at '), CodeText('https://<your freedombox>\
|
||||||
/roundcube'), PlainText('.')])])
|
/roundcube'), PlainText('.')])])
|
||||||
'<para>After Roundcube is installed, it can be accessed at <code>\
|
'<para>After Roundcube is installed, it can be accessed at <code>\
|
||||||
https://<your freedombox>/roundcube</code>.</para>'
|
https://<your freedombox>/roundcube</code>.</para>'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user