rtext 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +20 -0
- data/{README → README.rdoc} +5 -1
- data/RText_Protocol +444 -0
- data/Rakefile +10 -10
- data/lib/rtext/completer.rb +32 -26
- data/lib/rtext/context_builder.rb +113 -59
- data/lib/rtext/default_loader.rb +73 -8
- data/lib/rtext/default_service_provider.rb +30 -14
- data/lib/rtext/frontend/config.rb +58 -0
- data/lib/rtext/frontend/connector.rb +233 -0
- data/lib/rtext/frontend/connector_manager.rb +81 -0
- data/lib/rtext/frontend/context.rb +56 -0
- data/lib/rtext/generic.rb +13 -0
- data/lib/rtext/instantiator.rb +30 -7
- data/lib/rtext/language.rb +54 -27
- data/lib/rtext/link_detector.rb +57 -0
- data/lib/rtext/message_helper.rb +77 -0
- data/lib/rtext/parser.rb +19 -68
- data/lib/rtext/serializer.rb +18 -3
- data/lib/rtext/service.rb +182 -118
- data/lib/rtext/tokenizer.rb +102 -0
- data/test/completer_test.rb +327 -70
- data/test/context_builder_test.rb +671 -91
- data/test/instantiator_test.rb +153 -0
- data/test/integration/backend.out +10 -0
- data/test/integration/crash_on_request_editor.rb +12 -0
- data/test/integration/ecore_editor.rb +50 -0
- data/test/integration/frontend.log +25138 -0
- data/test/integration/model/invalid_encoding.invenc +2 -0
- data/test/integration/model/test.crash_on_request +18 -0
- data/test/integration/model/test.crashing_backend +18 -0
- data/test/integration/model/test.dont_open_socket +0 -0
- data/test/integration/model/test.invalid_cmd_line +0 -0
- data/test/integration/model/test.not_in_rtext +0 -0
- data/test/integration/model/test_large_with_errors.ect3 +43523 -0
- data/test/integration/model/test_metamodel.ect +18 -0
- data/test/integration/model/test_metamodel2.ect +5 -0
- data/test/integration/model/test_metamodel_error.ect2 +3 -0
- data/test/integration/model/test_metamodel_ok.ect2 +18 -0
- data/test/integration/test.rb +684 -0
- data/test/link_detector_test.rb +276 -0
- data/test/message_helper_test.rb +118 -0
- data/test/rtext_test.rb +4 -1
- data/test/serializer_test.rb +96 -1
- data/test/tokenizer_test.rb +125 -0
- metadata +36 -10
- data/RText_Plugin_Implementation_Guide +0 -268
- data/lib/rtext_plugin/connection_manager.rb +0 -59
data/Rakefile
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'rubygems/package_task'
|
2
|
+
require 'rdoc/task'
|
3
3
|
|
4
4
|
DocFiles = [
|
5
|
-
"README", "CHANGELOG", "MIT-LICENSE",
|
5
|
+
"README.rdoc", "CHANGELOG", "MIT-LICENSE",
|
6
6
|
"RText_Users_Guide",
|
7
|
-
"
|
7
|
+
"RText_Protocol"]
|
8
8
|
|
9
9
|
RTextGemSpec = Gem::Specification.new do |s|
|
10
10
|
s.name = %q{rtext}
|
11
|
-
s.version = "0.
|
11
|
+
s.version = "0.5.0"
|
12
12
|
s.date = Time.now.strftime("%Y-%m-%d")
|
13
13
|
s.summary = %q{Ruby Textual Modelling}
|
14
14
|
s.email = %q{martin dot thiede at gmx de}
|
15
15
|
s.homepage = %q{http://ruby-gen.org}
|
16
16
|
s.description = %q{RText can be used to derive textual languages from an RGen metamodel with very little effort.}
|
17
17
|
s.authors = ["Martin Thiede"]
|
18
|
-
s.add_dependency('rgen', '>= 0.6.
|
18
|
+
s.add_dependency('rgen', '>= 0.6.1')
|
19
19
|
gemfiles = Rake::FileList.new
|
20
20
|
gemfiles.include("{lib,test}/**/*")
|
21
21
|
gemfiles.include(DocFiles)
|
22
22
|
gemfiles.include("Rakefile")
|
23
23
|
gemfiles.exclude(/\b\.bak\b/)
|
24
24
|
s.files = gemfiles
|
25
|
-
s.rdoc_options = ["--main", "README", "-x", "test"]
|
25
|
+
s.rdoc_options = ["--main", "README.rdoc", "-x", "test"]
|
26
26
|
s.extra_rdoc_files = DocFiles
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
rd.main = "README"
|
29
|
+
RDoc::Task.new do |rd|
|
30
|
+
rd.main = "README.rdoc"
|
31
31
|
rd.rdoc_files.include(DocFiles)
|
32
32
|
rd.rdoc_files.include("lib/**/*.rb")
|
33
33
|
rd.rdoc_dir = "doc"
|
34
34
|
end
|
35
35
|
|
36
|
-
RTextPackageTask =
|
36
|
+
RTextPackageTask = Gem::PackageTask.new(RTextGemSpec) do |p|
|
37
37
|
p.need_zip = false
|
38
38
|
end
|
39
39
|
|
data/lib/rtext/completer.rb
CHANGED
@@ -23,6 +23,7 @@ class Completer
|
|
23
23
|
clazz = context && context.element && context.element.class.ecore
|
24
24
|
if clazz
|
25
25
|
if context.in_block
|
26
|
+
# command and lable completion within block
|
26
27
|
types = []
|
27
28
|
labled_refs = []
|
28
29
|
if context.feature
|
@@ -44,63 +45,68 @@ class Completer
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
47
|
-
types.uniq.
|
48
|
+
types.uniq.
|
48
49
|
sort{|a,b| a.name <=> b.name}.collect do |c|
|
49
50
|
class_completion_option(c)
|
50
51
|
end +
|
51
|
-
labled_refs.uniq.
|
52
|
+
labled_refs.uniq.collect do |r|
|
52
53
|
CompletionOption.new("#{r.name}:", "<#{r.eType.name}>")
|
53
54
|
end
|
54
|
-
|
55
|
+
elsif !context.problem
|
56
|
+
result = []
|
55
57
|
if context.feature
|
58
|
+
if context.after_label
|
59
|
+
description = "<#{context.feature.eType.name}>"
|
60
|
+
else
|
61
|
+
description = "[#{context.feature.name}] <#{context.feature.eType.name}>"
|
62
|
+
end
|
56
63
|
# value completion
|
57
64
|
if context.feature.is_a?(RGen::ECore::EAttribute) || !context.feature.containment
|
58
65
|
if context.feature.is_a?(RGen::ECore::EReference)
|
59
66
|
if ref_completion_option_provider
|
60
|
-
ref_completion_option_provider.call(context.feature)
|
67
|
+
result += ref_completion_option_provider.call(context.feature)
|
61
68
|
else
|
62
|
-
|
69
|
+
# no options
|
63
70
|
end
|
64
71
|
elsif context.feature.eType.is_a?(RGen::ECore::EEnum)
|
65
|
-
context.feature.eType.eLiterals.collect do |l|
|
66
|
-
CompletionOption.new("#{l.name}")
|
72
|
+
result += context.feature.eType.eLiterals.collect do |l|
|
73
|
+
CompletionOption.new("#{l.name}", "<#{context.feature.eType.name}>")
|
67
74
|
end
|
68
75
|
elsif context.feature.eType.instanceClass == String
|
69
|
-
|
76
|
+
if @lang.unquoted?(context.feature)
|
77
|
+
result += [ CompletionOption.new("#{context.feature.name.gsub(/\W/,"")}", description) ]
|
78
|
+
else
|
79
|
+
result += [ CompletionOption.new("\"\"", description) ]
|
80
|
+
end
|
70
81
|
elsif context.feature.eType.instanceClass == Integer
|
71
|
-
(0..
|
82
|
+
result += (0..0).collect{|i| CompletionOption.new("#{i}", description) }
|
72
83
|
elsif context.feature.eType.instanceClass == Float
|
73
|
-
(0..
|
84
|
+
result += (0..0).collect{|i| CompletionOption.new("#{i}.0", description) }
|
74
85
|
elsif context.feature.eType.instanceClass == RGen::MetamodelBuilder::DataTypes::Boolean
|
75
|
-
[true, false].collect{|b| CompletionOption.new("#{b}") }
|
86
|
+
result += [true, false].collect{|b| CompletionOption.new("#{b}", description) }
|
76
87
|
else
|
77
|
-
|
88
|
+
# no options
|
78
89
|
end
|
79
90
|
else
|
80
91
|
# containment reference, ignore
|
81
92
|
end
|
82
|
-
|
83
|
-
|
84
|
-
if !@lang.labled_arguments(clazz).any?{|f|
|
85
|
-
context.element.getGenericAsArray(f.name).size > 0}
|
86
|
-
result += @lang.unlabled_arguments(clazz).
|
87
|
-
select{|f| f.name.index(context.prefix) == 0 &&
|
88
|
-
context.element.getGenericAsArray(f.name).empty?}[0..0].collect do |f|
|
89
|
-
CompletionOption.new("<#{f.name}>", "<#{f.eType.name}>")
|
90
|
-
end
|
91
|
-
end
|
93
|
+
end
|
94
|
+
if !context.after_label
|
92
95
|
# label completion
|
93
96
|
result += @lang.labled_arguments(clazz).
|
94
|
-
select{|f|
|
95
|
-
context.element.
|
97
|
+
select{|f|
|
98
|
+
!context.element.eIsSet(f.name)}.collect do |f|
|
96
99
|
CompletionOption.new("#{f.name}:", "<#{f.eType.name}>")
|
97
100
|
end
|
98
|
-
result
|
99
101
|
end
|
102
|
+
result
|
103
|
+
else
|
104
|
+
# missing comma, after curly brace, etc.
|
105
|
+
[]
|
100
106
|
end
|
101
107
|
elsif context
|
102
108
|
# root classes
|
103
|
-
@lang.root_classes.
|
109
|
+
@lang.root_classes.
|
104
110
|
sort{|a,b| a.name <=> b.name}.collect do |c|
|
105
111
|
class_completion_option(c)
|
106
112
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rtext/instantiator'
|
2
|
+
require 'rtext/tokenizer'
|
2
3
|
|
3
4
|
module RText
|
4
5
|
|
@@ -25,23 +26,33 @@ module RText
|
|
25
26
|
#
|
26
27
|
module ContextBuilder
|
27
28
|
|
28
|
-
Context = Struct.new(:element, :feature, :prefix, :in_array, :in_block)
|
29
|
+
Context = Struct.new(:element, :feature, :prefix, :in_array, :in_block, :after_label, :problem)
|
29
30
|
|
30
31
|
class << self
|
32
|
+
include RText::Tokenizer
|
31
33
|
|
32
34
|
# Builds the context information based on a set of +content_lines+. Content lines
|
33
35
|
# are the RText lines containing the nested command headers in the original order.
|
34
36
|
# The cursor is assumed to be in the last context line at column +position_in_line+
|
35
37
|
def build_context(language, context_lines, position_in_line)
|
36
|
-
context_info = fix_context(context_lines, position_in_line)
|
38
|
+
context_info = fix_context(language, context_lines, position_in_line)
|
37
39
|
return nil unless context_info
|
38
40
|
element = instantiate_context_element(language, context_info)
|
39
41
|
if element
|
40
|
-
|
41
|
-
|
42
|
-
|
42
|
+
after_label = false
|
43
|
+
if context_info.role
|
44
|
+
if context_info.role.is_a?(Integer)
|
45
|
+
feature = language.unlabled_arguments(element.class.ecore)[context_info.role]
|
46
|
+
else
|
47
|
+
feature = element.class.ecore.eAllStructuralFeatures.find{|f| f.name == context_info.role}
|
48
|
+
after_label = true
|
49
|
+
end
|
50
|
+
else
|
51
|
+
feature = nil
|
52
|
+
end
|
53
|
+
Context.new(element, feature, context_info.prefix, context_info.in_array, context_info.in_block, after_label, context_info.problem)
|
43
54
|
else
|
44
|
-
Context.new(nil, nil, context_info.prefix, context_info.in_array, context_info.in_block)
|
55
|
+
Context.new(nil, nil, context_info.prefix, context_info.in_array, context_info.in_block, false, context_info.problem)
|
45
56
|
end
|
46
57
|
end
|
47
58
|
|
@@ -63,82 +74,124 @@ module ContextBuilder
|
|
63
74
|
def find_leaf_child(element, num_required_children)
|
64
75
|
childs = element.class.ecore.eAllReferences.select{|r| r.containment}.collect{|r|
|
65
76
|
element.getGenericAsArray(r.name)}.flatten
|
66
|
-
if
|
67
|
-
find_leaf_child(childs.first, num_required_children-1)
|
68
|
-
elsif num_required_children == 0
|
77
|
+
if num_required_children == 0
|
69
78
|
element
|
79
|
+
elsif childs.size > 0
|
80
|
+
find_leaf_child(childs.first, num_required_children-1)
|
70
81
|
else
|
71
82
|
nil
|
72
83
|
end
|
73
84
|
end
|
74
85
|
|
75
|
-
ContextInternal = Struct.new(:lines, :num_elements, :role, :prefix, :in_array, :in_block)
|
86
|
+
ContextInternal = Struct.new(:lines, :num_elements, :role, :prefix, :in_array, :in_block, :problem)
|
76
87
|
|
77
88
|
# extend +context_lines+ into a set of lines which can be processed by the RText
|
78
|
-
def fix_context(context_lines, position_in_line)
|
89
|
+
def fix_context(language, context_lines, position_in_line)
|
79
90
|
context_lines = context_lines.dup
|
80
91
|
# make sure there is at least one line
|
81
|
-
|
82
|
-
if context_lines.empty? || (position_in_line == 0 && context_lines.last != "")
|
92
|
+
if context_lines.empty?
|
83
93
|
context_lines << ""
|
84
94
|
end
|
85
95
|
position_in_line ||= context_lines.last.size
|
86
96
|
# cut off last line right of cursor
|
87
|
-
|
97
|
+
if position_in_line < 1
|
98
|
+
context_lines.pop
|
99
|
+
context_lines << ""
|
100
|
+
else
|
101
|
+
context_lines << context_lines.pop[0..position_in_line-1]
|
102
|
+
end
|
103
|
+
problem = nil
|
88
104
|
line = context_lines.last
|
89
|
-
if line =~
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
prefix = $1
|
104
|
-
line.sub!(/\[[^\]]*$/, "[]")
|
105
|
-
end
|
106
|
-
# labled value
|
107
|
-
elsif line =~ /\W(\w+):\s*(\S*)$/
|
108
|
-
role = $1
|
109
|
-
prefix = $2
|
105
|
+
if line =~ /\{\s*$/
|
106
|
+
# remove curly brace from last line, required for correct counting of num_elements
|
107
|
+
line.sub!(/\{\s*$/,"")
|
108
|
+
problem = :after_curly
|
109
|
+
end
|
110
|
+
|
111
|
+
num_elements = in_block = in_array = missing_comma = role = prefix = nil
|
112
|
+
tokens = tokenize(line, language.reference_regexp)
|
113
|
+
tokens.pop if tokens.last && tokens.last.kind == :newline
|
114
|
+
if tokens.size > 0 && tokens[0].kind == :identifier
|
115
|
+
if tokens.size > 1 || line =~ /\s+$/
|
116
|
+
# this line contains a new element
|
117
|
+
num_elements = 1
|
118
|
+
in_block = false
|
110
119
|
in_array = false
|
111
|
-
line.sub!(/\s*\w+:\s*\S*$/, "")
|
112
|
-
line.sub!(/,$/, "")
|
113
|
-
# unlabled value or label
|
114
|
-
elsif line =~ /[,\s](\S*)$/
|
115
120
|
role = nil
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
121
|
+
missing_comma = false
|
122
|
+
unlabled_index = 0
|
123
|
+
tokens[1..-1].each do |token|
|
124
|
+
if token.kind == "["
|
125
|
+
in_array = true
|
126
|
+
elsif token.kind == "]"
|
127
|
+
in_array = false
|
128
|
+
missing_comma = true
|
129
|
+
role = nil
|
130
|
+
elsif token.kind == :label
|
131
|
+
role = token.value.sub(/:$/, "")
|
132
|
+
elsif token.kind == ","
|
133
|
+
missing_comma = false
|
134
|
+
role = nil unless in_array
|
135
|
+
unlabled_index += 1 unless in_array
|
136
|
+
end
|
137
|
+
end
|
138
|
+
if ((tokens.size == 1 && line =~ /\s+$/) ||
|
139
|
+
tokens.last.kind == "," ||
|
140
|
+
in_array ||
|
141
|
+
([:error, :string, :integer, :float, :boolean, :identifier, :reference].
|
142
|
+
include?(tokens.last.kind) && line !~ /\s$/)) &&
|
143
|
+
!tokens.any?{|t| t.kind == :label} &&
|
144
|
+
!(problem == :after_curly)
|
145
|
+
role ||= unlabled_index
|
146
|
+
end
|
147
|
+
if [:string, :integer, :float, :boolean, :identifier, :reference].
|
148
|
+
include?(tokens.last.kind) && line =~ /\s$/ && tokens.size > 1
|
149
|
+
missing_comma = true
|
150
|
+
role = nil unless in_array
|
151
|
+
end
|
152
|
+
if [:error, :string, :integer, :float, :boolean, :identifier, :reference].
|
153
|
+
include?(tokens.last.kind) && line !~ /\s$/
|
154
|
+
prefix = tokens.last.value.to_s
|
155
|
+
else
|
156
|
+
prefix = ""
|
157
|
+
end
|
158
|
+
else
|
159
|
+
# in completion of command
|
160
|
+
num_elements = 0
|
161
|
+
missing_comma = false
|
162
|
+
in_block = (context_lines.size > 1)
|
163
|
+
prefix = tokens[0].value.to_s
|
132
164
|
role, in_array = find_role(context_lines[0..-2])
|
133
165
|
# fix single role lable
|
134
166
|
if context_lines[-2] =~ /^\s*\w+:\s*$/
|
135
167
|
context_lines[-1] = context_lines.pop
|
136
168
|
end
|
137
|
-
else
|
138
|
-
# comment, closing brackets, etc.
|
139
|
-
return nil
|
140
169
|
end
|
170
|
+
elsif line.strip.empty?
|
171
|
+
# in completion of command but without prefix
|
172
|
+
num_elements = 0
|
173
|
+
missing_comma = false
|
174
|
+
in_block = (context_lines.size > 1)
|
175
|
+
prefix = ""
|
176
|
+
role, in_array = find_role(context_lines[0..-2])
|
177
|
+
# fix single role lable
|
178
|
+
if context_lines[-2] =~ /^\s*\w+:\s*$/
|
179
|
+
context_lines[-1] = context_lines.pop
|
180
|
+
end
|
181
|
+
else
|
182
|
+
# comment, closing brackets, etc.
|
183
|
+
num_elements = 0
|
184
|
+
missing_comma = false
|
185
|
+
in_block = (context_lines.size > 1)
|
186
|
+
return nil
|
141
187
|
end
|
188
|
+
|
189
|
+
# remove prefix, a value which is currently being completed should not be part of the
|
190
|
+
# context model
|
191
|
+
if prefix && prefix.size > 0
|
192
|
+
line.slice!(-(prefix.size)..-1)
|
193
|
+
end
|
194
|
+
|
142
195
|
context_lines.reverse.each do |l|
|
143
196
|
if l =~ /\{\s*$/
|
144
197
|
context_lines << "}"
|
@@ -147,7 +200,8 @@ module ContextBuilder
|
|
147
200
|
context_lines << "]"
|
148
201
|
end
|
149
202
|
end
|
150
|
-
|
203
|
+
problem = :missing_comma if !problem && missing_comma
|
204
|
+
ContextInternal.new(context_lines, num_elements, role, prefix, in_array, in_block, problem)
|
151
205
|
end
|
152
206
|
|
153
207
|
def find_role(context_lines)
|
data/lib/rtext/default_loader.rb
CHANGED
@@ -36,10 +36,13 @@ class DefaultLoader
|
|
36
36
|
def initialize(language, fragmented_model, options={})
|
37
37
|
@lang = language
|
38
38
|
@model = fragmented_model
|
39
|
+
@files_added = []
|
40
|
+
@files_changed = []
|
41
|
+
@files_removed = []
|
39
42
|
@change_detector = RGen::Util::FileChangeDetector.new(
|
40
|
-
:file_added =>
|
41
|
-
:file_removed =>
|
42
|
-
:file_changed =>
|
43
|
+
:file_added => lambda {|f| @files_added << f },
|
44
|
+
:file_removed => lambda {|f| @files_removed << f},
|
45
|
+
:file_changed => lambda {|f| @files_changed << f})
|
43
46
|
@cache = options[:cache]
|
44
47
|
@fragment_by_file = {}
|
45
48
|
pattern = options[:pattern]
|
@@ -61,21 +64,75 @@ class DefaultLoader
|
|
61
64
|
# optionally, the proc may take second argument which is the overall number of files
|
62
65
|
# default: no after load proc
|
63
66
|
#
|
67
|
+
# :on_progress
|
68
|
+
# a proc which is called when some progress is made
|
69
|
+
# receives the current fragment being loaded, the actual work done as an integer and
|
70
|
+
# the overall work to be done as an integer
|
71
|
+
# default: no on progress proc
|
72
|
+
#
|
64
73
|
def load(options={})
|
65
74
|
@before_load_proc = options[:before_load]
|
66
75
|
@after_load_proc = options[:after_load]
|
67
76
|
files = @file_provider.call
|
68
77
|
@num_files = files.size
|
78
|
+
@files_added = []
|
79
|
+
@files_changed = []
|
80
|
+
@files_removed = []
|
69
81
|
@change_detector.check_files(files)
|
82
|
+
@progress_monitor = ProgressMonitor.new(options[:on_progress], @files_added + @files_changed)
|
83
|
+
@files_added.each {|f| file_added(f)}
|
84
|
+
@files_changed.each {|f| file_changed(f)}
|
85
|
+
@files_removed.each {|f| file_removed(f)}
|
86
|
+
@lang.reference_qualifier.call(@model.unresolved_refs, @model)
|
70
87
|
@model.resolve(:fragment_provider => method(:fragment_provider),
|
71
88
|
:use_target_type => @lang.per_type_identifier)
|
72
89
|
end
|
73
90
|
|
74
91
|
private
|
75
92
|
|
93
|
+
class ProgressMonitor
|
94
|
+
def initialize(on_progress_proc, files)
|
95
|
+
@on_progress_proc = on_progress_proc || lambda {|frag, work_done, work_overall| }
|
96
|
+
# there is a progress call twice for each element (in tokenizer and instantiator)
|
97
|
+
@work_overall = num_elements(files)*2
|
98
|
+
@work_done = 0
|
99
|
+
@work_last_sent = 0
|
100
|
+
end
|
101
|
+
|
102
|
+
def before_fragment_load(frag, kind)
|
103
|
+
@loading_cached = (kind == :load_cached)
|
104
|
+
end
|
105
|
+
|
106
|
+
def after_fragment_load(frag)
|
107
|
+
@work_done += frag.elements.size*2 if @loading_cached
|
108
|
+
@on_progress_proc.call(frag, @work_done, @work_overall)
|
109
|
+
@work_last_sent = @work_done
|
110
|
+
end
|
111
|
+
|
112
|
+
def instantiator_progress(frag)
|
113
|
+
@work_done += 1
|
114
|
+
if @work_done > @work_last_sent + 100
|
115
|
+
@on_progress_proc.call(frag, @work_done, @work_overall)
|
116
|
+
@work_last_sent = @work_done
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def num_elements(files)
|
123
|
+
result = 0
|
124
|
+
files.each do |f|
|
125
|
+
content = File.open(f, "rb"){|fh| fh.read}
|
126
|
+
result += content.scan(/\n\s*\w+\s+/).size
|
127
|
+
result += 1 if content =~ /^\s*\w+\s+/
|
128
|
+
end
|
129
|
+
result
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
76
133
|
def file_added(file)
|
77
134
|
fragment = RGen::Fragment::ModelFragment.new(file,
|
78
|
-
:identifier_provider => @lang.identifier_provider)
|
135
|
+
:identifier_provider => lambda {|e, c| @lang.identifier_provider.call(e, nil, nil, nil)})
|
79
136
|
load_fragment_cached(fragment)
|
80
137
|
@model.add_fragment(fragment)
|
81
138
|
@fragment_by_file[file] = fragment
|
@@ -88,7 +145,7 @@ class DefaultLoader
|
|
88
145
|
|
89
146
|
def file_changed(file)
|
90
147
|
fragment = RGen::Fragment::ModelFragment.new(file,
|
91
|
-
:identifier_provider => @lang.identifier_provider)
|
148
|
+
:identifier_provider => lambda {|e, c| @lang.identifier_provider.call(e, nil, nil, nil)})
|
92
149
|
load_fragment_cached(fragment)
|
93
150
|
if @dont_reload_with_errors && fragment.data[:problems].size > 0
|
94
151
|
# keep old fragment but attach new problems
|
@@ -135,6 +192,7 @@ class DefaultLoader
|
|
135
192
|
end
|
136
193
|
|
137
194
|
def call_before_load_proc(fragment, kind)
|
195
|
+
@progress_monitor.before_fragment_load(fragment, kind)
|
138
196
|
if @before_load_proc
|
139
197
|
if @before_load_proc.arity == 3
|
140
198
|
@before_load_proc.call(fragment, kind, @num_files)
|
@@ -145,6 +203,7 @@ class DefaultLoader
|
|
145
203
|
end
|
146
204
|
|
147
205
|
def call_after_load_proc(fragment)
|
206
|
+
@progress_monitor.after_fragment_load(fragment)
|
148
207
|
if @after_load_proc
|
149
208
|
if @after_load_proc.arity == 2
|
150
209
|
@after_load_proc.call(fragment, @num_files)
|
@@ -160,20 +219,26 @@ class DefaultLoader
|
|
160
219
|
problems = []
|
161
220
|
root_elements = []
|
162
221
|
inst = RText::Instantiator.new(@lang)
|
163
|
-
File.open(fragment.location) do |f|
|
222
|
+
File.open(fragment.location, "rb") do |f|
|
164
223
|
inst.instantiate(f.read,
|
165
224
|
:env => env,
|
166
225
|
:unresolved_refs => urefs,
|
167
226
|
:problems => problems,
|
168
227
|
:root_elements => root_elements,
|
169
228
|
:fragment_ref => fragment.fragment_ref,
|
170
|
-
:file_name => fragment.location
|
229
|
+
:file_name => fragment.location,
|
230
|
+
:on_progress => lambda do
|
231
|
+
@progress_monitor.instantiator_progress(fragment)
|
232
|
+
end)
|
171
233
|
end
|
172
|
-
|
234
|
+
# data might have been created during instantiation (e.g. comment or annotation handler)
|
235
|
+
fragment.data ||= {}
|
236
|
+
fragment.data[:problems] = problems
|
173
237
|
fragment.set_root_elements(root_elements,
|
174
238
|
:unresolved_refs => urefs,
|
175
239
|
:elements => env.elements)
|
176
240
|
fragment.build_index
|
241
|
+
@lang.reference_qualifier.call(urefs, fragment)
|
177
242
|
fragment.resolve_local(:use_target_type => @lang.per_type_identifier)
|
178
243
|
end
|
179
244
|
|