green_shoes 0.227.0 → 0.233.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.
- data/README.md +1 -0
- data/VERSION +1 -1
- data/lib/ext/highlighter.rb +2 -0
- data/lib/ext/highlighter/common.rb +197 -0
- data/lib/ext/highlighter/lang/ruby.rb +316 -0
- data/lib/ext/highlighter/markup.rb +222 -0
- data/lib/green_shoes.rb +1 -0
- data/lib/shoes/basic.rb +2 -0
- data/lib/shoes/help.rb +7 -2
- data/lib/shoes/helper_methods.rb +2 -1
- data/lib/shoes/main.rb +7 -2
- data/lib/shoes/ruby.rb +4 -0
- data/lib/shoes/slot.rb +7 -3
- data/samples/sample52.rb +32 -0
- data/samples/sample53.rb +10 -0
- data/samples/treeview.rb +60 -0
- data/snapshots/sample52.png +0 -0
- data/snapshots/sample53.png +0 -0
- data/static/manual-en.txt +31 -0
- metadata +12 -3
data/README.md
CHANGED
@@ -68,6 +68,7 @@ Except:
|
|
68
68
|
- hh/static/(all).png (c) 2008 why the lucky stiff
|
69
69
|
- lib/ext/hpricot/(all) (c) 2008 why the lucky stiff
|
70
70
|
- lib/ext/projector/(all).rb (c) 2010 MIZUTANI Tociyuki
|
71
|
+
- lib/ext/highlighter/(all) (c) 2008 why the lucky stiff and 2011 Steve Klabnik
|
71
72
|
- samples/akatsukiface.png (c) 2010 MIZUTANI Tociyuki
|
72
73
|
- samples/class-book.yaml (c) 2008 why the lucky stiff
|
73
74
|
- samples/splash-hand.png (c) 2008 why the lucky stiff
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.233.0
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module HH::Syntax
|
4
|
+
|
5
|
+
# A single token extracted by a tokenizer. It is simply the lexeme
|
6
|
+
# itself, decorated with a 'group' attribute to identify the type of the
|
7
|
+
# lexeme.
|
8
|
+
class Token < String
|
9
|
+
|
10
|
+
# the type of the lexeme that was extracted.
|
11
|
+
attr_reader :group
|
12
|
+
|
13
|
+
# the instruction associated with this token (:none, :region_open, or
|
14
|
+
# :region_close)
|
15
|
+
attr_reader :instruction
|
16
|
+
|
17
|
+
# Create a new Token representing the given text, and belonging to the
|
18
|
+
# given group.
|
19
|
+
def initialize( text, group, instruction = :none )
|
20
|
+
super text
|
21
|
+
@group = group
|
22
|
+
@instruction = instruction
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
# The base class of all tokenizers. It sets up the scanner and manages the
|
28
|
+
# looping until all tokens have been extracted. It also provides convenience
|
29
|
+
# methods to make sure adjacent tokens of identical groups are returned as
|
30
|
+
# a single token.
|
31
|
+
class Tokenizer
|
32
|
+
|
33
|
+
# The current group being processed by the tokenizer
|
34
|
+
attr_reader :group
|
35
|
+
|
36
|
+
# The current chunk of text being accumulated
|
37
|
+
attr_reader :chunk
|
38
|
+
|
39
|
+
# Start tokenizing. This sets up the state in preparation for tokenization,
|
40
|
+
# such as creating a new scanner for the text and saving the callback block.
|
41
|
+
# The block will be invoked for each token extracted.
|
42
|
+
def start( text, &block )
|
43
|
+
@chunk = ""
|
44
|
+
@group = :normal
|
45
|
+
@callback = block
|
46
|
+
@text = StringScanner.new( text )
|
47
|
+
setup
|
48
|
+
end
|
49
|
+
|
50
|
+
# Subclasses may override this method to provide implementation-specific
|
51
|
+
# setup logic.
|
52
|
+
def setup
|
53
|
+
end
|
54
|
+
|
55
|
+
# Finish tokenizing. This flushes the buffer, yielding any remaining text
|
56
|
+
# to the client.
|
57
|
+
def finish
|
58
|
+
start_group nil
|
59
|
+
teardown
|
60
|
+
end
|
61
|
+
|
62
|
+
# Subclasses may override this method to provide implementation-specific
|
63
|
+
# teardown logic.
|
64
|
+
def teardown
|
65
|
+
end
|
66
|
+
|
67
|
+
# Subclasses must implement this method, which is called for each iteration
|
68
|
+
# of the tokenization process. This method may extract multiple tokens.
|
69
|
+
def step
|
70
|
+
raise NotImplementedError, "subclasses must implement #step"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Begins tokenizing the given text, calling #step until the text has been
|
74
|
+
# exhausted.
|
75
|
+
def tokenize( text, &block )
|
76
|
+
start text, &block
|
77
|
+
step until @text.eos?
|
78
|
+
finish
|
79
|
+
end
|
80
|
+
|
81
|
+
# Specify a set of tokenizer-specific options. Each tokenizer may (or may
|
82
|
+
# not) publish any options, but if a tokenizer does those options may be
|
83
|
+
# used to specify optional behavior.
|
84
|
+
def set( opts={} )
|
85
|
+
( @options ||= Hash.new ).update opts
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the value of the specified option.
|
89
|
+
def option(opt)
|
90
|
+
@options ? @options[opt] : nil
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
EOL = /(?=\r\n?|\n|$)/
|
96
|
+
|
97
|
+
# A convenience for delegating method calls to the scanner.
|
98
|
+
def self.delegate( sym )
|
99
|
+
define_method( sym ) { |*a| @text.__send__( sym, *a ) }
|
100
|
+
end
|
101
|
+
|
102
|
+
delegate :bol?
|
103
|
+
delegate :eos?
|
104
|
+
delegate :scan
|
105
|
+
delegate :scan_until
|
106
|
+
delegate :check
|
107
|
+
delegate :check_until
|
108
|
+
delegate :getch
|
109
|
+
delegate :matched
|
110
|
+
delegate :pre_match
|
111
|
+
delegate :peek
|
112
|
+
delegate :pos
|
113
|
+
|
114
|
+
# Access the n-th subgroup from the most recent match.
|
115
|
+
def subgroup(n)
|
116
|
+
@text[n]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Append the given data to the currently active chunk.
|
120
|
+
def append( data )
|
121
|
+
@chunk << data
|
122
|
+
end
|
123
|
+
|
124
|
+
# Request that a new group be started. If the current group is the same
|
125
|
+
# as the group being requested, a new group will not be created. If a new
|
126
|
+
# group is created and the current chunk is not empty, the chunk's
|
127
|
+
# contents will be yielded to the client as a token, and then cleared.
|
128
|
+
#
|
129
|
+
# After the new group is started, if +data+ is non-nil it will be appended
|
130
|
+
# to the chunk.
|
131
|
+
def start_group( gr, data=nil )
|
132
|
+
flush_chunk if gr != @group
|
133
|
+
@group = gr
|
134
|
+
@chunk << data if data
|
135
|
+
end
|
136
|
+
|
137
|
+
def start_region( gr, data=nil )
|
138
|
+
flush_chunk
|
139
|
+
@group = gr
|
140
|
+
@callback.call( Token.new( data||"", @group, :region_open ) )
|
141
|
+
end
|
142
|
+
|
143
|
+
def end_region( gr, data=nil )
|
144
|
+
flush_chunk
|
145
|
+
@group = gr
|
146
|
+
@callback.call( Token.new( data||"", @group, :region_close ) )
|
147
|
+
end
|
148
|
+
|
149
|
+
def flush_chunk
|
150
|
+
@callback.call( Token.new( @chunk, @group ) ) unless @chunk.empty?
|
151
|
+
@chunk = ""
|
152
|
+
end
|
153
|
+
|
154
|
+
def subtokenize( syntax, text )
|
155
|
+
tokenizer = Syntax.load( syntax )
|
156
|
+
tokenizer.set @options if @options
|
157
|
+
flush_chunk
|
158
|
+
tokenizer.tokenize( text, &@callback )
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# A default tokenizer for handling syntaxes that are not explicitly handled
|
164
|
+
# elsewhere. It simply yields the given text as a single token.
|
165
|
+
class Default
|
166
|
+
|
167
|
+
# Yield the given text as a single token.
|
168
|
+
def tokenize( text )
|
169
|
+
yield Token.new( text, :normal )
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
# A hash for registering syntax implementations.
|
175
|
+
SYNTAX = Hash.new( Default )
|
176
|
+
|
177
|
+
# Load the implementation of the requested syntax. If the syntax cannot be
|
178
|
+
# found, or if it cannot be loaded for whatever reason, the Default syntax
|
179
|
+
# handler will be returned.
|
180
|
+
def load( syntax )
|
181
|
+
begin
|
182
|
+
require_relative "lang/#{syntax}"
|
183
|
+
rescue LoadError
|
184
|
+
end
|
185
|
+
SYNTAX[ syntax ].new
|
186
|
+
end
|
187
|
+
module_function :load
|
188
|
+
|
189
|
+
# Return an array of the names of supported syntaxes.
|
190
|
+
def all
|
191
|
+
lang_dir = File.join(File.dirname(__FILE__), "syntax", "lang")
|
192
|
+
Dir["#{lang_dir}/*.rb"].map { |path| File.basename(path, ".rb") }
|
193
|
+
end
|
194
|
+
module_function :all
|
195
|
+
|
196
|
+
|
197
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
|
2
|
+
module HH::Syntax
|
3
|
+
|
4
|
+
# A tokenizer for the Ruby language. It recognizes all common syntax
|
5
|
+
# (and some less common syntax) but because it is not a true lexer, it
|
6
|
+
# will make mistakes on some ambiguous cases.
|
7
|
+
class Ruby < Tokenizer
|
8
|
+
|
9
|
+
# The list of all identifiers recognized as keywords.
|
10
|
+
KEYWORDS =
|
11
|
+
%w{if then elsif else end begin do rescue ensure while for
|
12
|
+
class module def yield raise until unless and or not when
|
13
|
+
case super undef break next redo retry in return alias
|
14
|
+
defined?}
|
15
|
+
|
16
|
+
# Perform ruby-specific setup
|
17
|
+
def setup
|
18
|
+
@selector = false
|
19
|
+
@allow_operator = false
|
20
|
+
@heredocs = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Step through a single iteration of the tokenization process.
|
24
|
+
def step
|
25
|
+
case
|
26
|
+
when bol? && check( /=begin/ )
|
27
|
+
start_group( :comment, scan_until( /^=end#{EOL}/ ) )
|
28
|
+
when bol? && check( /__END__#{EOL}/ )
|
29
|
+
start_group( :comment, scan_until( /\Z/ ) )
|
30
|
+
else
|
31
|
+
case
|
32
|
+
when check( /def\s+/ )
|
33
|
+
start_group :keyword, scan( /def\s+/ )
|
34
|
+
start_group :method, scan_until( /(?=[;(\s]|#{EOL})/ )
|
35
|
+
when check( /class\s+/ )
|
36
|
+
start_group :keyword, scan( /class\s+/ )
|
37
|
+
start_group :class, scan_until( /(?=[;\s<]|#{EOL})/ )
|
38
|
+
when check( /module\s+/ )
|
39
|
+
start_group :keyword, scan( /module\s+/ )
|
40
|
+
start_group :module, scan_until( /(?=[;\s]|#{EOL})/ )
|
41
|
+
when check( /::/ )
|
42
|
+
start_group :punct, scan(/::/)
|
43
|
+
when check( /:"/ )
|
44
|
+
start_group :symbol, scan(/:/)
|
45
|
+
scan_delimited_region :symbol, :symbol, "", true
|
46
|
+
@allow_operator = true
|
47
|
+
when check( /:'/ )
|
48
|
+
start_group :symbol, scan(/:/)
|
49
|
+
scan_delimited_region :symbol, :symbol, "", false
|
50
|
+
@allow_operator = true
|
51
|
+
when scan( /:[_a-zA-Z@$][$@\w]*[=!?]?/ )
|
52
|
+
start_group :symbol, matched
|
53
|
+
@allow_operator = true
|
54
|
+
when scan( /\?(\\[^\n\r]|[^\\\n\r\s])/ )
|
55
|
+
start_group :char, matched
|
56
|
+
@allow_operator = true
|
57
|
+
when check( /(__FILE__|__LINE__|true|false|nil|self)[?!]?/ )
|
58
|
+
if @selector || matched[-1] == ?? || matched[-1] == ?!
|
59
|
+
start_group :ident,
|
60
|
+
scan(/(__FILE__|__LINE__|true|false|nil|self)[?!]?/)
|
61
|
+
else
|
62
|
+
start_group :constant,
|
63
|
+
scan(/(__FILE__|__LINE__|true|false|nil|self)/)
|
64
|
+
end
|
65
|
+
@selector = false
|
66
|
+
@allow_operator = true
|
67
|
+
when scan(/0([bB][01]+|[oO][0-7]+|[dD][0-9]+|[xX][0-9a-fA-F]+)/)
|
68
|
+
start_group :number, matched
|
69
|
+
@allow_operator = true
|
70
|
+
else
|
71
|
+
case peek(2)
|
72
|
+
when "%r"
|
73
|
+
scan_delimited_region :punct, :regex, scan( /../ ), true
|
74
|
+
@allow_operator = true
|
75
|
+
when "%w", "%q"
|
76
|
+
scan_delimited_region :punct, :string, scan( /../ ), false
|
77
|
+
@allow_operator = true
|
78
|
+
when "%s"
|
79
|
+
scan_delimited_region :punct, :symbol, scan( /../ ), false
|
80
|
+
@allow_operator = true
|
81
|
+
when "%W", "%Q", "%x"
|
82
|
+
scan_delimited_region :punct, :string, scan( /../ ), true
|
83
|
+
@allow_operator = true
|
84
|
+
when /%[^\sa-zA-Z0-9]/
|
85
|
+
scan_delimited_region :punct, :string, scan( /./ ), true
|
86
|
+
@allow_operator = true
|
87
|
+
when "<<"
|
88
|
+
saw_word = ( chunk[-1,1] =~ /[\w!?]/ )
|
89
|
+
start_group :punct, scan( /<</ )
|
90
|
+
if saw_word
|
91
|
+
@allow_operator = false
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
float_right = scan( /-/ )
|
96
|
+
append "-" if float_right
|
97
|
+
if ( type = scan( /['"]/ ) )
|
98
|
+
append type
|
99
|
+
delim = scan_until( /(?=#{type})/ )
|
100
|
+
if delim.nil?
|
101
|
+
append scan_until( /\Z/ )
|
102
|
+
return
|
103
|
+
end
|
104
|
+
else
|
105
|
+
delim = scan( /\w+/ ) or return
|
106
|
+
end
|
107
|
+
start_group :constant, delim
|
108
|
+
start_group :punct, scan( /#{type}/ ) if type
|
109
|
+
@heredocs << [ float_right, type, delim ]
|
110
|
+
@allow_operator = true
|
111
|
+
else
|
112
|
+
case peek(1)
|
113
|
+
when /[\n\r]/
|
114
|
+
unless @heredocs.empty?
|
115
|
+
scan_heredoc(*@heredocs.shift)
|
116
|
+
else
|
117
|
+
start_group :normal, scan( /\s+/ )
|
118
|
+
end
|
119
|
+
@allow_operator = false
|
120
|
+
when /\s/
|
121
|
+
start_group :normal, scan( /\s+/ )
|
122
|
+
when "#"
|
123
|
+
start_group :comment, scan( /#[^\n\r]*/ )
|
124
|
+
when /[A-Z]/
|
125
|
+
start_group @selector ? :ident : :constant, scan( /\w+/ )
|
126
|
+
@allow_operator = true
|
127
|
+
when /[a-z_]/
|
128
|
+
word = scan( /\w+[?!]?/ )
|
129
|
+
if !@selector && KEYWORDS.include?( word )
|
130
|
+
start_group :keyword, word
|
131
|
+
@allow_operator = false
|
132
|
+
elsif
|
133
|
+
start_group :ident, word
|
134
|
+
@allow_operator = true
|
135
|
+
end
|
136
|
+
@selector = false
|
137
|
+
when /\d/
|
138
|
+
start_group :number,
|
139
|
+
scan( /[\d_]+(\.[\d_]+)?([eE][\d_]+)?/ )
|
140
|
+
@allow_operator = true
|
141
|
+
when '"'
|
142
|
+
scan_delimited_region :punct, :string, "", true
|
143
|
+
@allow_operator = true
|
144
|
+
when '/'
|
145
|
+
if @allow_operator
|
146
|
+
start_group :punct, scan(%r{/})
|
147
|
+
@allow_operator = false
|
148
|
+
else
|
149
|
+
scan_delimited_region :punct, :regex, "", true
|
150
|
+
@allow_operator = true
|
151
|
+
end
|
152
|
+
when "'"
|
153
|
+
scan_delimited_region :punct, :string, "", false
|
154
|
+
@allow_operator = true
|
155
|
+
when "."
|
156
|
+
dots = scan( /\.{1,3}/ )
|
157
|
+
start_group :punct, dots
|
158
|
+
@selector = ( dots.length == 1 )
|
159
|
+
when /[@]/
|
160
|
+
start_group :attribute, scan( /@{1,2}\w*/ )
|
161
|
+
@allow_operator = true
|
162
|
+
when /[$]/
|
163
|
+
start_group :global, scan(/\$/)
|
164
|
+
start_group :global, scan( /\w+|./ ) if check(/./)
|
165
|
+
@allow_operator = true
|
166
|
+
when /[-!?*\/+=<>(\[\{}:;,&|%]/
|
167
|
+
start_group :punct, scan(/./)
|
168
|
+
@allow_operator = false
|
169
|
+
when /[)\]]/
|
170
|
+
start_group :punct, scan(/./)
|
171
|
+
@allow_operator = true
|
172
|
+
else
|
173
|
+
# all else just falls through this, to prevent
|
174
|
+
# infinite loops...
|
175
|
+
append getch
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# Scan a delimited region of text. This handles the simple cases (strings
|
185
|
+
# delimited with quotes) as well as the more complex cases of %-strings
|
186
|
+
# and here-documents.
|
187
|
+
#
|
188
|
+
# * +delim_group+ is the group to use to classify the delimiters of the
|
189
|
+
# region
|
190
|
+
# * +inner_group+ is the group to use to classify the contents of the
|
191
|
+
# region
|
192
|
+
# * +starter+ is the text to use as the starting delimiter
|
193
|
+
# * +exprs+ is a boolean flag indicating whether the region is an
|
194
|
+
# interpolated string or not
|
195
|
+
# * +delim+ is the text to use as the delimiter of the region. If +nil+,
|
196
|
+
# the next character will be treated as the delimiter.
|
197
|
+
# * +heredoc+ is either +false+, meaning the region is not a heredoc, or
|
198
|
+
# <tt>:flush</tt> (meaning the delimiter must be flushed left), or
|
199
|
+
# <tt>:float</tt> (meaning the delimiter doens't have to be flush left).
|
200
|
+
def scan_delimited_region( delim_group, inner_group, starter, exprs,
|
201
|
+
delim=nil, heredoc=false )
|
202
|
+
# begin
|
203
|
+
if !delim
|
204
|
+
start_group delim_group, starter
|
205
|
+
delim = scan( /./ )
|
206
|
+
append delim
|
207
|
+
|
208
|
+
delim = case delim
|
209
|
+
when '{' then '}'
|
210
|
+
when '(' then ')'
|
211
|
+
when '[' then ']'
|
212
|
+
when '<' then '>'
|
213
|
+
else delim
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
start_region inner_group
|
218
|
+
|
219
|
+
items = "\\\\|"
|
220
|
+
if heredoc
|
221
|
+
items << "(^"
|
222
|
+
items << '\s*' if heredoc == :float
|
223
|
+
items << "#{Regexp.escape(delim)}\s*?)#{EOL}"
|
224
|
+
else
|
225
|
+
items << "#{Regexp.escape(delim)}"
|
226
|
+
end
|
227
|
+
items << "|#(\\$|@@?|\\{)" if exprs
|
228
|
+
items = Regexp.new( items )
|
229
|
+
|
230
|
+
loop do
|
231
|
+
p = pos
|
232
|
+
match = scan_until( items )
|
233
|
+
if match.nil?
|
234
|
+
start_group inner_group, scan_until( /\Z/ )
|
235
|
+
break
|
236
|
+
else
|
237
|
+
text = pre_match[p..-1]
|
238
|
+
start_group inner_group, text if text.length > 0
|
239
|
+
case matched.strip
|
240
|
+
when "\\"
|
241
|
+
unless exprs
|
242
|
+
case peek(1)
|
243
|
+
when "'"
|
244
|
+
scan(/./)
|
245
|
+
start_group :escape, "\\'"
|
246
|
+
when "\\"
|
247
|
+
scan(/./)
|
248
|
+
start_group :escape, "\\\\"
|
249
|
+
else
|
250
|
+
start_group inner_group, "\\"
|
251
|
+
end
|
252
|
+
else
|
253
|
+
start_group :escape, "\\"
|
254
|
+
c = getch
|
255
|
+
append c
|
256
|
+
case c
|
257
|
+
when 'x'
|
258
|
+
append scan( /[a-fA-F0-9]{1,2}/ )
|
259
|
+
when /[0-7]/
|
260
|
+
append scan( /[0-7]{0,2}/ )
|
261
|
+
end
|
262
|
+
end
|
263
|
+
when delim
|
264
|
+
end_region inner_group
|
265
|
+
start_group delim_group, matched
|
266
|
+
break
|
267
|
+
when /^#/
|
268
|
+
do_highlight = (option(:expressions) == :highlight)
|
269
|
+
start_region :expr if do_highlight
|
270
|
+
start_group :expr, matched
|
271
|
+
case matched[1]
|
272
|
+
when ?{
|
273
|
+
depth = 1
|
274
|
+
content = ""
|
275
|
+
while depth > 0
|
276
|
+
p = pos
|
277
|
+
c = scan_until( /[\{}]/ )
|
278
|
+
if c.nil?
|
279
|
+
content << scan_until( /\Z/ )
|
280
|
+
break
|
281
|
+
else
|
282
|
+
depth += ( matched == "{" ? 1 : -1 )
|
283
|
+
content << pre_match[p..-1]
|
284
|
+
content << matched if depth > 0
|
285
|
+
end
|
286
|
+
end
|
287
|
+
if do_highlight
|
288
|
+
subtokenize "ruby", content
|
289
|
+
start_group :expr, "}"
|
290
|
+
else
|
291
|
+
append content + "}"
|
292
|
+
end
|
293
|
+
when ?$, ?@
|
294
|
+
append scan( /\w+/ )
|
295
|
+
end
|
296
|
+
end_region :expr if do_highlight
|
297
|
+
else raise "unexpected match on #{matched}"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# Scan a heredoc beginning at the current position.
|
304
|
+
#
|
305
|
+
# * +float+ indicates whether the delimiter may be floated to the right
|
306
|
+
# * +type+ is +nil+, a single quote, or a double quote
|
307
|
+
# * +delim+ is the delimiter to look for
|
308
|
+
def scan_heredoc(float, type, delim)
|
309
|
+
scan_delimited_region( :constant, :string, "", type != "'",
|
310
|
+
delim, float ? :float : :flush )
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
SYNTAX["ruby"] = Ruby
|
315
|
+
|
316
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
# syntax highlighting
|
2
|
+
|
3
|
+
require_relative 'common'
|
4
|
+
|
5
|
+
module HH::Markup
|
6
|
+
|
7
|
+
TOKENIZER = HH::Syntax.load "ruby"
|
8
|
+
COLORS = {
|
9
|
+
:comment => {:stroke => "#887"},
|
10
|
+
:keyword => {:stroke => "#111"},
|
11
|
+
:method => {:stroke => "#C09", :weight => "bold"},
|
12
|
+
# :class => {:stroke => "#0c4", :weight => "bold"},
|
13
|
+
# :module => {:stroke => "#050"},
|
14
|
+
# :punct => {:stroke => "#668", :weight => "bold"},
|
15
|
+
:symbol => {:stroke => "#C30"},
|
16
|
+
:string => {:stroke => "#C90"},
|
17
|
+
:number => {:stroke => "#396" },
|
18
|
+
:regex => {:stroke => "#000", :fill => "#FFC" },
|
19
|
+
# :char => {:stroke => "#f07"},
|
20
|
+
:attribute => {:stroke => "#369" },
|
21
|
+
# :global => {:stroke => "#7FB" },
|
22
|
+
:expr => {:stroke => "#722" },
|
23
|
+
# :escape => {:stroke => "#277" }
|
24
|
+
:ident => {:stroke => "#994c99"},
|
25
|
+
:constant => {:stroke => "#630", :weight => "bold"},
|
26
|
+
:class => {:stroke => "#630", :weight => "bold"},
|
27
|
+
:matching => {:stroke => "#ff0", :weight => "bold"},
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
def highlight str, pos=nil, colors=COLORS
|
32
|
+
tokens = []
|
33
|
+
TOKENIZER.tokenize(str) do |t|
|
34
|
+
if t.group == :punct
|
35
|
+
# split punctuation into single characters tokens
|
36
|
+
# TODO: to it in the parser
|
37
|
+
tokens += t.split('').map{|s| HH::Syntax::Token.new(s, :punct)}
|
38
|
+
else
|
39
|
+
# add token as is
|
40
|
+
tokens << t
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
res = []
|
45
|
+
tokens.each do |token|
|
46
|
+
res <<
|
47
|
+
if colors[token.group]
|
48
|
+
#span(token, colors[token.group])
|
49
|
+
tmp = fg(token, tr_color(colors[token.group][:stroke]))
|
50
|
+
colors[token.group][:fill] ? bg(tmp, tr_color(colors[token.group][:fill])) : tmp
|
51
|
+
elsif colors[:any]
|
52
|
+
#span(token, colors[:any])
|
53
|
+
tmp = fg(token, tr_color(colors[:any][:stroke]))
|
54
|
+
colors[:any][:fill] ? bg(tmp, tr_color(colors[:any][:fill])) : tmp
|
55
|
+
else
|
56
|
+
token
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if pos.nil? or pos < 0
|
61
|
+
return res.join
|
62
|
+
end
|
63
|
+
|
64
|
+
token_index, matching_index = matching_token(tokens, pos)
|
65
|
+
|
66
|
+
if token_index
|
67
|
+
#res[token_index] = span(tokens[token_index], colors[:matching])
|
68
|
+
tmp = fg(tokens[token_index], tr_color(colors[:matching][:stroke]))
|
69
|
+
res[token_index] = colors[:matching][:fill] ? bg(tmp, tr_color(colors[:matching][:fill])) : tmp
|
70
|
+
if matching_index
|
71
|
+
#res[matching_index] = span(tokens[matching_index], colors[:matching])
|
72
|
+
tmp = fg(tokens[matching_index], tr_color(colors[:matching][:stroke]))
|
73
|
+
res[matching_index] = colors[:matching][:fill] ? bg(tmp, tr_color(colors[:matching][:fill])) : tmp
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
res.join
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def matching_token(tokens, pos)
|
82
|
+
curr_pos = 0
|
83
|
+
token_index = nil
|
84
|
+
tokens.each_with_index do |t, i|
|
85
|
+
curr_pos += t.size
|
86
|
+
if token_index.nil? and curr_pos >= pos
|
87
|
+
token_index = i
|
88
|
+
break
|
89
|
+
end
|
90
|
+
end
|
91
|
+
if token_index.nil? then return nil end
|
92
|
+
|
93
|
+
match = matching_token_at_index(tokens, token_index);
|
94
|
+
if match.nil? and curr_pos == pos and token_index < tokens.size-1
|
95
|
+
# try the token before the cursor, instead of the one after
|
96
|
+
token_index += 1
|
97
|
+
match = matching_token_at_index(tokens, token_index)
|
98
|
+
end
|
99
|
+
|
100
|
+
if match
|
101
|
+
[token_index, match]
|
102
|
+
else
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def matching_token_at_index(tokens, index)
|
109
|
+
starts, ends, direction = matching_tokens(tokens, index)
|
110
|
+
if starts.nil?
|
111
|
+
return nil
|
112
|
+
end
|
113
|
+
|
114
|
+
stack_level = 1
|
115
|
+
index += direction
|
116
|
+
while index >= 0 and index < tokens.size
|
117
|
+
# TODO separate space in the tokenizer
|
118
|
+
t = tokens[index].gsub(/\s/, '')
|
119
|
+
if ends.include?(t) and not as_modifier?(tokens, index)
|
120
|
+
stack_level -= 1
|
121
|
+
return index if stack_level == 0
|
122
|
+
elsif starts.include?(t) and not as_modifier?(tokens, index)
|
123
|
+
stack_level += 1
|
124
|
+
end
|
125
|
+
index += direction
|
126
|
+
end
|
127
|
+
# no matching token found
|
128
|
+
return nil
|
129
|
+
end
|
130
|
+
|
131
|
+
# returns an array of tokens matching and the direction
|
132
|
+
def matching_tokens(tokens, index)
|
133
|
+
# TODO separate space in the tokenizer
|
134
|
+
token = tokens[index].gsub(/\s/, '')
|
135
|
+
starts = [token]
|
136
|
+
if OPEN_BRACKETS[token]
|
137
|
+
direction = 1
|
138
|
+
ends = [OPEN_BRACKETS[token]]
|
139
|
+
elsif CLOSE_BRACKETS[token]
|
140
|
+
direction = -1
|
141
|
+
ends = [CLOSE_BRACKETS[token]]
|
142
|
+
elsif OPEN_BLOCK.include?(token)
|
143
|
+
if as_modifier?(tokens, index)
|
144
|
+
return nil
|
145
|
+
end
|
146
|
+
direction = 1
|
147
|
+
ends = ['end']
|
148
|
+
starts = OPEN_BLOCK
|
149
|
+
elsif token == 'end'
|
150
|
+
direction = -1
|
151
|
+
ends = OPEN_BLOCK
|
152
|
+
else
|
153
|
+
return nil
|
154
|
+
end
|
155
|
+
|
156
|
+
[starts, ends, direction]
|
157
|
+
end
|
158
|
+
|
159
|
+
def as_modifier?(tokens, index)
|
160
|
+
|
161
|
+
if not MODIFIERS.include? tokens[index].gsub(/\s/, '')
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
index -= 1
|
166
|
+
# find last index before the token that is no space
|
167
|
+
index -= 1 while index >= 0 and tokens[index] =~ /\A[ \t]*\z/
|
168
|
+
|
169
|
+
if index < 0
|
170
|
+
# first character of the string
|
171
|
+
false
|
172
|
+
elsif tokens[index] =~ /\n[ \t]*\Z/
|
173
|
+
# first token of the line
|
174
|
+
false
|
175
|
+
elsif tokens[index].group == :punct
|
176
|
+
# preceded by a punctuation token on the same line
|
177
|
+
i = tokens[index].rindex(/\S/)
|
178
|
+
punc = tokens[index][i, 1]
|
179
|
+
# true if the preceeding statement was terminating
|
180
|
+
not NON_TERMINATING.include?(punc)
|
181
|
+
else
|
182
|
+
# preceded by a non punctuation token on the same line
|
183
|
+
true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
OPEN_BRACKETS = {
|
189
|
+
'{' => '}',
|
190
|
+
'(' => ')',
|
191
|
+
'[' => ']',
|
192
|
+
}
|
193
|
+
|
194
|
+
#close_bracket = {}
|
195
|
+
#OPEN_BRACKETS.each{|open, close| opens_bracket[close] = open}
|
196
|
+
#CLOSE_BRACKETS = opens_bracket
|
197
|
+
# the following is more readable :)
|
198
|
+
CLOSE_BRACKETS = {
|
199
|
+
'}' => '{',
|
200
|
+
')' => '(',
|
201
|
+
']' => '[',
|
202
|
+
}
|
203
|
+
|
204
|
+
BRACKETS = CLOSE_BRACKETS.keys + OPEN_BRACKETS.keys
|
205
|
+
|
206
|
+
OPEN_BLOCK = [
|
207
|
+
'def',
|
208
|
+
'class',
|
209
|
+
'module',
|
210
|
+
'do',
|
211
|
+
'if',
|
212
|
+
'unless',
|
213
|
+
'while',
|
214
|
+
'until',
|
215
|
+
'begin',
|
216
|
+
'for'
|
217
|
+
]
|
218
|
+
|
219
|
+
MODIFIERS = %w[if unless while until]
|
220
|
+
|
221
|
+
NON_TERMINATING = %w{+ - * / , . = ~ < > ( [}
|
222
|
+
end
|
data/lib/green_shoes.rb
CHANGED
@@ -48,3 +48,4 @@ autoload :ChipMunk, File.join(Shoes::DIR, 'ext/chipmunk')
|
|
48
48
|
autoload :Bloops, File.join(Shoes::DIR, 'ext/bloops')
|
49
49
|
autoload :Projector, File.join(Shoes::DIR, 'ext/projector')
|
50
50
|
autoload :Hpricot, File.join(Shoes::DIR, 'ext/hpricot')
|
51
|
+
autoload :HH, File.join(Shoes::DIR, 'ext/highlighter')
|
data/lib/shoes/basic.rb
CHANGED
data/lib/shoes/help.rb
CHANGED
@@ -3,6 +3,7 @@ class Manual < Shoes
|
|
3
3
|
url '/manual/(\d+)', :index
|
4
4
|
|
5
5
|
include Hpricot
|
6
|
+
include HH::Markup
|
6
7
|
|
7
8
|
def index pnum = 0
|
8
9
|
font LANG == 'ja' ? 'MS UI Gothic' : 'Arial'
|
@@ -84,7 +85,11 @@ class Manual < Shoes
|
|
84
85
|
flow do
|
85
86
|
background rgb(190, 190, 190), curve: 5
|
86
87
|
inscription link(fg('Run this', green)){eval mk_executable(_code), TOPLEVEL_BINDING}, margin_left: 480
|
87
|
-
|
88
|
+
if _code.include? 'te-su-to'
|
89
|
+
para fg(code(' ' + _code), maroon), NL, margin_left: -10
|
90
|
+
else
|
91
|
+
para code(highlight(' ' + _code, nil)), NL, margin_left: -10
|
92
|
+
end
|
88
93
|
end
|
89
94
|
para
|
90
95
|
end
|
@@ -329,7 +334,7 @@ class Manual < Shoes
|
|
329
334
|
|
330
335
|
def mk_sidebar_list num
|
331
336
|
toc = []
|
332
|
-
[0..3, 4..9, 10..16, 17..32, 33..
|
337
|
+
[0..3, 4..9, 10..16, 17..32, 33..36].each do |r|
|
333
338
|
toc.push TOC_LIST[r.first][0]
|
334
339
|
toc.push(TOC_LIST[r.first+1..r.last].to_a.map &:first) if r.include?(num)
|
335
340
|
end
|
data/lib/shoes/helper_methods.rb
CHANGED
@@ -194,7 +194,7 @@ class Shoes
|
|
194
194
|
mask_control app
|
195
195
|
repaint_all_by_order app
|
196
196
|
repaint_textcursors app
|
197
|
-
app.canvas.set_size 0, scrollable_height unless app.
|
197
|
+
app.canvas.set_size 0, scrollable_height unless(app.prjct or app.trvw)
|
198
198
|
true
|
199
199
|
end
|
200
200
|
|
@@ -284,6 +284,7 @@ class Shoes
|
|
284
284
|
def self.mouse_on? e
|
285
285
|
if e.is_a? Slot
|
286
286
|
mouse_x, mouse_y = e.app.win.pointer
|
287
|
+
mouse_y += e.app.scroll_top
|
287
288
|
(e.left..e.left+e.width).include?(mouse_x) and (e.top..e.top+e.height).include?(mouse_y)
|
288
289
|
else
|
289
290
|
mouse_x, mouse_y = e.real.pointer
|
data/lib/shoes/main.rb
CHANGED
@@ -12,7 +12,8 @@ class Shoes
|
|
12
12
|
args[:left] ||= 0
|
13
13
|
args[:top] ||= 0
|
14
14
|
projector = args[:prjct] = args[:projector]
|
15
|
-
args
|
15
|
+
treeview = args[:trvw] = args[:treeview]
|
16
|
+
[:projector, :treeview].each{|x| args.delete x}
|
16
17
|
|
17
18
|
app = App.new args
|
18
19
|
@apps.push app
|
@@ -62,7 +63,11 @@ class Shoes
|
|
62
63
|
mouse_leave_control app
|
63
64
|
end
|
64
65
|
|
65
|
-
app.canvas =
|
66
|
+
app.canvas = if treeview
|
67
|
+
Gtk::TreeView.new
|
68
|
+
else
|
69
|
+
projector ? Gtk::DrawingArea.new : Gtk::Layout.new
|
70
|
+
end
|
66
71
|
swin = Gtk::ScrolledWindow.new
|
67
72
|
swin.set_policy Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC
|
68
73
|
swin.vadjustment.step_increment = 10
|
data/lib/shoes/ruby.rb
CHANGED
data/lib/shoes/slot.rb
CHANGED
@@ -74,9 +74,8 @@ class Shoes
|
|
74
74
|
|
75
75
|
def fix_size; end
|
76
76
|
|
77
|
-
def clear &blk
|
78
|
-
@
|
79
|
-
@contents.each &:clear
|
77
|
+
def clear all = false, &blk
|
78
|
+
all ? @contents.each(&:clear_all) : @contents.each(&:clear)
|
80
79
|
@contents.each{|e| @app.mlcs.delete e; @app.mhcs.delete e}
|
81
80
|
@contents = []
|
82
81
|
if blk
|
@@ -91,6 +90,11 @@ class Shoes
|
|
91
90
|
end
|
92
91
|
end
|
93
92
|
|
93
|
+
def clear_all &blk
|
94
|
+
@app.delete_mouse_events self
|
95
|
+
clear true, &blk
|
96
|
+
end
|
97
|
+
|
94
98
|
def append &blk
|
95
99
|
prepend contents.length, &blk
|
96
100
|
end
|
data/samples/sample52.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require '../lib/green_shoes'
|
2
|
+
|
3
|
+
Shoes.app do
|
4
|
+
extend HH::Markup
|
5
|
+
colors = {
|
6
|
+
:comment => {:stroke => "#bba"},
|
7
|
+
:keyword => {:stroke => "#FCF91F"},
|
8
|
+
:method => {:stroke => "#C09"},
|
9
|
+
:symbol => {:stroke => "#9DF3C6"},
|
10
|
+
:string => {:stroke => "#C9F5A5"},
|
11
|
+
:number => {:stroke => "#C9F5A5"},
|
12
|
+
:regex => {:stroke => "#000", :fill => "#FFC" },
|
13
|
+
:attribute => {:stroke => "#C9F5A5"},
|
14
|
+
:expr => {:stroke => "#f33" },
|
15
|
+
:ident => {:stroke => "#6e7"},
|
16
|
+
:any => {:stroke => "#FFF"},
|
17
|
+
:constant => {:stroke => "#55f"},
|
18
|
+
:class => {:stroke => "#55f"},
|
19
|
+
:matching => {:stroke => "#f00"},
|
20
|
+
}
|
21
|
+
code = IO.read(ask_open_file)
|
22
|
+
button 'change color' do
|
23
|
+
@slot.clear do
|
24
|
+
background gray 0.1
|
25
|
+
para highlight code, nil, colors
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@slot = stack do
|
29
|
+
background gainsboro
|
30
|
+
para highlight code, nil
|
31
|
+
end
|
32
|
+
end
|
data/samples/sample53.rb
ADDED
data/samples/treeview.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# The following code was quoted from http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-gtk2-treev-trees
|
2
|
+
# and edited a little bit for Green Shoes
|
3
|
+
|
4
|
+
def setup_tree_view(treeview)
|
5
|
+
renderer = Gtk::CellRendererText.new
|
6
|
+
column = Gtk::TreeViewColumn.new("Buy", renderer, "text" => $buy_index)
|
7
|
+
treeview.append_column(column)
|
8
|
+
renderer = Gtk::CellRendererText.new
|
9
|
+
column = Gtk::TreeViewColumn.new("Count", renderer, "text" => $qty_index)
|
10
|
+
treeview.append_column(column)
|
11
|
+
renderer = Gtk::CellRendererText.new
|
12
|
+
column = Gtk::TreeViewColumn.new("Product", renderer, "text" => $prod_index)
|
13
|
+
treeview.append_column(column)
|
14
|
+
end
|
15
|
+
|
16
|
+
class GroceryItem
|
17
|
+
attr_accessor :product_type, :buy, :quantity, :product
|
18
|
+
def initialize(t,b,q,p)
|
19
|
+
@product_type, @buy, @quantity, @product = t, b, q, p
|
20
|
+
end
|
21
|
+
end
|
22
|
+
$buy_index = 0; $qty_index = 1; $prod_index = 2
|
23
|
+
$p_category = 0; $p_child = 1
|
24
|
+
|
25
|
+
list = Array.new
|
26
|
+
list[0] = GroceryItem.new($p_category, true, 0, "Cleaning Supplies")
|
27
|
+
list[1] = GroceryItem.new($p_child, true, 1, "Paper Towels")
|
28
|
+
list[2] = GroceryItem.new($p_child, true, 3, "Toilet Paper")
|
29
|
+
list[3] = GroceryItem.new($p_category, true, 0, "Food")
|
30
|
+
list[4] = GroceryItem.new($p_child, true, 2, "Bread")
|
31
|
+
list[5] = GroceryItem.new($p_child, false, 1, "Butter")
|
32
|
+
list[6] = GroceryItem.new($p_child, true, 1, "Milk")
|
33
|
+
list[7] = GroceryItem.new($p_child, false, 3, "Chips")
|
34
|
+
list[8] = GroceryItem.new($p_child, true, 4, "Soda")
|
35
|
+
|
36
|
+
setup_tree_view($app.canvas)
|
37
|
+
|
38
|
+
store = Gtk::TreeStore.new(TrueClass, Integer, String)
|
39
|
+
parent = child = nil
|
40
|
+
|
41
|
+
list.each_with_index do |e, i|
|
42
|
+
if (e.product_type == $p_category)
|
43
|
+
j = i + 1
|
44
|
+
while j < list.size && list[j].product_type != $p_category
|
45
|
+
list[i].quantity += list[j].quantity if list[j].buy
|
46
|
+
j += 1
|
47
|
+
end
|
48
|
+
parent = store.append(nil)
|
49
|
+
parent[$buy_index] = list[i].buy
|
50
|
+
parent[$qty_index] = list[i].quantity
|
51
|
+
parent[$prod_index] = list[i].product
|
52
|
+
else
|
53
|
+
child = store.append(parent)
|
54
|
+
child[$buy_index] = list[i].buy
|
55
|
+
child[$qty_index] = list[i].quantity
|
56
|
+
child[$prod_index] = list[i].product
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
$app.canvas.model = store
|
Binary file
|
Binary file
|
data/static/manual-en.txt
CHANGED
@@ -3877,3 +3877,34 @@ Hope this helps:
|
|
3877
3877
|
* You can join [[http://librelist.com/browser/shoes/ Shoes ML]] and feel free ask your questions.
|
3878
3878
|
* [[https://github.com/ashbb/green_shoes/ Current Source Code]] is on GitHub.
|
3879
3879
|
* Green Shoes Gem is on [[http://rubygems.org/gems/green_shoes RubyGems.org]].
|
3880
|
+
|
3881
|
+
== vs.RedShoes ==
|
3882
|
+
|
3883
|
+
Green Shoes is following Red Shoes, but not fully compatible.
|
3884
|
+
|
3885
|
+
==== TextBlock ====
|
3886
|
+
|
3887
|
+
The following two snippets are same in Red Shoes.
|
3888
|
+
|
3889
|
+
{{{
|
3890
|
+
Shoes.app do
|
3891
|
+
para 'hello ' * 20
|
3892
|
+
end
|
3893
|
+
}}}
|
3894
|
+
|
3895
|
+
{{{
|
3896
|
+
Shoes.app do
|
3897
|
+
20.times{para 'hello '}
|
3898
|
+
end
|
3899
|
+
}}}
|
3900
|
+
|
3901
|
+
But in Green Shoes, need to add `:width` size explicitly.
|
3902
|
+
|
3903
|
+
{{{
|
3904
|
+
Shoes.app do
|
3905
|
+
20.times{para 'hello ', width: 40}
|
3906
|
+
end
|
3907
|
+
}}}
|
3908
|
+
|
3909
|
+
If you don't specify the `:width` size, Green Shoes makes a TextBlock object with
|
3910
|
+
the `parent.width`.
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 233
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.233.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- ashbb
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-06-
|
17
|
+
date: 2011-06-14 00:00:00 +09:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -50,6 +50,10 @@ files:
|
|
50
50
|
- lib/ext/bloops/songs/simpsons_theme_song_by_why.rb
|
51
51
|
- lib/ext/chipmunk.rb
|
52
52
|
- lib/ext/chipmunk/chipmunk.so
|
53
|
+
- lib/ext/highlighter.rb
|
54
|
+
- lib/ext/highlighter/common.rb
|
55
|
+
- lib/ext/highlighter/lang/ruby.rb
|
56
|
+
- lib/ext/highlighter/markup.rb
|
53
57
|
- lib/ext/hpricot.rb
|
54
58
|
- lib/ext/hpricot/blankslate.rb
|
55
59
|
- lib/ext/hpricot/builder.rb
|
@@ -196,6 +200,8 @@ files:
|
|
196
200
|
- samples/sample5.rb
|
197
201
|
- samples/sample50.rb
|
198
202
|
- samples/sample51.rb
|
203
|
+
- samples/sample52.rb
|
204
|
+
- samples/sample53.rb
|
199
205
|
- samples/sample6.rb
|
200
206
|
- samples/sample7.rb
|
201
207
|
- samples/sample8.rb
|
@@ -203,6 +209,7 @@ files:
|
|
203
209
|
- samples/sample99.rb
|
204
210
|
- samples/shell.png
|
205
211
|
- samples/splash-hand.png
|
212
|
+
- samples/treeview.rb
|
206
213
|
- snapshots/helloworld.png
|
207
214
|
- snapshots/mini-hh.png
|
208
215
|
- snapshots/sample1.png
|
@@ -255,6 +262,8 @@ files:
|
|
255
262
|
- snapshots/sample5.png
|
256
263
|
- snapshots/sample50.png
|
257
264
|
- snapshots/sample51.png
|
265
|
+
- snapshots/sample52.png
|
266
|
+
- snapshots/sample53.png
|
258
267
|
- snapshots/sample6.png
|
259
268
|
- snapshots/sample7.png
|
260
269
|
- snapshots/sample8.png
|