edubkendo
9/26/2013 - 5:16 AM

Rsense hooked up to subl

Rsense hooked up to subl

import sublime
import sublime_plugin
import subprocess
import re
import os
import tempfile

# RUBY_METHOD_SEP_PATTERN = re.compile('[^.:]*$')
RUBY_METHOD_SEP_PATTERN = re.compile('((?<=\.).*$)|((?<=::).*$)')

class RsenseCompletions(sublime_plugin.EventListener):

    def get_project(self, view):
      fn = view.file_name()
      project = view.window().folders()
      if fn != None:
        return("--detect-project=" + str(fn) + " ")
      elif len(project) > 0:
        return("--detect-project=" + str(project[0]) + " ")
      else:
        return("")

    def get_temp_file(self, view):
      text = view.substr(sublime.Region(0, view.size()))
      if text != None:
        open_file, file_path = tempfile.mkstemp()
        open_file = os.fdopen(open_file, 'w')
        open_file.write(text)
        open_file.close()
        return(file_path)
      else:
        return(None)

    def make_command(self, view, prefix, location, path):
      rsense_com = "ruby /home/eric/IdeaProjects/rsense/bin/rsense code-completion "
      detect_proj = self.get_project(view)

      filestring = "--file=" + str(path) + " "

      if prefix != "" and prefix != None:
        prefix_str = "--prefix=" + prefix + " "
      else:
        prefix_str = ""

      loc_str = "--location=" + str(location) + " "
      return(rsense_com + detect_proj + filestring + prefix_str + loc_str)

    def run_command(self, command_string):
      pipe = subprocess.Popen(command_string, shell=True, stdout=subprocess.PIPE)
      output, error = pipe.communicate()
      if error != None:
        print(error)
      return(output)

    def _sanitize_output(self, output):
      return output.decode('utf-8')

    def _parse_output(self, output):
        lines = output.split("\n")
        line_parts = [line.split(" ", 5)for line in lines]
        return line_parts

    def clean_and_arrange(self, output):
      if output == None:
        return []

      completions = []
      parsed = self._parse_output(self._sanitize_output(output).strip())

      for line in parsed:
        if len(line) >= 5:
          show_string = line[1] + "\t" + line[3] + "\t" + line[4]
          compl = line[1]
          completions.append((show_string, compl))

      return completions

    # TODO: Filter completions for metadata returned by rsense.
    def get_completions(self, view, prefix, location, path):
      command_string = self.make_command(view, prefix, location, path)
      raw_output = self.run_command(command_string)
      return(self.clean_and_arrange(raw_output))


    def is_ruby_scope(self, view, location):
      scopes = [
                "source.ruby - comment",
                "source.ruby.rspec - string - comment"
      ]
      match = False

      for scope in scopes:

        if view.match_selector(location, scope):
          match = True

      return(match)

    def on_query_completions(self, view, prefix, locations):

      if locations == None:
        return []

      location = locations[0]

      if not self.is_ruby_scope(view, location):
        return []

      row, col = view.rowcol(location)
      line_start_offset = location - col
      line_text = view.substr(sublime.Region(line_start_offset, location + 1))

      if not RUBY_METHOD_SEP_PATTERN.search(line_text):
        return []

      tmp = self.get_temp_file(view)

      if tmp == None:
        return []

      return(self.get_completions(view, prefix, location, tmp))