summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoracio Sanson <horacio@allm.net>2017-01-16 09:07:02 +0900
committerHoracio Sanson <horacio@allm.net>2017-02-03 08:49:48 +0900
commitd9e9ad2211c06159914e0183e4842abc16e5666f (patch)
treeffa7e02948f10a42b42d33d3b568774c147bd98c
parente7d530a624fbb8854047c3983eaa0972a19f36c8 (diff)
downloadgitlab-ce-d9e9ad2211c06159914e0183e4842abc16e5666f.tar.gz
PlantUML support for Markdown
Allow rendering of PlantUML diagrams in Markdown documents using fenced blocks: ```plantuml Bob -> Sara : Hello Sara -> Bob : Go away ``` Closes: #4048
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock4
-rw-r--r--changelogs/unreleased/markdown-plantuml.yml4
-rw-r--r--config/initializers/plantuml_lexer.rb2
-rw-r--r--doc/administration/integration/plantuml.md18
-rw-r--r--lib/banzai/filter/plantuml_filter.rb39
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb1
-rw-r--r--lib/rouge/lexers/plantuml.rb21
-rw-r--r--spec/lib/banzai/filter/plantuml_filter_spec.rb32
9 files changed, 115 insertions, 8 deletions
diff --git a/Gemfile b/Gemfile
index dd7c93c5a75..479df411881 100644
--- a/Gemfile
+++ b/Gemfile
@@ -109,7 +109,7 @@ gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
-gem 'asciidoctor-plantuml', '0.0.6'
+gem 'asciidoctor-plantuml', '0.0.7'
gem 'rouge', '~> 2.0'
gem 'truncato', '~> 0.7.8'
diff --git a/Gemfile.lock b/Gemfile.lock
index 3b207d19d1f..f6b889dcca4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -54,7 +54,7 @@ GEM
faraday_middleware-multi_json (~> 0.0)
oauth2 (~> 1.0)
asciidoctor (1.5.3)
- asciidoctor-plantuml (0.0.6)
+ asciidoctor-plantuml (0.0.7)
asciidoctor (~> 1.5)
ast (2.3.0)
attr_encrypted (3.0.3)
@@ -841,7 +841,7 @@ DEPENDENCIES
allocations (~> 1.0)
asana (~> 0.4.0)
asciidoctor (~> 1.5.2)
- asciidoctor-plantuml (= 0.0.6)
+ asciidoctor-plantuml (= 0.0.7)
attr_encrypted (~> 3.0.0)
awesome_print (~> 1.2.0)
babosa (~> 1.0.2)
diff --git a/changelogs/unreleased/markdown-plantuml.yml b/changelogs/unreleased/markdown-plantuml.yml
new file mode 100644
index 00000000000..c855f0cbcf7
--- /dev/null
+++ b/changelogs/unreleased/markdown-plantuml.yml
@@ -0,0 +1,4 @@
+---
+title: PlantUML support for Markdown
+merge_request: 8588
+author: Horacio Sanson
diff --git a/config/initializers/plantuml_lexer.rb b/config/initializers/plantuml_lexer.rb
new file mode 100644
index 00000000000..e8a77b146fa
--- /dev/null
+++ b/config/initializers/plantuml_lexer.rb
@@ -0,0 +1,2 @@
+# Touch the lexers so it is registered with Rouge
+Rouge::Lexers::Plantuml
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index e5cf592e0a6..6515b1a264a 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -3,8 +3,8 @@
> [Introduced][ce-7810] in GitLab 8.16.
When [PlantUML](http://plantuml.com) integration is enabled and configured in
-GitLab we are able to create simple diagrams in AsciiDoc documents created in
-snippets, wikis, and repos.
+GitLab we are able to create simple diagrams in AsciiDoc and Markdown documents
+created in snippets, wikis, and repos.
## PlantUML Server
@@ -54,7 +54,7 @@ that, login with an Admin account and do following:
## Creating Diagrams
With PlantUML integration enabled and configured, we can start adding diagrams to
-our AsciiDoc snippets, wikis and repos using blocks:
+our AsciiDoc snippets, wikis and repos using delimited blocks:
```
[plantuml, format="png", id="myDiagram", width="200px"]
@@ -64,7 +64,14 @@ Alice -> Bob : Go Away
--
```
-The above block will be converted to an HTML img tag with source pointing to the
+And in Markdown using fenced code blocks:
+
+ ```plantuml
+ Bob -> Alice : hello
+ Alice -> Bob : Go Away
+ ```
+
+The above blocks will be converted to an HTML img tag with source pointing to the
PlantUML instance. If the PlantUML server is correctly configured, this should
render a nice diagram instead of the block:
@@ -77,7 +84,7 @@ Inside the block you can add any of the supported diagrams by PlantUML such as
and [Object](http://plantuml.com/object-diagram) diagrams. You do not need to use the PlantUML
diagram delimiters `@startuml`/`@enduml` as these are replaced by the AsciiDoc `plantuml` block.
-Some parameters can be added to the block definition:
+Some parameters can be added to the AsciiDoc block definition:
- *format*: Can be either `png` or `svg`. Note that `svg` is not supported by
all browsers so use with care. The default is `png`.
@@ -85,3 +92,4 @@ Some parameters can be added to the block definition:
- *width*: Width attribute added to the img tag.
- *height*: Height attribute added to the img tag.
+Markdown does not support any parameters and will always use PNG format.
diff --git a/lib/banzai/filter/plantuml_filter.rb b/lib/banzai/filter/plantuml_filter.rb
new file mode 100644
index 00000000000..e194cf59275
--- /dev/null
+++ b/lib/banzai/filter/plantuml_filter.rb
@@ -0,0 +1,39 @@
+require "nokogiri"
+require "asciidoctor-plantuml/plantuml"
+
+module Banzai
+ module Filter
+ # HTML that replaces all `code plantuml` tags with PlantUML img tags.
+ #
+ class PlantumlFilter < HTML::Pipeline::Filter
+ def call
+ return doc unless doc.at('pre.plantuml') and settings.plantuml_enabled
+
+ plantuml_setup
+
+ doc.css('pre.plantuml').each do |el|
+ img_tag = Nokogiri::HTML::DocumentFragment.parse(
+ Asciidoctor::PlantUml::Processor.plantuml_content(el.content, {}))
+ el.replace img_tag
+ end
+
+ doc
+ end
+
+ private
+
+ def settings
+ ApplicationSetting.current || ApplicationSetting.create_from_defaults
+ end
+
+ def plantuml_setup
+ Asciidoctor::PlantUml.configure do |conf|
+ conf.url = settings.plantuml_url
+ conf.png_enable = settings.plantuml_enabled
+ conf.svg_enable = false
+ conf.txt_enable = false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index ac95a79009b..b25d6f18d59 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -10,6 +10,7 @@ module Banzai
def self.filters
@filters ||= FilterArray[
Filter::SyntaxHighlightFilter,
+ Filter::PlantumlFilter,
Filter::SanitizationFilter,
Filter::MathFilter,
diff --git a/lib/rouge/lexers/plantuml.rb b/lib/rouge/lexers/plantuml.rb
new file mode 100644
index 00000000000..7d5700b7f6d
--- /dev/null
+++ b/lib/rouge/lexers/plantuml.rb
@@ -0,0 +1,21 @@
+module Rouge
+ module Lexers
+ class Plantuml < Lexer
+ title "A passthrough lexer used for PlantUML input"
+ desc "A boring lexer that doesn't highlight anything"
+
+ tag 'plantuml'
+ mimetypes 'text/plain'
+
+ default_options token: 'Text'
+
+ def token
+ @token ||= Token[option :token]
+ end
+
+ def stream_tokens(string, &b)
+ yield self.token, string
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb
new file mode 100644
index 00000000000..f85a5dcbd8b
--- /dev/null
+++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Banzai::Filter::PlantumlFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'should replace plantuml pre tag with img tag' do
+ stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080")
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<div class="imageblock"><div class="content"><img class="plantuml" src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq"></div></div>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+
+ it 'should not replace plantuml pre tag with img tag if disabled' do
+ stub_application_setting(plantuml_enabled: false)
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<pre class="plantuml"><code>Bob -&gt; Sara : Hello</code><pre></pre></pre>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+
+ it 'should not replace plantuml pre tag with img tag if url is invalid' do
+ stub_application_setting(plantuml_enabled: true, plantuml_url: "invalid")
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<div class="listingblock"><div class="content"><pre class="plantuml plantuml-error"> PlantUML Error: cannot connect to PlantUML server at "invalid"</pre></div></div>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+end