reline 0.0.7 → 0.1.4
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/README.md +4 -0
- data/lib/reline.rb +51 -24
- data/lib/reline/ansi.rb +59 -26
- data/lib/reline/config.rb +34 -8
- data/lib/reline/general_io.rb +8 -0
- data/lib/reline/history.rb +34 -14
- data/lib/reline/key_actor/emacs.rb +7 -7
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/line_editor.rb +439 -90
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +41 -4
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41e0f73e51def110f060454c69c3a3a29d3b0cedce2c432cc594df4f6cccf012
|
4
|
+
data.tar.gz: c47d69d20e28f8940c86eedba5349892ecf5e5745e83a8c701eab327e326c6ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b494460955ab34ccf2e4c0443e76598c692d2846162be5081ecc8234181b47771721e5969fa76acd54bcce7f6d2c3dbc7e6469b23897c144c6233db5c08c915b
|
7
|
+
data.tar.gz: 7c0f5bd0caf7f79113b479e9785aa2260536356ff7196fa1d034fe669f60fca7078771575d8002edf18a5c256105e22d550d9b4e0382071e2c240ef0a34b0287
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
[](https://travis-ci.com/ruby/reline)
|
2
2
|
|
3
|
+
This is a screen capture of *IRB improved by Reline*.
|
4
|
+
|
5
|
+

|
6
|
+
|
3
7
|
# Reline
|
4
8
|
|
5
9
|
Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
|
data/lib/reline.rb
CHANGED
@@ -32,55 +32,69 @@ module Reline
|
|
32
32
|
dig_perfect_match_proc
|
33
33
|
).each(&method(:attr_reader))
|
34
34
|
|
35
|
-
ATTR_ACCESSOR_NAMES = %i(
|
36
|
-
completion_case_fold
|
37
|
-
).each(&method(:attr_accessor))
|
38
|
-
|
39
35
|
attr_accessor :config
|
40
36
|
attr_accessor :key_stroke
|
41
37
|
attr_accessor :line_editor
|
42
38
|
attr_accessor :ambiguous_width
|
39
|
+
attr_accessor :last_incremental_search
|
43
40
|
attr_reader :output
|
44
41
|
|
45
42
|
def initialize
|
46
43
|
self.output = STDOUT
|
47
44
|
yield self
|
45
|
+
@completion_quote_character = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def encoding
|
49
|
+
Reline::IOGate.encoding
|
48
50
|
end
|
49
51
|
|
50
52
|
def completion_append_character=(val)
|
51
53
|
if val.nil?
|
52
54
|
@completion_append_character = nil
|
53
55
|
elsif val.size == 1
|
54
|
-
@completion_append_character = val.encode(
|
56
|
+
@completion_append_character = val.encode(Reline::IOGate.encoding)
|
55
57
|
elsif val.size > 1
|
56
|
-
@completion_append_character = val[0].encode(
|
58
|
+
@completion_append_character = val[0].encode(Reline::IOGate.encoding)
|
57
59
|
else
|
58
60
|
@completion_append_character = nil
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
62
64
|
def basic_word_break_characters=(v)
|
63
|
-
@basic_word_break_characters = v.encode(
|
65
|
+
@basic_word_break_characters = v.encode(Reline::IOGate.encoding)
|
64
66
|
end
|
65
67
|
|
66
68
|
def completer_word_break_characters=(v)
|
67
|
-
@completer_word_break_characters = v.encode(
|
69
|
+
@completer_word_break_characters = v.encode(Reline::IOGate.encoding)
|
68
70
|
end
|
69
71
|
|
70
72
|
def basic_quote_characters=(v)
|
71
|
-
@basic_quote_characters = v.encode(
|
73
|
+
@basic_quote_characters = v.encode(Reline::IOGate.encoding)
|
72
74
|
end
|
73
75
|
|
74
76
|
def completer_quote_characters=(v)
|
75
|
-
@completer_quote_characters = v.encode(
|
77
|
+
@completer_quote_characters = v.encode(Reline::IOGate.encoding)
|
76
78
|
end
|
77
79
|
|
78
80
|
def filename_quote_characters=(v)
|
79
|
-
@filename_quote_characters = v.encode(
|
81
|
+
@filename_quote_characters = v.encode(Reline::IOGate.encoding)
|
80
82
|
end
|
81
83
|
|
82
84
|
def special_prefixes=(v)
|
83
|
-
@special_prefixes = v.encode(
|
85
|
+
@special_prefixes = v.encode(Reline::IOGate.encoding)
|
86
|
+
end
|
87
|
+
|
88
|
+
def completion_case_fold=(v)
|
89
|
+
@config.completion_ignore_case = v
|
90
|
+
end
|
91
|
+
|
92
|
+
def completion_case_fold
|
93
|
+
@config.completion_ignore_case
|
94
|
+
end
|
95
|
+
|
96
|
+
def completion_quote_character
|
97
|
+
@completion_quote_character
|
84
98
|
end
|
85
99
|
|
86
100
|
def completion_proc=(p)
|
@@ -161,7 +175,7 @@ module Reline
|
|
161
175
|
|
162
176
|
whole_buffer = line_editor.whole_buffer.dup
|
163
177
|
whole_buffer.taint if RUBY_VERSION < '2.7'
|
164
|
-
if add_hist and whole_buffer and whole_buffer.chomp.size > 0
|
178
|
+
if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
|
165
179
|
Reline::HISTORY << whole_buffer
|
166
180
|
end
|
167
181
|
|
@@ -174,8 +188,8 @@ module Reline
|
|
174
188
|
|
175
189
|
line = line_editor.line.dup
|
176
190
|
line.taint if RUBY_VERSION < '2.7'
|
177
|
-
if add_hist and line and line.chomp.size > 0
|
178
|
-
Reline::HISTORY << line.chomp
|
191
|
+
if add_hist and line and line.chomp("\n").size > 0
|
192
|
+
Reline::HISTORY << line.chomp("\n")
|
179
193
|
end
|
180
194
|
|
181
195
|
line_editor.reset_line if line_editor.line.nil?
|
@@ -191,7 +205,7 @@ module Reline
|
|
191
205
|
otio = Reline::IOGate.prep
|
192
206
|
|
193
207
|
may_req_ambiguous_char_width
|
194
|
-
line_editor.reset(prompt)
|
208
|
+
line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
|
195
209
|
if multiline
|
196
210
|
line_editor.multiline_on
|
197
211
|
if block_given?
|
@@ -202,6 +216,7 @@ module Reline
|
|
202
216
|
end
|
203
217
|
line_editor.output = output
|
204
218
|
line_editor.completion_proc = completion_proc
|
219
|
+
line_editor.completion_append_character = completion_append_character
|
205
220
|
line_editor.output_modifier_proc = output_modifier_proc
|
206
221
|
line_editor.prompt_proc = prompt_proc
|
207
222
|
line_editor.auto_indent_proc = auto_indent_proc
|
@@ -321,8 +336,14 @@ module Reline
|
|
321
336
|
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
322
337
|
return if ambiguous_width
|
323
338
|
Reline::IOGate.move_cursor_column(0)
|
324
|
-
|
325
|
-
|
339
|
+
begin
|
340
|
+
output.write "\u{25bd}"
|
341
|
+
rescue Encoding::UndefinedConversionError
|
342
|
+
# LANG=C
|
343
|
+
@ambiguous_width = 1
|
344
|
+
else
|
345
|
+
@ambiguous_width = Reline::IOGate.cursor_pos.x
|
346
|
+
end
|
326
347
|
Reline::IOGate.move_cursor_column(0)
|
327
348
|
Reline::IOGate.erase_after_cursor
|
328
349
|
end
|
@@ -335,12 +356,14 @@ module Reline
|
|
335
356
|
# Documented API
|
336
357
|
#--------------------------------------------------------
|
337
358
|
|
338
|
-
(Core::ATTR_READER_NAMES
|
359
|
+
(Core::ATTR_READER_NAMES).each { |name|
|
339
360
|
def_single_delegators :core, "#{name}", "#{name}="
|
340
361
|
}
|
341
362
|
def_single_delegators :core, :input=, :output=
|
342
363
|
def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
|
343
364
|
def_single_delegators :core, :readline
|
365
|
+
def_single_delegators :core, :completion_case_fold, :completion_case_fold=
|
366
|
+
def_single_delegators :core, :completion_quote_character
|
344
367
|
def_instance_delegators self, :readline
|
345
368
|
private :readline
|
346
369
|
|
@@ -367,16 +390,22 @@ module Reline
|
|
367
390
|
def_single_delegator :line_editor, :rerender, :redisplay
|
368
391
|
def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
|
369
392
|
def_single_delegators :core, :ambiguous_width
|
393
|
+
def_single_delegators :core, :last_incremental_search
|
394
|
+
def_single_delegators :core, :last_incremental_search=
|
370
395
|
|
371
396
|
def_single_delegators :core, :readmultiline
|
372
397
|
def_instance_delegators self, :readmultiline
|
373
398
|
private :readmultiline
|
374
399
|
|
400
|
+
def self.encoding_system_needs
|
401
|
+
self.core.encoding
|
402
|
+
end
|
403
|
+
|
375
404
|
def self.core
|
376
405
|
@core ||= Core.new { |core|
|
377
406
|
core.config = Reline::Config.new
|
378
407
|
core.key_stroke = Reline::KeyStroke.new(core.config)
|
379
|
-
core.line_editor = Reline::LineEditor.new(core.config)
|
408
|
+
core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
|
380
409
|
|
381
410
|
core.basic_word_break_characters = " \t\n`><=;|&{("
|
382
411
|
core.completer_word_break_characters = " \t\n`><=;|&{("
|
@@ -390,14 +419,11 @@ module Reline
|
|
390
419
|
def self.line_editor
|
391
420
|
core.line_editor
|
392
421
|
end
|
393
|
-
|
394
|
-
HISTORY = History.new(core.config)
|
395
422
|
end
|
396
423
|
|
397
424
|
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
398
425
|
require 'reline/windows'
|
399
|
-
if Reline::Windows.
|
400
|
-
# Maybe Mintty on Cygwin
|
426
|
+
if Reline::Windows.msys_tty?
|
401
427
|
require 'reline/ansi'
|
402
428
|
Reline::IOGate = Reline::ANSI
|
403
429
|
else
|
@@ -407,4 +433,5 @@ else
|
|
407
433
|
require 'reline/ansi'
|
408
434
|
Reline::IOGate = Reline::ANSI
|
409
435
|
end
|
436
|
+
Reline::HISTORY = Reline::History.new(Reline.core.config)
|
410
437
|
require 'reline/general_io'
|
data/lib/reline/ansi.rb
CHANGED
@@ -1,16 +1,49 @@
|
|
1
|
+
require 'io/console'
|
2
|
+
|
1
3
|
class Reline::ANSI
|
4
|
+
def self.encoding
|
5
|
+
Encoding.default_external
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.win?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
2
12
|
RAW_KEYSTROKE_CONFIG = {
|
13
|
+
# Console (80x25)
|
14
|
+
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
15
|
+
[27, 91, 52, 126] => :ed_move_to_end, # End
|
16
|
+
[27, 91, 51, 126] => :key_delete, # Del
|
3
17
|
[27, 91, 65] => :ed_prev_history, # ↑
|
4
18
|
[27, 91, 66] => :ed_next_history, # ↓
|
5
19
|
[27, 91, 67] => :ed_next_char, # →
|
6
20
|
[27, 91, 68] => :ed_prev_char, # ←
|
7
|
-
|
8
|
-
|
9
|
-
[27, 91, 52, 126] => :ed_move_to_end, # End
|
21
|
+
|
22
|
+
# KDE
|
10
23
|
[27, 91, 72] => :ed_move_to_beg, # Home
|
11
24
|
[27, 91, 70] => :ed_move_to_end, # End
|
25
|
+
# Del is 0x08
|
26
|
+
[27, 71, 65] => :ed_prev_history, # ↑
|
27
|
+
[27, 71, 66] => :ed_next_history, # ↓
|
28
|
+
[27, 71, 67] => :ed_next_char, # →
|
29
|
+
[27, 71, 68] => :ed_prev_char, # ←
|
30
|
+
|
31
|
+
# GNOME
|
32
|
+
[27, 79, 72] => :ed_move_to_beg, # Home
|
33
|
+
[27, 79, 70] => :ed_move_to_end, # End
|
34
|
+
# Del is 0x08
|
35
|
+
# Arrow keys are the same of KDE
|
36
|
+
|
37
|
+
# others
|
12
38
|
[27, 32] => :em_set_mark, # M-<space>
|
13
39
|
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
40
|
+
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→
|
41
|
+
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←
|
42
|
+
|
43
|
+
[27, 79, 65] => :ed_prev_history, # ↑
|
44
|
+
[27, 79, 66] => :ed_next_history, # ↓
|
45
|
+
[27, 79, 67] => :ed_next_char, # →
|
46
|
+
[27, 79, 68] => :ed_prev_char, # ←
|
14
47
|
}
|
15
48
|
|
16
49
|
@@input = STDIN
|
@@ -28,7 +61,8 @@ class Reline::ANSI
|
|
28
61
|
unless @@buf.empty?
|
29
62
|
return @@buf.shift
|
30
63
|
end
|
31
|
-
@@input.getbyte
|
64
|
+
c = @@input.raw(intr: true, &:getbyte)
|
65
|
+
(c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
|
32
66
|
end
|
33
67
|
|
34
68
|
def self.ungetc(c)
|
@@ -36,16 +70,23 @@ class Reline::ANSI
|
|
36
70
|
end
|
37
71
|
|
38
72
|
def self.retrieve_keybuffer
|
73
|
+
begin
|
39
74
|
result = select([@@input], [], [], 0.001)
|
40
75
|
return if result.nil?
|
41
76
|
str = @@input.read_nonblock(1024)
|
42
77
|
str.bytes.each do |c|
|
43
78
|
@@buf.push(c)
|
44
79
|
end
|
80
|
+
rescue EOFError
|
81
|
+
end
|
45
82
|
end
|
46
83
|
|
47
84
|
def self.get_screen_size
|
48
|
-
@@input.winsize
|
85
|
+
s = @@input.winsize
|
86
|
+
return s if s[0] > 0 && s[1] > 0
|
87
|
+
s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
|
88
|
+
return s if s[0] > 0 && s[1] > 0
|
89
|
+
[24, 80]
|
49
90
|
rescue Errno::ENOTTY
|
50
91
|
[24, 80]
|
51
92
|
end
|
@@ -60,14 +101,18 @@ class Reline::ANSI
|
|
60
101
|
def self.cursor_pos
|
61
102
|
begin
|
62
103
|
res = ''
|
104
|
+
m = nil
|
63
105
|
@@input.raw do |stdin|
|
64
106
|
@@output << "\e[6n"
|
65
107
|
@@output.flush
|
66
108
|
while (c = stdin.getc) != 'R'
|
67
109
|
res << c if c
|
68
110
|
end
|
111
|
+
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)/)
|
112
|
+
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
113
|
+
stdin.ungetc ch
|
114
|
+
end
|
69
115
|
end
|
70
|
-
m = res.match(/(?<row>\d+);(?<column>\d+)/)
|
71
116
|
column = m[:column].to_i - 1
|
72
117
|
row = m[:row].to_i - 1
|
73
118
|
rescue Errno::ENOTTY
|
@@ -79,12 +124,12 @@ class Reline::ANSI
|
|
79
124
|
end
|
80
125
|
|
81
126
|
def self.move_cursor_column(x)
|
82
|
-
|
127
|
+
@@output.write "\e[#{x + 1}G"
|
83
128
|
end
|
84
129
|
|
85
130
|
def self.move_cursor_up(x)
|
86
131
|
if x > 0
|
87
|
-
|
132
|
+
@@output.write "\e[#{x}A" if x > 0
|
88
133
|
elsif x < 0
|
89
134
|
move_cursor_down(-x)
|
90
135
|
end
|
@@ -92,24 +137,24 @@ class Reline::ANSI
|
|
92
137
|
|
93
138
|
def self.move_cursor_down(x)
|
94
139
|
if x > 0
|
95
|
-
|
140
|
+
@@output.write "\e[#{x}B" if x > 0
|
96
141
|
elsif x < 0
|
97
142
|
move_cursor_up(-x)
|
98
143
|
end
|
99
144
|
end
|
100
145
|
|
101
146
|
def self.erase_after_cursor
|
102
|
-
|
147
|
+
@@output.write "\e[K"
|
103
148
|
end
|
104
149
|
|
105
150
|
def self.scroll_down(x)
|
106
151
|
return if x.zero?
|
107
|
-
|
152
|
+
@@output.write "\e[#{x}S"
|
108
153
|
end
|
109
154
|
|
110
155
|
def self.clear_screen
|
111
|
-
|
112
|
-
|
156
|
+
@@output.write "\e[2J"
|
157
|
+
@@output.write "\e[1;1H"
|
113
158
|
end
|
114
159
|
|
115
160
|
@@old_winch_handler = nil
|
@@ -120,24 +165,12 @@ class Reline::ANSI
|
|
120
165
|
def self.prep
|
121
166
|
retrieve_keybuffer
|
122
167
|
int_handle = Signal.trap('INT', 'IGNORE')
|
123
|
-
otio = `stty -g`.chomp
|
124
|
-
setting = ' -echo -icrnl cbreak'
|
125
|
-
stty = `stty -a`
|
126
|
-
if /-parenb\b/ =~ stty
|
127
|
-
setting << ' pass8'
|
128
|
-
end
|
129
|
-
if /\bdsusp *=/ =~ stty
|
130
|
-
setting << ' dsusp undef'
|
131
|
-
end
|
132
|
-
setting << ' -ixoff'
|
133
|
-
`stty #{setting}`
|
134
168
|
Signal.trap('INT', int_handle)
|
135
|
-
|
169
|
+
nil
|
136
170
|
end
|
137
171
|
|
138
172
|
def self.deprep(otio)
|
139
173
|
int_handle = Signal.trap('INT', 'IGNORE')
|
140
|
-
system("stty #{otio}", err: File::NULL)
|
141
174
|
Signal.trap('INT', int_handle)
|
142
175
|
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
143
176
|
end
|
data/lib/reline/config.rb
CHANGED
@@ -3,8 +3,6 @@ require 'pathname'
|
|
3
3
|
class Reline::Config
|
4
4
|
attr_reader :test_mode
|
5
5
|
|
6
|
-
DEFAULT_PATH = '~/.inputrc'
|
7
|
-
|
8
6
|
KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
|
9
7
|
|
10
8
|
class InvalidInputrc < RuntimeError
|
@@ -54,7 +52,7 @@ class Reline::Config
|
|
54
52
|
@key_actors[:emacs] = Reline::KeyActor::Emacs.new
|
55
53
|
@key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
|
56
54
|
@key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
|
57
|
-
@history_size =
|
55
|
+
@history_size = -1 # unlimited
|
58
56
|
@keyseq_timeout = 500
|
59
57
|
@test_mode = false
|
60
58
|
end
|
@@ -83,8 +81,34 @@ class Reline::Config
|
|
83
81
|
@key_actors[@keymap_label]
|
84
82
|
end
|
85
83
|
|
84
|
+
def inputrc_path
|
85
|
+
case ENV['INPUTRC']
|
86
|
+
when nil, ''
|
87
|
+
else
|
88
|
+
return File.expand_path(ENV['INPUTRC'])
|
89
|
+
end
|
90
|
+
|
91
|
+
# In the XDG Specification, if ~/.config/readline/inputrc exists, then
|
92
|
+
# ~/.inputrc should not be read, but for compatibility with GNU Readline,
|
93
|
+
# if ~/.inputrc exists, then it is given priority.
|
94
|
+
home_rc_path = File.expand_path('~/.inputrc')
|
95
|
+
return home_rc_path if File.exist?(home_rc_path)
|
96
|
+
|
97
|
+
case path = ENV['XDG_CONFIG_HOME']
|
98
|
+
when nil, ''
|
99
|
+
else
|
100
|
+
path = File.join(path, 'readline/inputrc')
|
101
|
+
return path if File.exist?(path) and path == File.expand_path(path)
|
102
|
+
end
|
103
|
+
|
104
|
+
path = File.expand_path('~/.config/readline/inputrc')
|
105
|
+
return path if File.exist?(path)
|
106
|
+
|
107
|
+
return home_rc_path
|
108
|
+
end
|
109
|
+
|
86
110
|
def read(file = nil)
|
87
|
-
file ||=
|
111
|
+
file ||= inputrc_path
|
88
112
|
begin
|
89
113
|
if file.respond_to?(:readlines)
|
90
114
|
lines = file.readlines
|
@@ -157,7 +181,7 @@ class Reline::Config
|
|
157
181
|
case directive
|
158
182
|
when 'if'
|
159
183
|
condition = false
|
160
|
-
case args
|
184
|
+
case args
|
161
185
|
when 'mode'
|
162
186
|
when 'term'
|
163
187
|
when 'version'
|
@@ -184,9 +208,8 @@ class Reline::Config
|
|
184
208
|
|
185
209
|
def bind_variable(name, value)
|
186
210
|
case name
|
187
|
-
when
|
188
|
-
|
189
|
-
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
211
|
+
when 'history-size'
|
212
|
+
@history_size = value.to_i
|
190
213
|
when 'bell-style'
|
191
214
|
@bell_style =
|
192
215
|
case value
|
@@ -225,6 +248,9 @@ class Reline::Config
|
|
225
248
|
end
|
226
249
|
when 'keyseq-timeout'
|
227
250
|
@keyseq_timeout = value.to_i
|
251
|
+
when *VARIABLE_NAMES then
|
252
|
+
variable_name = :"@#{name.tr(?-, ?_)}"
|
253
|
+
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
228
254
|
end
|
229
255
|
end
|
230
256
|
|