markdown_exec 2.7.3 → 2.7.5

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: c35f2f729da73920db53053340bbe0ced75bfbb16ad59697fa6ba4016b62ae74
4
- data.tar.gz: c20943723250feaa3e1b7218710cede9ebf4da4dd6eebf68584a805b9647b7d4
3
+ metadata.gz: e0463a06b2bac6770c2443819a9cedee15e7aa3404649f077924074fd3c639ab
4
+ data.tar.gz: 0f8b10556113950d468d92cfc11510178d7019d5b0e1c3f7ba0f61fdcab57414
5
5
  SHA512:
6
- metadata.gz: 185f571fd39b4bdce955a455695413390b83c3635236871a83098bd595b184b5a79a2cd2b2778fb1fa795d658566237ed251e751fe1981a71aff192ce22da376
7
- data.tar.gz: 19248dd05c973d9657362145826312fd2a07a7f6b4ad6834e623a19f289b35dc4d32c9c16401fc73a7e6309f4fc7ba9a5f63cc82a7db78299b623ea0d3b471f0
6
+ metadata.gz: 32d0e93870011249641e929ab4c6963905321301b508831ef5b56f7be925f69857e0bab3b4f030cfe39f6a8dff83376a099bd568616df872b8d4b7291c2f5227
7
+ data.tar.gz: aad2c863dd5bf6da344342e9336f6efa7045ec51d1471581b42bd26f42c1b1368d380b5f64781fb653154fd45f5f47db4d1fd7f22c8cc2f78c31a4781307b0dc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.7.5] - 2025-02-02
4
+
5
+ ### Added
6
+
7
+ - Option to control initial truncation of table cell text to fit screen width.
8
+ - Truncate text to fit table cell fit to screen width. Click on first row of any table to toggle.
9
+
10
+ ### Changed
11
+
12
+ - Fix the display of collapsible sections.
13
+ - Fix the display of shell expansion and command substitution output.
14
+ - Hide gem sources in caller.deref.
15
+
3
16
  ## [2.7.3] - 2025-01-29
4
17
 
5
18
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.7.3)
4
+ markdown_exec (2.7.5)
5
5
  clipboard (~> 1.3.6)
6
6
  open3 (~> 0.1.1)
7
7
  optparse (~> 0.1.1)
@@ -4,23 +4,23 @@ load 'test_helper'
4
4
 
5
5
  @test 'Options - Collapsible - Document options' {
6
6
  spec_mde_xansi_oname_doc_blocks_expect docs/dev/options-collapse.md \
7
- 'H1.1_L1.1_H2.1_H1.2_H2.2_H1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
7
+ 'H1.1_L1.1_H2.1_H1.2_H1.3_L1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
8
8
  }
9
9
 
10
10
  @test 'Options - Collapsible Heading - Expand' {
11
11
  spec_mde_xansi_oname_doc_blocks_expect docs/dev/options-collapse.md \
12
12
  H2.1 \
13
- 'H1.1_L1.1_H2.1_L2.1_h3.1_L3.1_D4.1_L4.1_H1.2_L1.2_H2.2_H1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
13
+ 'H1.1_L1.1_H2.1_L2.1_h3.1_L3.1_D4.1_L4.1_H1.2_H1.3_L1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
14
14
  }
15
15
 
16
16
  @test 'Options - Collapsible Divider' {
17
17
  spec_mde_xansi_oname_doc_blocks_expect docs/dev/options-collapse.md \
18
18
  D4.3 \
19
- 'H1.1_L1.1_H2.1_H1.2_H2.2_H1.3_H2.3_L2.3_h3.3_L3.3_D4.3'
19
+ 'H1.1_L1.1_H2.1_H1.2_H1.3_L1.3_H2.3_L2.3_h3.3_L3.3_D4.3'
20
20
  }
21
21
 
22
22
  @test 'Options - Reveal' {
23
23
  spec_mde_xansi_oname_doc_blocks_expect docs/dev/options-collapse.md \
24
- H2.2 h3.2 D4.2 \
25
- 'H1.1_L1.1_H2.1_H1.2_H2.2_L2.2_h3.2_L3.2_D4.2_L4.2_H1.3_L1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
24
+ H1.2 H2.2 h3.2 D4.2 \
25
+ 'H1.1_L1.1_H2.1_H1.2_L1.2_H2.2_L2.2_h3.2_L3.2_D4.2_L4.2_H1.3_L1.3_H2.3_L2.3_h3.3_L3.3_D4.3_L4.3'
26
26
  }
@@ -13,7 +13,7 @@ __filedirs_all()
13
13
  }
14
14
 
15
15
  _mde_echo_version() {
16
- echo "2.7.3"
16
+ echo "2.7.5"
17
17
  }
18
18
 
