From f012adc483d4a33fbd06845548936b4b6aa4dbd5 Mon Sep 17 00:00:00 2001 From: tompng Date: Fri, 18 Oct 2024 02:42:50 +0900 Subject: [PATCH] Cache symbol completion result --- lib/irb/completion.rb | 22 +++++++++++++++++++--- lib/irb/input-method.rb | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index 7f102dcdf..734eb9827 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -219,6 +219,22 @@ def doc_namespace(_preposing, matched, _postposing, bind:) retrieve_completion_data(matched, bind: bind, doc_namespace: true) end + def clear_symbol_cache + @all_symbols = nil + end + + def symbol_candidates(prefix, first:, last:) + limit = first + last + symbols = @all_symbols ||= Symbol.all_symbols.sort + start_index = symbols.bsearch_index { |sym| sym.to_s >= prefix } + end_index = (start_index...symbols.size).bsearch { |i| !symbols[i].start_with?(prefix) } || symbols.size + if end_index - start_index <= limit + symbols[start_index..end_index] + else + symbols[start_index, first] + symbols[end_index - last, last] + end + end + def retrieve_completion_data(input, bind:, doc_namespace:) case input # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting @@ -280,12 +296,12 @@ def retrieve_completion_data(input, bind:, doc_namespace:) nil else sym = $1 - candidates = Symbol.all_symbols.collect do |s| - s.inspect + candidates = symbol_candidates(sym[1..], first: 50, last: 50).filter_map do |s| + ins = s.inspect + ins if ins.start_with?(sym) rescue EncodingError # ignore end - candidates.grep(/^#{Regexp.quote(sym)}/) end when /^::([A-Z][^:\.\(\)]*)$/ # Absolute Constant or class methods diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index 38f05d771..5f2ca3c25 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -467,6 +467,7 @@ def gets Reline.output = @stdout Reline.prompt_proc = @prompt_proc Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc + @completor.clear_symbol_cache if @completor.respond_to? :clear_symbol_cache if l = Reline.readmultiline(@prompt, false, &@check_termination_proc) Reline::HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n"