@@ -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? ( /\A RubyVM/ ) && !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