summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Speicher <robert@gitlab.com>2016-07-10 20:30:41 +0000
committerRobert Speicher <robert@gitlab.com>2016-07-10 20:30:41 +0000
commite90a9b0159611195a512811517bb9d6237c8ffab (patch)
treee61a546339e2f8eb4943d975f11ad307808b4d2b
parent1a9adb2d34fc6e59785f2854ecfe5f8ac87a8386 (diff)
parent6ba884530f6d1132621e1050175ab3384ebdcbb5 (diff)
downloadgitlab-ce-e90a9b0159611195a512811517bb9d6237c8ffab.tar.gz
Merge branch 'blockquote-fence-filter' into 'master'
Add blockquote fence syntax to Markdown Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/16564 Before Markdown rendering happens, this will transform this: ``` Let me quote this here email: >>> Dear friend, How are you? Greetings, Me >>> ``` Into this, saving me from having to prefix all of those lines with `>` manually when I copy some multiline text from another medium: ``` Let me quote this here email: > Dear friend, > > How are you? > > Greetings, > > Me ``` See merge request !3954
-rw-r--r--CHANGELOG1
-rw-r--r--doc/markdown/markdown.md34
-rw-r--r--lib/banzai/filter/blockquote_fence_filter.rb71
-rw-r--r--lib/banzai/pipeline/pre_process_pipeline.rb3
-rw-r--r--spec/fixtures/blockquote_fence_after.md115
-rw-r--r--spec/fixtures/blockquote_fence_before.md131
-rw-r--r--spec/lib/banzai/filter/blockquote_fence_filter_spec.rb14
7 files changed, 367 insertions, 2 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3188ff68f56..0eb7595fbfa 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -18,6 +18,7 @@ v 8.10.0 (unreleased)
- Fix MR-auto-close text added to description. !4836
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
- Add Spring EmojiOne updates.
+ - Add syntax for multiline blockquote using `>>>` fence !3954
- Fix viewing notification settings when a project is pending deletion
- Fix pagination when sorting by columns with lots of ties (like priority)
- The Markdown reference parsers now re-use query results to prevent running the same queries multiple times !5020
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 236eb7b12c4..fb2dd582754 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -7,11 +7,12 @@
* [Newlines](#newlines)
* [Multiple underscores in words](#multiple-underscores-in-words)
* [URL auto-linking](#url-auto-linking)
+* [Multiline Blockquote](#multiline-blockquote)
* [Code and Syntax Highlighting](#code-and-syntax-highlighting)
* [Inline Diff](#inline-diff)
* [Emoji](#emoji)
* [Special GitLab references](#special-gitlab-references)
-* [Task lists](#task-lists)
+* [Task Lists](#task-lists)
**[Standard Markdown](#standard-markdown)**
@@ -89,6 +90,37 @@ GFM will autolink almost any URL you copy and paste into your text.
* irc://irc.freenode.net/gitlab
* http://localhost:3000
+## Multiline Blockquote
+
+On top of standard Markdown [blockquotes](#blockquotes), which require prepending `>` to quoted lines,
+GFM supports multiline blockquotes fenced by <code>>>></code>.
+
+```no-highlight
+>>>
+If you paste a message from somewhere else
+
+that
+
+spans
+
+multiple lines,
+
+you can quote that without having to manually prepend `>` to every line!
+>>>
+```
+
+>>>
+If you paste a message from somewhere else
+
+that
+
+spans
+
+multiple lines,
+
+you can quote that without having to manually prepend `>` to every line!
+>>>
+
## Code and Syntax Highlighting
_GitLab uses the [Rouge Ruby library][rouge] for syntax highlighting. For a
diff --git a/lib/banzai/filter/blockquote_fence_filter.rb b/lib/banzai/filter/blockquote_fence_filter.rb
new file mode 100644
index 00000000000..d2c4b1e4d76
--- /dev/null
+++ b/lib/banzai/filter/blockquote_fence_filter.rb
@@ -0,0 +1,71 @@
+module Banzai
+ module Filter
+ class BlockquoteFenceFilter < HTML::Pipeline::TextFilter
+ REGEX = %r{
+ (?<code>
+ # Code blocks:
+ # ```
+ # Anything, including `>>>` blocks which are ignored by this filter
+ # ```
+
+ ^```
+ .+?
+ \n```$
+ )
+ |
+ (?<html>
+ # HTML block:
+ # <tag>
+ # Anything, including `>>>` blocks which are ignored by this filter
+ # </tag>
+
+ ^<[^>]+?>\n
+ .+?
+ \n<\/[^>]+?>$
+ )
+ |
+ (?:
+ # Blockquote:
+ # >>>
+ # Anything, including code and HTML blocks
+ # >>>
+
+ ^>>>\n
+ (?<quote>
+ (?:
+ # Any character that doesn't introduce a code or HTML block
+ (?!
+ ^```
+ |
+ ^<[^>]+?>\n
+ )
+ .
+ |
+ # A code block
+ \g<code>
+ |
+ # An HTML block
+ \g<html>
+ )+?
+ )
+ \n>>>$
+ )
+ }mx.freeze
+
+ def initialize(text, context = nil, result = nil)
+ super text, context, result
+ @text = @text.delete("\r")
+ end
+
+ def call
+ @text.gsub(REGEX) do
+ if $~[:quote]
+ $~[:quote].gsub(/^/, "> ").gsub(/^> $/, ">")
+ else
+ $~[0]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/pre_process_pipeline.rb b/lib/banzai/pipeline/pre_process_pipeline.rb
index 50dc978b452..6cf219661d3 100644
--- a/lib/banzai/pipeline/pre_process_pipeline.rb
+++ b/lib/banzai/pipeline/pre_process_pipeline.rb
@@ -3,7 +3,8 @@ module Banzai
class PreProcessPipeline < BasePipeline
def self.filters
FilterArray[
- Filter::YamlFrontMatterFilter
+ Filter::YamlFrontMatterFilter,
+ Filter::BlockquoteFenceFilter,
]
end
diff --git a/spec/fixtures/blockquote_fence_after.md b/spec/fixtures/blockquote_fence_after.md
new file mode 100644
index 00000000000..2652a842c0e
--- /dev/null
+++ b/spec/fixtures/blockquote_fence_after.md
@@ -0,0 +1,115 @@
+Single `>>>` inside code block:
+
+```
+# Code
+>>>
+# Code
+```
+
+Double `>>>` inside code block:
+
+```txt
+# Code
+>>>
+# Code
+>>>
+# Code
+```
+
+Blockquote outside code block:
+
+> Quote
+
+Code block inside blockquote:
+
+> Quote
+>
+> ```
+> # Code
+> ```
+>
+> Quote
+
+Single `>>>` inside code block inside blockquote:
+
+> Quote
+>
+> ```
+> # Code
+> >>>
+> # Code
+> ```
+>
+> Quote
+
+Double `>>>` inside code block inside blockquote:
+
+> Quote
+>
+> ```
+> # Code
+> >>>
+> # Code
+> >>>
+> # Code
+> ```
+>
+> Quote
+
+Single `>>>` inside HTML:
+
+<pre>
+# Code
+>>>
+# Code
+</pre>
+
+Double `>>>` inside HTML:
+
+<pre>
+# Code
+>>>
+# Code
+>>>
+# Code
+</pre>
+
+Blockquote outside HTML:
+
+> Quote
+
+HTML inside blockquote:
+
+> Quote
+>
+> <pre>
+> # Code
+> </pre>
+>
+> Quote
+
+Single `>>>` inside HTML inside blockquote:
+
+> Quote
+>
+> <pre>
+> # Code
+> >>>
+> # Code
+> </pre>
+>
+> Quote
+
+Double `>>>` inside HTML inside blockquote:
+
+> Quote
+>
+> <pre>
+> # Code
+> >>>
+> # Code
+> >>>
+> # Code
+> </pre>
+>
+> Quote
diff --git a/spec/fixtures/blockquote_fence_before.md b/spec/fixtures/blockquote_fence_before.md
new file mode 100644
index 00000000000..d52eec72896
--- /dev/null
+++ b/spec/fixtures/blockquote_fence_before.md
@@ -0,0 +1,131 @@
+Single `>>>` inside code block:
+
+```
+# Code
+>>>
+# Code
+```
+
+Double `>>>` inside code block:
+
+```txt
+# Code
+>>>
+# Code
+>>>
+# Code
+```
+
+Blockquote outside code block:
+
+>>>
+Quote
+>>>
+
+Code block inside blockquote:
+
+>>>
+Quote
+
+```
+# Code
+```
+
+Quote
+>>>
+
+Single `>>>` inside code block inside blockquote:
+
+>>>
+Quote
+
+```
+# Code
+>>>
+# Code
+```
+
+Quote
+>>>
+
+Double `>>>` inside code block inside blockquote:
+
+>>>
+Quote
+
+```
+# Code
+>>>
+# Code
+>>>
+# Code
+```
+
+Quote
+>>>
+
+Single `>>>` inside HTML:
+
+<pre>
+# Code
+>>>
+# Code
+</pre>
+
+Double `>>>` inside HTML:
+
+<pre>
+# Code
+>>>
+# Code
+>>>
+# Code
+</pre>
+
+Blockquote outside HTML:
+
+>>>
+Quote
+>>>
+
+HTML inside blockquote:
+
+>>>
+Quote
+
+<pre>
+# Code
+</pre>
+
+Quote
+>>>
+
+Single `>>>` inside HTML inside blockquote:
+
+>>>
+Quote
+
+<pre>
+# Code
+>>>
+# Code
+</pre>
+
+Quote
+>>>
+
+Double `>>>` inside HTML inside blockquote:
+
+>>>
+Quote
+
+<pre>
+# Code
+>>>
+# Code
+>>>
+# Code
+</pre>
+
+Quote
+>>>
diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
new file mode 100644
index 00000000000..2799249ae3e
--- /dev/null
+++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
@@ -0,0 +1,14 @@
+require 'rails_helper'
+
+describe Banzai::Filter::BlockquoteFenceFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'converts blockquote fences to blockquote lines' do
+ content = File.read(Rails.root.join('spec/fixtures/blockquote_fence_before.md'))
+ expected = File.read(Rails.root.join('spec/fixtures/blockquote_fence_after.md'))
+
+ output = filter(content)
+
+ expect(output).to eq(expected)
+ end
+end