Skip to content

Instantly share code, notes, and snippets.

@mitranim
Last active November 9, 2018 11:42
Show Gist options
  • Save mitranim/0d4adc3f470b3d72fd0f22299ad9abce to your computer and use it in GitHub Desktop.
Save mitranim/0d4adc3f470b3d72fd0f22299ad9abce to your computer and use it in GitHub Desktop.
SublimeLinter eslint_d plugin. Uses the eslint_d daemon as it's meant to be used.
from os import path
import socket
import json
import re
import sublime
import sys
import uuid
from SublimeLinter.lint import NodeLinter
from SublimeLinter.lint.linter import LintMatch
PORTFILE = path.expanduser('~') + '/.eslint_d'
ERROR_MARKER = '# exit 1'
CONFIG_ERROR_RE = re.compile(r'Configuration for rule ["\w-]+ is invalid')
NOT_RUNNING_FLAG = str(uuid.uuid4())
def guess_view_dir(view):
return (
view.file_name() and path.dirname(view.file_name()) or
view.window() and
view.window().folders() and
len(view.window().folders()) and
view.window().folders()[0]
)
class Eslint(NodeLinter):
# Only JS
defaults = {
'selector': 'source.js',
}
# We could also enable linting in embedded JS, such as inside HTML. However,
# in practice it would be more annoying than useful. Embedded scripts follow
# their own rules.
# No subprocesses
cmd = None
# Note: this is tightly coupled to the '--format=compact' option
regex = re.compile(
r'^.+?: line (?P<line>\d+), col (?P<col>\d+), '
r'(?:(?P<error>Error)|(?P<warning>Warning)) - '
r'(?P<message>.+)'
)
def run(self, _cmd, code):
# TODO automatically start eslint_d when the portfile doesn't exist.
# For now, we tell the user to run `eslint_d start`.
try:
with open(PORTFILE) as portfile:
[port, token] = portfile.read().split()
port = int(port)
except Exception as err:
return NOT_RUNNING_FLAG
msg = token + ' ' + json.dumps({
'cwd': guess_view_dir(self.view),
'args': ['--stdin', '--format=compact'],
'text': code,
}, ensure_ascii=False)
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', port))
sock.sendall(bytes(msg, 'utf8'))
sock.shutdown(socket.SHUT_WR)
body = sock.recv(2**24)
sock.close()
return body.decode('utf8')
except ConnectionRefusedError as err:
# Probably a stale portfile, left after an abnormal exit. This means
# eslint_d is not actually running.
return NOT_RUNNING_FLAG
def find_errors(self, output):
if output == NOT_RUNNING_FLAG:
return [LintMatch(
match=True,
error='Error',
message='eslint_d daemon not found. Run `eslint_d start` from terminal.',
line=0,
col=0,
)]
match = CONFIG_ERROR_RE.search(output)
if match:
if output.endswith(ERROR_MARKER):
output = output[:-len(ERROR_MARKER)].strip()
return [LintMatch(match=match, error='Error', message=output, line=0, col=0)]
return super().find_errors(output)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment