Class: Rsense::Server::Command::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/rsense/server/command.rb

Defined Under Namespace

Classes: CompletionCandidate

Constant Summary collapse

LoadResult =
Java::org.cx4a.rsense::LoadResult

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Command

Returns a new instance of Command.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rsense/server/command.rb', line 47

def initialize(options)
  @context = Rsense::Server::Context.new
  @context.loadPathLevel = 0
  @options = options
  @errors = []
  @placeholders = []

  @type_inference_method = Rsense::Server::Command::TypeInferenceMethod.new()

  @require_method = Rsense::Server::Command::SpecialMeth.new() do |runtime, receivers, args, blcck, result|
    if args
      feature = Java::org.cx4a.rsense.typing.vertex::Vertex.getString(args[0])
      if feature
        rrequire(@context.project, feature, false, @context.loadPathLevel + 1)
      end
    end
  end

  @require_relative_method = Rsense::Server::Command::SpecialMeth.new() do |runtime, receivers, args, blcck, result|
    if args
      feature = Java::org.cx4a.rsense.typing.vertex::Vertex.getString(args[0])
      if feature
        files = Dir.glob(Pathname.new(args.first.node.position.file).dirname.join("#{feature}*"))
        files.each do |f|
          pth = Pathname.new(f).expand_path
          if pth.file?
            rload(project, f, "UTF-8", false)
          end
        end
      end
    end
  end

  @require_next_method = Rsense::Server::Command::SpecialMeth.new() do |runtime, receivers, args, blcck, result|
    if @context.feature
      rrequire(@context.project, @context.feature, false, @context.loadPathLevel + 1)
    end
  end

  @native_attr_method = Rsense::Server::Command::NativeAttrMethod.new()

  @alias_native_method = Rsense::Server::Command::AliasNativeMethod.new()

  clear()
end

Instance Attribute Details

#astObject

Returns the value of attribute ast.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def ast
  @ast
end

#contextObject

Returns the value of attribute context.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def context
  @context
end

#definitionFinderObject

Returns the value of attribute definitionFinder.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def definitionFinder
  @definitionFinder
end

#errorsObject

Returns the value of attribute errors.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def errors
  @errors
end

#graphObject

Returns the value of attribute graph.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def graph
  @graph
end

#optionsObject

Returns the value of attribute options.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def options
  @options
end

#parserObject

Returns the value of attribute parser.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def parser
  @parser
end

#placeholdersObject

Returns the value of attribute placeholders.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def placeholders
  @placeholders
end

#projectObject

Returns the value of attribute project.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def project
  @project
end

#projectsObject

Returns the value of attribute projects.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def projects
  @projects
end

#require_methodObject

Returns the value of attribute require_method.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def require_method
  @require_method
end

#require_next_methodObject

Returns the value of attribute require_next_method.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def require_next_method
  @require_next_method
end

#require_relative_methodObject

Returns the value of attribute require_relative_method.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def require_relative_method
  @require_relative_method
end

#resultObject

Returns the value of attribute result.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def result
  @result
end

#sandboxObject

Returns the value of attribute sandbox.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def sandbox
  @sandbox
end

#type_inference_methodObject

Returns the value of attribute type_inference_method.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def type_inference_method
  @type_inference_method
end

#whereListenerObject

Returns the value of attribute whereListener.



45
46
47
# File 'lib/rsense/server/command.rb', line 45

def whereListener
  @whereListener
end

Instance Method Details

#builtin_path(project) ⇒ Object



201
202
203
# File 'lib/rsense/server/command.rb', line 201

def builtin_path(project)
  Pathname.new(project.stubs.select { |stub| stub.match(/builtin/)}.first)
end

#check_shebang(source) ⇒ Object



138
139
140
141
# File 'lib/rsense/server/command.rb', line 138

