spirit_hands 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +17 -0
- data/.hound.yml +20 -0
- data/.pryrc +2 -0
- data/.rubocop.yml +20 -0
- data/.ruby-gemset +1 -0
- data/CHANGELOG.md +147 -0
- data/CONTRIBUTING.md +18 -0
- data/CONTRIBUTORS.md +10 -0
- data/Gemfile +3 -0
- data/LICENSE.md +22 -0
- data/README.md +133 -0
- data/Rakefile +3 -0
- data/gem-public_cert.pem +32 -0
- data/lib/spirit_hands/hirb/fixes/enabled.rb +38 -0
- data/lib/spirit_hands/hirb/fixes/pager.rb +144 -0
- data/lib/spirit_hands/hirb/fixes/util.rb +23 -0
- data/lib/spirit_hands/hirb/fixes/view.rb +10 -0
- data/lib/spirit_hands/hirb/fixes.rb +5 -0
- data/lib/spirit_hands/hirb.rb +2 -0
- data/lib/spirit_hands/load_plugins.rb +10 -0
- data/lib/spirit_hands/mattr_accessor_with_default.rb +48 -0
- data/lib/spirit_hands/melody.rb +41 -0
- data/lib/spirit_hands/options/color.rb +12 -0
- data/lib/spirit_hands/options/hirb.rb +34 -0
- data/lib/spirit_hands/options/less/colorize.rb +42 -0
- data/lib/spirit_hands/options/less/show_raw_unicode.rb +38 -0
- data/lib/spirit_hands/options/less.rb +2 -0
- data/lib/spirit_hands/options.rb +57 -0
- data/lib/spirit_hands/plugin.rb +28 -0
- data/lib/spirit_hands/print.rb +72 -0
- data/lib/spirit_hands/prompt/base.rb +249 -0
- data/lib/spirit_hands/prompt/main.rb +18 -0
- data/lib/spirit_hands/prompt/multiline.rb +17 -0
- data/lib/spirit_hands/prompt.rb +13 -0
- data/lib/spirit_hands/railtie.rb +7 -0
- data/lib/spirit_hands/terminal.rb +14 -0
- data/lib/spirit_hands/version.rb +3 -0
- data/lib/spirit_hands.rb +13 -0
- data/spirit_hands.gemspec +37 -0
- data.tar.gz.sig +0 -0
- metadata +258 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spirit_hands/plugin'
|
2
|
+
|
3
|
+
# awesome_print is autoloaded by Hirb::View patch and/or SpiritHands::Print
|
4
|
+
# pry was loaded earlier
|
5
|
+
SpiritHands.plugin 'pry-coolline'
|
6
|
+
SpiritHands.plugin 'pry-doc'
|
7
|
+
SpiritHands.plugin 'pry-git'
|
8
|
+
# pry-rails was loaded earlier (if needed)
|
9
|
+
SpiritHands.plugin 'pry-remote'
|
10
|
+
# hirb is autoloaded by SpiritHands.hirb = true
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Module
|
2
|
+
def mattr_accessor_with_default(property, default = nil, &block)
|
3
|
+
if block_given?
|
4
|
+
if default
|
5
|
+
raise ArgumentError, 'Must specify only one of +default+ or &block'
|
6
|
+
end
|
7
|
+
default = block
|
8
|
+
end
|
9
|
+
|
10
|
+
getter = property.to_sym
|
11
|
+
setter = "#{property}=".to_sym
|
12
|
+
class_var = "@@#{property}".to_sym
|
13
|
+
|
14
|
+
# self.property=
|
15
|
+
define_singleton_method(setter) do |value|
|
16
|
+
if value.nil?
|
17
|
+
remove_class_variable(class_var)
|
18
|
+
else
|
19
|
+
class_variable_set(class_var, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# self.property
|
24
|
+
if default.respond_to?(:call) # default is callable
|
25
|
+
define_singleton_method(getter) do
|
26
|
+
if class_variable_defined?(class_var)
|
27
|
+
class_variable_get(class_var)
|
28
|
+
else
|
29
|
+
default.()
|
30
|
+
end
|
31
|
+
end
|
32
|
+
else # default is literal object
|
33
|
+
default_value_name = "DEFAULT_#{property}".upcase.to_sym
|
34
|
+
const_set(default_value_name, default)
|
35
|
+
define_singleton_method(getter) do
|
36
|
+
if class_variable_defined?(class_var)
|
37
|
+
class_variable_get(class_var)
|
38
|
+
else
|
39
|
+
const_get(default_value_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
NO_OP = -> { }.freeze
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
# We're managing the loading of plugins. So don't let pry autoload them.
|
4
|
+
::Pry.config.should_load_plugins = false
|
5
|
+
|
6
|
+
if defined? ::Rails
|
7
|
+
STDERR.puts 'JF pry-rails' if ENV['SPIRIT_FINGERS_PLUGIN_DEBUG']
|
8
|
+
require 'pry-rails'
|
9
|
+
end
|
10
|
+
|
11
|
+
module SpiritHands
|
12
|
+
autoload :Print, 'spirit_hands/print'
|
13
|
+
autoload :Prompt, 'spirit_hands/prompt'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
@installed = false
|
17
|
+
# This modifies pry to play our tune
|
18
|
+
def melody!(app = nil)
|
19
|
+
return false if @installed
|
20
|
+
|
21
|
+
# Require all of our pry plugins
|
22
|
+
require 'spirit_hands/load_plugins'
|
23
|
+
|
24
|
+
setup_less_colorize
|
25
|
+
setup_less_show_raw_unicode
|
26
|
+
setup_hirb
|
27
|
+
|
28
|
+
# Use awesome_print for output, but keep pry's pager. If Hirb is
|
29
|
+
# enabled, try printing with it first.
|
30
|
+
::SpiritHands::Print.install!
|
31
|
+
|
32
|
+
# Friendlier prompt - line number, app name, nesting levels look like
|
33
|
+
# directory paths.
|
34
|
+
#
|
35
|
+
# Configuration (like Pry.color) can be changed later or even during console usage.
|
36
|
+
::SpiritHands::Prompt.install!(app)
|
37
|
+
|
38
|
+
@installed = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
autoload :Hirb, 'spirit_hands/hirb'
|
2
|
+
|
3
|
+
module SpiritHands
|
4
|
+
class << self
|
5
|
+
# Is hirb enabled?
|
6
|
+
def hirb
|
7
|
+
::Hirb.enabled?
|
8
|
+
end
|
9
|
+
|
10
|
+
# Set whether hirb is enabled (default: true)
|
11
|
+
def hirb=(h)
|
12
|
+
h = DEFAULT_HIRB if h.nil?
|
13
|
+
if hirb != h
|
14
|
+
if h
|
15
|
+
::Hirb.enable
|
16
|
+
else
|
17
|
+
::Hirb.disable
|
18
|
+
end
|
19
|
+
end
|
20
|
+
@hirb = !!h
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def setup_hirb
|
26
|
+
self.hirb = nil unless @hirb
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
DEFAULT_HIRB = true
|
31
|
+
|
32
|
+
# Whether to use hirb/unicode when hirb is enabled (default: true)
|
33
|
+
mattr_accessor_with_default :hirb_unicode, true
|
34
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module SpiritHands
|
4
|
+
class << self
|
5
|
+
# Allow less to display colorized output (default: true)
|
6
|
+
# (If, set updates LESS env var)
|
7
|
+
def less_colorize
|
8
|
+
ENV['LESS'].to_s.shellsplit.any? { |arg| arg == LESS_R_LONG || arg =~ LESS_R }
|
9
|
+
end
|
10
|
+
|
11
|
+
# true: add -R to LESS env var (default)
|
12
|
+
# false: remove -R from LESS env var
|
13
|
+
# nil: set to default (true)
|
14
|
+
def less_colorize=(n)
|
15
|
+
n = DEFAULT_LESS_COLORIZE if n.nil?
|
16
|
+
|
17
|
+
args = ENV['LESS'].to_s.shellsplit.map do |arg|
|
18
|
+
next if arg == LESS_R_LONG
|
19
|
+
if arg =~ LESS_R
|
20
|
+
arg = $1 + $2
|
21
|
+
end
|
22
|
+
arg unless arg.empty?
|
23
|
+
end
|
24
|
+
args << '-R' if n
|
25
|
+
new_less = args.collect.to_a.shelljoin
|
26
|
+
ENV['LESS'] = new_less.empty? ? nil : new_less
|
27
|
+
@less_colorize = !!n
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def setup_less_colorize
|
33
|
+
self.less_colorize = nil unless @less_colorize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
DEFAULT_LESS_COLORIZE = true
|
40
|
+
LESS_R_LONG = '--RAW-CONTROL-CHARS'.freeze
|
41
|
+
LESS_R = /\A(.*-[^-R]*)R(.*)\z/.freeze
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module SpiritHands
|
4
|
+
class << self
|
5
|
+
# Allow less to display colorized output (default: true)
|
6
|
+
# (If, set updates LESS env var)
|
7
|
+
def less_show_raw_unicode
|
8
|
+
ENV['LESSUTFBINFMT'] == LESS_SHOW_RAW_BINFMT
|
9
|
+
end
|
10
|
+
|
11
|
+
# true: set LESSUTFBINFMT to %*c
|
12
|
+
# false: unset LESSUTFBINFMT
|
13
|
+
# String: set custom LESSUTFBINFMT
|
14
|
+
# nil: set default(true)
|
15
|
+
def less_show_raw_unicode=(n)
|
16
|
+
n = DEFAULT_LESS_SHOW_RAW_UNICODE if n.nil?
|
17
|
+
ENV['LESSUTFBINFMT'] = if n.is_a?(String)
|
18
|
+
n
|
19
|
+
elsif n
|
20
|
+
LESS_SHOW_RAW_BINFMT
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
@less_show_raw_unicode = !!n
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def setup_less_show_raw_unicode
|
30
|
+
self.less_show_raw_unicode = nil unless @less_show_raw_unicode
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
DEFAULT_LESS_SHOW_RAW_UNICODE = true
|
37
|
+
LESS_SHOW_RAW_BINFMT = '*n%c'.freeze
|
38
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'readline'
|
3
|
+
require 'spirit_hands/mattr_accessor_with_default'
|
4
|
+
require 'spirit_hands/options/color'
|
5
|
+
require 'spirit_hands/options/less'
|
6
|
+
require 'spirit_hands/options/hirb'
|
7
|
+
|
8
|
+
module SpiritHands
|
9
|
+
autoload :Terminal, 'spirit_hands/terminal'
|
10
|
+
|
11
|
+
### Options ###
|
12
|
+
|
13
|
+
# When printing values, start with this (default: '=> ')
|
14
|
+
mattr_accessor_with_default :value_prompt, '=> '
|
15
|
+
|
16
|
+
# Spaces to indent value (default: 2 spaces)
|
17
|
+
mattr_accessor_with_default :value_indent, 2
|
18
|
+
|
19
|
+
# Name of the app, which can be displayed to <app/> tag in prompt
|
20
|
+
mattr_accessor_with_default :app, -> {
|
21
|
+
# Trumpet emoji or pry
|
22
|
+
(Terminal.unicode?) ? "\u{1F3BA}" : 'pry'
|
23
|
+
}
|
24
|
+
|
25
|
+
# <color>...</color>
|
26
|
+
# <bold>...</color>
|
27
|
+
# <cmd/> command number
|
28
|
+
# <app/> SpiritHands.app, which can be String or a Rails Applicatino object
|
29
|
+
# <sep/> SpiritHands.prompt_separator
|
30
|
+
#
|
31
|
+
# Use \ to escape literal <, so in a Ruby string constant, "\\<"
|
32
|
+
#
|
33
|
+
mattr_accessor_with_default :prompt,
|
34
|
+
'<b>[<cmd/>]</b> <blue><app/></blue><tgt/> <red><sep/></red> '
|
35
|
+
|
36
|
+
# Color the prompt?
|
37
|
+
#
|
38
|
+
# A different setting than Pry.color since some may like colored output, but a
|
39
|
+
# plain prompt.
|
40
|
+
#
|
41
|
+
# Default: 'true' for GNU readline or rb-readline which correctly count line
|
42
|
+
# widths with color codes when using \001 and \002 hints. 'false' for
|
43
|
+
# libedit-based wrapper (standard on OS X unless ruby is explicitly compiled
|
44
|
+
# otherwise).
|
45
|
+
mattr_accessor_with_default :colored_prompt, -> { ::Readline::VERSION !~ /EditLine/ }
|
46
|
+
|
47
|
+
# Separator between application name and input in the prompt.
|
48
|
+
#
|
49
|
+
# Default: right angle quote (chevron) or >
|
50
|
+
#
|
51
|
+
mattr_accessor_with_default :prompt_separator, -> {
|
52
|
+
(Terminal.unicode?) ? "\u{BB}" : '>'
|
53
|
+
}
|
54
|
+
|
55
|
+
# Enable or disable AwesomePrint (default: true)
|
56
|
+
mattr_accessor_with_default :awesome_print, true
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SpiritHands
|
2
|
+
class << self
|
3
|
+
# A thin wrapper around require for troubleshooting
|
4
|
+
def plugin(*requires)
|
5
|
+
cond = requires.pop if requires.last.respond_to? :call
|
6
|
+
requires.each do |r|
|
7
|
+
begin
|
8
|
+
if cond && !cond.()
|
9
|
+
plugin_debug "JF require #{r} (skipped)"
|
10
|
+
next
|
11
|
+
end
|
12
|
+
res = require r
|
13
|
+
rescue LoadError
|
14
|
+
plugin_debug "JF require #{r} FAILED"
|
15
|
+
else
|
16
|
+
plugin_debug "JF require #{r} -> #{res}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def plugin_debug(*args)
|
24
|
+
return if !ENV['SPIRIT_FINGERS_PLUGIN_DEBUG']
|
25
|
+
STDERR.puts(*args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module SpiritHands
|
2
|
+
module Print
|
3
|
+
class << self
|
4
|
+
def install!
|
5
|
+
::Pry.config.print = PRINT_FUNCTION
|
6
|
+
end
|
7
|
+
|
8
|
+
def pretty(value)
|
9
|
+
if ::SpiritHands.awesome_print
|
10
|
+
require 'awesome_print' unless defined?(AwesomePrint)
|
11
|
+
opts = { :indent => ::SpiritHands.value_indent }
|
12
|
+
opts[:plain] = true if !SpiritHands.color
|
13
|
+
value.ai(opts)
|
14
|
+
else
|
15
|
+
value.inspect
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def hirb_unicode_enabled?
|
20
|
+
::Hirb::Formatter.dynamic_config.keys.any? do |key|
|
21
|
+
if opts = ::Hirb::Formatter.dynamic_config[key][:options]
|
22
|
+
opts && opts[:unicode]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def print(_output, value, _pry_)
|
28
|
+
if ::Hirb.enabled?
|
29
|
+
setup_hirb_unicode
|
30
|
+
return if ::Hirb::View.view_or_page_output(value)
|
31
|
+
end
|
32
|
+
_pry_.pager.page("#{::SpiritHands.value_prompt}#{pretty(value)}")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
PRINT_FUNCTION = ->(_output, value, _pry_) do
|
38
|
+
::SpiritHands::Print.print(_output, value, _pry_)
|
39
|
+
end
|
40
|
+
|
41
|
+
def hirb_unicode_enable
|
42
|
+
return false unless ::SpiritHands::Terminal.unicode?
|
43
|
+
require 'hirb/unicode'
|
44
|
+
|
45
|
+
::Hirb::Formatter.dynamic_config.keys.each do |key|
|
46
|
+
::Hirb::Formatter.dynamic_config[key][:options] ||= {}
|
47
|
+
::Hirb::Formatter.dynamic_config[key][:options][:unicode] = true
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def hirb_unicode_disable
|
53
|
+
::Hirb::Formatter.dynamic_config.keys.each do |key|
|
54
|
+
::Hirb::Formatter.dynamic_config[key][:options] ||= {}
|
55
|
+
::Hirb::Formatter.dynamic_config[key][:options][:unicode] = false
|
56
|
+
end
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup_hirb_unicode
|
61
|
+
if hirb_unicode_enabled? != SpiritHands.hirb_unicode
|
62
|
+
if SpiritHands.hirb_unicode
|
63
|
+
hirb_unicode_enable
|
64
|
+
else
|
65
|
+
hirb_unicode_disable
|
66
|
+
end
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
module SpiritHands
|
2
|
+
module Prompt
|
3
|
+
class << self
|
4
|
+
private
|
5
|
+
|
6
|
+
def render(state, prompt, color = true)
|
7
|
+
r = Render.new(state, prompt, color)
|
8
|
+
res = r.to_s
|
9
|
+
STDERR.puts "\n" + (r.errors * "\n") + "\n" if r.errors?
|
10
|
+
res
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# :object Object
|
15
|
+
# :level Fixnum
|
16
|
+
# :pry Pry
|
17
|
+
# :app String or Rails::Application
|
18
|
+
# :multiline false: normal prompt, true: multiline prompt
|
19
|
+
State = Struct.new(:object, :level, :pry, :app, :multiline)
|
20
|
+
|
21
|
+
# <....>
|
22
|
+
# <..../>
|
23
|
+
# </....>
|
24
|
+
#
|
25
|
+
class Render
|
26
|
+
# <tag> ... </tag>, tag -> inner part of escape codes
|
27
|
+
MATCHED_TAG_CODES = {
|
28
|
+
'b' => 1,
|
29
|
+
'bold' => 1,
|
30
|
+
'bright' => 1,
|
31
|
+
'strong' => 1,
|
32
|
+
|
33
|
+
'dark' => 2,
|
34
|
+
'faint' => 2,
|
35
|
+
|
36
|
+
'i' => 3,
|
37
|
+
'italic' => 3,
|
38
|
+
'em' => 3,
|
39
|
+
|
40
|
+
'u' => 4,
|
41
|
+
'underline' => 4,
|
42
|
+
|
43
|
+
'blink' => 5, # evil
|
44
|
+
'flash' => 5,
|
45
|
+
|
46
|
+
'rapid-blink' => 6, # sinister
|
47
|
+
'rapid-flash' => 6,
|
48
|
+
|
49
|
+
'reverse' => 7,
|
50
|
+
'negative' => 7,
|
51
|
+
'inverse' => 7,
|
52
|
+
|
53
|
+
'concealed' => 8,
|
54
|
+
|
55
|
+
'strike' => 9,
|
56
|
+
'strikethrough' => 9,
|
57
|
+
|
58
|
+
'black' => 30,
|
59
|
+
'red' => 31,
|
60
|
+
'green' => 32,
|
61
|
+
'yellow' => 33,
|
62
|
+
'blue' => 34,
|
63
|
+
'magenta' => 35,
|
64
|
+
'cyan' => 36,
|
65
|
+
'white' => 37,
|
66
|
+
|
67
|
+
'bgblack' => 40,
|
68
|
+
'bgred' => 41,
|
69
|
+
'bggreen' => 42,
|
70
|
+
'bgyellow' => 43,
|
71
|
+
'bgblue' => 44,
|
72
|
+
'bgmagenta' => 45,
|
73
|
+
'bgcyan' => 46,
|
74
|
+
'bgwhite' => 47,
|
75
|
+
}
|
76
|
+
|
77
|
+
# <.../>
|
78
|
+
SINGLE_TAGS = {
|
79
|
+
# <cmd/>: command number
|
80
|
+
'cmd' => ->(state) { state.pry.input_array.size },
|
81
|
+
|
82
|
+
# <tgt/>: target string
|
83
|
+
'tgt' => ->(state) {
|
84
|
+
unless (str = Pry.view_clip(state.object)) == 'main'
|
85
|
+
state.level = 0 if state.level < 0
|
86
|
+
"(#{'../' * state.level}#{str})"
|
87
|
+
else
|
88
|
+
''
|
89
|
+
end
|
90
|
+
},
|
91
|
+
|
92
|
+
# <app/>: state.app (Object) converted to String
|
93
|
+
'app' => ->(state) {
|
94
|
+
app = state.app
|
95
|
+
if app.class.respond_to?(:parent_name) && \
|
96
|
+
app.class.parent_name.respond_to?(:underscore)
|
97
|
+
app.class.parent_name.underscore
|
98
|
+
elsif app
|
99
|
+
app.to_s
|
100
|
+
else
|
101
|
+
::SpiritHands.app
|
102
|
+
end
|
103
|
+
},
|
104
|
+
|
105
|
+
# <sep/>: SpiritHands.prompt_separator
|
106
|
+
'sep' => ->(_state) {
|
107
|
+
::SpiritHands.prompt_separator
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
# Array<String>
|
112
|
+
attr_reader :errors
|
113
|
+
|
114
|
+
def errors?
|
115
|
+
errors.any?
|
116
|
+
end
|
117
|
+
|
118
|
+
# :state SpiritHands::Prompt::State
|
119
|
+
# :prompt String
|
120
|
+
# :color true or false/nil
|
121
|
+
def initialize(state, prompt, color)
|
122
|
+
@state = state
|
123
|
+
@prompt = prompt
|
124
|
+
@color = color
|
125
|
+
end
|
126
|
+
|
127
|
+
def to_s
|
128
|
+
@errors = []
|
129
|
+
@tag_stack = []
|
130
|
+
@result = ''
|
131
|
+
@color_applied = false
|
132
|
+
@in_tag = false
|
133
|
+
|
134
|
+
@prompt.each_char do |c|
|
135
|
+
if @in_tag
|
136
|
+
tag_char(c)
|
137
|
+
else
|
138
|
+
nontag_char(c)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @tag_stack.any? --> error/s
|
143
|
+
@tag_stack.each { |t| errors << "<#{t}>: Missing </#{t}>" }
|
144
|
+
|
145
|
+
(errors?) ? '' : @result
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def tag_char(c)
|
151
|
+
case c
|
152
|
+
when '/'
|
153
|
+
# close: </
|
154
|
+
# single <.+/
|
155
|
+
@tag_type = (@tag.blank?) ? :close : :single
|
156
|
+
when '>' # close tag
|
157
|
+
@tag.downcase!
|
158
|
+
send @tag_type # :start, :close or :single
|
159
|
+
@in_tag = false
|
160
|
+
else # append to existing tag
|
161
|
+
@tag += c
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def nontag_char(c)
|
166
|
+
if @escape
|
167
|
+
nontag_escaped_char(c)
|
168
|
+
else
|
169
|
+
nontag_unescaped_char(c)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def nontag_escaped_char(c)
|
174
|
+
@escape = false
|
175
|
+
@result += (@state.multiline) ? ' ' : c
|
176
|
+
end
|
177
|
+
|
178
|
+
def nontag_unescaped_char(c)
|
179
|
+
case c
|
180
|
+
when '\\' # escape next char
|
181
|
+
@escape = true
|
182
|
+
when '<' # start tag
|
183
|
+
@in_tag = true
|
184
|
+
@tag_type = :start
|
185
|
+
@tag = ''
|
186
|
+
else # normal char
|
187
|
+
@result += (@state.multiline) ? ' ' : c
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# <...>
|
192
|
+
def start
|
193
|
+
code = MATCHED_TAG_CODES[@tag]
|
194
|
+
if !code
|
195
|
+
errors << "Unknown <#{@tag}>"
|
196
|
+
return
|
197
|
+
end
|
198
|
+
@result += esc(code)
|
199
|
+
@tag_stack << @tag
|
200
|
+
end
|
201
|
+
|
202
|
+
# </...>
|
203
|
+
def close
|
204
|
+
code = MATCHED_TAG_CODES[@tag]
|
205
|
+
if !code
|
206
|
+
errors << "Unknown </#{@tag}>"
|
207
|
+
return
|
208
|
+
end
|
209
|
+
idx = @tag_stack.rindex @tag
|
210
|
+
if idx.nil?
|
211
|
+
errors << "</#{@tag}>: missing start <#{@tag}>"
|
212
|
+
return
|
213
|
+
end
|
214
|
+
# remove the now closed tag from the stack
|
215
|
+
@tag_stack.delete_at idx
|
216
|
+
# reset and reapply all codes on the @tag_stack
|
217
|
+
@result += reset
|
218
|
+
@tag_stack.each { |tag| @result += esc(MATCHED_TAG_CODES[tag]) }
|
219
|
+
end
|
220
|
+
|
221
|
+
# <.../>
|
222
|
+
def single
|
223
|
+
f = SINGLE_TAGS[@tag]
|
224
|
+
if !f
|
225
|
+
errors << "Unknown </#{@tag}>"
|
226
|
+
return
|
227
|
+
end
|
228
|
+
result = f.(@state).to_s
|
229
|
+
|
230
|
+
# blank out all but sep for multiline prompt, vs. main (normal)
|
231
|
+
if @state.multiline && @tag != 'sep'
|
232
|
+
result = ' ' * result.length
|
233
|
+
end
|
234
|
+
@result += result
|
235
|
+
end
|
236
|
+
|
237
|
+
def reset
|
238
|
+
esc(0)
|
239
|
+
end
|
240
|
+
|
241
|
+
# convert a code to an actual character
|
242
|
+
def esc(code)
|
243
|
+
return '' if !@color
|
244
|
+
@color_applied = true
|
245
|
+
"\001\e[#{code}m\002".freeze
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spirit_hands/prompt/base'
|
2
|
+
|
3
|
+
module SpiritHands
|
4
|
+
module Prompt
|
5
|
+
class << self
|
6
|
+
private
|
7
|
+
|
8
|
+
# Normal, main pry prompt
|
9
|
+
def main
|
10
|
+
->(object, level, pry) do
|
11
|
+
s = State.new(object, level, pry, ::SpiritHands.app, false)
|
12
|
+
color = ::SpiritHands.color && ::SpiritHands.colored_prompt
|
13
|
+
render(s, ::SpiritHands.prompt, color)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spirit_hands/prompt/base'
|
2
|
+
|
3
|
+
module SpiritHands
|
4
|
+
module Prompt
|
5
|
+
class << self
|
6
|
+
private
|
7
|
+
|
8
|
+
# Wait pry prompt in multiline input
|
9
|
+
def multiline
|
10
|
+
->(object, level, pry) {
|
11
|
+
s = State.new(object, level, pry, ::SpiritHands.app, true)
|
12
|
+
render(s, ::SpiritHands.prompt, ::SpiritHands.color && ::SpiritHands.colored_prompt)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spirit_hands/prompt/main'
|
2
|
+
require 'spirit_hands/prompt/multiline'
|
3
|
+
|
4
|
+
module SpiritHands
|
5
|
+
module Prompt
|
6
|
+
class << self
|
7
|
+
def install!(app = nil)
|
8
|
+
::SpiritHands.app ||= app
|
9
|
+
::Pry.config.prompt = [ main, multiline ].freeze
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|