mirror of
https://github.com/ruby/ruby.git
synced 2025-09-16 17:14:01 +02:00

* Get rid of inconsistent dll linkages against vcpkg readline * [ruby/irb] Enhance colored inspect outputdffcdb5269
* [ruby/irb] Add color_printer.rb to gemspecb4df0fd8b2
* [ruby/irb] Fix failing tests7723ade899
* irb: add more syntax errors colorizing support (#3967) * [ruby/irb] Do not colorize partially-correct inspect This is to prevent a yellow-mixed output for ActiveSupport::TimeWithZone. Follows up https://github.com/ruby/irb/pull/159 and https://github.com/ruby/ruby/pull/3967.a5804c3560
* [ruby/irb] Remove unnecessary ignore_error in dispatch_seq Just forgotten ina5804c3560
e42e548793
* Increase timeout for reline with --jit-wait for failures like: http://ci.rvm.jp/logfiles/brlog.trunk-mjit-wait.20201229-130509 http://ci.rvm.jp/logfiles/brlog.trunk-mjit-wait.20201229-165132 http://ci.rvm.jp/logfiles/brlog.trunk-mjit-wait.20201228-015519 * [ruby/irb] Stringify when a non-object is passed to PP#text If a nested object is passed to #pp, it may be sometimes passed to the #text method as an object without being stringified. This is fixed on the Ruby main repository;433a3be86a
but it was a bug of Ripper so still needs this workaround for using irb as a gem on Ruby 3.0.0 or earlier. Co-authored-by: k0kubun <takashikkbn@gmail.com>8d13df22ee
* [ruby/irb] Newline in oneliner def doesn't reset indent This closes ruby/irb#132.43456dcf5e
* [ruby/irb] Escape invalid byte sequence in Exception This fixes ruby/irb#141.0815317d42
* [ruby/irb] Handle indentations related to keyword "do" correctly This fixes ruby/irb#158.964643400b
* [ruby/irb] Heredoc may contain multiple newlines in a single token Use the start token as the indentation criteria so that it works properly in heredoc. ref. https://github.com/ruby/reline/pull/2429704808dfd
* [ruby/irb] Use Ripper::Lexer#scan to take broken tokens ref. https://github.com/ruby/reline/pull/24254f90cb6c9
* [ruby/irb] Use error tokens if there are no correct tokens in the same place For example, the broken code "%www" will result in only one error token.9fa39a7cf3
* [ruby/irb] Ensure to restore $VERBOSEcef474a76a
* 600x larger timeout for Reline I didn't notice it's msec. 2.5s is too short. http://ci.rvm.jp/results/trunk-mjit-wait@phosphorus-docker/3311385 * [ruby/irb] fix typo in `IRB::Irb#convert_invalid_byte_sequence`d09d3c3d68
* [ruby/irb] do not escape a predicate method for doc namespace * Fixes #88d431a30af4
* [ruby/irb] refactoring an error handling in `IRB::Inspector` * moved rescue clause to `#inspect_value` to catch all failures in inspectors * test with all (currently five kind of) inspect modes - tweaked the input due to only `Marshal` can inspect(dump) a `BasicObject`9d112fab8e
* [ruby/irb] Use Exception#full_message to show backtrace in the correct order [Bug #17466]1c76845cca
* [ruby/irb] Fix BACK_TRACE_LIMIT logic30dc5d43fe
* irb: Drop lines from backtrace for tests in Ruby repository * [ruby/reline] Update cursor correctly when just cursor moving This fixes ruby/reline#236 and ruby/reline#239.3e3c89d00b
* [ruby/reline] Correct var names in Reline were different from vi-*-mode-string8255fc93b9
* [ruby/reline] Remove debug printd7fbaedc6a
* [ruby/reline] Suppress crashing when auto_indent_proc returns broken indent info Co-authored-by: Juanito Fatas <me@juanitofatas.com>7c24276275
* [ruby/reline] Suppress crashing when dynamic_prompt_proc returns a broken prompt list Co-authored-by: Juanito Fatas <me@juanitofatas.com>558f7be168
* [ruby/reline] Suppress auto indent for adding newlines in pasting Co-authored-by: Juanito Fatas <me@juanitofatas.com>074bb017a7
* [ruby/reline] Add acknowledgments and license for rb-readline19df59b916
* [ruby/irb] Fix comment, irb gem supports 2.5.0 or older36118015ba
* should use `assert_include` here. Random ordering test can introduce antoher candidate so it should be `assert_include`. * [ruby/irb] Add missing require This is useful if you want to use IRB::ColorPrinter as a library like: ``` begin require 'irb/color_printer' IRB::ColorPrinter.pp(obj) rescue LoadError pp(obj) end ```f8461691c7
* [ruby/irb] Make IRB::ColorPrinter.pp compatible with PP.pp The incompatible interface is not helpful, again if you want to use it as a standalone library, falling it back to PP. Original PP.pp also ends with `out << "\n"`.4c74c7d84c
* Suppress constant redefinition warnings * Fix the failing test with XDG_CONFIG_HOME * [ruby/irb] Version 1.3.1c230d08911
* [ruby/reline] Handle ed_search_{prev,next}_history in multiline correctly The current line was being handled incorrectly when displaying the hit history, so it has been fixed to be correct.a3df4343b3
* [ruby/reline] Move the cursor correctly when deleting at eol This fixes ruby/reline#246.07a73ba601
* [ruby/reline] Version 0.2.1a3b3c6ee60
* [ruby/reline] Initialize a variable just in case29b10f6e98
* [ruby/reline] Tests with yamatanooroti don't need chdir Because of chdir, log files ware created in temporary directries on Windows.200b469a68
* [ruby/reline] Windows needs more times to wait rendering53ff2b09c7
* [ruby/reline] Support for change in Windows-specific behavior at eol The behavior of automatically moving the cursor to the next line when displaying a char at the eol on Windows suddenly disappeared.cad4de6ee8
* [ruby/reline] Reline::Windows.erase_after_cursor erases attributes too68b961dfc7
* [ruby/irb] [ruby/irb] [ruby/reline] Version 0.2.2dfb710946f
1a1cdf9628
fe99faf8bd
* [ruby/irb] handle `__ENCODING__` as a keyword as wella6a33d908f
* [ruby/irb] handle repeated exception separatelyfcf6b34bc5
* [ruby/irb] skip a failling test on TruffleRuby * due to the difference of backtrace pointed out by @aycabta5e00a0ae61
* [ruby/irb] Version 1.3.2a7699026cc
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org> Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com> Co-authored-by: Nobuhiro IMAI <nov@yo.rim.or.jp> Co-authored-by: Koichi Sasada <ko1@atdot.net> Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
347 lines
8.7 KiB
Ruby
347 lines
8.7 KiB
Ruby
class Reline::Config
|
|
attr_reader :test_mode
|
|
|
|
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}|./
|
|
|
|
class InvalidInputrc < RuntimeError
|
|
attr_accessor :file, :lineno
|
|
end
|
|
|
|
VARIABLE_NAMES = %w{
|
|
bind-tty-special-chars
|
|
blink-matching-paren
|
|
byte-oriented
|
|
completion-ignore-case
|
|
convert-meta
|
|
disable-completion
|
|
enable-keypad
|
|
expand-tilde
|
|
history-preserve-point
|
|
history-size
|
|
horizontal-scroll-mode
|
|
input-meta
|
|
keyseq-timeout
|
|
mark-directories
|
|
mark-modified-lines
|
|
mark-symlinked-directories
|
|
match-hidden-files
|
|
meta-flag
|
|
output-meta
|
|
page-completions
|
|
prefer-visible-bell
|
|
print-completions-horizontally
|
|
show-all-if-ambiguous
|
|
show-all-if-unmodified
|
|
visible-stats
|
|
show-mode-in-prompt
|
|
vi-cmd-mode-string
|
|
vi-ins-mode-string
|
|
emacs-mode-string
|
|
enable-bracketed-paste
|
|
isearch-terminators
|
|
}
|
|
VARIABLE_NAME_SYMBOLS = VARIABLE_NAMES.map { |v| :"#{v.tr(?-, ?_)}" }
|
|
VARIABLE_NAME_SYMBOLS.each do |v|
|
|
attr_accessor v
|
|
end
|
|
|
|
def initialize
|
|
@additional_key_bindings = {} # from inputrc
|
|
@default_key_bindings = {} # environment-dependent
|
|
@skip_section = nil
|
|
@if_stack = nil
|
|
@editing_mode_label = :emacs
|
|
@keymap_label = :emacs
|
|
@key_actors = {}
|
|
@key_actors[:emacs] = Reline::KeyActor::Emacs.new
|
|
@key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
|
|
@key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
|
|
@vi_cmd_mode_string = '(cmd)'
|
|
@vi_ins_mode_string = '(ins)'
|
|
@emacs_mode_string = '@'
|
|
# https://tiswww.case.edu/php/chet/readline/readline.html#IDX25
|
|
@history_size = -1 # unlimited
|
|
@keyseq_timeout = 500
|
|
@test_mode = false
|
|
end
|
|
|
|
def reset
|
|
if editing_mode_is?(:vi_command)
|
|
@editing_mode_label = :vi_insert
|
|
end
|
|
@additional_key_bindings = {}
|
|
@default_key_bindings = {}
|
|
end
|
|
|
|
def editing_mode
|
|
@key_actors[@editing_mode_label]
|
|
end
|
|
|
|
def editing_mode=(val)
|
|
@editing_mode_label = val
|
|
end
|
|
|
|
def editing_mode_is?(*val)
|
|
(val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
|
|
end
|
|
|
|
def keymap
|
|
@key_actors[@keymap_label]
|
|
end
|
|
|
|
def inputrc_path
|
|
case ENV['INPUTRC']
|
|
when nil, ''
|
|
else
|
|
return File.expand_path(ENV['INPUTRC'])
|
|
end
|
|
|
|
# In the XDG Specification, if ~/.config/readline/inputrc exists, then
|
|
# ~/.inputrc should not be read, but for compatibility with GNU Readline,
|
|
# if ~/.inputrc exists, then it is given priority.
|
|
home_rc_path = File.expand_path('~/.inputrc')
|
|
return home_rc_path if File.exist?(home_rc_path)
|
|
|
|
case path = ENV['XDG_CONFIG_HOME']
|
|
when nil, ''
|
|
else
|
|
path = File.join(path, 'readline/inputrc')
|
|
return path if File.exist?(path) and path == File.expand_path(path)
|
|
end
|
|
|
|
path = File.expand_path('~/.config/readline/inputrc')
|
|
return path if File.exist?(path)
|
|
|
|
return home_rc_path
|
|
end
|
|
|
|
def read(file = nil)
|
|
file ||= inputrc_path
|
|
begin
|
|
if file.respond_to?(:readlines)
|
|
lines = file.readlines
|
|
else
|
|
lines = File.readlines(file)
|
|
end
|
|
rescue Errno::ENOENT
|
|
return nil
|
|
end
|
|
|
|
read_lines(lines, file)
|
|
self
|
|
rescue InvalidInputrc => e
|
|
warn e.message
|
|
nil
|
|
end
|
|
|
|
def key_bindings
|
|
# override @default_key_bindings with @additional_key_bindings
|
|
@default_key_bindings.merge(@additional_key_bindings)
|
|
end
|
|
|
|
def add_default_key_binding(keystroke, target)
|
|
@default_key_bindings[keystroke] = target
|
|
end
|
|
|
|
def reset_default_key_bindings
|
|
@default_key_bindings = {}
|
|
end
|
|
|
|
def read_lines(lines, file = nil)
|
|
conditions = [@skip_section, @if_stack]
|
|
@skip_section = nil
|
|
@if_stack = []
|
|
|
|
lines.each_with_index do |line, no|
|
|
next if line.match(/\A\s*#/)
|
|
|
|
no += 1
|
|
|
|
line = line.chomp.lstrip
|
|
if line.start_with?('$')
|
|
handle_directive(line[1..-1], file, no)
|
|
next
|
|
end
|
|
|
|
next if @skip_section
|
|
|
|
case line
|
|
when /^set +([^ ]+) +([^ ]+)/i
|
|
var, value = $1.downcase, $2
|
|
bind_variable(var, value)
|
|
next
|
|
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
|
|
key, func_name = $1, $2
|
|
keystroke, func = bind_key(key, func_name)
|
|
next unless keystroke
|
|
@additional_key_bindings[keystroke] = func
|
|
end
|
|
end
|
|
unless @if_stack.empty?
|
|
raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
|
|
end
|
|
ensure
|
|
@skip_section, @if_stack = conditions
|
|
end
|
|
|
|
def handle_directive(directive, file, no)
|
|
directive, args = directive.split(' ')
|
|
case directive
|
|
when 'if'
|
|
condition = false
|
|
case args
|
|
when 'mode'
|
|
when 'term'
|
|
when 'version'
|
|
else # application name
|
|
condition = true if args == 'Ruby'
|
|
condition = true if args == 'Reline'
|
|
end
|
|
@if_stack << [file, no, @skip_section]
|
|
@skip_section = !condition
|
|
when 'else'
|
|
if @if_stack.empty?
|
|
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
|
|
end
|
|
@skip_section = !@skip_section
|
|
when 'endif'
|
|
if @if_stack.empty?
|
|
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
|
|
end
|
|
@skip_section = @if_stack.pop
|
|
when 'include'
|
|
read(args)
|
|
end
|
|
end
|
|
|
|
def bind_variable(name, value)
|
|
case name
|
|
when 'history-size'
|
|
begin
|
|
@history_size = Integer(value)
|
|
rescue ArgumentError
|
|
@history_size = 500
|
|
end
|
|
when 'bell-style'
|
|
@bell_style =
|
|
case value
|
|
when 'none', 'off'
|
|
:none
|
|
when 'audible', 'on'
|
|
:audible
|
|
when 'visible'
|
|
:visible
|
|
else
|
|
:audible
|
|
end
|
|
when 'comment-begin'
|
|
@comment_begin = value.dup
|
|
when 'completion-query-items'
|
|
@completion_query_items = value.to_i
|
|
when 'isearch-terminators'
|
|
@isearch_terminators = retrieve_string(value)
|
|
when 'editing-mode'
|
|
case value
|
|
when 'emacs'
|
|
@editing_mode_label = :emacs
|
|
@keymap_label = :emacs
|
|
when 'vi'
|
|
@editing_mode_label = :vi_insert
|
|
@keymap_label = :vi_insert
|
|
end
|
|
when 'keymap'
|
|
case value
|
|
when 'emacs', 'emacs-standard', 'emacs-meta', 'emacs-ctlx'
|
|
@keymap_label = :emacs
|
|
when 'vi', 'vi-move', 'vi-command'
|
|
@keymap_label = :vi_command
|
|
when 'vi-insert'
|
|
@keymap_label = :vi_insert
|
|
end
|
|
when 'keyseq-timeout'
|
|
@keyseq_timeout = value.to_i
|
|
when 'show-mode-in-prompt'
|
|
case value
|
|
when 'off'
|
|
@show_mode_in_prompt = false
|
|
when 'on'
|
|
@show_mode_in_prompt = true
|
|
else
|
|
@show_mode_in_prompt = false
|
|
end
|
|
when 'vi-cmd-mode-string'
|
|
@vi_cmd_mode_string = retrieve_string(value)
|
|
when 'vi-ins-mode-string'
|
|
@vi_ins_mode_string = retrieve_string(value)
|
|
when 'emacs-mode-string'
|
|
@emacs_mode_string = retrieve_string(value)
|
|
when *VARIABLE_NAMES then
|
|
variable_name = :"@#{name.tr(?-, ?_)}"
|
|
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
|
end
|
|
end
|
|
|
|
def retrieve_string(str)
|
|
if str =~ /\A"(.*)"\z/
|
|
parse_keyseq($1).map(&:chr).join
|
|
else
|
|
parse_keyseq(str).map(&:chr).join
|
|
end
|
|
end
|
|
|
|
def bind_key(key, func_name)
|
|
if key =~ /\A"(.*)"\z/
|
|
keyseq = parse_keyseq($1)
|
|
else
|
|
keyseq = nil
|
|
end
|
|
if func_name =~ /"(.*)"/
|
|
func = parse_keyseq($1)
|
|
else
|
|
func = func_name.tr(?-, ?_).to_sym # It must be macro.
|
|
end
|
|
[keyseq, func]
|
|
end
|
|
|
|
def key_notation_to_code(notation)
|
|
case notation
|
|
when /\\(?:C|Control)-([A-Za-z_])/
|
|
(1 + $1.downcase.ord - ?a.ord)
|
|
when /\\(?:M|Meta)-([0-9A-Za-z_])/
|
|
modified_key = $1
|
|
case $1
|
|
when /[0-9]/
|
|
?\M-0.bytes.first + (modified_key.ord - ?0.ord)
|
|
when /[A-Z]/
|
|
?\M-A.bytes.first + (modified_key.ord - ?A.ord)
|
|
when /[a-z]/
|
|
?\M-a.bytes.first + (modified_key.ord - ?a.ord)
|
|
end
|
|
when /\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]/, /\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]/
|
|
# 129 M-^A
|
|
when /\\(\d{1,3})/ then $1.to_i(8) # octal
|
|
when /\\x(\h{1,2})/ then $1.to_i(16) # hexadecimal
|
|
when "\\e" then ?\e.ord
|
|
when "\\\\" then ?\\.ord
|
|
when "\\\"" then ?".ord
|
|
when "\\'" then ?'.ord
|
|
when "\\a" then ?\a.ord
|
|
when "\\b" then ?\b.ord
|
|
when "\\d" then ?\d.ord
|
|
when "\\f" then ?\f.ord
|
|
when "\\n" then ?\n.ord
|
|
when "\\r" then ?\r.ord
|
|
when "\\t" then ?\t.ord
|
|
when "\\v" then ?\v.ord
|
|
else notation.ord
|
|
end
|
|
end
|
|
|
|
def parse_keyseq(str)
|
|
ret = []
|
|
str.scan(KEYSEQ_PATTERN) do
|
|
ret << key_notation_to_code($&)
|
|
end
|
|
ret
|
|
end
|
|
end
|