19
19
  _mde() {
@@ -33,7 +33,7 @@ divider4_collapse: false
33
33
  divider4_collapsible: true
34
34
  heading1_center: false
35
35
  heading1_collapse: false
36
- heading1_collapsible: false
36
+ heading1_collapsible: true
37
37
  heading2_center: false
38
38
  heading2_collapse: true
39
39
  heading2_collapsible: true
data/lib/collapser.rb CHANGED
@@ -6,18 +6,20 @@
6
6
  require_relative 'constants'
7
7
 
8
8
  class Collapser
9
- attr_accessor :options, :state
9
+ attr_accessor :compress_ids, :expand_ids, :options
10
10
 
11
11
  def initialize(
12
12
  collapsed_level: nil,
13
13
  collapsible_types: COLLAPSIBLE_TYPES,
14
- options: {},
15
- state: Hash.new(nil)
14
+ compress_ids:,
15
+ expand_ids:,
16
+ options: {}
16
17
  )
17
18
  @collapsed_level = collapsed_level
18
19
  @collapsible_types = collapsible_types.dup
19
20
  @options = options.dup
20
- @state = state # do not dup
21
+ @compress_ids = compress_ids # by ref, user action
22
+ @expand_ids = expand_ids # by ref, user action
21
23
  end
22
24
 
23
25
  def collapse_per_options?(fcb, options: @options)
@@ -27,13 +29,15 @@ class Collapser
27
29
  criteria
28
30
  end
29
31
 
30
- def collapse_per_state?(fcb, default: false, state: @state)
31
- return false if state.nil?
32
-
33
- criteria = state[fcb.id]
34
- return default if criteria.nil?
35
-
36
- !!criteria
32
+ # collapse per user action
33
+ def collapse_per_state?(fcb, default: false)
34
+ if @compress_ids.key?(fcb.id) && !!@compress_ids[fcb.id]
35
+ true
36
+ elsif @expand_ids.key?(fcb.id) && !!@expand_ids[fcb.id]
37
+ false
38
+ else
39
+ default
40
+ end
37
41
  end
38
42
 
39
43
  def collapse_per_token?(fcb)
@@ -52,10 +56,11 @@ class Collapser
52
56
  end
53
57
 
54
58
  def collapse?(fcb, initialize: false)
59
+ per_options_and_token = (collapse_per_options?(fcb) || collapse_per_token?(fcb)) && !expand_per_token?(fcb)
55
60
  if initialize
56
- (collapse_per_options?(fcb) || collapse_per_token?(fcb)) && !expand_per_token?(fcb)
61
+ per_options_and_token
57
62
  else
58
- collapse_per_state?(fcb, default: false)
63
+ collapse_per_state?(fcb, default: per_options_and_token)
59
64
  end
60
65
  end
61
66
 
@@ -100,8 +105,13 @@ class Collapser
100
105
  else
101
106
  fcb.hide = true
102
107
  end
103
- @state[fcb.id] = fcb.level if fcb.collapse
104
-
108
+ if fcb.collapse
109
+ @compress_ids[fcb.id] = fcb.level
110
+ @expand_ids.delete(fcb.id)
111
+ else
112
+ @compress_ids.delete(fcb.id)
113
+ @expand_ids[fcb.id] = fcb.level
114
+ end
105
115
  collapsed_level
106
116
  end
107
117
 
@@ -138,13 +148,15 @@ OPTIONS = {
138
148
  heading3_collapse: false,
139
149
  heading3_collapsible: true
140
150
  }.freeze
141
- STATE = {}.freeze
142
151
 
143
152
  class CollapserTest < Minitest::Test
144
153
  def setup
145
- @collapser = Collapser.new(collapsible_types: COLLAPSIBLE_TYPES.dup,
146
- options: OPTIONS.dup,
147
- state: STATE).dup
154
+ @collapser = Collapser.new(
155
+ collapsible_types: COLLAPSIBLE_TYPES.dup,
156
+ options: OPTIONS.dup,
157
+ compress_ids: {},
158
+ expand_ids: {}
159
+ ).dup
148
160
  end
149
161
 
150
162
  def test_analyze
@@ -312,7 +324,8 @@ class CollapserTest < Minitest::Test
312
324
  { name: 'collapsed remains collapsed',
313
325
  fcbs: [fc_h1a__collapse_collapsible],
314
326
  options: { heading1_collapsible: true },
315
- state: { 'h1a' => 1 },
327
+ compress_ids: { 'h1a' => 1 },
328
+ expand_ids: {},
316
329
  initialize: false,
317
330
  expected: [fc_h1a__collapse_collapsible] }
318
331
  ]
@@ -324,7 +337,8 @@ class CollapserTest < Minitest::Test
324
337
  collapsed_level: test_case[:collapsed_level],
325
338
  collapsible_types: test_case[:collapsible_types] || COLLAPSIBLE_TYPES,
326
339
  options: (test_case[:options] || OPTIONS).dup,
327
- state: (test_case[:state] || STATE).dup
340
+ compress_ids: test_case[:compress_ids] || {},
341
+ expand_ids: {}
328
342
  )
329
343
  analysis = @collapser.analyze(
330
344
  test_case[:fcbs],
data/lib/fcb.rb CHANGED
@@ -33,6 +33,10 @@ module MarkdownExec
33
33
  title: '',
34
34
  type: ''
35
35
  }.merge(options)
36
+ # @attrs[:raw_body] ||= @attrs[:body]
37
+ # @attrs[:raw_dname] ||= @attrs[:dname]
38
+ # @attrs[:raw_s0printable] ||= @attrs[:s0printable]
39
+ # @attrs[:raw_s1decorated] ||= @attrs[:s1decorated]
36
40
  end
37
41
 
38
42
  def code_name_included?(*names)
@@ -43,6 +47,10 @@ module MarkdownExec
43
47
  Regexp.new(regexp) =~ @attrs[:oname]
44
48
  end
45
49
 
50
+ def delete_key(key)
51
+ @attrs.delete(key)
52
+ end
53
+
46
54
  # Derives a title from the body of an FCB object.
47
55
  # @param fcb [Object] The FCB object whose title is to be derived.
48
56
  # @return [String] The derived title.
