137 lines
2.7 KiB
Ruby
137 lines
2.7 KiB
Ruby
class ::Fingers::Hinter
|
|
def initialize(
|
|
input:,
|
|
width:,
|
|
state:,
|
|
output:, patterns: Fingers.config.patterns,
|
|
alphabet: Fingers.config.alphabet,
|
|
huffman: Huffman.new,
|
|
formatter: ::Fingers::MatchFormatter.new
|
|
)
|
|
@input = input
|
|
@width = width
|
|
@hints_by_text = {}
|
|
@state = state
|
|
@output = output
|
|
@formatter = formatter
|
|
@huffman = huffman
|
|
@patterns = patterns
|
|
@alphabet = alphabet
|
|
end
|
|
|
|
def run
|
|
lines[0..-2].each { |line| process_line(line, "\n") }
|
|
process_line(lines[-1], "")
|
|
|
|
STDOUT.flush
|
|
output.flush
|
|
|
|
build_lookup_table!
|
|
end
|
|
|
|
def lookup(hint)
|
|
lookup_table[hint]
|
|
end
|
|
|
|
def matches
|
|
@matches ||= @hints_by_text.keys.uniq.flatten
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :hints,
|
|
:hints_by_text,
|
|
:input,
|
|
:lookup_table,
|
|
:width,
|
|
:state,
|
|
:formatter,
|
|
:huffman,
|
|
:output,
|
|
:patterns,
|
|
:alphabet
|
|
|
|
def build_lookup_table!
|
|
@lookup_table = hints_by_text.invert
|
|
end
|
|
|
|
def process_line(line, ending)
|
|
Fingers.logger.info("processing line")
|
|
result = line.gsub(pattern) { |_m| replace($~) }
|
|
output.print(result + ending)
|
|
end
|
|
|
|
def pattern
|
|
@pattern ||= Regexp.compile("(#{patterns.join("|")})")
|
|
end
|
|
|
|
def hints
|
|
return @hints if @hints
|
|
|
|
@hints = huffman.generate_hints(alphabet: alphabet, n: n_matches)
|
|
end
|
|
|
|
def replace(match)
|
|
text = match[0]
|
|
|
|
#captured_text = match && match.named_captures["capture"] || text
|
|
captured_text = match && match || text
|
|
|
|
#if match.named_captures["capture"]
|
|
#match_start, match_end = match.offset(0)
|
|
#capture_start, capture_end = match.offset(:capture)
|
|
|
|
#capture_offset = [capture_start - match_start, capture_end - capture_start]
|
|
#else
|
|
capture_offset = nil
|
|
#end
|
|
|
|
# Converting match data to string
|
|
captured_text = captured_text.to_s
|
|
|
|
if hints_by_text.has_key?(captured_text)
|
|
hint = hints_by_text[captured_text]
|
|
else
|
|
hint = hints.pop
|
|
hints_by_text[captured_text] = hint
|
|
end
|
|
|
|
|
|
# TODO: this should be output hint without ansi escape sequences
|
|
formatter.format(
|
|
hint: hint,
|
|
highlight: text,
|
|
selected: state.selected_hints.include?(hint),
|
|
offset: capture_offset
|
|
)
|
|
|
|
end
|
|
|
|
def lines
|
|
@lines ||= input.split("\n")
|
|
end
|
|
|
|
def n_matches
|
|
return @n_matches if @n_matches
|
|
|
|
match_set = ::Set.new
|
|
|
|
Fingers.benchmark_stamp("counting-matches:start")
|
|
|
|
lines.each do |line|
|
|
Fingers.logger.info("line: #{line}")
|
|
Fingers.logger.info("pattern: #{pattern}")
|
|
Fingers.logger.info("----")
|
|
line.scan(pattern) do |match|
|
|
match_set.add($&)
|
|
end
|
|
end
|
|
|
|
Fingers.benchmark_stamp("counting-matches:end")
|
|
|
|
@n_matches = match_set.length
|
|
|
|
@n_matches
|
|
end
|
|
end
|