Commit b039a169462ba0f04402d4f1af127216b65f119d

Authored by Robert Speicher
1 parent e31a9dd2

GFM refactor: Move the actual parsing to a class under the Gitlab module

app/helpers/gitlab_markdown_helper.rb
1 1 module GitlabMarkdownHelper
2   - REFERENCE_PATTERN = %r{
3   - ([^\w&;])? # Prefix (1)
4   - ( # Reference (2)
5   - @([\w\._]+) | # User name (3)
6   - [#!$](\d+) | # Issue/MR/Snippet ID (4)
7   - [\h]{6,40} # Commit ID (2)
8   - )
9   - ([^\w&;])? # Suffix (5)
10   - }x.freeze
11   -
12 2 def gfm(text, html_options = {})
13 3 return text if text.nil?
14 4 return text if @project.nil?
... ... @@ -22,21 +12,10 @@ module GitlabMarkdownHelper
22 12 "{gfm-extraction-#{md5}}"
23 13 end
24 14  
25   - text.gsub!(REFERENCE_PATTERN) do |match|
26   - vals = {
27   - prefix: $1,
28   - reference: $2,
29   - user_name: $3,
30   - reference_id: $4,
31   - suffix: $5
32   - }
  15 + # TODO: add popups with additional information
33 16  
34   - if ref_link = reference_link(vals, html_options)
35   - sprintf('%s%s%s', vals[:prefix], ref_link, vals[:suffix])
36   - else
37   - match
38   - end
39   - end
  17 + parser = Gitlab::Markdown.new(@project, html_options)
  18 + text = parser.parse(text)
40 19  
41 20 # Insert pre block extractions
42 21 text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
... ... @@ -71,39 +50,4 @@ module GitlabMarkdownHelper
71 50  
72 51 @__renderer.render(text).html_safe
73 52 end
74   -
75   - private
76   -
77   - def reference_link(vals, html_options)
78   - # TODO: add popups with additional information
79   - case vals[:reference]
80   -
81   - # team member: @foo
82   - when /^@/
83   - user = @project.users.where(name: vals[:user_name]).first
84   - member = @project.users_projects.where(user_id: user).first if user
85   - link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
86   -
87   - # issue: #123
88   - when /^#/
89   - issue = @project.issues.where(id: vals[:reference_id]).first
90   - link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) if issue
91   -
92   - # merge request: !123
93   - when /^!/
94   - merge_request = @project.merge_requests.where(id: vals[:reference_id]).first
95   - link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) if merge_request
96   -
97   - # snippet: $123
98   - when /^\$/
99   - snippet = @project.snippets.where(id: vals[:reference_id]).first
100   - link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) if snippet
101   -
102   - # commit: 123456...
103   - when /^\h/
104   - commit = @project.commit(vals[:reference])
105   - link_to(vals[:reference], project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}")) if commit
106   -
107   - end
108   - end
109 53 end
... ...
lib/gitlab/markdown.rb 0 → 100644
... ... @@ -0,0 +1,98 @@
  1 +module Gitlab
  2 + # Custom parsing for Gitlab-flavored Markdown
  3 + #
  4 + # Examples
  5 + #
  6 + # >> m = Markdown.new(...)
  7 + #
  8 + # >> m.parse("Hey @david, can you fix this?")
  9 + # => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?"
  10 + #
  11 + # >> m.parse("Commit 35d5f7c closes #1234")
  12 + # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
  13 + class Markdown
  14 + include Rails.application.routes.url_helpers
  15 + include ActionView::Helpers
  16 +
  17 + REFERENCE_PATTERN = %r{
  18 + ([^\w&;])? # Prefix (1)
  19 + ( # Reference (2)
  20 + @([\w\._]+) # User name (3)
  21 + |[#!$](\d+) # Issue/MR/Snippet ID (4)
  22 + |([\h]{6,40}) # Commit ID (5)
  23 + )
  24 + ([^\w&;])? # Suffix (6)
  25 + }x.freeze
  26 +
  27 + attr_reader :html_options
  28 +
  29 + def initialize(project, html_options = {})
  30 + @project = project
  31 + @html_options = html_options
  32 + end
  33 +
  34 + def parse(text)
  35 + text.gsub(REFERENCE_PATTERN) do |match|
  36 + prefix = $1 || ''
  37 + reference = $2
  38 + identifier = $3 || $4 || $5
  39 + suffix = $6 || ''
  40 +
  41 + if ref_link = reference_link(reference, identifier)
  42 + prefix + ref_link + suffix
  43 + else
  44 + match
  45 + end
  46 + end
  47 + end
  48 +
  49 + private
  50 +
  51 + # Private: Dispatches to a dedicated processing method based on reference
  52 + #
  53 + # reference - Object reference ("@1234", "!567", etc.)
  54 + # identifier - Object identifier (Issue ID, SHA hash, etc.)
  55 + #
  56 + # Returns string rendered by the processing method
  57 + def reference_link(reference, identifier)
  58 + case reference
  59 + when /^@/ then reference_user(identifier)
  60 + when /^#/ then reference_issue(identifier)
  61 + when /^!/ then reference_merge_request(identifier)
  62 + when /^\$/ then reference_snippet(identifier)
  63 + when /^\h/ then reference_commit(identifier)
  64 + end
  65 + end
  66 +
  67 + def reference_user(identifier)
  68 + if user = @project.users.where(name: identifier).first
  69 + member = @project.users_projects.where(user_id: user).first
  70 + link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
  71 + end
  72 + end
  73 +
  74 + def reference_issue(identifier)
  75 + if issue = @project.issues.where(id: identifier).first
  76 + link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}"))
  77 + end
  78 + end
  79 +
  80 + def reference_merge_request(identifier)
  81 + if merge_request = @project.merge_requests.where(id: identifier).first
  82 + link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}"))
  83 + end
  84 + end
  85 +
  86 + def reference_snippet(identifier)
  87 + if snippet = @project.snippets.where(id: identifier).first
  88 + link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}"))
  89 + end
  90 + end
  91 +
  92 + def reference_commit(identifier)
  93 + if commit = @project.commit(identifier)
  94 + link_to(identifier, project_commit_path(@project, id: commit.id), html_options.merge(title: "Commit: #{commit.author_name} - #{CommitDecorator.new(commit).title}", class: "gfm gfm-commit #{html_options[:class]}"))
  95 + end
  96 + end
  97 + end
  98 +end
... ...