@@ -57,10 +65,38 @@ module MarkdownExec
57
65
  @attrs[:title] = if body_content.count == 1
58
66
  body_content.first
59
67
  else
60
- FCB::format_multiline_body_as_title(body_content)
68
+ FCB.format_multiline_body_as_title(body_content)
61
69
  end
62
70
  end
63
71
 
72
+ # def body=(value)
73
+ # ww0 'body=', value
74
+ # # binding.irb
75
+ # @attrs[:raw_body] ||= value
76
+ # @attrs[:body] = value
77
+ # end
78
+
79
+ # def dname=(value)
80
+ # ww0 'dname=', value
81
+ # binding.irb if value == ' | Species| Not specified'
82
+ # @attrs[:raw_dname] ||= value
83
+ # @attrs[:dname] = value
84
+ # end
85
+
86
+ # def s0printable=(value)
87
+ # ww0 's0printable=', value
88
+ # # binding.irb
89
+ # @attrs[:raw_s0printable] ||= value
90
+ # @attrs[:s0printable] = value
91
+ # end
92
+
93
+ # def s1decorated=(value)
94
+ # ww0 's1decorated=', value
95
+ # # binding.irb
96
+ # @attrs[:raw_s1decorated] ||= value
97
+ # @attrs[:s1decorated] = value
98
+ # end
99
+
64
100
  # Processes a block to generate its summary, modifying its attributes
65
101
  # based on various matching criteria.
66
102
  # It handles special formatting for bash blocks, extracting and setting
@@ -75,6 +111,7 @@ module MarkdownExec
75
111
  block_name_nick_match: @delegate_object[:block_name_nick_match],
76
112
  id: ''
77
113
  )
114
+ # binding.irb
78
115
  call = @attrs[:call] = @attrs[:start_line]&.match(
79
116
  Regexp.new(block_calls_scan)
80
117
  )&.fetch(1, nil)
@@ -85,7 +122,7 @@ module MarkdownExec
85
122
  @attrs[:nickname] = $~[0]
86
123
  derive_title_from_body
87
124
  else
88
- bm = NamedCaptureExtractor::extract_named_groups(
125
+ bm = NamedCaptureExtractor.extract_named_groups(
89
126
  titlexcall,
90
127
  block_name_match
91
128
  )
@@ -161,7 +198,6 @@ module MarkdownExec
161
198
  end
162
199
 
163
200
  # Expand variables in attributes
164
- ####
165
201
  def expand_variables_in_attributes!(pattern, replacements)
166
202
  @attrs[:raw_dname] ||= @attrs[:dname]
167
203
  @attrs[:dname] = @attrs[:dname]&.gsub(pattern) do |match|
@@ -179,14 +215,14 @@ module MarkdownExec
179
215
  end
180
216
 
181
217
  # Replace variables in each line of `body` if `body` is present
182
- if @attrs[:body]
183
- @attrs[:raw_body] ||= @attrs[:body]
184
- @attrs[:body] = @attrs[:body]&.map do |line|
185
- if line.empty?
186
- line
187
- else
188
- line.gsub(pattern) { |match| replacements[match] }
189
- end
218
+ return unless @attrs[:body]
219
+
220
+ @attrs[:raw_body] ||= @attrs[:body]
221
+ @attrs[:body] = @attrs[:body]&.map do |line|
222
+ if line.empty?
223
+ line
224
+ else
225
+ line.gsub(pattern) { |match| replacements[match] }
190
226
  end
191
227
  end
192
228
  end
data/lib/format_table.rb CHANGED
@@ -63,20 +63,31 @@ module MarkdownTableFormatter
63
63
  end
64
64
  end
65
65
 
66
- def format_cell(cell, align, width)
67
- case align
68
- when :center
69
- cell.center(width)
70
- when :right
71
- cell.rjust(width)
72
- else
73
- cell.ljust(width)
74
- end
66
+ def format_cell(cell, align, width, truncate: true)
67
+ plain_string = cell.gsub(/\033\[[\d;]+m|\033\[0m/, '')
68
+ truncated = false
69
+ ret = TrackedString.new(
70
+ case
71
+ when truncate && plain_string.length > width
72
+ truncated = true
73
+ plain_string[0, width]
74
+ when align == :center
75
+ cell.center(width)
76
+ when align == :right
77
+ cell.rjust(width)
78
+ else
79
+ cell.ljust(width)
80
+ end
81
+ )
82
+ ret.truncated = truncated
83
+ ret
75
84
  end
76
85
 
77
86
  def format_row_line__hs(
78
87
  row, alignment_indicators, column_widths, decorate,
79
- text_sym: :text, style_sym: :color
88
+ style_sym: :color,
89
+ text_sym: :text,
90
+ truncate: true
80
91
  )
81
92
  return HierarchyString.new if row.cells.nil?
82
93
 
@@ -92,8 +103,10 @@ module MarkdownTableFormatter
92
103
  style_sym => decorate && decorate[row.role] }
93
104
  else
94
105
  {
95
- text_sym => format_cell(cell, alignment_indicators[i],
96
- column_widths[i]),
106
+ text_sym => format_cell(
107
+ cell, alignment_indicators[i], column_widths[i],
108
+ truncate: truncate
109
+ ),
97
110
  style_sym => decoration_style(row.role, row.counter, decorate)
98
111
  }
99
112
  end
@@ -106,9 +119,15 @@ module MarkdownTableFormatter
106
119
  )
107
120
  end
108
121
 
109
- def format_rows__hs(rows, alignment_indicators, column_widths, decorate)
122
+ def format_rows__hs(
123
+ rows, alignment_indicators, column_widths, decorate,
124
+ truncate: true
125
+ )
110
126
  rows.map do |row|
111
- format_row_line__hs(row, alignment_indicators, column_widths, decorate)
127
+ format_row_line__hs(
128
+ row, alignment_indicators, column_widths, decorate,
129
+ truncate: truncate
130
+ )
112
131
  end
113
132
  end
114
133
 
@@ -116,7 +135,11 @@ module MarkdownTableFormatter
116
135
  format_table__hs(**kwargs).map(&:decorate)
117
136
  end
118
137
 
119
- def format_table__hs(lines:, column_count:, decorate: nil)
138
+ def format_table__hs(
139
+ lines:, column_count:, decorate: nil,
140
+ table_width: nil,
141
+ truncate: true
142
+ )
120
143
  unless column_count.positive?
121
144
  return lines.map do |line|
122
145
  HierarchyString.new([{ text: line }])
@@ -129,7 +152,23 @@ module MarkdownTableFormatter
129
152
  alignment_indicators, column_widths =
130
153
  calculate_column_alignment_and_widths(rows, column_count)
131
154
 
132
- format_rows__hs(rows, alignment_indicators, column_widths, decorate)
155
+ # ww0 'table_width', table_width
156
+ # ww0 'truncate', truncate
157
+
158
+ unless table_width.nil?
159
+ sum_column_widths = column_widths.sum
160
+ if sum_column_widths > table_width
161
+ ratio = table_width.to_f / sum_column_widths
162
+ column_widths.each_with_index do |width, i|
163
+ column_widths[i] = (width * ratio).to_i
164
+ end
165
+ end
166
+ end
167
+
168
+ format_rows__hs(
169
+ rows, alignment_indicators, column_widths, decorate,
170
+ truncate: truncate
171
+ ).tap { |ret| binding.irb if ret.class == TrackedString }
133
172
  end
134
173
 
135
174
  def insert_every_other(array, obj)
@@ -43,6 +43,7 @@ require_relative 'table_extractor'
43
43
  require_relative 'text_analyzer'
44
44
 
45
45
  $pd = false unless defined?($pd)
46
+ $table_cell_truncate = true
46
47
 
47
48
  class String
48
49
  # Checks if the string is not empty.
@@ -291,9 +292,25 @@ module HashDelegatorSelf
291
292
  row: delegate_object[:table_row_color],
292
293
  separator_line: delegate_object[:table_separator_line_color]
293
294
  },
