reline 0.3.8 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 709b8943f16732f771d45da031e9676dc01c8b75f0410134a8b1fa8ab590d294
4
- data.tar.gz: 04aa52c6ea6a8939402a1554b42bce891bd65a13be6b76cbfd3f4859df1455d4
3
+ metadata.gz: 5fbe3e08832a8893e51895e3efe21ff3e728414d85ae95d62f2c854c1608f966
4
+ data.tar.gz: 8a0af70e8ce6cf9454fdb40070a405e53e0d2afcad9b4ad87345e2d5092662e6
5
5
  SHA512:
6
- metadata.gz: ab8a124f732cfa4b8522f397a546fc89ea93f188ca9f44f7f560ea2afb00abbe3b95486c17a20b826d360a8bb064ca441bd357acffe1eb4ec371fbf6380cd37d
7
- data.tar.gz: e756e58d4ae8929045998b8278fcee48ba1867741cc4d47bd72beb3e3a74902938d4c8a9dcd4c0452f20b25f5b4fe05eb96929bc39c28f326dc88c9bdf7be458
6
+ metadata.gz: 1b480360a8dde5c140028bcaa408cdcd08469499ee331fd7441ffb7f63a9dda835e395ffc7b95b9c78fe3ad3209190deac1639f47c8973e2c1839a73d386201b
7
+ data.tar.gz: df35e1166aaec1003a40abb889d5c7a9268bd59293dcd3a1910dd2b5aa36177ba4b03c93aae746c7066c4b267115d621f8c8510b4a40871f27a7c96e1e384581
data/README.md CHANGED
@@ -55,6 +55,13 @@ end
55
55
 
