Skip to content

Commit ff54f32

Browse files
committed
Refactor show_doc_dialog_proc into smaller methods
1 parent 384f338 commit ff54f32

1 file changed

Lines changed: 92 additions & 88 deletions

File tree

lib/irb/input-method.rb

Lines changed: 92 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,16 @@ def inspect
255255

256256
class RelineInputMethod < StdioInputMethod
257257
HISTORY = Reline::HISTORY
258+
ALT_KEY_NAME = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
259+
PRESS_ALT_D_TO_READ_FULL_DOC = "Press #{ALT_KEY_NAME}+d to read the full document".freeze
260+
PRESS_ALT_D_TO_SEE_MORE = "Press #{ALT_KEY_NAME}+d to see more".freeze
261+
ALT_D_SEQUENCES = [
262+
[27, 100], # Normal Alt+d when convert-meta isn't used.
263+
# When option/alt is not configured as a meta key in terminal emulator,
264+
# option/alt + d will send a unicode character depend on OS keyboard setting.
265+
[195, 164], # "ä" in somewhere (FIXME: environment information is unknown).
266+
[226, 136, 130] # "∂" Alt+d on Mac keyboard.
267+
].freeze
258268
include HistorySavingAbility
259269
# Creates a new input method object using Reline
260270
def initialize(completor)
@@ -328,125 +338,119 @@ def show_doc_dialog_proc
328338
input_method = self # self is changed in the lambda below.
329339
->() {
330340
dialog.trap_key = nil
331-
alt_d = [
332-
[27, 100], # Normal Alt+d when convert-meta isn't used.
333-
# When option/alt is not configured as a meta key in terminal emulator,
334-
# option/alt + d will send a unicode character depend on OS keyboard setting.
335-
[195, 164], # "ä" in somewhere (FIXME: environment information is unknown).
336-
[226, 136, 130] # "∂" Alt+d on Mac keyboard.
337-
]
338-
339-
if just_cursor_moving and completion_journey_data.nil?
341+
342+
if just_cursor_moving && completion_journey_data.nil?
340343
return nil
341344
end
342345
cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
343-
return nil if result.nil? or pointer.nil? or pointer < 0
346+
return nil if result.nil? || pointer.nil? || pointer < 0
344347

345348
name = input_method.retrieve_doc_namespace(result[pointer])
346349
# Use first one because document dialog does not support multiple namespaces.
347350
name = name.first if name.is_a?(Array)
348351

349352
show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
350353

351-
driver = input_method.rdoc_ri_driver
354+
x, width = input_method.dialog_doc_position(cursor_pos_to_render, autocomplete_dialog, screen_width)
355+
return nil unless x
352356

353-
if key.match?(dialog.name)
354-
if show_easter_egg
355-
IRB.__send__(:easter_egg)
356-
else
357-
# RDoc::RI::Driver#display_names uses pager command internally.
358-
# Some pager command like `more` doesn't use alternate screen
359-
# so we need to turn on and off alternate screen manually.
360-
begin
361-
print "\e[?1049h"
362-
driver.display_names([name])
363-
rescue RDoc::RI::Driver::NotFoundError
364-
ensure
365-
print "\e[?1049l"
366-
end
367-
end
357+
dialog.trap_key = ALT_D_SEQUENCES
358+
open_doc = key.match?(dialog.name)
359+
360+
contents = if show_easter_egg
361+
input_method.easter_egg_dialog_contents(open_doc: open_doc)
362+
else
363+
input_method.rdoc_dialog_contents(name, width, open_doc: open_doc)
368364
end
365+
return nil unless contents
366+
367+
contents = contents.take(preferred_dialog_height)
368+
y = cursor_pos_to_render.y
369+
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
370+
}
371+
end
369372

