forked from arlimus/inquirer.rb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
595 additions
and
569 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,18 @@ | ||
require 'inquirer/version' | ||
require 'inquirer/utils/iohelper' | ||
require 'inquirer/prompts/list' | ||
require 'inquirer/prompts/checkbox' | ||
require 'inquirer/prompts/input' | ||
require 'inquirer/prompts/confirm' | ||
|
||
module Ask | ||
extend self | ||
# implement prompts | ||
def list *args | ||
List.ask *args | ||
end | ||
def checkbox *args | ||
Checkbox.ask *args | ||
module Prompts | ||
PROMPTS = [] | ||
end | ||
def input *args | ||
Input.ask *args | ||
end | ||
def confirm *args | ||
Confirm.ask *args | ||
# require prompts after defining Prompts module, | ||
# so prompts can append their names to Prompts::PROMPTS | ||
Dir["#{File.dirname(__FILE__)}/inquirer/prompts/*.rb"].each{|f| require f} | ||
# implement prompts | ||
Prompts::PROMPTS.each do |prompt| | ||
define_method(prompt) do |*args| | ||
Prompts.const_get(prompt.capitalize).ask(*args) | ||
end | ||
end | ||
end |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,135 +1,142 @@ | ||
require 'term/ansicolor' | ||
require 'inquirer/style' | ||
|
||
# Base rendering for simple lists | ||
module CheckboxRenderer | ||
def render heading = nil, list = [], footer = nil | ||
# render the heading | ||
( heading.nil? ? "" : @heading % heading ) + | ||
# render the list | ||
list.map do |li| | ||
render_item li | ||
end.join("") + | ||
# render the footer | ||
( footer.nil? ? "" : @footer % footer ) | ||
end | ||
|
||
def renderResponse heading = nil, response = nil | ||
# render the heading | ||
( heading.nil? ? "" : @heading % heading ) + | ||
# render the footer | ||
( response.nil? ? "" : @response % response ) | ||
end | ||
module Ask | ||
module Prompts | ||
PROMPTS << :checkbox | ||
|
||
# Base rendering for simple lists | ||
module CheckboxRenderer | ||
def render heading = nil, list = [], footer = nil | ||
# render the heading | ||
( heading.nil? ? "" : @heading % heading ) + | ||
# render the list | ||
list.map do |li| | ||
render_item li | ||
end.join("") + | ||
# render the footer | ||
( footer.nil? ? "" : @footer % footer ) | ||
end | ||
|
||
private | ||
def renderResponse heading = nil, response = nil | ||
# render the heading | ||
( heading.nil? ? "" : @heading % heading ) + | ||
# render the footer | ||
( response.nil? ? "" : @response % response ) | ||
end | ||
|
||
def render_item x | ||
( x["selected"] ? @selector : " " ) + | ||
( x["active"] ? @checkbox_on : @checkbox_off ) + | ||
" " + | ||
( x["active"] ? @active_item : @item ) % x["value"] | ||
end | ||
private | ||
|
||
end | ||
def render_item x | ||
( x["selected"] ? @selector : " " ) + | ||
( x["active"] ? @checkbox_on : @checkbox_off ) + | ||
" " + | ||
( x["active"] ? @active_item : @item ) % x["value"] | ||
end | ||
|
||
# Formatting for rendering | ||
class CheckboxDefault | ||
include CheckboxRenderer | ||
C = Term::ANSIColor | ||
def initialize( style ) | ||
@heading = "%s:\n" | ||
@footer = "%s\n" | ||
@item = "%s\n" | ||
@active_item = "%s" + "\n" | ||
@selector = C.cyan style.selector | ||
@checkbox_on = C.cyan style.checkbox_on | ||
@checkbox_off = style.checkbox_off | ||
end | ||
end | ||
end | ||
|
||
# Default formatting for response | ||
class CheckboxResponseDefault | ||
include CheckboxRenderer | ||
C = Term::ANSIColor | ||
def initialize( style = nil ) | ||
@heading = "%s: " | ||
@response = C.cyan("%s") + "\n" | ||
end | ||
end | ||
# Formatting for rendering | ||
class CheckboxDefault | ||
include CheckboxRenderer | ||
C = Term::ANSIColor | ||
def initialize( style ) | ||
@heading = "%s:\n" | ||
@footer = "%s\n" | ||
@item = "%s\n" | ||
@active_item = "%s" + "\n" | ||
@selector = C.cyan style.selector | ||
@checkbox_on = C.cyan style.checkbox_on | ||
@checkbox_off = style.checkbox_off | ||
end | ||
end | ||
|
||
class Checkbox | ||
def initialize question = nil, elements = [], default = nil, renderer = nil, responseRenderer = nil | ||
@elements = elements | ||
@question = question | ||
@pos = 0 | ||
@active = default || elements.map{|i| false} | ||
@prompt = "" | ||
@renderer = renderer || CheckboxDefault.new( Inquirer::Style::Default ) | ||
@responseRenderer = responseRenderer = CheckboxResponseDefault.new() | ||
end | ||
# Default formatting for response | ||
class CheckboxResponseDefault | ||
include CheckboxRenderer | ||
C = Term::ANSIColor | ||
def initialize( style = nil ) | ||
@heading = "%s: " | ||
@response = C.cyan("%s") + "\n" | ||
end | ||
end | ||
|
||
def update_prompt | ||
# transform the list into | ||
# {"value"=>..., "selected"=> true|false, "active"=> true|false } | ||
e = @elements. | ||
# attach the array position | ||
map.with_index(0). | ||
map do |c,pos| | ||
{ "value"=>c, "selected" => pos == @pos, "active" => @active[pos] } | ||
class Checkbox | ||
def initialize question = nil, elements = [], default = nil, renderer = nil, responseRenderer = nil | ||
@elements = elements | ||
@question = question | ||
@pos = 0 | ||
@active = default || elements.map{|i| false} | ||
@prompt = "" | ||
@renderer = renderer || CheckboxDefault.new( Inquirer::Style::Default ) | ||
@responseRenderer = responseRenderer = CheckboxResponseDefault.new() | ||
end | ||
# call the renderer | ||
@prompt = @renderer.render(@question, e) | ||
end | ||
|
||
def update_response | ||
e = @elements | ||
.map.with_index(0) | ||
.select {|f, pos| @active[pos] } | ||
.map {|f, pos| f } | ||
@prompt = @responseRenderer.renderResponse(@question, e.join(", ")) | ||
end | ||
def update_prompt | ||
# transform the list into | ||
# {"value"=>..., "selected"=> true|false, "active"=> true|false } | ||
e = @elements. | ||
# attach the array position | ||
map.with_index(0). | ||
map do |c,pos| | ||
{ "value"=>c, "selected" => pos == @pos, "active" => @active[pos] } | ||
end | ||
# call the renderer | ||
@prompt = @renderer.render(@question, e) | ||
end | ||
|
||
# Run the list selection, wait for the user to select an item and return | ||
# the selected index | ||
# Params: | ||
# +clear+:: +Bool+ whether to clear the selection prompt once this is done | ||
# defaults to true; set it to false if you want the prompt to remain after | ||
# the user is done with selecting | ||
# +response+:: +Bool+ whether show the rendered response when this is done | ||
# defaults to true; set it to false if you want the prompt to remain after | ||
# the user is done with selecting | ||
def run clear, response | ||
# finish if there's nothing to do | ||
return @active if Array(@elements).empty? | ||
|
||
# hides the cursor while prompting | ||
IOHelper.without_cursor do | ||
# render the | ||
IOHelper.render( update_prompt ) | ||
# loop through user input | ||
IOHelper.read_key_while do |key| | ||
@pos = (@pos - 1) % @elements.length if key == "up" | ||
@pos = (@pos + 1) % @elements.length if key == "down" | ||
@active[@pos] = !@active[@pos] if key == "space" | ||
IOHelper.rerender( update_prompt ) | ||
# we are done if the user hits return | ||
key != "return" | ||
def update_response | ||
e = @elements | ||
.map.with_index(0) | ||
.select {|f, pos| @active[pos] } | ||
.map {|f, pos| f } | ||
@prompt = @responseRenderer.renderResponse(@question, e.join(", ")) | ||
end | ||
end | ||
|
||
# clear the final prompt and the line | ||
IOHelper.clear if clear | ||
# Run the list selection, wait for the user to select an item and return | ||
# the selected index | ||
# Params: | ||
# +clear+:: +Bool+ whether to clear the selection prompt once this is done | ||
# defaults to true; set it to false if you want the prompt to remain after | ||
# the user is done with selecting | ||
# +response+:: +Bool+ whether show the rendered response when this is done | ||
# defaults to true; set it to false if you want the prompt to remain after | ||
# the user is done with selecting | ||
def run clear, response | ||
# finish if there's nothing to do | ||
return @active if Array(@elements).empty? | ||
|
||
# hides the cursor while prompting | ||
IOHelper.without_cursor do | ||
# render the | ||
IOHelper.render( update_prompt ) | ||
# loop through user input | ||
IOHelper.read_key_while do |key| | ||
@pos = (@pos - 1) % @elements.length if key == "up" | ||
@pos = (@pos + 1) % @elements.length if key == "down" | ||
@active[@pos] = !@active[@pos] if key == "space" | ||
IOHelper.rerender( update_prompt ) | ||
# we are done if the user hits return | ||
key != "return" | ||
end | ||
end | ||
|
||
# clear the final prompt and the line | ||
IOHelper.clear if clear | ||
|
||
# show the answer | ||
IOHelper.render( update_response ) if response | ||
|
||
# return the index of the selected item | ||
@active | ||
end | ||
|
||
# show the answer | ||
IOHelper.render( update_response ) if response | ||
def self.ask question = nil, elements = [], opts = {} | ||
l = Checkbox.new question, elements, opts[:default], opts[:renderer], opts[:rendererResponse] | ||
l.run opts.fetch(:clear, true), opts.fetch(:response, true) | ||
end | ||
|
||
# return the index of the selected item | ||
@active | ||
end | ||
end | ||
|
||
def self.ask question = nil, elements = [], opts = {} | ||
l = Checkbox.new question, elements, opts[:default], opts[:renderer], opts[:rendererResponse] | ||
l.run opts.fetch(:clear, true), opts.fetch(:response, true) | ||
end | ||
|
||
end |
Oops, something went wrong.