56
56
  See also: [test/reline/yamatanooroti/multiline_repl](https://github.com/ruby/reline/blob/master/test/reline/yamatanooroti/multiline_repl)
57
57
 
58
+ ## Documentation
59
+
60
+ ### Reline::Face
61
+
62
+ You can modify the text color and text decorations in your terminal emulator.
63
+ See [doc/reline/face.md](./doc/reline/face.md)
64
+
58
65
  ## Contributing
59
66
 
60
67
  Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/reline.
data/lib/reline/config.rb CHANGED
@@ -252,7 +252,7 @@ class Reline::Config
252
252
  end
253
253
  @skip_section = @if_stack.pop
254
254
  when 'include'
255
- read(args)
255
+ read(File.expand_path(args))
256
256
  end
257
257
  end
258
258
 
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Reline::Face
4
+ SGR_PARAMETERS = {
5
+ foreground: {
6
+ black: 30,
7
+ red: 31,
8
+ green: 32,
9
+ yellow: 33,
10
+ blue: 34,
11
+ magenta: 35,
12
+ cyan: 36,
13
+ white: 37,
14
+ bright_black: 90,
15
+ gray: 90,
16
+ bright_red: 91,
17
+ bright_green: 92,
18
+ bright_yellow: 93,
19
+ bright_blue: 94,
20
+ bright_magenta: 95,
21
+ bright_cyan: 96,
22
+ bright_white: 97
23
+ },
24
+ background: {
25
+ black: 40,
26
+ red: 41,
27
+ green: 42,
28
+ yellow: 43,
29
+ blue: 44,
30
+ magenta: 45,
31
+ cyan: 46,
32
+ white: 47,
33
+ bright_black: 100,
34
+ gray: 100,
35
+ bright_red: 101,
36
+ bright_green: 102,
37
+ bright_yellow: 103,
38
+ bright_blue: 104,
39
+ bright_magenta: 105,
40
+ bright_cyan: 106,
41
+ bright_white: 107,
42
+ },
43
+ style: {
44
+ reset: 0,
45
+ bold: 1,
46
+ faint: 2,
47
+ italicized: 3,
48
+ underlined: 4,
49
+ slowly_blinking: 5,
50
+ blinking: 5,
51
+ rapidly_blinking: 6,
52
+ negative: 7,
53
+ concealed: 8,
54
+ crossed_out: 9
55
+ }
56
+ }.freeze
57
+
58
+ class Config
59
+ ESSENTIAL_DEFINE_NAMES = %i(default enhanced scrollbar).freeze
60
+ RESET_SGR = "\e[0m".freeze
61
+
62
+ def initialize(name, &block)
63
+ @definition = {}
64
+ block.call(self)
65
+ ESSENTIAL_DEFINE_NAMES.each do |name|
66
+ @definition[name] ||= { style: :reset, escape_sequence: RESET_SGR }
67
+ end
68
+ end
69
+
70
+ attr_reader :definition
71
+
72
+ def define(name, **values)
73
+ values[:escape_sequence] = format_to_sgr(values.to_a).freeze
74
+ @definition[name] = values
75
+ end
76
+
77
+ def reconfigure
78
+ @definition.each_value do |values|
79
+ values.delete(:escape_sequence)
80
+ values[:escape_sequence] = format_to_sgr(values.to_a).freeze
81
+ end
82
+ end
83
+
84
+ def [](name)
85
+ @definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
86
+ end
87
+
88
+ private
89
+
90
+ def sgr_rgb(key, value)
91
+ return nil unless rgb_expression?(value)
92
+ if Reline::Face.truecolor?
93
+ sgr_rgb_truecolor(key, value)
94
+ else
95
+ sgr_rgb_256color(key, value)
96
+ end
97
+ end
98
+
99
+ def sgr_rgb_truecolor(key, value)
100
+ case key
101
+ when :foreground
102
+ "38;2;"
103
+ when :background
104
+ "48;2;"
105
+ end + value[1, 6].scan(/../).map(&:hex).join(";")
106
+ end
107
+
108
+ def sgr_rgb_256color(key, value)
109
+ # 256 colors are
110
+ # 0..15: standard colors, hight intensity colors
111
+ # 16..232: 216 colors (R, G, B each 6 steps)
112
+ # 233..255: grayscale colors (24 steps)
113
+ # This methods converts rgb_expression to 216 colors
114
+ rgb = value[1, 6].scan(/../).map(&:hex)
115
+ # Color steps are [0, 95, 135, 175, 215, 255]
116
+ r, g, b = rgb.map { |v| v <= 95 ? v / 48 : (v - 35) / 40 }
117
+ color = (16 + 36 * r + 6 * g + b)
118
+ case key
119
+ when :foreground
120
+ "38;5;#{color}"
121
+ when :background
122
+ "48;5;#{color}"
123
+ end
124
+ end
125
+
126
+ def format_to_sgr(ordered_values)
127
+ sgr = "\e[" + ordered_values.map do |key_value|
128
+ key, value = key_value
129
+ case key
130
+ when :foreground, :background
131
+ case value
132
+ when Symbol
133
+ SGR_PARAMETERS[key][value]
134
+ when String
135
+ sgr_rgb(key, value)
136
+ end
137
+ when :style
138
+ [ value ].flatten.map do |style_name|
139
+ SGR_PARAMETERS[:style][style_name]
140
+ end.then do |sgr_parameters|
141
+ sgr_parameters.include?(nil) ? nil : sgr_parameters
142
+ end
143
+ end.then do |rendition_expression|
144
+ unless rendition_expression
145
+ raise ArgumentError, "invalid SGR parameter: #{value.inspect}"
146
+ end
147
+ rendition_expression
148
+ end
149
+ end.join(';') + "m"
150
+ sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr
151
+ end
152
+
153
+ def rgb_expression?(color)
154
+ color.respond_to?(:match?) and color.match?(/\A#[0-9a-fA-F]{6}\z/)
155
+ end
156
+ end
157
+
158
+ private_constant :SGR_PARAMETERS, :Config
159
+
160
+ def self.truecolor?
161
+ @force_truecolor || %w[truecolor 24bit].include?(ENV['COLORTERM'])
162
+ end
163
+
164
+ def self.force_truecolor
165
+ @force_truecolor = true
166
+ @configs&.each_value(&:reconfigure)
167
+ end
168
+
169
+ def self.[](name)
170
+ @configs[name]
171
+ end
172
+
173
+ def self.config(name, &block)
174
+ @configs ||= {}
175
+ @configs[name] = Config.new(name, &block)
176
+ end
177
+
178
+ def self.configs
179
+ @configs.transform_values(&:definition)
180
+ end
181
+
182
+ def self.load_initial_configs
183
+ config(:default) do |conf|
184
+ conf.define :default, style: :reset
185
+ conf.define :enhanced, style: :reset
186
+ conf.define :scrollbar, style: :reset
187
+ end
188
+ config(:completion_dialog) do |conf|
189
+ conf.define :default, foreground: :white, background: :cyan
190
+ conf.define :enhanced, foreground: :white, background: :magenta
191
+ conf.define :scrollbar, foreground: :white, background: :cyan
192
+ end
193
+ end
194
+
195
+ def self.reset_to_initial_configs
196
+ @configs = {}
197
+ load_initial_configs
198
+ end
199
+ end
@@ -3,7 +3,11 @@ require 'io/wait'
3
3
  class Reline::GeneralIO
4
4
  def self.reset(encoding: nil)
5
5
  @@pasting = false
6
- @@encoding = encoding
6
+ if encoding
7
+ @@encoding = encoding
8
+ elsif defined?(@@encoding)
9
+ remove_class_variable(:@@encoding)
10
+ end
7
11
  end
8
12
 
9
13
  def self.encoding
@@ -14,7 +14,7 @@ class Reline::KillRing
14
14
  end
15
15
 
16
16
  def ==(other)
17
- object_id == other.object_id
17
+ equal?(other)
18
18
  end
19
19
  end
20
20
 
@@ -831,27 +831,24 @@ class Reline::LineEditor
831
831
  dialog.column = 0
832
832
  dialog.width = @screen_size.last
833
833
  end
834
+ face = Reline::Face[dialog_render_info.face || :default]
835
+ scrollbar_sgr = face[:scrollbar]
836
+ default_sgr = face[:default]
837
+ enhanced_sgr = face[:enhanced]
834
838
  dialog.contents = contents.map.with_index do |item, i|
835
- if i == pointer
836
- fg_color = dialog_render_info.pointer_fg_color
837
- bg_color = dialog_render_info.pointer_bg_color
838
- else
839
- fg_color = dialog_render_info.fg_color
840
- bg_color = dialog_render_info.bg_color
841
- end
839
+ line_sgr = i == pointer ? enhanced_sgr : default_sgr
842
840
  str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
843
841
  str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
844
- colored_content = "\e[#{bg_color}m\e[#{fg_color}m#{str}"
842
+ colored_content = "#{line_sgr}#{str}"
845
843
  if scrollbar_pos
846
- color_seq = "\e[37m"
847
844
  if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
848
- colored_content + color_seq + @full_block
845
+ colored_content + scrollbar_sgr + @full_block
849
846
  elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
850
- colored_content + color_seq + @upper_half_block
847
+ colored_content + scrollbar_sgr + @upper_half_block
851
848
  elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
852
- colored_content + color_seq + @lower_half_block
849
+ colored_content + scrollbar_sgr + @lower_half_block
853
850
  else
854
- colored_content + color_seq + ' ' * @block_elem_width
851
+ colored_content + scrollbar_sgr + ' ' * @block_elem_width
855
852
  end
856
853
  else
857
854
  colored_content
@@ -1316,7 +1313,7 @@ class Reline::LineEditor
1316
1313
  end
1317
1314
  if not just_show_list and target < completed
1318
1315
  @line = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
1319
- line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
1316
+ line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n")[@line_index] || String.new(encoding: @encoding)
1320
1317
  @cursor_max = calculate_width(@line)
1321
1318
  @cursor = calculate_width(line_to_pointer)
1322
1319
  @byte_pointer = line_to_pointer.bytesize
@@ -1363,7 +1360,7 @@ class Reline::LineEditor
1363
1360
  completed = @completion_journey_data.list[@completion_journey_data.pointer]
1364
1361
  new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
1365
1362
  @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
1366
- line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
1363
+ line_to_pointer = (@completion_journey_data.preposing + completed).split("\n")[@line_index]
1367
1364
  line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
1368
1365
  @cursor_max = calculate_width(@line)
1369
1366
  @cursor = calculate_width(line_to_pointer)
@@ -1,6 +1,6 @@
1
1
  class Reline::Unicode::EastAsianWidth
2
2
  # This is based on EastAsianWidth.txt
3
- # EastAsianWidth.txt
3
+ # UNICODE_VERSION = '15.1.0'
4
4
 
5
5
  # Fullwidth
6
6
  TYPE_F = /^[#{ %W(
@@ -60,14 +60,14 @@ class Reline::Unicode::EastAsianWidth
60
60
  \u{2E80}-\u{2E99}
61
61
  \u{2E9B}-\u{2EF3}
62
62
  \u{2F00}-\u{2FD5}
63
- \u{2FF0}-\u{2FFB}
63
+ \u{2FF0}-\u{2FFF}
64
64
  \u{3001}-\u{303E}
65
65
  \u{3041}-\u{3096}
66
66
  \u{3099}-\u{30FF}
67
67
  \u{3105}-\u{312F}
68
68
  \u{3131}-\u{318E}
69
69
  \u{3190}-\u{31E3}
70
- \u{31F0}-\u{321E}
70
+ \u{31EF}-\u{321E}
71
71
  \u{3220}-\u{3247}
72
72
  \u{3250}-\u{4DBF}
73
73
  \u{4E00}-\u{A48C}
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.3.8'
2
+ VERSION = '0.4.2'
3
3
  end
data/lib/reline.rb CHANGED
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
7
7
  require 'reline/line_editor'
8
8
  require 'reline/history'
9
9
  require 'reline/terminfo'
10
+ require 'reline/face'
10
11
  require 'rbconfig'
11
12
 
12
13
  module Reline
@@ -36,10 +37,8 @@ module Reline
36
37
  DialogRenderInfo = Struct.new(
37
38
  :pos,
38
39
  :contents,
39
- :bg_color,
40
- :pointer_bg_color,
41
- :fg_color,
42
- :pointer_fg_color,
40
+ :face,
41
+ :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
43
42
  :width,
44
43
  :height,
45
44
  :scrollbar,
@@ -260,10 +259,7 @@ module Reline
260
259
  contents: result,
261
260
  scrollbar: true,
262
261
  height: [15, preferred_dialog_height].min,
263
- bg_color: 46,
264
- pointer_bg_color: 45,
265
- fg_color: 37,
266
- pointer_fg_color: 37
262
+ face: :completion_dialog
267
263
  )
268
264
  }
269
265
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
@@ -606,4 +602,6 @@ else
606
602
  io
607
603
  end
608
604
 
605
+ Reline::Face.load_initial_configs
606
+
609
607
  Reline::HISTORY = Reline::History.new(Reline.core.config)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-20 00:00:00.000000000 Z
11
+ date: 2024-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -37,6 +37,7 @@ files:
37
37
  - lib/reline.rb
38
38
  - lib/reline/ansi.rb
39
39
  - lib/reline/config.rb
40
+ - lib/reline/face.rb
40
41
  - lib/reline/general_io.rb
41
42
  - lib/reline/history.rb
42
43
  - lib/reline/key_actor.rb
@@ -72,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
73
  - !ruby/object:Gem::Version
73
74
  version: '0'
74
75
  requirements: []
75
- rubygems_version: 3.4.10
76
+ rubygems_version: 3.5.1
76
77
  signing_key:
77
78
  specification_version: 4
78
79
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.