294
- lines: lines
295
+ lines: lines,
296
+ table_width: screen_width_for_table,
297
+ truncate: $table_cell_truncate
295
298
  )
296
299
 
300
+ truncated_table_cell = false
301
+ table__hs.each do |table_hs|
302
+ table_hs.substrings.each do |substrings|
303
+ substrings.each do |node|
304
+ if node[:text].class == TrackedString
305
+ truncated_table_cell = node[:text].truncated
306
+ break if truncated_table_cell
307
+ end
308
+ end
309
+ break if truncated_table_cell
310
+ end
311
+ break if truncated_table_cell
312
+ end
313
+
297
314
  unless table__hs.count == range.size
298
315
  raise 'Invalid result from MarkdownTableFormatter.format_table()'
299
316
  end
@@ -317,6 +334,13 @@ module HashDelegatorSelf
317
334
  end
318
335
  fcb.s3indent ||= ''
319
336
  fcb.dname = fcb.indented_decorated = fcb.s3indent + fcb.s3formatted_table_row.decorate
337
+
338
+ if ind.zero?
339
+ fcb.truncated_table_cell = truncated_table_cell
340
+ # if truncated_table_cell
341
+ fcb.delete_key(:disabled)
342
+ # end
343
+ end
320
344
  end
321
345
  end
322
346
  end
@@ -581,7 +605,8 @@ module MarkdownExec
581
605
  @p_params = {}
582
606
  @p_rest = []
583
607
 
584
- @compressed_ids = nil
608
+ @compressed_ids = {}
609
+ @expanded_ids = {}
585
610
  end
586
611
 
587
612
  ##
@@ -902,8 +927,10 @@ module MarkdownExec
902
927
 
903
928
  # private
904
929
 