def check_shebang(source)
  return true unless source.match(/^#!/)
  source.match(/^(#!)(\/\w+)*\/ruby/)
end

#clearObject



311
312
313
314
315
316
317
318
319
320
# File 'lib/rsense/server/command.rb', line 311

def clear
  @parser = Rsense::Server::Parser.new
  @context.clear()
  @projects = {}
  @sandbox = Rsense::Server::Project.new("(sandbox)", Pathname.new("."))
  @definitionFinder = Rsense::Server::Listeners::FindDefinitionEventListener.new(@context)
  @whereListener = Rsense::Server::Listeners::WhereEventListener.new(@context)
  open_project(@sandbox)
  prepare_project()
end

#code_completion(file, location, code_str = "") ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/rsense/server/command.rb', line 238

def code_completion(file, location, code_str="")
  prepare(@project)
  if code_str.empty?
    code = Rsense::Server::Code.new(Pathname.new(file).read)
  else
    code = Rsense::Server::Code.new(code_str)
  end

  begin
    source = code.inject_inference_marker(location)
    @ast = @parser.parse_string(source, file.to_s)
    @project.graph.load(@ast)
    # result = Java::org.cx4a.rsense::CodeCompletionResult.new
    # result.setAST(@ast)
  rescue Java::OrgJrubyparserLexer::SyntaxException => e
    @errors << e
  end

  candidates = []
  @receivers = []

  @context.typeSet.each do |receiver|
    @receivers << receiver
    ruby_class = receiver.getMetaClass
    ruby_class.getMethods(true).each do |name|
      rmethod = ruby_class.searchMethod(name)
      candidates << CompletionCandidate.new(name, rmethod.toString(), rmethod.getModule().getMethodPath(nil), method_kind)
    end
    if receiver.to_java_object.java_kind_of?(Java::org.cx4a.rsense.ruby::RubyModule)
      rmodule = receiver
      rmodule.getConstants(true).each do |name|
        direct_module = rmodule.getConstantModule(name)
        constant = direct_module.getConstant(name)
        base_name = direct_module.toString()
        qname = "#{base_name}::#{name}"
        kind = kind_check(constant)
        candidates << CompletionCandidate.new(name, qname, base_name, kind)
      end
    end
  end
  candidates
end

#deep_check(gem_path, dep_paths, feature) ⇒ Object



227
228
229
230
231
232
# File 'lib/rsense/server/command.rb', line 227

def deep_check(gem_path, dep_paths, feature)
  checkpaths = gem_path + dep_paths
  checkpaths.map do |p|
    Dir.glob(Pathname.new(p).join("**/*#{feature}*"))
  end.flatten.compact
end

#dependency_matches(dependencies, feature) ⇒ Object



213
214
215
216
217
218
# File 'lib/rsense/server/command.rb', line 213

def dependency_matches(dependencies, feature)
  dmatch = dependencies.select { |d| d.name =~ /#{feature}/ }
  if dmatch
    dmatch.map { |dm| Pathname.new(dm.path.first) unless dm.path.first == nil }.compact
  end
end

#dependency_paths(dependencies) ⇒ Object



209
210
211
# File 'lib/rsense/server/command.rb', line 209

def dependency_paths(dependencies)
  dependencies.map { |d| Pathname.new(d.path.first).parent }.flatten
end

#kind_check(constant) ⇒ Object



285
286
287
288
289
290
291
292
293
# File 'lib/rsense/server/command.rb', line 285

def kind_check(constant)
  if constant.class == Java::org.cx4a.rsense.ruby::RubyClass
    Java::org.cx4a.rsense::CodeCompletionResult::CompletionCandidate::Kind::CLASS
  elsif constant.class == Java::org.cx4a.rsense.ruby::RubyModule
    Java::org.cx4a.rsense::CodeCompletionResult::CompletionCandidate::Kind::MODULE
  else
    Java::org.cx4a.rsense::CodeCompletionResult::CompletionCandidate::Kind::CONSTANT
  end
end

#load_builtin(project) ⇒ Object



193
194
195
196
197
198
199
# File 'lib/rsense/server/command.rb', line 193

def load_builtin(project)
  builtin = builtin_path(project)
  rload(project, builtin, "UTF-8", false)
  project.stubs.each do |p|
    rload(project, Pathname.new(p), "UTF-8", false) unless p.match(/builtin/)
  end
end

#load_gem(project, source) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rsense/server/command.rb', line 125

def load_gem(project, source)
  begin
    @ast = @parser.parse_string(source.source, source.name)
    project.graph.load(@ast)
  rescue Java::OrgJrubyparserLexer::SyntaxException => e
    @errors << e
  rescue Java::JavaLang::NullPointerException => e
    @errors << e
  rescue Java::JavaUtil::ConcurrentModificationException => e
      @errors << e
  end
end

#load_path_matches(project, feature) ⇒ Object



220
221
222
223
224
225
# File 'lib/rsense/server/command.rb', line 220

def load_path_matches(project, feature)
  load_path = project.load_path
  load_path.compact.map do |lp|
    Dir.glob(Pathname.new(lp).join("**/*#{feature}*"))
  end.flatten.compact.reject {|f| File.directory?(f) }
end

#method_kindObject



281
282
283
# File 'lib/rsense/server/command.rb', line 281

def method_kind
  Java::org.cx4a.rsense::CodeCompletionResult::CompletionCandidate::Kind::METHOD
end

#open_project(project) ⇒ Object



234
235
236
# File 'lib/rsense/server/command.rb', line 234

def open_project(project)
  @projects[project.name] = project
end

#prepare(project) ⇒ Object



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rsense/server/command.rb', line 295

def prepare(project)
  @context.project = project
  @context.typeSet = Java::org.cx4a.rsense.typing::TypeSet.new
  @context.main = true
  @type_inference_method.context = @context
  @graph = project.graph
  @native_attr_method.graph = @graph
  @graph.addSpecialMethod(Rsense::Server::Command::TYPE_INFERENCE_METHOD_NAME, @type_inference_method)
  @graph.addSpecialMethod("require", @require_method)
  @graph.addSpecialMethod("require_next", @require_next_method)
  @graph.addSpecialMethod("require_relative", @require_relative_method)
  @graph.addSpecialMethod("native_accessor", @native_attr_method)
  @graph.addSpecialMethod("alias_native", @alias_native_method)
  load_builtin(project)
end

#prepare_projectObject



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/rsense/server/command.rb', line 328

def prepare_project()
  if @options.name
    name = @options.name
  else
    name = "(sandbox)"
  end
  file = @options.project_path
  @project = Rsense::Server::Project.new(name, file)
  prepare(project)
  set_features_loaded(@project.dependencies)
  codes = Rsense::Server::Command::Preload.dependency_code(@project.dependencies)
  codes.each do |c|
    load_gem(@project, c)
  end
end

#rload(project, file, encoding, prep) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rsense/server/command.rb', line 93

def rload(project, file, encoding, prep)
  file = Pathname.new(file)
  feature = file.basename.to_s.sub(file.extname, "")
  return LoadResult.alreadyLoaded() if project.loaded?(file)
  return LoadResult.alreadyLoaded() if project.loaded?(feature)
  return if file.extname =~ /(\.so|\.dylib|\.dll|\.java|\.class|\.jar|\.c$|\.h$|\.m$|\.js|\.html|\.css)/

  project.loaded << file

  oldmain = @context.main

  if prep
    prepare(project)
  else
    @context.main = false
  end
  return if file.directory?

  source = file.read
  return unless check_shebang(source)

  begin
    @ast = @parser.parse_string(source, file.to_s)
    project.graph.load(@ast)

  rescue Java::OrgJrubyparserLexer::SyntaxException => e
    @errors << e
  rescue Java::JavaUtil::ConcurrentModificationException => e
    @errors << e
  end
end

#rrequire(project, feature, background, loadPathLevel = 0) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/rsense/server/command.rb', line 143

def rrequire(project, feature, background, loadPathLevel=0)

  encoding = "UTF-8"

  lplevel = @context.loadPathLevel
  @context.loadPathLevel = loadPathLevel
  if lplevel > 2 && background == false
    return @placeholders << [project, feature]
  end

  return LoadResult.alreadyLoaded() if project.loaded?(feature)

  if PROJMAN && PROJMAN.roptions && PROJMAN.roptions.project_path
    project_matches = Dir.glob(Pathname.new(PROJMAN.roptions.project_path).join("**/#{feature}*"))
    if project_matches
      project_matches.each do |p|
        return rload(project, p, "UTF-8", false)
      end
    end
  end

  stubs = stub_matches(project, feature)
  stubs.each do |stub|
    return rload(project, Pathname.new(stub), encoding, false)
  end

  lpmatches = load_path_matches(project, feature)
  lpmatches.each do |lp|
    return rload(project, lp, encoding, false)
  end

  unless lpmatches
    dependencies = project.dependencies
    dpmatches = dependency_matches(dependencies, feature)
    dpmatches.each do |dp|
      rload(project, dp, encoding, false)
    end
  end

  unless lpmatches || dpmatches
    dep_paths = dependency_paths(dependencies)
    gem_path = project.gem_path.map {|gp| Pathname.new(gp) }

    checked = deep_check(gem_path, dep_paths, feature)
    checked.each do |cp|
      rload(project, cp, encoding, false)
    end
  end
end

#set_features_loaded(deps) ⇒ Object



322
323
324
325
326
# File 'lib/rsense/server/command.rb', line 322

def set_features_loaded(deps)
  deps.each do |d|
    @project.loaded << d.name
  end
end

#stub_matches(project, feature) ⇒ Object



205
206
207
# File 'lib/rsense/server/command.rb', line 205

def stub_matches(project, feature)
  project.stubs.select { |stub| stub.to_s =~ /#{feature}/ }
end