373+
def easter_egg_dialog_contents(open_doc: false)
374+
IRB.__send__(:easter_egg) if open_doc
375+
type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
376+
lines = IRB.send(:easter_egg_logo, type).split("\n")
377+
lines[0][0, PRESS_ALT_D_TO_SEE_MORE.size] = PRESS_ALT_D_TO_SEE_MORE
378+
lines
379+
end
380+
381+
def rdoc_dialog_contents(name, width, open_doc: false)
382+
driver = rdoc_ri_driver
383+
return unless driver
384+
385+
if open_doc
370386
begin
371-
name = driver.expand_name(name)
387+
print "\e[?1049h"
388+
driver.display_names([name])
372389
rescue RDoc::RI::Driver::NotFoundError
373-
return nil
374-
rescue
375-
return nil # unknown error
376-
end
377-
doc = nil
378-
used_for_class = false
379-
if not name =~ /#|\./
380-
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
381-
if not found.empty?
382-
doc = driver.class_document(name, found, klasses, includes, extends)
383-
used_for_class = true
384-
end
390+
ensure
391+
print "\e[?1049l"
385392
end
386-
unless used_for_class
387-
doc = RDoc::Markup::Document.new
388-
begin
389-
driver.add_method(doc, name)
390-
rescue RDoc::RI::Driver::NotFoundError
391-
doc = nil
392-
rescue
393-
return nil # unknown error
394-
end
393+
end
394+
395+
name = driver.expand_name(name)
396+
397+
doc = if name =~ /#|\./
398+
d = RDoc::Markup::Document.new
399+
driver.add_method(d, name)
400+
d
401+
else
402+
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
403+
if found.empty?
404+
d = RDoc::Markup::Document.new
405+
driver.add_method(d, name)
406+
d
407+
else
408+
driver.class_document(name, found, klasses, includes, extends)
395409
end
396-
return nil if doc.nil?
397-
width = 40
398-
399-
right_x = cursor_pos_to_render.x + autocomplete_dialog.width
400-
if right_x + width > screen_width
401-
right_width = screen_width - (right_x + 1)
402-
left_x = autocomplete_dialog.column - width
403-
left_x = 0 if left_x < 0
404-
left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
405-
if right_width.positive? and left_width.positive?
406-
if right_width >= left_width
407-
width = right_width
408-
x = right_x
409-
else
410-
width = left_width
411-
x = left_x
412-
end
413-
elsif right_width.positive? and left_width <= 0
410+
end
411+
412+
formatter = RDoc::Markup::ToAnsi.new
413+
formatter.width = width
414+
[PRESS_ALT_D_TO_READ_FULL_DOC] + doc.accept(formatter).split("\n")
415+
rescue RDoc::RI::Driver::NotFoundError
416+
end
417+
418+
def dialog_doc_position(cursor_pos_to_render, autocomplete_dialog, screen_width)
419+
width = 40
420+
right_x = cursor_pos_to_render.x + autocomplete_dialog.width
421+
if right_x + width > screen_width
422+
right_width = screen_width - (right_x + 1)
423+
left_x = autocomplete_dialog.column - width
424+
left_x = 0 if left_x < 0
425+
left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
426+
if right_width.positive? && left_width.positive?
427+
if right_width >= left_width
414428
width = right_width
415429
x = right_x
416-
elsif right_width <= 0 and left_width.positive?
430+
else
417431
width = left_width
418432
x = left_x
419-
else # Both are negative width.
420-
return nil
421433
end
422-
else
434+
elsif right_width.positive? && left_width <= 0
435+
width = right_width
423436
x = right_x
424-
end
425-
formatter = RDoc::Markup::ToAnsi.new
426-
formatter.width = width
427-
dialog.trap_key = alt_d
428-
mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
429-
if show_easter_egg
430-
type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
431-
contents = IRB.send(:easter_egg_logo, type).split("\n")
432-
message = "Press #{mod_key}+d to see more"
433-
contents[0][0, message.size] = message
437+
elsif right_width <= 0 && left_width.positive?
438+
width = left_width
439+
x = left_x
434440
else
435-
message = "Press #{mod_key}+d to read the full document"
436-
contents = [message] + doc.accept(formatter).split("\n")
441+
return nil
437442
end
438-
contents = contents.take(preferred_dialog_height)
439-
440-
y = cursor_pos_to_render.y
441-
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
442-
}
443+
else
444+
x = right_x
445+
end
446+
[x, width]
443447
end
444448

445449
def display_document(matched)
446450
driver = rdoc_ri_driver
447451
return unless driver
448452

449-
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
453+
if matched =~ /\A(?:::)?RubyVM/ && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
450454
IRB.__send__(:easter_egg)
451455
return
452456
end

0 commit comments

Comments
 (0)