Skip to content

Commit

Permalink
Check conditional nestings in INPUTRC
Browse files Browse the repository at this point in the history
Closes: #2222
  • Loading branch information
nobu authored and aycabta committed Jun 2, 2019
1 parent a1e6e45 commit f4b060d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 12 deletions.
43 changes: 31 additions & 12 deletions lib/reline/config.rb
Expand Up @@ -5,6 +5,10 @@ class Reline::Config

DEFAULT_PATH = '~/.inputrc'

class InvalidInputrc < RuntimeError
attr_accessor :file, :lineno
end

VARIABLE_NAMES = %w{
bind-tty-special-chars
blink-matching-paren
Expand Down Expand Up @@ -41,7 +45,7 @@ def initialize
@additional_key_bindings = {} # from inputrc
@default_key_bindings = {} # environment-dependent
@skip_section = nil
@if_stack = []
@if_stack = nil
@editing_mode_label = :emacs
@keymap_label = :emacs
@key_actors = {}
Expand Down Expand Up @@ -89,8 +93,11 @@ def read(file = nil)
return nil
end

read_lines(lines)
read_lines(lines, file)
self
rescue InvalidInputrc => e
warn e.message
nil
end

def key_bindings
Expand All @@ -106,13 +113,19 @@ def reset_default_key_bindings
@default_key_bindings = {}
end

def read_lines(lines)
lines.each do |line|
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.start_with?('#')

no += 1

line = line.chomp.gsub(/^\s*/, '')
if line[0, 1] == '$'
handle_directive(line[1..-1])
handle_directive(line[1..-1], file, no)
next
end

Expand All @@ -130,9 +143,14 @@ def read_lines(lines)
@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)
def handle_directive(directive, file, no)
directive, args = directive.split(' ')
case directive
when 'if'
Expand All @@ -145,17 +163,18 @@ def handle_directive(directive)
condition = true if args == 'Ruby'
condition = true if args == 'Reline'
end
unless @skip_section.nil?
@if_stack << @skip_section
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'
@skip_section = nil
unless @if_stack.empty?
@skip_section = @if_stack.pop
if @if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
end
@skip_section = @if_stack.pop
when 'include'
read(args)
end
Expand Down
27 changes: 27 additions & 0 deletions test/reline/test_config.rb
Expand Up @@ -117,6 +117,33 @@ def test_if_with_indent
end
end

def test_unclosed_if
e = assert_raise(Reline::Config::InvalidInputrc) do
@config.read_lines(<<~LINES.split(/(?<=\n)/), "INPUTRC")
$if Ruby
LINES
end
assert_equal "INPUTRC:1: unclosed if", e.message
end

def test_unmatched_else
e = assert_raise(Reline::Config::InvalidInputrc) do
@config.read_lines(<<~LINES.split(/(?<=\n)/), "INPUTRC")
$else
LINES
end
assert_equal "INPUTRC:1: unmatched else", e.message
end

def test_unmatched_endif
e = assert_raise(Reline::Config::InvalidInputrc) do
@config.read_lines(<<~LINES.split(/(?<=\n)/), "INPUTRC")
$endif
LINES
end
assert_equal "INPUTRC:1: unmatched endif", e.message
end

def test_default_key_bindings
@config.add_default_key_binding('abcd'.bytes, 'EFGH'.bytes)
@config.read_lines(<<~'LINES'.split(/^/))
Expand Down

0 comments on commit f4b060d

Please sign in to comment.