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 +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +1 -1
- data/bats/options-collapse.bats +5 -5
- data/bin/tab_completion.sh +1 -1
- data/docs/dev/options-collapse.md +1 -1
- data/lib/collapser.rb +35 -21
- data/lib/fcb.rb +47 -11
- data/lib/format_table.rb +55 -16
- data/lib/hash_delegator.rb +121 -58
- data/lib/hierarchy_string.rb +9 -0
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +1 -0
- data/lib/mdoc.rb +16 -86
- data/lib/menu.src.yml +6 -0
- data/lib/menu.yml +5 -0
- data/lib/ww.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0463a06b2bac6770c2443819a9cedee15e7aa3404649f077924074fd3c639ab
|
4
|
+
data.tar.gz: 0f8b10556113950d468d92cfc11510178d7019d5b0e1c3f7ba0f61fdcab57414
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/bats/options-collapse.bats
CHANGED
@@ -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.
|
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.
|
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.
|
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
|
}
|
data/bin/tab_completion.sh
CHANGED
data/lib/collapser.rb
CHANGED
@@ -6,18 +6,20 @@
|
|
6
6
|
require_relative 'constants'
|
7
7
|
|
8
8
|
class Collapser
|
9
|
-
attr_accessor :
|
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
|
-
|
15
|
-
|
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
|
-
@
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
61
|
+
per_options_and_token
|
57
62
|
else
|
58
|
-
collapse_per_state?(fcb, default:
|
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
|
-
|
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(
|
146
|
-
|
147
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
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(
|
96
|
-
|
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(
|
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(
|
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(
|
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
|
-
|
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)
|
data/lib/hash_delegator.rb
CHANGED
@@ -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 =
|
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(
|
906
|
-
|
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:,
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
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
|
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::
|
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:
|
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: [],
|
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
|
-
)
|
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
|
-
)
|
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
|
-
|
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
|
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 @
|
2931
|
-
|
2932
|
-
|
2933
|
-
|
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
|
4561
|
+
menu_blocks.find do |block|
|
4499
4562
|
block.dname.include?(prior_answer)
|
4500
|
-
|
4563
|
+
end&.name
|
4501
4564
|
when Struct
|
4502
4565
|
prior_answer.index || prior_answer.name
|
4503
4566
|
end
|
data/lib/hierarchy_string.rb
CHANGED
@@ -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
|
data/lib/markdown_exec.rb
CHANGED
data/lib/mdoc.rb
CHANGED
@@ -220,101 +220,31 @@ module MarkdownExec
|
|
220
220
|
end
|
221
221
|
|
222
222
|
collapser = Collapser.new(
|
223
|
-
options: opts,
|
223
|
+
options: opts,
|
224
|
+
compress_ids: opts[:compressed_ids] || {},
|
225
|
+
expand_ids: opts[:expanded_ids] || {}
|
224
226
|
)
|
225
|
-
selrows = collapser.reject(
|
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.
|
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
|
-
|
238
|
-
!(
|
239
|
-
|
240
|
-
|
241
|
-
|
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
|
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
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.
|
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-
|
11
|
+
date: 2025-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|