Repository: zulip/zulip

Issue:
bugdown: Don't rstrip inline code blocks.
We currently rstrip regular code blocks, to make copy-pasting from the terminal easier (see #3998). However, inline code blocks should keep all their spaces.

To work on this issue, I would start by reading http://zulip.readthedocs.io/en/latest/markdown.html and trying to understanding the code in #4185.



Discussion:
Hello @zulip/server-markdown members, this issue was labeled with the **area: markdown** label, so you may want to check it out!
@zulipbot claim
Congratulations, @TAAPArthur, you've successfully claimed your first issue! Contributing to Zulip will (hopefully) be a fun and rewarding experience, and I'm here to help get you off to a good start.

First things first:
* Join me on the [Zulip developers' server](https://chat.zulip.org), to get help, chat about this issue, and meet the other developers.
* Sign the [Dropbox Contributor License Agreement](https://opensource.dropbox.com/cla/), so that Zulip can use your code.
* [Unwatch this repository](https://help.github.com/articles/unwatching-repositories/), so that you don't get 100 emails a day.

As you work on this issue, you'll also want to refer to the [Zulip code contribution guide](http://zulip.readthedocs.io/en/latest/index.html#code-docs), as well as the rest of the developer documentation on that site.


See you on the other side (that is, the pull request side)!

@zulipbot claim
Congratulations, @IshanGupta10, you've successfully claimed your first issue! Contributing to Zulip will (hopefully) be a fun and rewarding experience, and I'm here to help get you off to a good start.

First things first:
* Join me on the [Zulip developers' server](https://chat.zulip.org), to get help, chat about this issue, and meet the other developers.
* Sign the [Dropbox Contributor License Agreement](https://opensource.dropbox.com/cla/), so that Zulip can use your code.
* [Unwatch this repository](https://help.github.com/articles/unwatching-repositories/), so that you don't get 100 emails a day.

As you work on this issue, you'll also want to refer to the [Zulip code contribution guide](http://zulip.readthedocs.io/en/latest/index.html#code-docs), as well as the rest of the developer documentation on that site.


See you on the other side (that is, the pull request side)!

Hello @IshanGupta10, you have been unassigned from this issue because you have not updated this issue or any referenced pull requests for over 10 days.

You can reclaim this issue or claim any other issue by commenting `@zulipbot claim` on that issue.

Thanks for your contributions, and hope to see you again soon!


Resolving patch:
diff --git a/zerver/lib/bugdown/__init__.py b/zerver/lib/bugdown/__init__.py
--- a/zerver/lib/bugdown/__init__.py
+++ b/zerver/lib/bugdown/__init__.py
@@ -355,6 +355,24 @@ def run(self, root: Element) -> None:
                 continue
             img.set("src", get_camo_url(url))
 
+class BacktickPattern(markdown.inlinepatterns.Pattern):
+    """ Return a `<code>` element containing the matching text. """
+    def __init__(self, pattern):
+        # type: (Text) -> None
+        markdown.inlinepatterns.Pattern.__init__(self, pattern)
+        self.ESCAPED_BSLASH = '%s%s%s' % (markdown.util.STX, ord('\\'), markdown.util.ETX)
+        self.tag = 'code'
+
+    def handleMatch(self, m):
+        # type: (Match[Text]) -> Union[Text, Element]
+        if m.group(4):
+            el = markdown.util.etree.Element(self.tag)
+            # Modified to not strip whitespace
+            el.text = markdown.util.AtomicString(m.group(4))
+            return el
+        else:
+            return m.group(2).replace('\\\\', self.ESCAPED_BSLASH)
+
 class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
     TWITTER_MAX_IMAGE_HEIGHT = 400
     TWITTER_MAX_TO_PREVIEW = 3
@@ -1346,7 +1364,7 @@ def extendMarkdown(self, md: markdown.Markdown, md_globals: Dict[str, Any]) -> N
         for k in ('image_link', 'image_reference', 'automail',
                   'autolink', 'link', 'reference', 'short_reference',
                   'escape', 'strong_em', 'emphasis', 'emphasis2',
-                  'linebreak', 'strong'):
+                  'linebreak', 'strong', 'backtick'):
             del md.inlinePatterns[k]
         try:
             # linebreak2 was removed upstream in version 3.2.1, so
@@ -1357,6 +1375,12 @@ def extendMarkdown(self, md: markdown.Markdown, md_globals: Dict[str, Any]) -> N
 
         md.preprocessors.add("custom_text_notifications", AlertWordsNotificationProcessor(md), "_end")
 
+        # Inline code block without whitespace stripping
+        md.inlinePatterns.add(
+            "backtick",
+            BacktickPattern(r'(?:(?<!\\)((?:\\{2})+)(?=`+)|(?<!\\)(`+)(.+?)(?<!`)\3(?!`))'),
+            "_begin")
+
         # Custom bold syntax: **foo** but not __foo__
         md.inlinePatterns.add('strong',
                               markdown.inlinepatterns.SimpleTagPattern(r'(\*\*)([^\n]+?)\2', 'strong'),


Test patch:
diff --git a/zerver/fixtures/markdown_test_cases.json b/zerver/fixtures/markdown_test_cases.json
--- a/zerver/fixtures/markdown_test_cases.json
+++ b/zerver/fixtures/markdown_test_cases.json
@@ -25,6 +25,12 @@
       "expected_output": "<p>Hamlet once said</p>\n<div class=\"codehilite\"><pre><span></span>def func():\n    x = 1\n\n    y = 2\n\n    z = 3\n</pre></div>\n\n\n<p>And all was good.</p>",
       "text_content": "Hamlet once said\ndef func():\n    x = 1\n\n    y = 2\n\n    z = 3\n\n\n\nAnd all was good."
     },
+    {
+      "name": "inline_code_spaces",
+      "input": "` outer ` ```    space    ```",
+      "expected_output": "<p><code> outer </code> <code>    space    </code></p>",
+      "text_content": " outer      space    "
+    },
     {
       "name": "codeblock_backticks",
       "input": "\n```\nfenced code\n```\n\n```inline code```\n",
@@ -93,8 +99,8 @@
     {
       "name": "dangerous_block",
       "input": "``` one ```\n\n``` two ```\n\n~~~~\nx = 1",
-      "expected_output": "<p><code>one</code></p>\n<p><code>two</code></p>\n<div class=\"codehilite\"><pre><span></span>x = 1\n</pre></div>",
-      "text_content": "one\ntwo\nx = 1\n"
+      "expected_output": "<p><code> one </code></p>\n<p><code> two </code></p>\n<div class=\"codehilite\"><pre><span></span>x = 1\n</pre></div>",
+      "text_content": " one \n two \nx = 1\n"
     },
     {
       "name": "four_space_code_block",