summaryrefslogtreecommitdiff
path: root/lib/gitlab/markdown.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/markdown.rb')
-rw-r--r--lib/gitlab/markdown.rb212
1 files changed, 63 insertions, 149 deletions
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 886a09f52af..f4e2cefca51 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -19,24 +19,21 @@ module Gitlab
# context - Hash of context options passed to our HTML Pipeline
#
# Returns an HTML-safe String
- def self.render(markdown, context = {})
- html = renderer.render(markdown)
- html = gfm(html, context)
-
- html.html_safe
+ def self.render(text, context = {})
+ cache_key = context.delete(:cache_key)
+ cache_key = full_cache_key(cache_key, context[:pipeline])
+
+ if cache_key
+ Rails.cache.fetch(cache_key) do
+ cacheless_render(text, context)
+ end
+ else
+ cacheless_render(text, context)
+ end
end
- # Convert a Markdown String into HTML without going through the HTML
- # Pipeline.
- #
- # Note that because the pipeline is skipped, SanitizationFilter is as well.
- # Do not output the result of this method to the user.
- #
- # markdown - Markdown String
- #
- # Returns a String
- def self.render_without_gfm(markdown)
- renderer.render(markdown)
+ def self.render_result(text, context = {})
+ Pipeline[context[:pipeline]].call(text, context)
end
# Perform post-processing on an HTML String
@@ -46,156 +43,73 @@ module Gitlab
# permission to make (`RedactorFilter`).
#
# html - String to process
- # options - Hash of options to customize output
+ # context - Hash of options to customize output
# :pipeline - Symbol pipeline type
# :project - Project
# :user - User object
#
# Returns an HTML-safe String
- def self.post_process(html, options)
- context = {
- project: options[:project],
- current_user: options[:user]
- }
- doc = post_processor.to_document(html, context)
+ def self.post_process(html, context)
+ context = Pipeline[context[:pipeline]].transform_context(context)
- if options[:pipeline] == :atom
- doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
+ pipeline = Pipeline[:post_process]
+ if context[:xhtml]
+ pipeline.to_document(html, context).to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
else
- doc.to_html
+ pipeline.to_html(html, context)
end.html_safe
end
- # Provide autoload paths for filters to prevent a circular dependency error
- autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter'
- autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter'
- autoload :CommitReferenceFilter, 'gitlab/markdown/commit_reference_filter'
- autoload :EmojiFilter, 'gitlab/markdown/emoji_filter'
- autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/external_issue_reference_filter'
- autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter'
- autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter'
- autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter'
- autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter'
- autoload :RedactorFilter, 'gitlab/markdown/redactor_filter'
- autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
- autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter'
- autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter'
- autoload :SyntaxHighlightFilter, 'gitlab/markdown/syntax_highlight_filter'
- autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter'
- autoload :TaskListFilter, 'gitlab/markdown/task_list_filter'
- autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter'
- autoload :UploadLinkFilter, 'gitlab/markdown/upload_link_filter'
-
- # Public: Parse the provided HTML with GitLab-Flavored Markdown
- #
- # html - HTML String
- # options - A Hash of options used to customize output (default: {})
- # :no_header_anchors - Disable header anchors in TableOfContentsFilter
- # :path - Current path String
- # :pipeline - Symbol pipeline type
- # :project - Current Project object
- # :project_wiki - Current ProjectWiki object
- # :ref - Current ref String
- #
- # Returns an HTML-safe String
- def self.gfm(html, options = {})
- return '' unless html.present?
-
- @pipeline ||= HTML::Pipeline.new(filters)
-
- context = {
- # SanitizationFilter
- pipeline: options[:pipeline],
-
- # EmojiFilter
- asset_host: Gitlab::Application.config.asset_host,
- asset_root: Gitlab.config.gitlab.base_url,
-
- # ReferenceFilter
- only_path: only_path_pipeline?(options[:pipeline]),
- project: options[:project],
-
- # RelativeLinkFilter
- project_wiki: options[:project_wiki],
- ref: options[:ref],
- requested_path: options[:path],
-
- # TableOfContentsFilter
- no_header_anchors: options[:no_header_anchors]
- }
-
- @pipeline.to_html(html, context).html_safe
- end
-
private
- # Check if a pipeline enables the `only_path` context option
- #
- # Returns Boolean
- def self.only_path_pipeline?(pipeline)
- case pipeline
- when :atom, :email
- false
- else
- true
- end
- end
-
- def self.redcarpet_options
- # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- @redcarpet_options ||= {
- fenced_code_blocks: true,
- footnotes: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- space_after_headers: true,
- strikethrough: true,
- superscript: true,
- tables: true
- }.freeze
- end
+ def self.cacheless_render(text, context = {})
+ result = render_result(text, context)
- def self.renderer
- @markdown ||= begin
- renderer = Redcarpet::Render::HTML.new
- Redcarpet::Markdown.new(renderer, redcarpet_options)
+ output = result[:output]
+ if output.respond_to?(:to_html)
+ output.to_html
+ else
+ output.to_s
end
end
- def self.post_processor
- @post_processor ||= HTML::Pipeline.new([Gitlab::Markdown::RedactorFilter])
+ def self.full_cache_key(cache_key, pipeline_name)
+ return unless cache_key
+ ["markdown", *cache_key, pipeline_name || :full]
end
- # Filters used in our pipeline
- #
- # SanitizationFilter should come first so that all generated reference HTML
- # goes through untouched.
- #
- # See https://github.com/jch/html-pipeline#filters for more filters.
- def self.filters
- [
- Gitlab::Markdown::SyntaxHighlightFilter,
- Gitlab::Markdown::SanitizationFilter,
-
- Gitlab::Markdown::UploadLinkFilter,
- Gitlab::Markdown::EmojiFilter,
- Gitlab::Markdown::TableOfContentsFilter,
- Gitlab::Markdown::AutolinkFilter,
- Gitlab::Markdown::ExternalLinkFilter,
-
- Gitlab::Markdown::UserReferenceFilter,
- Gitlab::Markdown::IssueReferenceFilter,
- Gitlab::Markdown::ExternalIssueReferenceFilter,
- Gitlab::Markdown::MergeRequestReferenceFilter,
- Gitlab::Markdown::SnippetReferenceFilter,
- Gitlab::Markdown::CommitRangeReferenceFilter,
- Gitlab::Markdown::CommitReferenceFilter,
- Gitlab::Markdown::LabelReferenceFilter,
-
- Gitlab::Markdown::RelativeLinkFilter,
-
- Gitlab::Markdown::TaskListFilter
- ]
- end
+ # Provide autoload paths for filters to prevent a circular dependency error
+ autoload :AutolinkFilter, 'gitlab/markdown/filter/autolink_filter'
+ autoload :CommitRangeReferenceFilter, 'gitlab/markdown/filter/commit_range_reference_filter'
+ autoload :CommitReferenceFilter, 'gitlab/markdown/filter/commit_reference_filter'
+ autoload :EmojiFilter, 'gitlab/markdown/filter/emoji_filter'
+ autoload :ExternalIssueReferenceFilter, 'gitlab/markdown/filter/external_issue_reference_filter'
+ autoload :ExternalLinkFilter, 'gitlab/markdown/filter/external_link_filter'
+ autoload :IssueReferenceFilter, 'gitlab/markdown/filter/issue_reference_filter'
+ autoload :LabelReferenceFilter, 'gitlab/markdown/filter/label_reference_filter'
+ autoload :MarkdownFilter, 'gitlab/markdown/filter/markdown_filter'
+ autoload :MergeRequestReferenceFilter, 'gitlab/markdown/filter/merge_request_reference_filter'
+ autoload :RedactorFilter, 'gitlab/markdown/filter/redactor_filter'
+ autoload :ReferenceGathererFilter, 'gitlab/markdown/filter/reference_gatherer_filter'
+ autoload :RelativeLinkFilter, 'gitlab/markdown/filter/relative_link_filter'
+ autoload :SanitizationFilter, 'gitlab/markdown/filter/sanitization_filter'
+ autoload :SnippetReferenceFilter, 'gitlab/markdown/filter/snippet_reference_filter'
+ autoload :SyntaxHighlightFilter, 'gitlab/markdown/filter/syntax_highlight_filter'
+ autoload :TableOfContentsFilter, 'gitlab/markdown/filter/table_of_contents_filter'
+ autoload :TaskListFilter, 'gitlab/markdown/filter/task_list_filter'
+ autoload :UserReferenceFilter, 'gitlab/markdown/filter/user_reference_filter'
+ autoload :UploadLinkFilter, 'gitlab/markdown/filter/upload_link_filter'
+
+ autoload :AsciidocPipeline, 'gitlab/markdown/pipeline/asciidoc_pipeline'
+ autoload :AtomPipeline, 'gitlab/markdown/pipeline/atom_pipeline'
+ autoload :DescriptionPipeline, 'gitlab/markdown/pipeline/description_pipeline'
+ autoload :EmailPipeline, 'gitlab/markdown/pipeline/email_pipeline'
+ autoload :FullPipeline, 'gitlab/markdown/pipeline/full_pipeline'
+ autoload :GfmPipeline, 'gitlab/markdown/pipeline/gfm_pipeline'
+ autoload :NotePipeline, 'gitlab/markdown/pipeline/note_pipeline'
+ autoload :PlainMarkdownPipeline, 'gitlab/markdown/pipeline/plain_markdown_pipeline'
+ autoload :PostProcessPipeline, 'gitlab/markdown/pipeline/post_process_pipeline'
+ autoload :ReferenceExtractionPipeline, 'gitlab/markdown/pipeline/reference_extraction_pipeline'
+ autoload :SingleLinePipeline, 'gitlab/markdown/pipeline/single_line_pipeline'
end
end