905
- def build_replacement_dictionary(commands, link_state,
906
- initial_code_required: false, key_format:)
930
+ def build_replacement_dictionary(
931
+ commands, link_state,
932
+ initial_code_required: false, key_format:
933
+ )
907
934
  evaluate_shell_expressions(
908
935
  (link_state&.inherited_lines_block || ''), commands,
909
936
  initial_code_required: initial_code_required,
@@ -983,7 +1010,7 @@ module MarkdownExec
983
1010
 
984
1011
  # sets ENV
985
1012
  def code_from_vars_block_to_set_environment_variables(selected)
986
- code_lines = []
1013
+ code_lines = []
987
1014
  case data = YAML.load(selected.body.join("\n"))
988
1015
  when Hash
989
1016
  data.each do |key, value|
@@ -1232,14 +1259,21 @@ module MarkdownExec
1232
1259
  # to the block's display name.
1233
1260
  # return number of lines added
1234
1261
  def create_and_add_chrome_block(
1235
- blocks:, case_conversion: nil, center: nil,
1236
- collapse: nil, color_method:, decor_patterns: [],
1237
- disabled: true, format_option:, id: '',
1238
- level: 0, match_data:, type: '',
1239
- wrap: nil,
1240
- fcb: nil
1262
+ blocks:,
1263
+ case_conversion: nil,
1264
+ center: nil,
1265
+ collapse: nil,
1266
+ color_method:,
1267
+ decor_patterns: [],
1268
+ disabled: true,
1269
+ fcb: nil,
1270
+ format_option:,
1271
+ id: '',
1272
+ level: 0,
1273
+ match_data:,
1274
+ type: '',
1275
+ wrap: nil
1241
1276
  )
1242
- ww 'match_data', match_data
1243
1277
  line_cap = NamedCaptureExtractor.extract_named_group_match_data(match_data)
1244
1278
  # replace tabs in indent
1245
1279
  line_cap[:indent] ||= ''
@@ -1296,7 +1330,24 @@ module MarkdownExec
1296
1330
 
1297
1331
  line_obj[:line] = line_obj[:indent] + line_obj[:text]
1298
1332
 
1299
- if !use_fcb
1333
+ if use_fcb
1334
+ fcb.center = center
1335
+ fcb.chrome = true
1336
+ fcb.collapse = collapse.nil? ? (line_obj[:collapse] == COLLAPSIBLE_TOKEN_COLLAPSE) : collapse
1337
+ fcb.token = line_obj[:collapse]
1338
+ fcb.disabled = disabled ? TtyMenu::DISABLE : nil
1339
+ fcb.id = "#{id}.#{index}"
1340
+ fcb.level = level
1341
+ fcb.s0indent = indent
1342
+ fcb.s0printable = line_obj[:text]
1343
+ fcb.s1decorated = decorated
1344
+ fcb.dname = line_obj[:indent] + decorated
1345
+ fcb.indent = line_obj[:indent]
1346
+ fcb.oname = line_obj[:text]
1347
+ fcb.text = line_obj[:text]
1348
+ fcb.type = type
1349
+ use_fcb = false # next line is new record
1350
+ else
1300
1351
  fcb = FCB.new(
1301
1352
  center: center,
1302
1353
  chrome: true,
@@ -1314,23 +1365,6 @@ module MarkdownExec
1314
1365
  text: line_obj[:text],
1315
1366
  type: type
1316
1367
  )
1317
- else
1318
- fcb.center = center
1319
- fcb.chrome = true
1320
- fcb.collapse = collapse.nil? ? (line_obj[:collapse] == COLLAPSIBLE_TOKEN_COLLAPSE) : collapse
1321
- fcb.token = line_obj[:collapse]
1322
- fcb.disabled = disabled ? TtyMenu::DISABLE : nil
1323
- fcb.id = "#{id}.#{index}"
1324
- fcb.level = level
1325
- fcb.s0indent = indent
1326
- fcb.s0printable = line_obj[:text]
1327
- fcb.s1decorated = decorated
1328
- fcb.dname = line_obj[:indent] + decorated
1329
- fcb.indent = line_obj[:indent]
1330
- fcb.oname = line_obj[:text]
1331
- fcb.text = line_obj[:text]
1332
- fcb.type = type
1333
- use_fcb = false # next line is new record
1334
1368
  end
1335
1369
 
1336
1370
  blocks.push fcb
@@ -1378,7 +1412,7 @@ module MarkdownExec
1378
1412
  @delegate_object[criteria[:color]].to_sym,
1379
1413
  decor_patterns:
1380
1414
  @decor_patterns_from_delegate_object_for_block_create,
1381
- disabled: !(criteria[:collapsible] && @delegate_object[criteria[:collapsible]]),
1415
+ disabled: fcb.truncated_table_cell.nil? && !(criteria[:collapsible] && @delegate_object[criteria[:collapsible]]),
1382
1416
  fcb: fcb,
1383
1417
  id: "#{id}.#{index}",
1384
1418
  format_option: criteria[:format] &&
@@ -1669,7 +1703,13 @@ module MarkdownExec
1669
1703
  selected:, mdoc:, block_source:, link_state: LinkState.new
1670
1704
  )
1671
1705
  # order should not be important other than else clause
1672
- if selected.type == BlockType::EDIT
1706
+ if selected.type == BlockType::TEXT && !selected.truncated_table_cell.nil?
1707
+ debounce_reset
1708
+ $table_cell_truncate = !$table_cell_truncate
1709
+
1710
+ LoadFileLinkState.new(LoadFile::REUSE, link_state)
1711
+
1712
+ elsif selected.type == BlockType::EDIT
1673
1713
  debounce_reset
1674
1714
  vux_edit_inherited
1675
1715
  return :break if pause_user_exit
@@ -1814,7 +1854,7 @@ module MarkdownExec
1814
1854
  filename: '*',
1815
1855
  form: '%{line}',
1816
1856
  link_state:,
1817
- regexp: "^(?<line>.*)$",
1857
+ regexp: '^(?<line>.*)$',
1818
1858
  selected:
1819
1859
  )
1820
1860
  block_data = HashDelegator.parse_yaml_data_from_body(selected.body)
@@ -2207,7 +2247,8 @@ module MarkdownExec
2207
2247
  def execute_required_lines(
2208
2248
  blockname: '',
2209
2249
  erls: {},
2210
- required_lines: [], shell:
2250
+ required_lines: [],
2251
+ shell:
2211
2252
  )
2212
2253
  if @delegate_object[:save_executed_script]
