mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
IRB is improved with Reline and RDoc
Reline is a readline stdlib compatible library. It also supports multiline input. IRB is improved with Reline and supports multiline. Besides, supports showing documents when completed. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67645 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
91faab7f14
commit
7f273ac6d0
34 changed files with 8183 additions and 1119 deletions
235
lib/reline/config.rb
Normal file
235
lib/reline/config.rb
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
require 'pathname'
|
||||
|
||||
class Reline::Config
|
||||
DEFAULT_PATH = Pathname.new(Dir.home).join('.inputrc')
|
||||
|
||||
def initialize
|
||||
@skip_section = nil
|
||||
@if_stack = []
|
||||
@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
|
||||
end
|
||||
|
||||
def reset
|
||||
if editing_mode_is?(:vi_command)
|
||||
@editing_mode_label = :vi_insert
|
||||
end
|
||||
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 read(file = DEFAULT_PATH)
|
||||
begin
|
||||
if file.respond_to?(:readlines)
|
||||
lines = file.readlines
|
||||
else
|
||||
File.open(file, 'rt') do |f|
|
||||
lines = f.readlines
|
||||
end
|
||||
end
|
||||
rescue Errno::ENOENT
|
||||
$stderr.puts "no such file #{file}"
|
||||
return nil
|
||||
end
|
||||
|
||||
read_lines(lines)
|
||||
self
|
||||
end
|
||||
|
||||
def read_lines(lines)
|
||||
lines.each do |line|
|
||||
line = line.chomp.gsub(/^\s*/, '')
|
||||
if line[0, 1] == '$'
|
||||
handle_directive(line[1..-1])
|
||||
next
|
||||
end
|
||||
|
||||
next if @skip_section
|
||||
|
||||
if line.match(/^set +([^ ]+) +([^ ]+)/i)
|
||||
var, value = $1.downcase, $2.downcase
|
||||
bind_variable(var, value)
|
||||
next
|
||||
end
|
||||
|
||||
if line =~ /\s*(.*)\s*:\s*(.*)\s*$/
|
||||
key, func_name = $1, $2
|
||||
bind_key(key, func_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_directive(directive)
|
||||
directive, args = directive.split(' ')
|
||||
case directive
|
||||
when 'if'
|
||||
condition = false
|
||||
case args # TODO: variables
|
||||
when 'mode'
|
||||
when 'term'
|
||||
when 'version'
|
||||
else # application name
|
||||
condition = true if args == 'Ruby'
|
||||
end
|
||||
unless @skip_section.nil?
|
||||
@if_stack << @skip_section
|
||||
end
|
||||
@skip_section = !condition
|
||||
when 'else'
|
||||
@skip_section = !@skip_section
|
||||
when 'endif'
|
||||
@skip_section = nil
|
||||
unless @if_stack.empty?
|
||||
@skip_section = @if_stack.pop
|
||||
end
|
||||
when 'include'
|
||||
read(args)
|
||||
end
|
||||
end
|
||||
|
||||
def bind_variable(name, value)
|
||||
case name
|
||||
when %w{
|
||||
bind-tty-special-chars
|
||||
blink-matching-paren
|
||||
byte-oriented
|
||||
completion-ignore-case
|
||||
convert-meta
|
||||
disable-completion
|
||||
enable-keypad
|
||||
expand-tilde
|
||||
history-preserve-point
|
||||
horizontal-scroll-mode
|
||||
input-meta
|
||||
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
|
||||
} then
|
||||
variable_name = :"@#{name.tr(?-, ?_)}"
|
||||
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
||||
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 = instance_eval(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
|
||||
end
|
||||
end
|
||||
|
||||
def bind_key(key, func_name)
|
||||
if key =~ /"(.*)"/
|
||||
keyseq = parse_keyseq($1).force_encoding('ASCII-8BIT')
|
||||
else
|
||||
keyseq = nil
|
||||
end
|
||||
if func_name =~ /"(.*)"/
|
||||
func = parse_keyseq($1).force_encoding('ASCII-8BIT')
|
||||
else
|
||||
func = func_name.to_sym # It must be macro.
|
||||
end
|
||||
[keyseq, func]
|
||||
end
|
||||
|
||||
def key_notation_to_char(notation)
|
||||
case notation
|
||||
when /\\C-([A-Za-z_])/
|
||||
(1 + $1.downcase.ord - ?a.ord).chr('ASCII-8BIT')
|
||||
when /\\M-([0-9A-Za-z_])/
|
||||
modified_key = $1
|
||||
code =
|
||||
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
|
||||
code.chr('ASCII-8BIT')
|
||||
when /\\C-M-[A-Za-z_]/, /\\M-C-[A-Za-z_]/
|
||||
# 129 M-^A
|
||||
when /\\(\d{1,3})/ then $1.to_i(8).chr # octal
|
||||
when /\\x(\h{1,2})/ then $1.to_i(16).chr # hexadecimal
|
||||
when "\\e" then ?\e
|
||||
when "\\\\" then ?\\
|
||||
when "\\\"" then ?"
|
||||
when "\\'" then ?'
|
||||
when "\\a" then ?\a
|
||||
when "\\b" then ?\b
|
||||
when "\\d" then ?\d
|
||||
when "\\f" then ?\f
|
||||
when "\\n" then ?\n
|
||||
when "\\r" then ?\r
|
||||
when "\\t" then ?\t
|
||||
when "\\v" then ?\v
|
||||
else notation
|
||||
end
|
||||
end
|
||||
|
||||
def parse_keyseq(str)
|
||||
# TODO: Control- and Meta-
|
||||
ret = String.new(encoding: 'ASCII-8BIT')
|
||||
while str =~ /(\\C-[A-Za-z_]|\\M-[0-9A-Za-z_]|\\C-M-[A-Za-z_]|\\M-C-[A-Za-z_]|\\e|\\\\|\\"|\\'|\\a|\\b|\\d|\\f|\\n|\\r|\\t|\\v|\\\d{1,3}|\\x\h{1,2}|.)/
|
||||
ret << key_notation_to_char($&)
|
||||
str = $'
|
||||
end
|
||||
ret
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue