Class: RubyRich::Markdown::TerminalRenderer

Inherits:
Object
  • Object
show all
Defined in:
lib/clacky/rich_ui_controller.rb

Instance Method Summary collapse

Instance Method Details

#clacky_constrain_table_widths(natural_widths) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/clacky/rich_ui_controller.rb', line 250

def clacky_constrain_table_widths(natural_widths)
  return natural_widths if natural_widths.empty?

  border_overhead = (natural_widths.length * 3) + 1
  max_table_width = [[@options[:width].to_i - 1, 20].max, border_overhead + natural_widths.length].max
  available_content_width = [max_table_width - border_overhead, natural_widths.length].max
  widths = natural_widths.map { |width| [width, 1].max }
  return widths if widths.sum <= available_content_width

  min_width = available_content_width < natural_widths.length * 3 ? 1 : 3
  while widths.sum > available_content_width
    index = widths.each_with_index.select { |width, _| width > min_width }.max_by(&:first)&.last
    break unless index

    widths[index] -= 1
  end
  widths
end

#clacky_fit_table_rows(header_row, body_rows) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/clacky/rich_ui_controller.rb', line 224

def clacky_fit_table_rows(header_row, body_rows)
  column_count = [header_row.length, *body_rows.map(&:length)].max.to_i
  normalized_header = header_row + Array.new([0, column_count - header_row.length].max, "")
  normalized_body = body_rows.map { |row| row + Array.new([0, column_count - row.length].max, "") }
  natural_widths = clacky_table_natural_widths(normalized_header, normalized_body)
  column_widths = clacky_constrain_table_widths(natural_widths)

  headers = normalized_header.each_with_index.map { |cell, index| clacky_wrap_table_cell(clacky_table_cell_text(cell), column_widths[index]) }
  rows = normalized_body.map do |row|
    row.each_with_index.map { |cell, index| clacky_wrap_table_cell(clacky_table_cell_text(cell), column_widths[index]) }
  end

  [headers, rows]
end

#clacky_table_cell_text(cell) ⇒ Object



246
247
248
# File 'lib/clacky/rich_ui_controller.rb', line 246

def clacky_table_cell_text(cell)
  process_inline(cell).to_s.gsub(/\e\[[0-9;:]*m/, "")
end

#clacky_table_natural_widths(header_row, body_rows) ⇒ Object



239
240
241
242
243
244
# File 'lib/clacky/rich_ui_controller.rb', line 239

def clacky_table_natural_widths(header_row, body_rows)
  rows = [header_row] + body_rows
  rows.transpose.map do |cells|
    cells.map { |cell| clacky_visible_width(clacky_table_cell_text(cell)) }.max.to_i
  end
end

#clacky_visible_width(text) ⇒ Object



314
315
316
# File 'lib/clacky/rich_ui_controller.rb', line 314

def clacky_visible_width(text)
  text.to_s.gsub(/\e\[[0-9;:]*m/, "").split("\n").map(&:display_width).max.to_i
end

#clacky_wrap_table_cell(text, width) ⇒ Object



269
270
271
272
273
274
# File 'lib/clacky/rich_ui_controller.rb', line 269

def clacky_wrap_table_cell(text, width)
  width = [width.to_i, 1].max
  text.to_s.split("\n", -1).flat_map do |line|
    clacky_wrap_table_line(line, width)
  end.join("\n")
end

#clacky_wrap_table_line(line, width) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/clacky/rich_ui_controller.rb', line 276

def clacky_wrap_table_line(line, width)
  return [""] if line.empty?

  lines = []
  current = +""
  current_width = 0
  in_escape = false
  escape = +""

  line.each_char do |char|
    if in_escape
      escape << char
      if char == "m"
        current << escape
        escape = +""
        in_escape = false
      end
      next
    elsif char.ord == 27
      escape << char
      in_escape = true
      next
    end

    char_width = Unicode::DisplayWidth.of(char)
    if current_width.positive? && current_width + char_width > width
      lines << current
      current = +""
      current_width = 0
    end
    current << char
    current_width += char_width
  end

  lines << current unless current.empty?
  lines.empty? ? [""] : lines
end

#table(header, body) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/clacky/rich_ui_controller.rb', line 194

def table(header, body)
  all_rows = @table_state[:all_rows]
  reset_table_state
  return "" if all_rows.empty?

  header_line_count = [header.to_s.strip.split("\n").size, 1].max
  header_rows = all_rows[0...header_line_count]
  body_rows = all_rows[header_line_count..] || []

  return "" if header_rows.empty? || body_rows.empty?

  headers, fitted_body_rows = clacky_fit_table_rows(header_rows.last, body_rows)
  begin
    tbl = RubyRich::Table.new(headers: headers, border_style: @options[:table_border_style] || :simple)
    fitted_body_rows.each do |row|
      padded = row + Array.new([0, headers.length - row.length].max, "")
      tbl.add_row(padded[0...headers.length])
    end
    return "#{tbl.render}\n\n"
  rescue
    # fall through to the original plain fallback shape
  end

  result = "\n"
  result += "#{header.strip}\n"
  result += "#{"-" * [header.strip.length, 20].min}\n"
  result += "#{body.strip}\n" if body && !body.strip.empty?
  "#{result}\n"
end