diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..cc1923a --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.8 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fb62dc4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: python -python: - - "3.3" -# command to install dependencies -install: - - pip install flake8 - - pip install pydocstyle -# command to run tests -script: - - flake8 . --max-line-length=120 - - pydocstyle . --add-ignore=D202 diff --git a/linter.py b/linter.py index c2d85df..b38b88b 100644 --- a/linter.py +++ b/linter.py @@ -1,9 +1,9 @@ # # linter.py -# Linter for SublimeLinter3, a code checking framework for Sublime Text 3 +# Linter for SublimeLinter, a code checking framework for Sublime Text # # Written by Aparajita Fishman -# Copyright (c) 2015-2016 The SublimeLinter Community +# Copyright (c) 2015-2025 The SublimeLinter Community # Copyright (c) 2013-2014 Aparajita Fishman # # License: MIT @@ -23,56 +23,63 @@ class Ruby(RubyLinter): } cmd = 'ruby -wc' - regex = ( - r'^(?P.+?):(?P\d+): (?:(?P.*?error)|(?Pwarning))[,:] (?P[^\r\n]+)\r?\n' - r'(?:^[^\r\n]+\r?\n^(?P.*?)\^)?' - ) - multiline = True - comment_re = r'\s*#' + regex = r""" + (?xm) + ^(?:(?P.*:\s)?)? # optional "C:/ruby...:" prefix + (?P.+?):(?P\d+): # file and line + (?:\s?(?:(?P.*?error)s?|(?Pwarning))) # "syntax error" or warning + [,:]?\s(?P[^\n]+) # headline message + (?:\n # optional multiline block + (?: + (?:\s*\d+\s*\|[^\n]*\n)* # optional leading context lines + >\s*(?P\d+)\s*\|[^\n]*\n # culprit line + \s*\|\s(?P.*?)\^\s # caret line with message + (?P[^\n]*) # rest of caret line (error text) + )? + )? + """ on_stderr = None def split_match(self, match): """ - Return the components of the match. - - We override this because unrelated library files can throw errors, - and we only want errors from the linted file. + Return the error as matched by the regex. + We override this for a better error message. """ - if match: - if match.group('file') != '-': - match = None - - match, line, col, error, warning, message, _ = super().split_match(match) - near = self.search_token(message) + error = super().split_match(match) + if culprit_message := error.get("culprit_message", None): + error["message"] = culprit_message + error["near"] = self.search_token(error.message) + if error.error: + error["error"] = error.error.replace(" ", "-") - return match, line, col, error, warning, message, near + return error def search_token(self, message): """Search text token to be highlighted.""" # First search for variable name enclosed in quotes - m = re.search("(?<=`).*(?=')", message) + m = re.search(r"(?<=`).*(?=')", message) # Then search for variable name following a dash if m is None: - m = re.search('(?<= - )\S+', message) + m = re.search(r'(?<= - )\S+', message) # Then search for mismatched indentation if m is None: - m = re.search("(?<=mismatched indentations at ')end", message) + m = re.search(r"(?<=mismatched indentations at ')end", message) # Then search for equal operator in conditional if m is None: - m = re.search('(?<=found )=(?= in conditional)', message) + m = re.search(r'(?<=found )=(?= in conditional)', message) # Then search for use of operator in void context if m is None: - m = re.search('\S+(?= in void context)', message) + m = re.search(r'\S+(?= in void context)', message) # Then search for END in method if m is None: - m = re.search('END(?= in method)', message) + m = re.search(r'END(?= in method)', message) return m.group(0) if m else None