lib/rib/extra/autoindent.rb in rib-0.9.1 vs lib/rib/extra/autoindent.rb in rib-0.9.2
- old
+ new
@@ -38,17 +38,26 @@
/^module/ => /^(end)\b/ ,
/^while/ => /^(end)\b/ ,
/^until/ => /^(end)\b/ ,
# consider cases:
# 'do
- # "do
+ # ' do
+ # "' do
# /do
# '{
- # "{
- # /{
- /[^'"\/]do( *\|.*\|)?$/ => /^(end)\b/ ,
- /[^'"\/]\{( *\|.*\|)?$/ => /^(\})\B/ ,
+ # %q{
+ # %q| do
+ # hey, two lines are even harder!
+ # "
+ # begin
+ /do( *\|.*\|)?$/ => /^(end)\b/ ,
+ /\{( *\|.*\|)?$/ => /^(\})\B/ ,
+ # those are too hard to deal with, so we use syntax error to double check
+ # what about this then?
+ # v = if true
+ # else
+ # end
}
# --------------- Rib API ---------------
def before_loop
@@ -57,46 +66,77 @@
super
end
def get_input
return super if Autoindent.disabled?
+ # this is only a fix in case we don't autoindent correctly
+ # if we're autoindenting 100% correct, then this is a useless check
autoindent_stack.clear if multiline_buffer.empty?
+
+ # this should be called after ::Readline.readline, but it's blocking,
+ # and i don't know if there's any hook to do this, so here we use thread
Thread.new do
sleep(0.01)
- # this should be called after ::Readline.readline, but it's blocking,
- # and i don't know if there's any hook to do this, so here we use thread
- ::Readline.line_buffer = current_autoindent
+ ::Readline.line_buffer = current_autoindent if
+ ::Readline.line_buffer.empty?
end
+
super
end
- def loop_eval input
+ def eval_input raw_input
return super if Autoindent.disabled?
- if indented = handle_autoindent(input.strip)
- super(indented)
- else
- super
- end
+ input = raw_input.strip
+ indent = detect_autoindent(input)
+ result, err = if indent.first.to_s.start_with?('left')
+ super(handle_last_line(input))
+ else
+ super
+ end
+ handle_autoindent(input, indent, err)
+ [result, err]
end
# --------------- Plugin API ---------------
- def handle_autoindent input
- _, up = BLOCK_REGEXP.find{ |key, _| input =~ key }
- if up
- autoindent_stack << up
- nil
+ def detect_autoindent input
+ _, backmark = BLOCK_REGEXP.find{ |key, _| input =~ key }
+ if backmark # e.g. begin
+ [:right, backmark]
elsif input =~ autoindent_stack.last
- if $1 # e.g. end, }, etc
- autoindent_stack.pop
- handle_last_line(input)
- else # e.g. elsif, rescue, etc
- handle_last_line(input, current_autoindent(autoindent_stack.size-1))
+ if $1 # e.g. end, }, etc
+ [:left_end]
+ else # e.g. elsif, rescue, etc
+ [:left_tmp]
end
+ else
+ [:stay]
end
end
- def handle_last_line input, indent=current_autoindent
+ def handle_autoindent input, indent, err
+ case indent.first
+ when :right # we need to go deeper
+ if multiline?(err)
+ if err.message =~ /unterminated \w+ meets end of file/
+ # skip if we're in the middle of a string or regexp
+ else
+ # indent.last is the way (input regexp matches) to go back
+ autoindent_stack << indent.last
+ end
+ end
+
+ when :left_end # we need to go back
+ # could happen in either multiline or not
+ autoindent_stack.pop
+
+ when :left_tmp # temporarily go back
+ handle_last_line(input) if multiline?(err)
+ end
+ end
+
+ def handle_last_line input,
+ indent=current_autoindent(autoindent_stack.size-1)
new_input = "#{indent}#{input}"
puts("\e[1A\e[K#{prompt}#{new_input}")
new_input
end