Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 216 lines (181 sloc) 4.32 KB
#!/usr/bin/env fancy
# -*- set ft=fancy -*-
try {
require("readline")
} catch LoadError {
require("rb-readline/readline")
}
hightlight_code? = false
try {
require("coderay")
require(File absolute_path: $ __DIR__ + "/../ruby_lib/interactive/hilight")
hightlight_code? = true
} catch LoadError {
hightlight_code? = false
}
["Welcome to the (still very simple) Fancy REPL",
"Fancy #{Fancy VERSION}"] println
HISTORY_FILE = File absolute_path: "~/.fancy_history"
HISTORY = []
PROMPT = "ifancy[%d]> "
class Prompt {
def initialize: @str {
@line = 0
}
def inc_line {
@line = @line + 1
}
def aug_line: num {
@line = @line + num
}
def to_s {
sprintf(@str, @line)
}
}
class Feature {
@@hooks = <[]>
read_slots: ('name, 'desc)
def initialize: @name will: @desc by: @block {
@@hooks[@name]: self
}
def run: string {
@block call: string
}
def about: name_width (@name size) {
sprintf("%-#{name_width}s : %s", @name, @desc)
}
def Feature match: name str: string {
if: (@@hooks[name]) then: |feature| {
feature run: string
return true
}
return false
}
def Feature find: name do: block else: else_block {
@@hooks with_value_for_key: name do: block else: else_block
}
def Feature each: block {
@@hooks values sort_by: 'name . each: block
}
metaclass provides_interface: 'each:
extend: Fancy Enumerable
}
ARGV rest each: |file| {
"LOADING: #{file}" println
require: file
}
Console newline;
def double_or_empty?: line {
(line =~ /^\s*$/) or: (HISTORY [-2] == line)
}
def load_history {
if: (File exists?: HISTORY_FILE) then: {
File read: HISTORY_FILE with: |f| {
f readlines each: |l| {
l = l strip()
Readline HISTORY <<(l)
HISTORY << l
}
}
} else: {
File touch: HISTORY_FILE
}
}
def save_history {
puts("saving history")
unless: @history_saved do: {
File write: HISTORY_FILE with: |f| {
HISTORY last: 100 . each: |l| {
f println: l
}
}
@history_saved = true
}
}
def Readline completion: block {
Readline completion_proc=(block)
}
Readline completion_append_character=(" ")
Readline completion: |str| {
receiver = nil
end_idx = -2
methods = []
3 times: {
try {
receiver = Readline line_buffer() split: " " . [[0,end_idx]] . join: " " . eval
methods = receiver methods
} catch Fancy Parser ParseError => e {
end_idx = end_idx - 1
} catch Exception => e {
methods = Object instance_methods
}
}
completions = []
try {
regexp = Regexp new(str)
completions = methods map: @{ to_s } . select: @{ =~ regexp } . map: @{ gsub(/^:/, "") }
} catch RegexpError {
} finally {
completions
}
}
def read_line: prompt {
try {
return Readline readline(prompt to_s, true)
} catch ArgumentError {
return ""
}
}
load_history
at_exit() { save_history }
bnd = binding()
prompt = Prompt new: PROMPT
Feature new: "exit" will: "Exit the shell" by: { System exit }
Feature new: "quit" will: "Exit the shell" by: { System exit }
Feature new: "?" will: "Give information on a command" by: |line| {
feature_name = line words[1]
if: feature_name then: {
Feature find: feature_name do: @{
about println
} else: {
"Sorry, #{feature_name} is not a feature that is loaded" println
}
} else: {
max_width = Feature map: @{ name size } . max
Feature each: @{ about: max_width . println }
}
}
Feature new: "#{" will: "Create multiline capabilities" by: {
line = read_line: "-> "
line_s = ""
until: { line =~ /^\#}$/ == 0} do: {
line_s = line_s ++ line ++ "\n"
line = read_line: "-> "
}
try {
Fancy eval: line_s binding: bnd . inspect println
prompt aug_line: (line_s split: "\n" . size)
} catch Exception => e {
e message println
}
}
loop: {
line = read_line: prompt
{ System exit } unless: line
{ next } if: $ Feature match: (line words[0]) str: line
HISTORY << line
if: (double_or_empty?: line) then: {
Readline::HISTORY pop()
HISTORY pop()
}
try {
if: hightlight_code? then: {
"=> #{CodeRay.scan((Fancy eval: line binding: bnd . inspect), 'fancy).term()}" println
} else: {
"=> #{Fancy eval: line binding: bnd . inspect}" println
}
prompt inc_line
} catch Exception => e {
e message println
}
}