Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruby: Lint: added Rubocop linter #2749

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/chrome/komodo/content/pref/pref-syntax-checking.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,23 @@ function javaScriptInfo(languageName) {
};
}

languageInfo.Ruby = {
browseForRubocopBinary: () => {
let rubocop_binary = document.getElementById('rubocop_binary');
let currentPath = rubocop_binary.value;
let path = ko.filepicker.browseForExeFile(null, currentPath || "");
if (path)
rubocop_binary.value = path;
},
browseForRubocopConfig: () => {
let rubocop_config = document.getElementById('rubocop_config');
let currentPath = rubocop_config.value;
let path = ko.filepicker.browseForExeFile(null, currentPath || "");
if (path)
rubocop_config.value = path;
}
};

function typescript_setup() {
if (!('TypeScript' in dialog)) {
dialog.TypeScript = {};
Expand Down
40 changes: 40 additions & 0 deletions src/chrome/komodo/content/pref/pref-syntax-checking.xul
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,46 @@
</menulist>
</hbox>
</groupbox>
<groupbox orient="vertical">
<caption label="&rubocopChecking.label;"/>
<description>
&rubocopChecking.description;
</description>
<hbox align="center">
<checkbox id="lint_rubocop_enabled"
pref="true"
preftype="boolean"
label="&rubocopChecking.checkbox;" />
</hbox>
<hbox>
<description>
&rubocopChecking.binary;
</description>
<textbox id="rubocop_binary"
flex="1"
value=''
pref="true"
placeholder="&rubocopChecking.binaryPlaceholder;"
preftype="string"/>
<button id='rubocop_linter_browse'
label="&browse.label;"
oncommand="languageInfo.Ruby.browseForRubocopBinary();"/>
</hbox>
<hbox>
<description>
&rubocopChecking.config;
</description>
<textbox id="rubocop_config"
flex="1"
value=''
pref="true"
placeholder="&rubocopChecking.configPlaceholder;"
preftype="string"/>
<button id='eslint_config_browse'
label="&browse.label;"
oncommand="languageInfo.Ruby.browseForRubocopConfig();"/>
</hbox>
</groupbox>
</vbox>

<vbox id="langSyntaxCheck-Sass">
Expand Down
7 changes: 7 additions & 0 deletions src/chrome/komodo/locale/en-US/pref/pref.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,13 @@ adding an additional caret at the clicked position.">
<!ENTITY rubyDebuggerNotWorking.description "The Ruby debugger extension does not work with the version of Ruby selected or that is on your path. You need to use Ruby version 1.8.2 or later. You can get Ruby from the Ruby home page at">
<!ENTITY filePrefRubyUseThisInterpreter.label "Use this interpreter">
<!ENTITY filePrefRubyLevelStricness.description "You can configure the level of strictness that is used when doing background syntax checks.">
<!ENTITY rubocopChecking.label "Rubocop Linter Checking">
<!ENTITY rubocopChecking.checkbox "Enable the Rubocop linter">
<!ENTITY rubocopChecking.description "Use the Rubocop linter when doing background syntax checking.">
<!ENTITY rubocopChecking.binary "Rubocop binary:">
<!ENTITY rubocopChecking.binaryPlaceholder "Find on path...">
<!ENTITY rubocopChecking.config "Rubocop config:">
<!ENTITY rubocopChecking.configPlaceholder "Find in current working directory...">
<!ENTITY filePrefRubyAdditionalDirectory.description "Specify any additional directories that you want Komodo to add to the Ruby path when debugging, syntax checking or in the interactive shell.">
<!ENTITY filePrefRubyExcludeDirectory.description "Specify any directories you want to exclude from code autocompletion scans.">

Expand Down
1 change: 1 addition & 0 deletions src/lint/Conscript
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ if ($havePy2to3) {
$cons->InstallXpcomComponent('koCSSExLinter.py');
$cons->InstallXpcomComponent('koHTMLLinter.py');
$cons->InstallXpcomComponent('koPHPLinter.py');
$cons->InstallXpcomComponent('koRubocopLinter.py');
$cons->InstallXpcomComponent('koEsLintLinter.py');
$cons->InstallXpcomComponent('koJavaScriptLinter.py');
$cons->InstallXpcomComponent('koLintService.py');
Expand Down
110 changes: 110 additions & 0 deletions src/lint/koRubocopLinter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from xpcom import components
from koLintResult import KoLintResult, SEV_ERROR, SEV_WARNING, SEV_INFO
from koLintResults import koLintResults
import os
import logging
import tempfile
import process
import koprocessutils
import which
import json

Cc = components.classes
Ci = components.interfaces

log = logging.getLogger("koRubocopLinter")
#log.setLevel(logging.DEBUG)


class KoRubocopLinter(object):
_com_interfaces_ = [Ci.koILinter]
_reg_clsid_ = "{0BED01B1-6BAD-4B55-A407-3C6273C0032D}"
_reg_contractid_ = "@addons.defman.me/koRubocopLinter;1"
_reg_categories_ = [
("category-komodo-linter", 'Ruby'),
]

def __init__(self,):
self.ignore_cops = ["Style/FileName"]
self.file_ext = '.rb'
self.project = Cc["@activestate.com/koPartService;1"].getService(Ci.koIPartService)
self.ruby_linter = Cc["@activestate.com/koLinter?language=Ruby;1"].getService(Ci.koILinter)

def lint(self, request):
text = request.content.encode(request.encoding.python_encoding_name)
return self.lint_with_text(request, text)

def lint_with_text(self, request, text):
if not request.prefset.getBoolean("lint_rubocop_enabled", False):
log.debug("Rubocop: not enabled")
return self.ruby_linter.lint(request)
try:
rubocop = request.prefset.getString('rubocop_binary' ,'')
if rubocop == '':
log.debug('Rubocop: looking for the rubocop executable on $PATH')
rubocop = which.which('rubocop')
except which.WhichError:
log.debug("Rubocop: rubocop is not found")
return self.ruby_linter.lint(request)

cwd = None
cmd = []
rbfile = None

if self.project.currentProject is not None:
cwd = self.project.currentProject.liveDirectory
log.debug("Rubocop: using current project directory")
else:
cwd = request.cwd
log.debug("Rubocop: cwd = %s" % (cwd))

if cwd is not None:
for ext in ['yaml', 'yml']:
config = os.path.join(cwd, '.rubocop.{}'.format(ext))
if os.path.exists(config):
log.debug("Config file: {}".format(config))
break
else:
config = request.prefset.getString('rubocop_config', '')
log.debug("Config file (set by user): {}".format(config))
if config and os.path.isfile(config):
cmd = [rubocop, '--format', 'json', '--config', config]
else:
cmd = [rubocop, '--format', 'json']
log.debug("Rubocop: .rubocop.yml or .rubocop.yaml are not found")

cmd += ['--stdin', request.koDoc.file.encodedPath]

log.debug("Rubocop: command = %s" % (" ".join(cmd)))

env = koprocessutils.getUserEnv()
cwd = cwd or None
p = process.ProcessOpen(cmd, cwd=cwd, env=env, stdin=process.PIPE)
stdout, stderr = p.communicate(input=text)

results = koLintResults()
data = json.loads(stdout)['files'][0]

for offense in data['offenses']:
if offense['cop_name'] in self.ignore_cops:
log.debug("Rubocop: cop '%s' ignored" % (offense['cop_name']))
continue
line = offense['location']['line']
column = offense['location']['column']
column_end = column + offense['location']['length']
if offense['severity'] in ['refactor', 'convention']:
severity = SEV_INFO
elif offense['severity'] == "warning":
severity = SEV_WARNING
else:
severity = SEV_ERROR
description = "%s: %s" % (offense['cop_name'], offense['message'])
result = KoLintResult(description=description,
severity=severity,
lineStart=line,
lineEnd=line,
columnStart=column,
columnEnd=column_end)
results.addResult(result)
log.debug("Rubocop: lint results: %d" % (len(data['offenses'])))
return results