Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active February 8, 2017 13:47
Show Gist options
  • Save JoshCheek/20cfab07f16d3a2f8d28749687b3a58f to your computer and use it in GitHub Desktop.
Save JoshCheek/20cfab07f16d3a2f8d28749687b3a58f to your computer and use it in GitHub Desktop.
Example of how you could use SiB to do dynamic tab completion
# Based on an issue someone opened on a gem I'm mirroring
# https://github.com/JoshCheek/rcodetools/issues/1#issuecomment-278332781
require_relative 'completion'
Completion.new(source: DATA.read, line: 20, column: 12).completions
# => [["Foo", "mouse"],
# ["Foo", "monster"],
# ["Foo", "mongoose"],
# ["Object", "mocking_bird"]]
__END__
class Foo
def mouse
:squeek
end
def monster
:rar
end
def mongoose
:blep
end
end
class Object
def mocking_bird
:oooh_look_at_me_SQUAWK_whoooo_im_an_object_SQUAWK!
end
end
1+Foo.new.mo+2
require 'seeing_is_believing'
require 'parser/ruby24'
require 'json'
class Completion
def initialize(source:, line:, column:)
self.code = SeeingIsBelieving::Code.new source
self.line = line
self.column = column
self.index = column + code.linenum_to_index(line)
self.ast = find_ast code.root, index
end
def completions
# This is for a :send ast on an explicit receiver, you'd have to figure out
# what it should be for each syntactic context you might be completing in
receiver, to_complete = ast.children
handler = SeeingIsBelieving.call code.raw, rewrite_code: -> * do
code.rewriter.replace ast.location.expression,
competions_for_send(receiver)
code.rewriter.process
end
handler.result[line]
.map(&JSON.method(:parse))
.select { |klass, method| method.start_with? to_complete.to_s }
end
private
attr_accessor :code, :ast, :line, :column, :index
def contains?(ast, index)
return false unless ast.kind_of? AST::Node
expr = ast.location.expression
expr.begin_pos <= index && index <= expr.end_pos
end
def find_ast(ast, index)
return nil unless contains?(ast, index)
ast.children.map { |child| find_ast child, index }.compact.first || ast
end
def competions_for_send(ast)
receiver_code = ast.location.expression.source
<<-RUBY
( receiver = (#{receiver_code})
klass = receiver.class
begin klass = receiver.singleton_class
rescue TypeError
# you can't get the singleton class of every object
end
require 'json'
klass.ancestors.each do |ancestor|
ancestor.instance_methods(false).each do |method|
$SiB.record_result :inspect, #{line}, [ancestor.name, method], &:to_json
end
end
exit 0
)
RUBY
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment