rtext 0.4.0 → 0.5.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/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
|
|