[gnome-builder] eslint: Fix plugin



commit 34cb8f4edbf014866f3178a826867ab82d9129ef
Author: Patrick Griffis <tingping tingping se>
Date:   Thu Sep 7 10:58:59 2017 -0400

    eslint: Fix plugin
    
    This makes the plugin functional along with numerous other fixes
    and cleanup

 plugins/eslint/eslint_plugin/__init__.py |  123 ++++++++++++++++++------------
 1 files changed, 74 insertions(+), 49 deletions(-)
---
diff --git a/plugins/eslint/eslint_plugin/__init__.py b/plugins/eslint/eslint_plugin/__init__.py
index 95ed22f..c1e1c90 100644
--- a/plugins/eslint/eslint_plugin/__init__.py
+++ b/plugins/eslint/eslint_plugin/__init__.py
@@ -20,79 +20,103 @@
 #
 
 import gi
-import re
+import json
+import threading
 
 gi.require_version('Ide', '1.0')
 
-from gi.repository import GObject
-from gi.repository import Gio
-from gi.repository import Gtk
-from gi.repository import Ide
-
-import threading
+from gi.repository import (
+    GLib,
+    GObject,
+    Gio,
+    Gtk,
+    Ide,
+)
 
 _ = Ide.gettext
 
-def severtity_from_eslint(severity):
-    if 'Warning' in severity:
-        return Ide.DiagnosticSeverity.WARNING
-    # eslint has only warning and error, so default to error
-    return Ide.DiagnosticSeverity.ERROR
 
-class ESLintDiagnosticProvider(Ide.Object, Ide.DiagnosticProvider):
-    def do_load(self):
-        self.diagnostics_list = []
+SEVERITY_MAP = {
+    1: Ide.DiagnosticSeverity.WARNING,
+    2: Ide.DiagnosticSeverity.ERROR
+}
+
 
+class ESLintDiagnosticProvider(Ide.Object, Ide.DiagnosticProvider):
     def do_diagnose_async(self, file, buffer, cancellable, callback, user_data):
         self.diagnostics_list = []
         task = Gio.Task.new(self, cancellable, callback)
+        task.diagnostics_list = []
+
+        context = self.get_context()
+        unsaved_file = context.get_unsaved_files().get_unsaved_file(file.get_file())
+        pipeline = self.get_context().get_build_manager().get_pipeline()
+        srcdir = pipeline.get_srcdir()
+        runtime = pipeline.get_configuration().get_runtime()
+        launcher = runtime.create_launcher()
+        launcher.set_flags(Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE)
+        launcher.set_cwd(srcdir)
+        launcher.push_args(('eslint', '-f', 'json'))
 
-        unsaved_files = self.get_context().get_unsaved_files()
-        unsaved_file = unsaved_files.get_unsaved_file (file.get_file ())
         if unsaved_file:
             file_content = unsaved_file.get_content().get_data().decode('utf-8')
         else:
             file_content = None
 
-        settings = Gio.Settings.new('org.gnome.builder.plugins.eslint')
-        if not settings.get_boolean('enable-eslint'):
-            task.return_boolean(True)
+        if file_content:
+            launcher.push_argv('--stdin')
+            launcher.push_argv('--stdin-filename=' + file.get_path())
         else:
-            threading.Thread(target=self.execute, args=[task, file, file_content], 
name='eslint-thread').start()
+            launcher.push_argv(file.get_path())
 
+        threading.Thread(target=self.execute, args=(task, launcher, file, file_content),
+                         name='eslint-thread').start()
 
-    def execute(self, task, file, file_content):
+    def execute(self, task, launcher, file, file_content):
         try:
-            launcher = 
Ide.SubprocessLauncher.new(Gio.SubprocessFlags.STDOUT_PIPE|Gio.SubprocessFlags.STDIN_PIPE)
-            launcher.push_argv('eslint')
-            launcher.push_argv('-f')
-            launcher.push_argv('compact')
-            if file_content:
-                launcher.push_argv('--stdin')
-                launcher.push_argv('--stdin-filename=' + file.get_path())
-            else:
-                launcher.push_argv(file.get_path())
-
             sub_process = launcher.spawn()
-
-            result, stdout, stderr = sub_process.communicate_utf8(file_content, None)
-
-            for line in iter(stdout.splitlines()):
-                m = re.search('.*: line (\d+), col (\d+), (.*) - (.*)', line)
-                if m is None:
-                    break
-                line_number = max(0, int(m.group(1)) - 1)
-                column_number = max(0, int(m.group(2)) - 1)
-                severity = severtity_from_eslint(m.group(3))
-                message = m.group(4)
-                source_location = Ide.SourceLocation.new(file, line_number, column_number, 0)
-                self.diagnostics_list.append(Ide.Diagnostic.new(severity, message, source_location))
-        except Exception as e:
-            pass
-        task.return_boolean(True)
+            success, stdout, stderr = sub_process.communicate_utf8(file_content, None)
+
+            if not success:
+                task.return_boolean(False)
+                return
+
+            results = json.loads(stdout)
+            for result in results:
+                for message in result.get('messages', []):
+                    start_line = max(message['line'] - 1, 0)
+                    start_col = max(message['column'] - 1, 0)
+                    start = Ide.SourceLocation.new(file, start_line, start_col, 0)
+                    end = None
+                    if 'endLine' in message:
+                        end_line = max(message['endLine'] - 1, 0)
+                        end_col = max(message['endColumn'] - 1, 0)
+                        end = Ide.SourceLocation.new(file, end_line, end_col, 0)
+
+                    severity = SEVERITY_MAP[message['severity']]
+                    diagnostic = Ide.Diagnostic.new(severity, message['message'], start)
+                    if end is not None:
+                        range_ = Ide.SourceRange.new(start, end)
+                        diagnostic.add_range(range_)
+                        # if 'fix' in message:
+                        # Fixes often come without end* information so we
+                        # will rarely get here, instead it has a file offset
+                        # which is not actually implemented in IdeSourceLocation
+                        # fixit = Ide.Fixit.new(range_, message['fix']['text'])
+                        # diagnostic.take_fixit(fixit)
+
+                    task.diagnostics_list.append(diagnostic)
+        except GLib.Error as err:
+            task.return_error(err)
+        except (json.JSONDecodeError, UnicodeDecodeError, IndexError) as e:
+            task.return_error(GLib.Error('Failed to decode eslint json: {}'.format(e)))
+        else:
+            task.return_boolean(True)
 
     def do_diagnose_finish(self, result):
-        return Ide.Diagnostics.new(self.diagnostics_list)
+        if result.propagate_boolean():
+            return Ide.Diagnostics.new(result.diagnostics_list)
+
 
 class ESLintPreferencesAddin(GObject.Object, Ide.PreferencesAddin):
     def do_load(self, preferences):
@@ -107,5 +131,6 @@ class ESLintPreferencesAddin(GObject.Object, Ide.PreferencesAddin):
                                              # translators: these are keywords used to search for preferences
                                              _("eslint javascript lint code execute execution"),
                                              500)
+
     def do_unload(self, preferences):
         preferences.remove_id(self.eslint)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]