From fad95ce3f744d7d233a2f9eb8001314ebcfe443d Mon Sep 17 00:00:00 2001 From: Alan Hamlett Date: Thu, 15 Mar 2018 01:33:38 -0700 Subject: [PATCH] Upgrade wakatime-cli to v10.1.2 --- plugin/packages/wakatime/__about__.py | 2 +- .../wakatime/dependencies/__init__.py | 10 ++- .../packages/wakatime/dependencies/c_cpp.py | 4 +- plugin/packages/wakatime/dependencies/data.py | 4 +- .../packages/wakatime/dependencies/dotnet.py | 4 +- plugin/packages/wakatime/dependencies/elm.py | 47 ++++++++++ plugin/packages/wakatime/dependencies/go.py | 4 +- .../packages/wakatime/dependencies/haskell.py | 53 +++++++++++ plugin/packages/wakatime/dependencies/haxe.py | 48 ++++++++++ .../dependencies/{templates.py => html.py} | 68 +------------- .../wakatime/dependencies/javascript.py | 60 +++++++++++++ plugin/packages/wakatime/dependencies/jvm.py | 90 ++++++++++++++++++- .../wakatime/dependencies/objective.py | 84 +++++++++++++++++ plugin/packages/wakatime/dependencies/php.py | 8 +- .../packages/wakatime/dependencies/python.py | 4 +- plugin/packages/wakatime/dependencies/rust.py | 48 ++++++++++ .../packages/wakatime/dependencies/unknown.py | 4 +- plugin/packages/wakatime/exceptions.py | 5 ++ plugin/packages/wakatime/heartbeat.py | 18 ++-- .../packages/pygments/lexers/javascript.py | 4 +- plugin/packages/wakatime/stats.py | 44 ++++++++- 21 files changed, 520 insertions(+), 93 deletions(-) create mode 100644 plugin/packages/wakatime/dependencies/elm.py create mode 100644 plugin/packages/wakatime/dependencies/haskell.py create mode 100644 plugin/packages/wakatime/dependencies/haxe.py rename plugin/packages/wakatime/dependencies/{templates.py => html.py} (81%) create mode 100644 plugin/packages/wakatime/dependencies/javascript.py create mode 100644 plugin/packages/wakatime/dependencies/objective.py create mode 100644 plugin/packages/wakatime/dependencies/rust.py diff --git a/plugin/packages/wakatime/__about__.py b/plugin/packages/wakatime/__about__.py index b680411..e8ddfd3 100644 --- a/plugin/packages/wakatime/__about__.py +++ b/plugin/packages/wakatime/__about__.py @@ -1,7 +1,7 @@ __title__ = 'wakatime' __description__ = 'Common interface to the WakaTime api.' __url__ = 'https://github.com/wakatime/wakatime' -__version_info__ = ('10', '1', '0') +__version_info__ = ('10', '1', '2') __version__ = '.'.join(__version_info__) __author__ = 'Alan Hamlett' __author_email__ = 'alan@wakatime.com' diff --git a/plugin/packages/wakatime/dependencies/__init__.py b/plugin/packages/wakatime/dependencies/__init__.py index dccb3bf..b590ecb 100644 --- a/plugin/packages/wakatime/dependencies/__init__.py +++ b/plugin/packages/wakatime/dependencies/__init__.py @@ -106,8 +106,8 @@ class DependencyParser(object): self.lexer = lexer if self.lexer: - module_name = self.lexer.__module__.rsplit('.', 1)[-1] - class_name = self.lexer.__class__.__name__.replace('Lexer', 'Parser', 1) + module_name = self.root_lexer.__module__.rsplit('.', 1)[-1] + class_name = self.root_lexer.__class__.__name__.replace('Lexer', 'Parser', 1) else: module_name = 'unknown' class_name = 'UnknownParser' @@ -121,6 +121,12 @@ class DependencyParser(object): except ImportError: log.debug('Parsing dependencies not supported for {0}.{1}'.format(module_name, class_name)) + @property + def root_lexer(self): + if hasattr(self.lexer, 'root_lexer'): + return self.lexer.root_lexer + return self.lexer + def parse(self): if self.parser: plugin = self.parser(self.source_file, lexer=self.lexer) diff --git a/plugin/packages/wakatime/dependencies/c_cpp.py b/plugin/packages/wakatime/dependencies/c_cpp.py index 8729743..3d4eb6d 100644 --- a/plugin/packages/wakatime/dependencies/c_cpp.py +++ b/plugin/packages/wakatime/dependencies/c_cpp.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.c_cpp - ~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.c_cpp + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from C++ code. diff --git a/plugin/packages/wakatime/dependencies/data.py b/plugin/packages/wakatime/dependencies/data.py index 389a1b6..121b70b 100644 --- a/plugin/packages/wakatime/dependencies/data.py +++ b/plugin/packages/wakatime/dependencies/data.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.data - ~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.data + ~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from data files. diff --git a/plugin/packages/wakatime/dependencies/dotnet.py b/plugin/packages/wakatime/dependencies/dotnet.py index 7d67341..53557e9 100644 --- a/plugin/packages/wakatime/dependencies/dotnet.py +++ b/plugin/packages/wakatime/dependencies/dotnet.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.dotnet - ~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.dotnet + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from .NET code. diff --git a/plugin/packages/wakatime/dependencies/elm.py b/plugin/packages/wakatime/dependencies/elm.py new file mode 100644 index 0000000..86db024 --- /dev/null +++ b/plugin/packages/wakatime/dependencies/elm.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.elm + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from Elm code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +from . import TokenParser + + +class ElmParser(TokenParser): + state = None + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Namespace': + self._process_namespace(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + elif self.partial(token) == 'Class': + self._process_class(token, content) + else: + self._process_other(token, content) + + def _process_namespace(self, token, content): + self.state = content.strip() + + def _process_class(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + + def _process_text(self, token, content): + pass + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + return content.strip().split('.')[0].strip() diff --git a/plugin/packages/wakatime/dependencies/go.py b/plugin/packages/wakatime/dependencies/go.py index 2231e70..95bea21 100644 --- a/plugin/packages/wakatime/dependencies/go.py +++ b/plugin/packages/wakatime/dependencies/go.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.go - ~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.go + ~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Go code. diff --git a/plugin/packages/wakatime/dependencies/haskell.py b/plugin/packages/wakatime/dependencies/haskell.py new file mode 100644 index 0000000..6e39381 --- /dev/null +++ b/plugin/packages/wakatime/dependencies/haskell.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.haskell + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from Haskell code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +from . import TokenParser + + +class HaskellParser(TokenParser): + state = None + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Reserved': + self._process_reserved(token, content) + elif self.partial(token) == 'Namespace': + self._process_namespace(token, content) + elif self.partial(token) == 'Keyword': + self._process_keyword(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + else: + self._process_other(token, content) + + def _process_reserved(self, token, content): + self.state = content.strip() + + def _process_namespace(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + + def _process_keyword(self, token, content): + if self.state != 'import' or content.strip() != 'qualified': + self.state = None + + def _process_text(self, token, content): + pass + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + return content.strip().split('.')[0].strip() diff --git a/plugin/packages/wakatime/dependencies/haxe.py b/plugin/packages/wakatime/dependencies/haxe.py new file mode 100644 index 0000000..2c09e02 --- /dev/null +++ b/plugin/packages/wakatime/dependencies/haxe.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.haxe + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from Haxe code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +from . import TokenParser + + +class HaxeParser(TokenParser): + exclude = [ + r'^haxe$', + ] + state = None + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Namespace': + self._process_namespace(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + else: + self._process_other(token, content) + + def _process_namespace(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + self.state = None + else: + self.state = content + + def _process_text(self, token, content): + pass + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + return content.strip() diff --git a/plugin/packages/wakatime/dependencies/templates.py b/plugin/packages/wakatime/dependencies/html.py similarity index 81% rename from plugin/packages/wakatime/dependencies/templates.py rename to plugin/packages/wakatime/dependencies/html.py index 422a971..a2b34b4 100644 --- a/plugin/packages/wakatime/dependencies/templates.py +++ b/plugin/packages/wakatime/dependencies/html.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.templates - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.html + ~~~~~~~~~~~~~~~~~~~~~~~~~~ - Parse dependencies from Templates. + Parse dependencies from HTML. :copyright: (c) 2014 Alan Hamlett. :license: BSD, see LICENSE for more details. @@ -69,7 +69,7 @@ KEYWORDS = [ ] -class HtmlDjangoParser(TokenParser): +class HtmlParser(TokenParser): tags = [] opening_tag = False getting_attrs = False @@ -141,63 +141,3 @@ class HtmlDjangoParser(TokenParser): elif content.startswith('"') or content.startswith("'"): if self.current_attr_value is None: self.current_attr_value = content - - -class VelocityHtmlParser(HtmlDjangoParser): - pass - - -class MyghtyHtmlParser(HtmlDjangoParser): - pass - - -class MasonParser(HtmlDjangoParser): - pass - - -class MakoHtmlParser(HtmlDjangoParser): - pass - - -class CheetahHtmlParser(HtmlDjangoParser): - pass - - -class HtmlGenshiParser(HtmlDjangoParser): - pass - - -class RhtmlParser(HtmlDjangoParser): - pass - - -class HtmlPhpParser(HtmlDjangoParser): - pass - - -class HtmlSmartyParser(HtmlDjangoParser): - pass - - -class EvoqueHtmlParser(HtmlDjangoParser): - pass - - -class ColdfusionHtmlParser(HtmlDjangoParser): - pass - - -class LassoHtmlParser(HtmlDjangoParser): - pass - - -class HandlebarsHtmlParser(HtmlDjangoParser): - pass - - -class YamlJinjaParser(HtmlDjangoParser): - pass - - -class TwigHtmlParser(HtmlDjangoParser): - pass diff --git a/plugin/packages/wakatime/dependencies/javascript.py b/plugin/packages/wakatime/dependencies/javascript.py new file mode 100644 index 0000000..75ef535 --- /dev/null +++ b/plugin/packages/wakatime/dependencies/javascript.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.javascript + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from JavaScript code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +import re + +from . import TokenParser + + +class JavascriptParser(TokenParser): + state = None + extension = re.compile(r'\.\w{1,4}$') + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Reserved': + self._process_reserved(token, content) + elif self.partial(token) == 'Single': + self._process_string(token, content) + elif self.partial(token) == 'Punctuation': + self._process_punctuation(token, content) + else: + self._process_other(token, content) + + def _process_reserved(self, token, content): + if self.state is None: + self.state = content + + def _process_string(self, token, content): + if self.state == 'import': + self.append(self._format_module(content)) + self.state = None + + def _process_punctuation(self, token, content): + if content == ';': + self.state = None + + def _process_other(self, token, content): + pass + + def _format_module(self, content): + content = content.strip().strip('"').strip("'").strip() + content = content.split('/')[-1].split('\\')[-1] + content = self.extension.sub('', content, count=1) + return content + + +class TypeScriptParser(JavascriptParser): + pass diff --git a/plugin/packages/wakatime/dependencies/jvm.py b/plugin/packages/wakatime/dependencies/jvm.py index 421474d..7107666 100644 --- a/plugin/packages/wakatime/dependencies/jvm.py +++ b/plugin/packages/wakatime/dependencies/jvm.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.java - ~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.java + ~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Java code. @@ -94,3 +94,89 @@ class JavaParser(TokenParser): def _process_other(self, token, content): pass + + +class KotlinParser(TokenParser): + state = None + exclude = [ + r'^java\.', + ] + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Keyword': + self._process_keyword(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + elif self.partial(token) == 'Namespace': + self._process_namespace(token, content) + else: + self._process_other(token, content) + + def _process_keyword(self, token, content): + self.state = content + + def _process_text(self, token, content): + pass + + def _process_namespace(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + self.state = None + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + content = content.split(u('.')) + + if content[-1] == u('*'): + content = content[:len(content) - 1] + + if len(content) == 0: + return None + + if len(content) == 1: + return content[0] + + return u('.').join(content[:2]) + + +class ScalaParser(TokenParser): + state = None + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Keyword': + self._process_keyword(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + elif self.partial(token) == 'Namespace': + self._process_namespace(token, content) + else: + self._process_other(token, content) + + def _process_keyword(self, token, content): + self.state = content + + def _process_text(self, token, content): + pass + + def _process_namespace(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + self.state = None + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + return content.strip().lstrip('__root__').strip('_').strip('.') diff --git a/plugin/packages/wakatime/dependencies/objective.py b/plugin/packages/wakatime/dependencies/objective.py new file mode 100644 index 0000000..bc06bdf --- /dev/null +++ b/plugin/packages/wakatime/dependencies/objective.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.objective + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from Objective-C and Swift code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +import re + +from . import TokenParser + + +class SwiftParser(TokenParser): + state = None + exclude = [ + r'^foundation$', + ] + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Declaration': + self._process_declaration(token, content) + elif self.partial(token) == 'Class': + self._process_class(token, content) + else: + self._process_other(token, content) + + def _process_declaration(self, token, content): + if self.state is None: + self.state = content + + def _process_class(self, token, content): + if self.state == 'import': + self.append(content) + self.state = None + + def _process_other(self, token, content): + pass + + +class ObjectiveCParser(TokenParser): + state = None + extension = re.compile(r'\.[mh]$') + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Preproc': + self._process_preproc(token, content) + else: + self._process_other(token, content) + + def _process_preproc(self, token, content): + if self.state: + self._process_import(token, content) + + self.state = content + + def _process_import(self, token, content): + if self.state == '#' and content.startswith('import '): + self.append(self._format(content)) + self.state = None + + def _process_other(self, token, content): + pass + + def _format(self, content): + content = content.strip().lstrip('import ').strip() + content = content.strip('"').strip("'").strip() + content = content.strip('<').strip('>').strip() + content = content.split('/')[0] + content = self.extension.sub('', content, count=1) + return content diff --git a/plugin/packages/wakatime/dependencies/php.py b/plugin/packages/wakatime/dependencies/php.py index e4aa0a2..70798e3 100644 --- a/plugin/packages/wakatime/dependencies/php.py +++ b/plugin/packages/wakatime/dependencies/php.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.php - ~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.php + ~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from PHP code. @@ -16,6 +16,10 @@ from ..compat import u class PhpParser(TokenParser): state = None parens = 0 + exclude = [ + r'^app$', + r'app\.php$', + ] def parse(self): for index, token, content in self.tokens: diff --git a/plugin/packages/wakatime/dependencies/python.py b/plugin/packages/wakatime/dependencies/python.py index 43b10bd..6cab7dd 100644 --- a/plugin/packages/wakatime/dependencies/python.py +++ b/plugin/packages/wakatime/dependencies/python.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.python - ~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.python + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Python code. diff --git a/plugin/packages/wakatime/dependencies/rust.py b/plugin/packages/wakatime/dependencies/rust.py new file mode 100644 index 0000000..b43762e --- /dev/null +++ b/plugin/packages/wakatime/dependencies/rust.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.rust + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from Rust code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +from . import TokenParser + + +class RustParser(TokenParser): + state = None + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Keyword': + self._process_keyword(token, content) + elif self.partial(token) == 'Whitespace': + self._process_whitespace(token, content) + elif self.partial(token) == 'Name': + self._process_name(token, content) + else: + self._process_other(token, content) + + def _process_keyword(self, token, content): + if self.state == 'extern' and content == 'crate': + self.state = 'extern crate' + else: + self.state = content + + def _process_whitespace(self, token, content): + pass + + def _process_name(self, token, content): + if self.state == 'extern crate': + self.append(content) + self.state = None + + def _process_other(self, token, content): + self.state = None diff --git a/plugin/packages/wakatime/dependencies/unknown.py b/plugin/packages/wakatime/dependencies/unknown.py index 5d269eb..e37561f 100644 --- a/plugin/packages/wakatime/dependencies/unknown.py +++ b/plugin/packages/wakatime/dependencies/unknown.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.unknown - ~~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.unknown + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from files of unknown language. diff --git a/plugin/packages/wakatime/exceptions.py b/plugin/packages/wakatime/exceptions.py index e99ba90..a0d5285 100644 --- a/plugin/packages/wakatime/exceptions.py +++ b/plugin/packages/wakatime/exceptions.py @@ -12,3 +12,8 @@ class NotYetImplemented(Exception): """This method needs to be implemented.""" + + +class SkipHeartbeat(Exception): + """Raised to prevent the current heartbeat from being sent.""" + pass diff --git a/plugin/packages/wakatime/heartbeat.py b/plugin/packages/wakatime/heartbeat.py index c0b2e02..757838e 100644 --- a/plugin/packages/wakatime/heartbeat.py +++ b/plugin/packages/wakatime/heartbeat.py @@ -12,6 +12,7 @@ import logging import re from .compat import u, json +from .exceptions import SkipHeartbeat from .project import get_project_info from .stats import get_file_stats from .utils import get_user_agent, should_exclude, format_file_path, find_project_file @@ -77,12 +78,17 @@ class Heartbeat(object): self.project = project self.branch = branch - stats = get_file_stats(self.entity, - entity_type=self.type, - lineno=data.get('lineno'), - cursorpos=data.get('cursorpos'), - plugin=args.plugin, - language=data.get('language')) + try: + stats = get_file_stats(self.entity, + entity_type=self.type, + lineno=data.get('lineno'), + cursorpos=data.get('cursorpos'), + plugin=args.plugin, + language=data.get('language')) + except SkipHeartbeat as ex: + self.skip = u(ex) or 'Skipping' + return + else: self.project = data.get('project') self.branch = data.get('branch') diff --git a/plugin/packages/wakatime/packages/pygments/lexers/javascript.py b/plugin/packages/wakatime/packages/pygments/lexers/javascript.py index 862535c..42d68d3 100644 --- a/plugin/packages/wakatime/packages/pygments/lexers/javascript.py +++ b/plugin/packages/wakatime/packages/pygments/lexers/javascript.py @@ -37,7 +37,7 @@ class JavascriptLexer(RegexLexer): name = 'JavaScript' aliases = ['js', 'javascript'] - filenames = ['*.js', '*.jsm'] + filenames = ['*.js', '*.jsm', '*.mjs'] mimetypes = ['application/javascript', 'application/x-javascript', 'text/x-javascript', 'text/javascript'] @@ -1035,7 +1035,6 @@ class CoffeeScriptLexer(RegexLexer): filenames = ['*.coffee'] mimetypes = ['text/coffeescript'] - _operator_re = ( r'\+\+|~|&&|\band\b|\bor\b|\bis\b|\bisnt\b|\bnot\b|\?|:|' r'\|\||\\(?=\n)|' @@ -1464,6 +1463,7 @@ class EarlGreyLexer(RegexLexer): ], } + class JuttleLexer(RegexLexer): """ For `Juttle`_ source code. diff --git a/plugin/packages/wakatime/stats.py b/plugin/packages/wakatime/stats.py index 9d889d4..0f34229 100644 --- a/plugin/packages/wakatime/stats.py +++ b/plugin/packages/wakatime/stats.py @@ -17,6 +17,7 @@ import sys from .compat import u, open from .constants import MAX_FILE_SIZE_SUPPORTED from .dependencies import DependencyParser +from .exceptions import SkipHeartbeat from .language_priorities import LANGUAGES from .packages.pygments.lexers import ( @@ -53,6 +54,8 @@ def get_file_stats(file_name, entity_type='file', lineno=None, cursorpos=None, if not language: language, lexer = guess_language(file_name) + language = use_root_language(language, lexer) + parser = DependencyParser(file_name, lexer) dependencies = parser.parse() @@ -118,6 +121,8 @@ def guess_lexer_using_filename(file_name, text): try: lexer = custom_pygments_guess_lexer_for_filename(file_name, text) + except SkipHeartbeat as ex: + raise SkipHeartbeat(u(ex)) except: log.traceback(logging.DEBUG) @@ -167,7 +172,7 @@ def get_language_from_extension(file_name): filepart, extension = os.path.splitext(file_name) - if re.match(r'\.h.*', extension, re.IGNORECASE) or re.match(r'\.c.*', extension, re.IGNORECASE): + if re.match(r'\.h.*$', extension, re.IGNORECASE) or re.match(r'\.c.*$', extension, re.IGNORECASE): if os.path.exists(u('{0}{1}').format(u(filepart), u('.c'))) or os.path.exists(u('{0}{1}').format(u(filepart), u('.C'))): return 'C' @@ -178,6 +183,18 @@ def get_language_from_extension(file_name): if '.c' in available_extensions: return 'C' + if os.path.exists(u('{0}{1}').format(u(filepart), u('.m'))) or os.path.exists(u('{0}{1}').format(u(filepart), u('.M'))): + return 'Objective-C' + + if os.path.exists(u('{0}{1}').format(u(filepart), u('.mm'))) or os.path.exists(u('{0}{1}').format(u(filepart), u('.MM'))): + return 'Objective-C++' + + if re.match(r'\.m$', extension, re.IGNORECASE) and (os.path.exists(u('{0}{1}').format(u(filepart), u('.h'))) or os.path.exists(u('{0}{1}').format(u(filepart), u('.H')))): + return 'Objective-C' + + if re.match(r'\.mm$', extension, re.IGNORECASE) and (os.path.exists(u('{0}{1}').format(u(filepart), u('.h'))) or os.path.exists(u('{0}{1}').format(u(filepart), u('.H')))): + return 'Objective-C++' + return None @@ -236,6 +253,13 @@ def get_lexer(language): return None +def use_root_language(language, lexer): + if lexer and hasattr(lexer, 'root_lexer'): + return u(lexer.root_lexer.name) + + return language + + def get_language_from_json(language, key): """Finds the given language in a json file.""" @@ -299,6 +323,12 @@ def custom_pygments_guess_lexer_for_filename(_fn, _text, **options): return lexer(**options) result.append(customize_lexer_priority(_fn, rv, lexer)) + matlab = list(filter(lambda x: x[2].name.lower() == 'matlab', result)) + if len(matlab) > 0: + objc = list(filter(lambda x: x[2].name.lower() == 'objective-c', result)) + if objc and objc[0][0] == matlab[0][0]: + raise SkipHeartbeat('Skipping because not enough language accuracy.') + def type_sort(t): # sort by: # - analyse score @@ -322,7 +352,17 @@ def customize_lexer_priority(file_name, accuracy, lexer): elif lexer_name == 'matlab': available_extensions = extensions_in_same_folder(file_name) if '.mat' in available_extensions: - priority = 0.06 + accuracy += 0.01 + if '.h' not in available_extensions: + accuracy += 0.01 + elif lexer_name == 'objective-c': + available_extensions = extensions_in_same_folder(file_name) + if '.mat' in available_extensions: + accuracy -= 0.01 + else: + accuracy += 0.01 + if '.h' in available_extensions: + accuracy += 0.01 return (accuracy, priority, lexer)