snippets_helper.rb 5.0 KB
Newer Older
1 2
# frozen_string_literal: true

G
gitlabhq 已提交
3
module SnippetsHelper
O
Oswaldo Ferreira 已提交
4 5 6 7 8 9 10 11 12 13
  def snippets_upload_path(snippet, user)
    return unless user

    if snippet&.persisted?
      upload_path('personal_snippet', id: snippet.id)
    else
      upload_path('user', id: user.id)
    end
  end

14 15
  def download_raw_snippet_button(snippet)
    link_to(icon('download'),
16
            gitlab_raw_snippet_path(snippet, inline: false),
17 18 19 20 21 22 23
            target: '_blank',
            rel: 'noopener noreferrer',
            class: "btn btn-sm has-tooltip",
            title: 'Download',
            data: { container: 'body' })
  end

24 25 26
  # Return the path of a snippets index for a user or for a project
  #
  # @returns String, path to snippet index
27
  def subject_snippets_path(subject = nil, opts = nil)
28
    if subject.is_a?(Project)
29
      project_snippets_path(subject, opts)
30 31 32 33 34
    else # assume subject === User
      dashboard_snippets_path(opts)
    end
  end

V
Valery Sizov 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
  # Get an array of line numbers surrounding a matching
  # line, bounded by min/max.
  #
  # @returns Array of line numbers
  def bounded_line_numbers(line, min, max, surrounding_lines)
    lower = line - surrounding_lines > min ? line - surrounding_lines : min
    upper = line + surrounding_lines < max ? line + surrounding_lines : max
    (lower..upper).to_a
  end

  # Returns a sorted set of lines to be included in a snippet preview.
  # This ensures matching adjacent lines do not display duplicated
  # surrounding code.
  #
  # @returns Array, unique and sorted.
V
Valery Sizov 已提交
50
  def matching_lines(lined_content, surrounding_lines, query)
V
Valery Sizov 已提交
51 52 53 54 55 56 57
    used_lines = []
    lined_content.each_with_index do |line, line_number|
      used_lines.concat bounded_line_numbers(
        line_number,
        0,
        lined_content.size,
        surrounding_lines
58
      ) if line.downcase.include?(query.downcase)
V
Valery Sizov 已提交
59 60 61 62 63 64 65 66 67
    end

    used_lines.uniq.sort
  end

  # 'Chunkify' entire snippet.  Splits the snippet data into matching lines +
  # surrounding_lines() worth of unmatching lines.
  #
  # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
V
Valery Sizov 已提交
68
  def chunk_snippet(snippet, query, surrounding_lines = 3)
V
Valery Sizov 已提交
69
    lined_content = snippet.content.split("\n")
V
Valery Sizov 已提交
70
    used_lines = matching_lines(lined_content, surrounding_lines, query)
V
Valery Sizov 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

    snippet_chunk = []
    snippet_chunks = []
    snippet_start_line = 0
    last_line = -1

    # Go through each used line, and add consecutive lines as a single chunk
    # to the snippet chunk array.
    used_lines.each do |line_number|
      if last_line < 0
        # Start a new chunk.
        snippet_start_line = line_number
        snippet_chunk << lined_content[line_number]
      elsif last_line == line_number - 1
        # Consecutive line, continue chunk.
        snippet_chunk << lined_content[line_number]
      else
        # Non-consecutive line, add chunk to chunk array.
        snippet_chunks << {
          data: snippet_chunk.join("\n"),
          start_line: snippet_start_line + 1
        }

        # Start a new chunk.
        snippet_chunk = [lined_content[line_number]]
        snippet_start_line = line_number
      end
98

V
Valery Sizov 已提交
99 100 101 102 103 104 105 106 107 108 109
      last_line = line_number
    end
    # Add final chunk to chunk array
    snippet_chunks << {
      data: snippet_chunk.join("\n"),
      start_line: snippet_start_line + 1
    }

    # Return snippet with chunk array
    { snippet_object: snippet, snippet_chunks: snippet_chunks }
  end
H
haseeb 已提交
110

111
  def snippet_embed_tag(snippet)
112
    content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js))
113 114 115 116 117 118 119 120 121 122 123
  end

  def snippet_embed_input(snippet)
    content_tag(:input,
                nil,
                type: :text,
                readonly: true,
                class: 'js-snippet-url-area snippet-embed-input form-control',
                data: { url: gitlab_snippet_url(snippet) },
                value: snippet_embed_tag(snippet),
                autocomplete: 'off')
124 125 126 127 128 129
  end

  def snippet_badge(snippet)
    return unless attrs = snippet_badge_attributes(snippet)

    css_class, text = attrs
130
    tag.span(class: %w[badge badge-gray]) do
131 132 133 134 135 136 137 138 139 140
      concat(tag.i(class: ['fa', css_class]))
      concat(' ')
      concat(text)
    end
  end

  def snippet_badge_attributes(snippet)
    if snippet.private?
      ['fa-lock', _('private')]
    end
H
haseeb 已提交
141 142
  end

143
  def embedded_raw_snippet_button
H
haseeb 已提交
144
    blob = @snippet.blob
145
    return if blob.empty? || blob.binary? || blob.stored_externally?
H
haseeb 已提交
146

147
    link_to(external_snippet_icon('doc-code'),
148
            gitlab_raw_snippet_url(@snippet),
149 150 151 152
            class: 'btn',
            target: '_blank',
            rel: 'noopener noreferrer',
            title: 'Open raw')
H
haseeb 已提交
153 154 155
  end

  def embedded_snippet_download_button
156
    link_to(external_snippet_icon('download'),
157
            gitlab_raw_snippet_url(@snippet, inline: false),
158 159 160 161
            class: 'btn',
            target: '_blank',
            title: 'Download',
            rel: 'noopener noreferrer')
H
haseeb 已提交
162
  end
163 164 165 166 167 168 169 170 171 172

  def snippet_file_name(snippet)
    blob = if Feature.enabled?(:version_snippets, current_user) && !snippet.repository.empty?
             snippet.blobs.first
           else
             snippet.blob
           end

    blob.name
  end
G
gitlabhq 已提交
173
end