Created
April 1, 2019 15:58
-
-
Save krainboltgreene/cd78670507eb5bc162a26e6c59c20e75 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "highline" | |
class RenderingEngine < Concurrent::Actor::Context | |
attr_reader :search | |
attr_reader :terminal | |
attr_reader :previous | |
attr_reader :current | |
def initialize() | |
@search = SearchEngine.spawn(:search) | |
@terminal = TerminalEngine.spawn(:terminal) | |
@previous = [] | |
@current = [] | |
end | |
def on_message(_) | |
render | |
collect | |
push | |
end | |
private def collect | |
terminal.tell("catch") | |
end | |
private def push | |
search.tell(["push", terminal.ask!("pull")]) | |
terminal.ask("clear") | |
end | |
private def render | |
Rails.logger.debug("Rendering") | |
flush | |
pad | |
report unless empty? | |
loading if waiting? | |
idle | |
pipe if different? | |
end | |
private def pad | |
output("\n" * (terminal.ask!("height") + 1), false) | |
end | |
private def loading | |
output("Search...", true) | |
end | |
private def empty? | |
search.ask!("empty?") | |
end | |
private def waiting? | |
search.ask!("waiting?") | |
end | |
private def idle | |
output("Search: #{search.ask!("query")}", false) | |
end | |
private def report | |
Rails.logger.debug("#{self.class}: Printing out results") | |
output(search.ask!("results"), true) | |
end | |
private def output(value, newline) | |
current << [value, newline] | |
end | |
private def different? | |
previous != current | |
end | |
private def flush | |
@previous = current.dup | |
@current = [] | |
end | |
private def pipe | |
current.each.with_index do |(value, newline), index| | |
if newline | |
Rails.logger.info(value + "\n") | |
else | |
Rails.logger.info(value) | |
end | |
end | |
end | |
end | |
class TerminalEngine < Concurrent::Actor::Context | |
attr_reader :client | |
attr_accessor :input | |
def initialize() | |
@client = HighLine.new.terminal | |
@input = nil | |
end | |
def on_message(event) | |
case event | |
when "height" then client.terminal_size.last | |
when "catch" then Concurrent::Promises.future do | |
client.raw_no_echo_mode | |
self.input = client.get_character.chomp.tap do | |
client.restore_mode | |
end | |
end | |
when "pull" then input | |
when "clear" then self.input = nil; | |
else pass | |
end | |
end | |
end | |
class SearchEngine < Concurrent::Actor::Context | |
DELETE = "\u007F" | |
EXIT = "\u0003" | |
attr_reader :query | |
attr_accessor :waiting | |
def initialize | |
@results = nil | |
@query = "" | |
@waiting = false | |
end | |
def on_message(event) | |
if event.is_a?(Array) && event.first == "push" | |
lookup(event.last) | |
else | |
case event | |
when "waiting?" | |
waiting | |
when "empty?" | |
results.empty? | |
when "query" | |
query | |
when "results" | |
results | |
else pass | |
end | |
end | |
end | |
def lookup(input) | |
return if input.nil? || input.empty? | |
return if input.include?(":") | |
exit if input.include?(EXIT) | |
return if input.include?(DELETE) && query.each_char.size.zero? | |
if input.include?(DELETE) | |
Rails.logger.debug("#{self.class}: Deleting last character (#{query} -> #{query.each_char.to_a.first(query.size - 1).join("")})") | |
@query = query.each_char.to_a.first(query.size - 1).join("") | |
else | |
Rails.logger.debug("#{self.class}: Appending input to the query (#{input})") | |
@query += input | |
end | |
return Rails.logger.debug("#{self.class}: Query is too small") if query.size <= 3 | |
Rails.logger.debug("#{self.class}: Waiting for results") | |
self.waiting = true | |
Concurrent::Promises.future do | |
@results = Search.find(query) | |
Rails.logger.debug("#{self.class}: Results came back") | |
self.waiting = false | |
end | |
end | |
private def results | |
if @results.present? | |
@results.to_tables | |
else | |
"" | |
end | |
end | |
end | |
Rails.logger.debug("Starting render") | |
engine = RenderingEngine.spawn(:output) | |
engine.tell(:empty) | |
while true | |
engine.tell(:empty) && sleep(1) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment