rex-text 0.2.43 → 0.2.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e65388b19aabaf76461efffee8b8b0b5c23265a5eff2f9adee5300a5664210c6
4
- data.tar.gz: 4d697d31bf0464783450ff70494bb08f5d00e9186cea660e426e693bc6d025b6
3
+ metadata.gz: b88966aea3c2991faabd788caf7b9141968550554530da585e6cb46207c33d64
4
+ data.tar.gz: 233562b44e969d9a210695571a3aa84fcd4c4d84a6b0d22846696f84ff67a1d5
5
5
  SHA512:
6
- metadata.gz: ef32b2087d8fd1016e69a7584baf2a44999d661d8261468b5e8a462ee42523336b32b5e6dad59b6308b7fdac2b006d848e71bdb3b9c81798c7c70364f0d15ec6
7
- data.tar.gz: 14edb8ce455acae1c6caaca90ee259dbc0d29df0b539440f8242c29e919ebc6ad8954d398c00166f74f7bf14b08e9ddb03b0a886e674447cb8b1c98ec30245a4
6
+ metadata.gz: 6cd18682c4ffcaedc3c3177f27c42e93b4009cce7316090d3a64f84207895af48393f8cd431bd062fcc5c14f10241ad5537b464e2c5484bc1c513a4ed7d76502
7
+ data.tar.gz: 29cc99e565a56b899e43f8f9312ab9520abb3838ee68d8d3702de6ee13f080bc1929401837a0a32df3e00e29f673ae3d5aeee880e765fcf2f1b5727f60dfea76
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- _<) ��# xg�+'4�%g+?e�-�$����lV7��/��C���lT��&�rK�`�e?��3yf������
2
- PAl*���9�r�\a��u��>L�܃�!r�,����'r�@�vv��y���Д
3
- �_XN�z��$Uk��,~������-��{�u�م(��m-�������O���Ȑ��)�>i{�o ���,I!M��7�"�p���leȣ��+
1
+ >�ni����u-�t76�5w�8��X�Nt���k�ܘ\$$�W;��_����i�j2H����|��(�i���m���E��k���xtR��@ĝ
2
+ �L�W��@Q2&�պ�(
@@ -10,6 +10,7 @@ module Text
10
10
  #
11
11
  ###
12
12
  module Color
13
+ SUPPORTED_FORMAT_CODES = %w[%cya %red %grn %blu %yel %whi %mag %blk %dred %dgrn %dblu %dyel %dcya %dwhi %dmag %und %bld %clr %bgblu %bgyel %bggrn %bgmag %bgblk %bgred %bgcyn %bgwhi]
13
14
 
14
15
  AnsiAttributes =
15
16
  {
@@ -1,5 +1,5 @@
1
1
  module Rex
2
2
  module Text
3
- VERSION = "0.2.43"
3
+ VERSION = "0.2.44"
4
4
  end
5
5
  end
@@ -390,6 +390,7 @@ protected
390
390
  # Converts a row to a string.
391
391
  #
392
392
  def row_to_s(row) # :nodoc:
393
+ row = row.each_with_index.map { |cell, index| style_table_field(cell, index) }
393
394
  optimal_widths = calculate_optimal_widths
394
395
  values_as_chunks = chunk_values(row, optimal_widths)
395
396
  chunks_to_s(values_as_chunks, optimal_widths)
@@ -401,17 +402,134 @@ protected
401
402
  # widths. For now it simply returns the string's length.
402
403
  #
403
404
  def display_width(str)
404
- str.length
405
+ Rex::Text.display_width(str)
405
406
  end
406
407
 
408
+ #
409
+ # Returns a string of color/formatting codes made up of the previously stored color_state
410
+ # e.g. if a `%blu` color code spans multiple lines this will return a string of `%blu` to be appended to
411
+ # the beginning of each row
412
+ #
413
+ # @param [Hash<String, String>] color_state tracks current color/formatting codes within table row
414
+ # @returns [String] Color code string such as `%blu%grn'
415
+ def color_code_string_for(color_state)
416
+ result = ''.dup
417
+ color_state.each do |_format, value|
418
+ if value.is_a?(Array)
419
+ result << value.uniq.join
420
+ else
421
+ result << value
422
+ end
423
+ end
424
+ result
425
+ end
426
+
427
+ # @returns [Hash<String, String>] The supported color codes from {Rex::Text::Color} grouped into sections
428
+ def color_code_groups
429
+ return @color_code_groups if @color_code_groups
430
+
431
+ @color_code_groups = {
432
+ foreground: %w[
433
+ %cya %red %grn %blu %yel %whi %mag %blk
434
+ %dred %dgrn %dblu %dyel %dcya %dwhi %dmag
435
+ ],
436
+ background: %w[
437
+ %bgblu %bgyel %bggrn %bgmag %bgblk %bgred %bgcyn %bgwhi
438
+ ],
439
+ decoration: %w[
440
+ %und %bld
441
+ ],
442
+ clear: %w[
443
+ %clr
444
+ ]
445
+ }
446
+
447
+ # Developer exception raised to ensure all color codes are accounted for. Verified via tests.
448
+ missing_color_codes = (Rex::Text::Color::SUPPORTED_FORMAT_CODES - @color_code_groups.values.flatten)
449
+ raise "Unsupported color codes #{missing_color_codes.join(', ')}" if missing_color_codes.any?
450
+
451
+ @color_code_groups
452
+ end
453
+
454
+ # Find the preceding color type and value of a given string
455
+ # @param [String] string A string such as '%bgyel etc'
456
+ # @returns [Array,nil] A tuple with the color type and value, or nil
457
+ def find_color_type_and_value(string)
458
+ color_code_groups.each do |color_type, color_values|
459
+ color_value = color_values.find { |color_value| string.start_with?(color_value) }
460
+ if color_value
461
+ return [color_type, color_value]
462
+ end
463
+ end
464
+
465
+ nil
466
+ end
467
+
468
+ #
469
+ # Takes an array of row values and an integer of optimal column width, loops over array and parses
470
+ # each string to gather color/formatting tags and handles those appropriately while not increasing the column width
471
+ #
472
+ # e.g. if a formatting "%blu" spans across multiple lines it needs to be added to the beginning off every following
473
+ # line, and each line will have a "%clr" added to the end of each row
474
+ #
475
+ # @param [Array<String>] values
476
+ # @param [Integer] optimal_widths
407
477
  def chunk_values(values, optimal_widths)
408
478
  # First split long strings into an array of chunks, where each chunk size is the calculated column width
409
479
  values_as_chunks = values.each_with_index.map do |value, idx|
480
+ color_state = {}
410
481
  column_width = optimal_widths[idx]
411
- value
412
- .chars
413
- .each_slice(column_width)
414
- .map(&:join)
482
+ chunks = []
483
+ current_chunk = nil
484
+ chars = value.chars
485
+ char_index = 0
486
+
487
+ # Check if any color code(s) from previous the string need appended
488
+ while char_index < chars.length do
489
+ # If a new chunk has started, start the chunk with any previous color codes
490
+ if current_chunk.nil? && color_state.any?
491
+ current_chunk = color_code_string_for(color_state)
492
+ end
493
+ current_chunk ||= ''.dup
494
+
495
+ # Check if the remaining chars start with a color code such as %blu
496
+ color_type_and_value = chars[char_index] == '%' ? find_color_type_and_value(chars[char_index..].join) : nil
497
+ if color_type_and_value.nil?
498
+ current_chunk << chars[char_index]
499
+ char_index += 1
500
+ else
501
+ color_type, color_code = color_type_and_value
502
+
503
+ if color_type == :clear
504
+ color_state.clear
505
+ elsif color_type == :decoration
506
+ # Multiple decorations can be enabled
507
+ color_state[:decoration] ||= []
508
+ color_state[:decoration] << color_code
509
+ else
510
+ # There can only be one foreground or background color
511
+ color_state[color_type] = color_code
512
+ end
513
+
514
+ current_chunk << color_code
515
+ char_index += color_code.length
516
+ end
517
+
518
+ # If we've reached the final character of the string, or need to word wrap
519
+ # it's time to push the current chunk, and start a new row. Also discard
520
+ # any values that are purely colors and have no display_width
521
+ is_final_character = char_index >= chars.length
522
+ display_width = display_width(current_chunk)
523
+ if (is_final_character && display_width != 0) || display_width == column_width
524
+ if color_state.any? && !current_chunk.end_with?('%clr')
525
+ current_chunk << '%clr'
526
+ end
527
+ chunks.push(current_chunk)
528
+ current_chunk = nil
529
+ end
530
+ end
531
+
532
+ chunks
415
533
  end
416
534
 
417
535
  values_as_chunks
@@ -424,12 +542,13 @@ protected
424
542
  line = ""
425
543
  row_chunks.each_with_index do |chunk, idx|
426
544
  column_width = optimal_widths[idx]
545
+ chunk_length_with_padding = column_width + (chunk.to_s.length - display_width(chunk.to_s))
427
546
 
428
547
  if idx == 0
429
548
  line << ' ' * indent
430
549
  end
431
550
 
432
- line << chunk.to_s.ljust(column_width)
551
+ line << chunk.to_s.ljust(chunk_length_with_padding)
433
552
  line << ' ' * cellpad
434
553
  end
435
554
 
@@ -519,13 +638,12 @@ protected
519
638
  str_cp
520
639
  end
521
640
 
522
- def style_table_field(str, _idx)
641
+ def style_table_field(str, idx)
523
642
  str_cp = str.dup
524
643
 
525
- # Not invoking as color currently conflicts with the wrapping of tables
526
- # colprops[idx]['Stylers'].each do |s|
527
- # str_cp = s.style(str_cp)
528
- # end
644
+ colprops[idx]['Stylers'].each do |s|
645
+ str_cp = s.style(str_cp)
646
+ end
529
647
 
530
648
  str_cp
531
649
  end
data/lib/rex/text.rb CHANGED
@@ -98,6 +98,21 @@ module Rex
98
98
  end
99
99
 
100
100
 
101
+ # @return [Regexp] Matches a valid color code, i.e. "%blu,%yel,...etc"
102
+ COLOR_CODES_REGEX = /#{Regexp.union(Rex::Text::Color::SUPPORTED_FORMAT_CODES.compact).source}/
103
+ private_constant :COLOR_CODES_REGEX
104
+
105
+ #
106
+ # Function that aims to calculate the display width of the given string.
107
+ # In the future this will be aware of East Asian characters having different display
108
+ # widths. For now it simply returns the string's length ignoring color codes.
109
+ #
110
+ # @param [String] str
111
+ # @return [Integer]
112
+ def self.display_width(str)
113
+ str.gsub(COLOR_CODES_REGEX, '').length
114
+ end
115
+
101
116
  #
102
117
  # Convert 16-byte string to a GUID string
103
118
  #
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rex-text
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.43
4
+ version: 0.2.44
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -93,7 +93,7 @@ cert_chain:
93
93
  EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
94
94
  9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
95
95
  -----END CERTIFICATE-----
96
- date: 2022-09-01 00:00:00.000000000 Z
96
+ date: 2022-09-02 00:00:00.000000000 Z
97
97
  dependencies:
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rake
metadata.gz.sig CHANGED
Binary file