# File lib/rbreadline.rb, line 4015
  def _rl_isearch_dispatch(cxt, c)
    f = nil

    if c.class == Fixnum && c < 0
      cxt.sflags |= SF_FAILED
      cxt.history_pos = cxt.last_found_line
      return -1
    end

    # Translate the keys we do something with to opcodes.
    if (c && @_rl_keymap[c])
      f = @_rl_keymap[c]
      if (f == :rl_reverse_search_history)
        cxt.lastc = (cxt.sflags & SF_REVERSE)!=0 ? -1 : -2
      elsif (f == :rl_forward_search_history)
        cxt.lastc = (cxt.sflags & SF_REVERSE)!=0 ? -2 : -1
      elsif (f == :rl_rubout)
        cxt.lastc = -3
      elsif (c == "\C-G")
        cxt.lastc = -4
      elsif (c == "\C-W")  # XXX
        cxt.lastc = -5
      elsif (c == "\C-Y")  # XXX
        cxt.lastc = -6
      end
    end

    # The characters in isearch_terminators (set from the user-settable
    #   variable isearch-terminators) are used to terminate the search but
    #   not subsequently execute the character as a command.  The default
    #   value is "\033\012" (ESC and C-J).
    if (cxt.lastc.class == String && cxt.search_terminators.include?(cxt.lastc))
      # ESC still terminates the search, but if there is pending
      #input or if input arrives within 0.1 seconds (on systems
      #with select(2)) it is used as a prefix character
      #with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
      #to allow the arrow keys to be used like ^F and ^B are used
      #to terminate the search and execute the movement command.
      #XXX - since _rl_input_available depends on the application-
      #settable keyboard timeout value, this could alternatively
      #use _rl_input_queued(100000)
      if (cxt.lastc == ESC && _rl_input_available())
        rl_execute_next(ESC)
      end
      return (0)
    end

    if !@rl_byte_oriented
      if (cxt.lastc.class == String && (cxt.mb.length == 1) && endsrch_char(cxt.lastc))
        # This sets rl_pending_input to c; it will be picked up the next
        #   time rl_read_key is called.
        rl_execute_next(cxt.lastc)
        return (0)
      end
    elsif (cxt.lastc.class == String && endsrch_char(cxt.lastc))
      # This sets rl_pending_input to LASTC; it will be picked up the next
      #   time rl_read_key is called.
      rl_execute_next(cxt.lastc)
      return (0)
    end

    # Now dispatch on the character.  `Opcodes' affect the search string or
    #   state.  Other characters are added to the string.
    case (cxt.lastc)

      # search again
    when -1
      if (cxt.search_string_index == 0)
        if (@last_isearch_string)
          cxt.search_string_size = 64 + @last_isearch_string_len
          cxt.search_string = @last_isearch_string.dup
          cxt.search_string_index = @last_isearch_string_len
          rl_display_search(cxt.search_string, (cxt.sflags & SF_REVERSE)!=0, -1)
        else
          return (1)
        end
      elsif (cxt.sflags & SF_REVERSE)!=0
        cxt.sline_index-=1
      elsif (cxt.sline_index != cxt.sline_len)
        cxt.sline_index+=1
      else
        rl_ding()
      end

      # switch directions
    when -2
      cxt.direction = -cxt.direction
      if (cxt.direction < 0)
        cxt.sflags |= SF_REVERSE
      else
        cxt.sflags &= ~SF_REVERSE
      end
      # delete character from search string.
    when -3  # C-H, DEL
      # This is tricky.  To do this right, we need to keep a
      # stack of search positions for the current search, with
      # sentinels marking the beginning and end.  But this will
      # do until we have a real isearch-undo.
      if (cxt.search_string_index == 0)
        rl_ding()
      else
        cxt.search_string_index -= 1
        cxt.search_string.chop!
      end
    when -4  # C-G, abort
      rl_replace_line(cxt.lines[cxt.save_line], false)
      @rl_point = cxt.save_point
      @rl_mark = cxt.save_mark
      rl_restore_prompt()
      rl_clear_message()
      return -1
    when -5  # C-W
      # skip over portion of line we already matched and yank word
      wstart = @rl_point + cxt.search_string_index
      if (wstart >= @rl_end)
        rl_ding()
      else
        # if not in a word, move to one.
        cval = _rl_char_value(@rl_line_buffer, wstart)
        if (!_rl_walphabetic(cval))
          rl_ding()
        else
          if !@rl_byte_oriented
            n = _rl_find_next_mbchar(@rl_line_buffer, wstart, 1, MB_FIND_NONZERO)
          else
            n = wstart+1
          end
          while (n < @rl_end)
            cval = _rl_char_value(@rl_line_buffer, n)
            break if !_rl_walphabetic(cval)
            if !@rl_byte_oriented
              n = _rl_find_next_mbchar(@rl_line_buffer, n, 1, MB_FIND_NONZERO)
            else
              n = n+1
            end
          end
          wlen = n - wstart + 1
          if (cxt.search_string_index + wlen + 1 >= cxt.search_string_size)
            cxt.search_string_size += wlen + 1
          end
          cxt.search_string[cxt.search_string_index..-1] = @rl_line_buffer[wstart,wlen]
          cxt.search_string_index += wlen
        end
      end

    when -6  # C-Y
      # skip over portion of line we already matched and yank rest
      wstart = @rl_point + cxt.search_string_index
      if (wstart >= @rl_end)
        rl_ding()
      else
        n = @rl_end - wstart + 1
        if (cxt.search_string_index + n + 1 >= cxt.search_string_size)
          cxt.search_string_size += n + 1
        end
        cxt.search_string[cxt.search_string_index..-1] = @rl_line_buffer[wstart,n]
      end

      # Add character to search string and continue search.
    else
      if (cxt.search_string_index + 2 >= cxt.search_string_size)
        cxt.search_string_size += 128
      end
      if !@rl_byte_oriented
        for j in 0 ... cxt.mb.length
          cxt.search_string << cxt.mb[j,1]
          cxt.search_string_index += 1
        end
      else
        cxt.search_string << c
        cxt.search_string_index += 1
      end
    end

    while (cxt.sflags &= ~(SF_FOUND|SF_FAILED))!=0
      limit = cxt.sline_len - cxt.search_string_index + 1
      # Search the current line.
      while ((cxt.sflags & SF_REVERSE)!=0 ? (cxt.sline_index >= 0) : (cxt.sline_index < limit))

        if (cxt.search_string[0,cxt.search_string_index] == cxt.sline[cxt.sline_index,cxt.search_string_index])
          cxt.sflags |= SF_FOUND
          break
        else
          cxt.sline_index += cxt.direction
        end
      end
      break if (cxt.sflags & SF_FOUND)!=0

      # Move to the next line, but skip new copies of the line
      # we just found and lines shorter than the string we're
      # searching for.
      begin
        # Move to the next line.
        cxt.history_pos += cxt.direction

        # At limit for direction?
        if ((cxt.sflags & SF_REVERSE)!=0 ? (cxt.history_pos < 0) : (cxt.history_pos == cxt.hlen))
          cxt.sflags |= SF_FAILED
          break
        end

        # We will need these later.
        cxt.sline = cxt.lines[cxt.history_pos]
        cxt.sline_len = cxt.sline.length
      end while ((cxt.prev_line_found && cxt.prev_line_found == cxt.lines[cxt.history_pos]) ||
                 (cxt.search_string_index > cxt.sline_len))

      break if (cxt.sflags & SF_FAILED)!=0

      # Now set up the line for searching...
      cxt.sline_index = (cxt.sflags & SF_REVERSE)!=0 ? cxt.sline_len - cxt.search_string_index : 0
    end

    if (cxt.sflags & SF_FAILED)!=0
      # We cannot find the search string.  Ding the bell.
      rl_ding()
      cxt.history_pos = cxt.last_found_line
      return 1
    end

    # We have found the search string.  Just display it.  But don't
    #   actually move there in the history list until the user accepts
    #   the location.
    if (cxt.sflags & SF_FOUND)!=0
      cxt.prev_line_found = cxt.lines[cxt.history_pos]
      rl_replace_line(cxt.lines[cxt.history_pos], false)
      @rl_point = cxt.sline_index
      cxt.last_found_line = cxt.history_pos
      rl_display_search(cxt.search_string, (cxt.sflags & SF_REVERSE)!=0, (cxt.history_pos == cxt.save_line) ? -1 : cxt.history_pos)
    end
    1
  end