2213
2254
  write_command_file(blockname: blockname,
@@ -2242,12 +2283,12 @@ module MarkdownExec
2242
2283
  end
2243
2284
 
2244
2285
  def expand_variable_references!(
2245
- echo_format: 'echo $%s',
2246
- link_state:,
2247
2286
  blocks:,
2287
+ echo_format: 'echo $%s',
2248
2288
  group_name: :variable,
2249
2289
  initial_code_required: false,
2250
2290
  key_format: '${%s}',
2291
+ link_state:,
2251
2292
  pattern: nil
2252
2293
  )
2253
2294
  pattern ||= options_variable_expression_regexp
@@ -2563,11 +2604,14 @@ module MarkdownExec
2563
2604
  label_format_below = @delegate_object[:shell_code_label_format_below]
2564
2605
 
2565
2606
  ([
2566
- label_format_above.present? ?
2607
+ if label_format_above.present?
2567
2608
  format(
2568
2609
  label_format_above,
2569
2610
  block_source.merge({ block_name: selected.pub_name })
2570
- ) : nil
2611
+ )
2612
+ else
2613
+ nil
2614
+ end
2571
2615
  ] +
2572
2616
  output_lines.map do |line|
2573
2617
  re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
@@ -2579,11 +2623,14 @@ module MarkdownExec
2579
2623
  )
2580
2624
  end +
2581
2625
  [
2582
- label_format_below.present? ?
2626
+ if label_format_below.present?
2583
2627
  format(
2584
2628
  label_format_below,
2585
2629
  block_source.merge({ block_name: selected.pub_name })
2586
- ) : nil
2630
+ )
2631
+ else
2632
+ nil
2633
+ end
2587
2634
  ]).compact
2588
2635
  end
2589
2636
 
@@ -2809,9 +2856,11 @@ module MarkdownExec
2809
2856
  def mdoc_menu_and_blocks_from_nested_files(link_state, source_id: '')
2810
2857
  # read blocks, load document opts block, and re-process blocks
2811
2858
  #
2859
+ reload_blocks = false
2860
+
2812
2861
  all_blocks, mdoc = mdoc_and_blocks_from_nested_files(source_id: source_id)
2813
2862
  if load_auto_opts_block(all_blocks, mdoc: mdoc)
2814
- all_blocks, mdoc = mdoc_and_blocks_from_nested_files(source_id: source_id)
2863
+ reload_blocks = true
2815
2864
  end
2816
2865
 
2817
2866
  # load document shell block
@@ -2819,6 +2868,7 @@ module MarkdownExec
2819
2868
  if code_lines = load_document_shell_block(all_blocks, mdoc: mdoc)
2820
2869
  next_state_set_code(nil, link_state, code_lines)
2821
2870
  link_state.inherited_lines = code_lines
2871
+ reload_blocks = true
2822
2872
  end
2823
2873
 
2824
2874
  # load document vars block
@@ -2828,15 +2878,31 @@ module MarkdownExec
2828
2878
  code_lines)
2829
2879
  next_state_set_code(nil, link_state, new_code)
2830
2880
  link_state.inherited_lines = new_code
2881
+ reload_blocks = true
2882
+ end
2883
+
2884
+ if reload_blocks
2885
+ all_blocks, mdoc = mdoc_and_blocks_from_nested_files(source_id: source_id)
2831
2886
  end
2832
2887
 
2833
2888
  # filter by name, collapsed
2834
2889
  #
