diff -r 177b186dd23a roundup/cgi/templating.py --- a/roundup/cgi/templating.py Fri Oct 23 18:38:37 2020 -0400 +++ b/roundup/cgi/templating.py Sat Oct 24 17:34:32 2020 +0200 @@ -69,7 +69,13 @@ # don't allow disabled protocols in links _safe_protocols = re.compile('(?!' + ':|'.join([re.escape(s) for s in _disable_url_schemes]) + ':)', re.IGNORECASE) - markdown = lambda s: Markdown(safe_mode='escape', extras={ 'fenced-code-blocks' : True }).convert(s) + def _extras(config): + extras = { 'fenced-code-blocks' : True } + if config['MARKDOWN_BREAK_ON_NEWLINE']: + extras['break-on-newline'] = True + return extras + + markdown = lambda s, c: Markdown(safe_mode='escape', extras=_extras(c)).convert(s) except ImportError: markdown = None @@ -107,7 +113,13 @@ else: md.treeprocessors['restrict_links'] = RestrictLinksProcessor() - markdown = lambda s: markdown_impl(s, extensions=[SafeHtml(), 'fenced_code']) + def _extensions(config): + extensions = [SafeHtml(), 'fenced_code'] + if config['MARKDOWN_BREAK_ON_NEWLINE']: + extensions.append('nl2br') + return extensions + + markdown = lambda s, c: markdown_impl(s, extensions=_extensions(c)) except ImportError: markdown = None @@ -117,7 +129,14 @@ try: import mistune mistune._scheme_blacklist = [ s + ':' for s in _disable_url_schemes ] - markdown = mistune.markdown + + def _options(config): + options = {} + if config['MARKDOWN_BREAK_ON_NEWLINE']: + options['hard_wrap'] = True + return options + + markdown = lambda s, c: mistune.markdown(s, **_options(c)) except ImportError: markdown = None @@ -1731,8 +1750,9 @@ if hyperlink: s = self.hyper_re.sub(self._hyper_repl_markdown, s) try: - s = u2s(markdown(s2u(s))) + s = u2s(markdown(s2u(s), self._db.config)) except Exception: # when markdown formatting fails return markup + raise return self.plain(escape=0, hyperlink=hyperlink) return s diff -r 177b186dd23a roundup/configuration.py --- a/roundup/configuration.py Fri Oct 23 18:38:37 2020 -0400 +++ b/roundup/configuration.py Sat Oct 24 17:34:32 2020 +0200 @@ -1329,6 +1329,10 @@ "won't be attached to nosy mails. They will be replaced by\n" "a link to the tracker's download page for the file.") ), "Nosy messages sending"), + ("markdown", ( + (BooleanOption, "break_on_newline", "no", + "Replace single new line characters with
?"), + ), "Markdown rendering options."), ) ### Configuration classes diff -r 177b186dd23a share/roundup/templates/jinja2/html/issue.item.html --- a/share/roundup/templates/jinja2/html/issue.item.html Fri Oct 23 18:38:37 2020 -0400 +++ b/share/roundup/templates/jinja2/html/issue.item.html Sat Oct 24 17:34:32 2020 +0200 @@ -32,7 +32,7 @@ var node = $('#change_note')[0]; var initSimpleMde = function () { node.parentNode.appendChild($('', { type: 'hidden', name: 'msg-1@type', value: 'text/markdown'})[0]); - var simplemde = new SimpleMDE({ element: node, status: false, styleSelectedText: false, renderingConfig: {singleLineBreaks: false}}); + var simplemde = new SimpleMDE({ element: node, status: false, styleSelectedText: false, renderingConfig: {singleLineBreaks: Boolean({{ config.MARKDOWN_BREAK_ON_NEWLINE }}) }}); simplemde.render(); }; {% if context.id %} diff -r 177b186dd23a test/test_templating.py --- a/test/test_templating.py Fri Oct 23 18:38:37 2020 -0400 +++ b/test/test_templating.py Sat Oct 24 17:34:32 2020 +0200 @@ -1,6 +1,7 @@ from __future__ import print_function import unittest from cgi import FieldStorage, MiniFieldStorage +from operator import setitem from roundup.cgi.templating import * from .test_actions import MockNull, true @@ -74,7 +75,7 @@ # add client props for testing anti_csrf_nonce self.client.session_api = MockNull(_sid="1234567890") self.client.db.getuid = lambda : 10 - self.client.db.config = {'WEB_CSRF_TOKEN_LIFETIME': 10 } + self.client.db.config = {'WEB_CSRF_TOKEN_LIFETIME': 10, 'MARKDOWN_BREAK_ON_NEWLINE': False } class HTMLDatabaseTestCase(TemplatingTestCase): def test_HTMLDatabase___getitem__(self): @@ -477,6 +478,16 @@ # so processing it returns original text self.assertEqual(m.replace('\n\n', '\n'), u2s(u'embedded code block <pre>\n``` python\nline 1\nline 2\n```\nnew </pre> paragraph')) + def test_break_on_newline(self): + self.client.db.config['MARKDOWN_BREAK_ON_NEWLINE'] = True + p = StringHTMLProperty(self.client, 'test', '1', None, 'test', u2s(u'A string with\nline break')) + m = p.markdown() + self.assertEqual(1, m.count('