2835
- menu_blocks, @compressed_ids = mdoc.fcbs_per_options(
2836
- @delegate_object.merge!(compressed_ids: @compressed_ids)
2890
+ menu_blocks = mdoc.fcbs_per_options(
2891
+ @delegate_object.merge!(compressed_ids: @compressed_ids,
2892
+ expanded_ids: @expanded_ids)
2837
2893
  )
2838
2894
 
2895
+ # restore pre-expansion (raw) values
2896
+ #
2897
+ menu_blocks.each do |fcb|
2898
+ fcb.dname = fcb.raw_dname unless fcb.raw_dname.nil?
2899
+ fcb.s0printable = fcb.raw_s0printable unless fcb.raw_s0printable.nil?
2900
+ fcb.s1decorated = fcb.raw_s1decorated unless fcb.raw_s1decorated.nil?
2901
+ fcb.body = fcb.raw_body unless fcb.raw_body.nil?
2902
+ end
2903
+
2839
2904
  # re-expand blocks
2905
+ #
2840
2906
  menu_blocks.each do |fcb|
2841
2907
  fcb.body = fcb.raw_body || fcb.body || []
2842
2908
  fcb.dname = fcb.raw_dname || fcb.dname
@@ -2858,6 +2924,7 @@ module MarkdownExec
2858
2924
  HashDelegator.tables_into_columns!(menu_blocks, @delegate_object,
2859
2925
  screen_width_for_table)
2860
2926
 
2927
+
2861
2928
  [all_blocks, menu_blocks, mdoc]
2862
2929
  end
2863
2930
 
@@ -2918,19 +2985,16 @@ module MarkdownExec
2918
2985
  end
2919
2986
  end
2920
2987
 
2921
- def menu_compress_collapsible_block(selected)
2922
- @compressed_ids.merge!(selected.id => selected.level)
2923
- end
2924
-
2925
- def menu_expand_collapsible_block(selected)
2926
- @compressed_ids.delete(selected.id)
2927
- end
2928
-
2929
2988
  def menu_toggle_collapsible_block(selected)
2930
- if @compressed_ids.keys.include?(selected.id)
2931
- menu_expand_collapsible_block(selected)
2932
- else
2933
- menu_compress_collapsible_block(selected)
2989
+ # return true if @compress_ids.key?(fcb.id) && !!@compress_ids[fcb.id]
2990
+ # return false if @expand_ids.key?(fcb.id) && !!@expand_ids[fcb.id]
2991
+ # binding.irb
2992
+ if @compressed_ids.key?(selected.id) && !!@compressed_ids[selected.id]
2993
+ @compressed_ids.delete(selected.id)
2994
+ @expanded_ids[selected.id] = selected.level
2995
+ else # @expand_ids.key?(fcb.id) && !!@expand_ids[fcb.id]
2996
+ @compressed_ids[selected.id] = selected.level
2997
+ @expanded_ids.delete(selected.id)
2934
2998
  end
2935
2999
  end
2936
3000
 
@@ -3403,7 +3467,6 @@ module MarkdownExec
3403
3467
  def saved_asset_for_history(
3404
3468
  file:, form:, match_info:
3405
3469
  )
3406
-
3407
3470
  OpenStruct.new(
3408
3471
  file: file[(Dir.pwd.length + 1)..-1],
3409
3472
  full: file,
@@ -4495,9 +4558,9 @@ module MarkdownExec
4495
4558
  when nil
4496
4559
  nil
4497
4560
  when String
4498
- menu_blocks.find { |block|
4561
+ menu_blocks.find do |block|
4499
4562
  block.dname.include?(prior_answer)
4500
- }&.name
4563
+ end&.name
4501
4564
  when Struct
4502
4565
  prior_answer.index || prior_answer.name
4503
4566
  end
@@ -2,6 +2,15 @@
2
2
 
3
3
  require_relative 'ansi_string'
4
4
 
5
+ class TrackedString < String
6
+ attr_accessor :truncated
7
+
8
+ def initialize(str)
9
+ super(str)
10
+ @truncated = false
11
+ end
12
+ end
13
+
5
14
  # Class representing a hierarchy of substrings stored as Hash nodes
6
15
  # HierarchyString is a class that represents and manipulates strings based on a hierarchical structure.
7
16
  # The input to the class can be a single hash or an array of nested hashes, where each hash contains a
@@ -7,5 +7,5 @@ module MarkdownExec
7
7
  BIN_NAME = 'mde'
8
8
  GEM_NAME = 'markdown_exec'
9
9
  TAP_DEBUG = 'MDE_DEBUG'
10
- VERSION = '2.7.3'
10
+ VERSION = '2.7.5'
11
11
  end
data/lib/markdown_exec.rb CHANGED
@@ -282,6 +282,7 @@ module MarkdownExec
282
282
  include StringUtil
283
283
 
284
284
  def initialize(options = {})
285
+ # ww0 'options', options, caller.deref
285
286
  @option_parser = nil
286
287
 
287
288
  @options = HashDelegator.new(options)
data/lib/mdoc.rb CHANGED
@@ -220,101 +220,31 @@ module MarkdownExec
220
220
  end
221
221
 
222
222
  collapser = Collapser.new(
223
- options: opts, state: opts[:compressed_ids] || {}
223
+ options: opts,
224
+ compress_ids: opts[:compressed_ids] || {},
225
+ expand_ids: opts[:expanded_ids] || {}
224
226
  )
225
- selrows = collapser.reject(selrows, initialize: opts[:compressed_ids].nil?) do |fcb, hide, collapsed_level|
227
+ selrows = collapser.reject(
228
+ selrows,
229
+ initialize: opts[:compressed_ids].nil?
230
+ ) do |fcb, _hide, _collapsed_level|
226
231
  # update fcb per state
227
232
  if fcb.collapsible
228
233
  fcb.s1decorated = fcb.s1decorated + ' ' + (fcb.collapse ? opts[:menu_collapsible_symbol_collapsed] : opts[:menu_collapsible_symbol_expanded])
229
234
  end
230
235
  end
231
- opts[:compressed_ids] = collapser.state
236
+ opts[:compressed_ids] = collapser.compress_ids
237
+ opts[:expanded_ids] = collapser.expand_ids
232
238
 
233
239
  # remove
234
240
  # . empty chrome between code; edges are same as blanks
235
241
  #
236
- [
237
- select_elements_with_neighbor_conditions(selrows) do |prev_element, current, next_element|
238
- !(current[:chrome] && !current.oname.present?) ||
239
- !(!prev_element.nil? &&
240
- prev_element.shell.present? &&
241
- !next_element.nil? &&
242
- next_element.shell.present?)
243
- end,
244
- opts[:compressed_ids]
245
- ]
246
- end
247
-
248
- # Filters out blocks that are nested within a hierarchy of "hidden" blocks.
249
- #
250
- # The method iterates over selected rows and uses a callback block to determine if a given block
251
- # should trigger hiding for subsequent blocks in the hierarchy. Once hiding is triggered, all
252
- # blocks with a level greater than the triggering block's level are excluded until the next
253
- # visible collapsible block.
254
- #
255
- # @param selrows [Array] The array of selected rows to filter based on the callback's results.
256
- # @param callback [Lambda/Proc] Alternate to yield block.
257
- # @param collapsible_types [Array] Types to select, nil for all.
258
- # @yield [block] A callback to evaluate each block; should return true to initiate hiding.
259
- # @return [Array] Filtered list of rows, excluding those hidden by hierarchical hiding rules.
260
- #
261
- # Example:
262
- # proc_condition = Proc.new { |fcb| fcb.type == BlockType::HEADING && fcb.level == 1 }
263
- # reject_collapsed_blocks(selrows, callback: proc_condition)
264
- #
265
- # lambda_condition = ->(fcb) { fcb.type == BlockType::HEADING && fcb.level == 1 }
266
- # reject_collapsed_blocks(selrows, callback: lambda_condition)
267
- #
268
- # Block: Exits the enclosing method (test_with_block) if return is used.
269
- # Flexible with arguments
270
- # Proc: Exits the enclosing method (test_with_proc) when return is encountered, similar to a block.
271
- # Lambda: Only exits the lambda itself, allowing reject_collapsed_blocks to continue execution.
272
- # Stricter argument checking.
273
- #
274
- # **`lambda` provides more control** and avoids the early exit behavior caused by `return` in blocks or `Proc` objects, making it a safer choice when you want `reject_collapsed_blocks` to complete its execution regardless of the callback’s behavior.
275
- def reject_collapsed_blocks(
276
- selrows,
277
- callback: nil,
278
- reject_callback: nil,
279
- collapsible_types: nil,
280
- &block
281
- )
282
- block ||= callback # Use callback if no block is provided
283
- hiding = false # State to indicate if hiding is active
284
- hidden_level = nil # Level at which hiding was triggered
285
-
286
- selrows.reject do |fcb| # Reject rows that should be hidden based on the hierarchy
287
- if hiding
288
- # Currently in hiding mode; evaluate if the current block should remain hidden
289
- if collapsible_types.nil? || collapsible_types.include?(fcb.type)
290
- if hidden_level.nil?
291
- # No specific hidden level yet, allow the item to show
292
- false
293
- elsif fcb.level > hidden_level
294
- reject_callback.call(fcb, ) if reject_callback
295
- # The current block is at a deeper level and thus remains hidden
296
- true
297
- else
298
- # At the same or higher level than hidden_level, check if the callback initiates hiding again
299
- hiding = block.call(fcb)
300
- hidden_level = fcb.level if hiding # Update hidden level if hiding continues
301
- false # Do not hide the initiating block itself
302
- end
303
- else
304
- reject_callback.call(fcb) if reject_callback
305
- # Non-collapsible block types (e.g., text or note) continue hiding by default
306
- true
307
- end
308
-
309
- elsif block.call(fcb)
310
- # If callback triggers hiding, initialize hiding state and hidden_level
311
- hiding = fcb.type # Start hiding subsequent blocks
312
- hidden_level = fcb.level # Define the hierarchical level for hiding
313
- false # Do not hide the initiating block itself
314
-
315
- else
316
- false # Default: do not hide if no hiding state
317
- end
242
+ select_elements_with_neighbor_conditions(selrows) do |prev_element, current, next_element|
243
+ !(current[:chrome] && !current.oname.present?) ||
244
+ !(!prev_element.nil? &&
245
+ prev_element.shell.present? &&
246
+ !next_element.nil? &&
247
+ next_element.shell.present?)
318
248
  end
319
249
  end
320
250
 
@@ -605,7 +535,7 @@ if $PROGRAM_NAME == __FILE__
605
535
 
606
536
  def test_fcbs_per_options
607
537
  opts = { hide_blocks_by_name: true, block_name_hidden_match: 'block1' }
608
- result, _ = @doc.fcbs_per_options(opts)
538
+ result = @doc.fcbs_per_options(opts)
609
539
  assert_equal [@table[1], @table[2]], result
610
540
  end if false ### broken test
611
541
 
data/lib/menu.src.yml CHANGED
@@ -1587,6 +1587,12 @@
1587
1587
  :description: Color for table border
1588
1588
  :default: fg_bg_rgbh_00_00_df_14_18_1c
1589
1589
 
1590
+ - :opt_name: table_cell_text_truncate
1591
+ :env_var: MDE_TABLE_CELL_TEXT_TRUNCATE
1592
+ :arg_name: BOOL
1593
+ :default: true
1594
+ :procname: val_as_bool
1595
+
1590
1596
  - :opt_name: table_center
1591
1597
  :env_var: MDE_TABLE_CENTER
1592
1598
  :arg_name: BOOL
data/lib/menu.yml CHANGED
@@ -1355,6 +1355,11 @@
1355
1355
  :env_var: MDE_TABLE_BORDER_COLOR
1356
1356
  :description: Color for table border
1357
1357
  :default: fg_bg_rgbh_00_00_df_14_18_1c
1358
+ - :opt_name: table_cell_text_truncate
1359
+ :env_var: MDE_TABLE_CELL_TEXT_TRUNCATE
1360
+ :arg_name: BOOL
1361
+ :default: true
1362
+ :procname: val_as_bool
1358
1363
  - :opt_name: table_center
1359
1364
  :env_var: MDE_TABLE_CENTER
1360
1365
  :arg_name: BOOL
data/lib/ww.rb CHANGED
@@ -83,7 +83,7 @@ class Array
83
83
  unless defined?(deref)
84
84
  def deref
85
85
  map(&:deref).select do |line|
86
- !%r{^/vendor/}.match(line)
86
+ !%r{^/(vendor|\.bundle)/}.match(line)
87
87
  end
88
88
  end
89
89
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown_exec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.3
4
+ version: 2.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fareed Stevenson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-30 00:00:00.000000000 Z
11
+ date: 2025-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard