[gnome-builder] Added a Rubocop plugin for linting ruby files
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] Added a Rubocop plugin for linting ruby files
- Date: Mon, 11 Oct 2021 18:02:15 +0000 (UTC)
commit 154ff901b0f5f96971e65970f00a99ba1ab6a452
Author: jebw <jeb jdwilkins co uk>
Date: Sun Oct 3 14:57:42 2021 +0100
Added a Rubocop plugin for linting ruby files
This plugin is derived from the ESLint plugin,
modified to use the Rubocop linter.
meson_options.txt | 1 +
src/plugins/meson.build | 2 +
src/plugins/rubocop/meson.build | 16 ++++
src/plugins/rubocop/rubocop.plugin | 11 +++
src/plugins/rubocop/rubocop_plugin.py | 142 ++++++++++++++++++++++++++++++++++
5 files changed, 172 insertions(+)
---
diff --git a/meson_options.txt b/meson_options.txt
index 747e937ca..657e9beaa 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -67,6 +67,7 @@ option('plugin_qemu', type: 'boolean')
option('plugin_quick_highlight', type: 'boolean')
option('plugin_retab', type: 'boolean')
option('plugin_rls', type: 'boolean', value: false)
+option('plugin_rubocop', type: 'boolean')
option('plugin_rust_analyzer', type: 'boolean')
option('plugin_shellcmd', type: 'boolean')
option('plugin_spellcheck', type: 'boolean')
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index 6150ccacf..fe7ee0ae9 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -112,6 +112,7 @@ subdir('recent')
subdir('restore-cursor')
subdir('retab')
subdir('rls')
+subdir('rubocop')
subdir('rust-analyzer')
subdir('shellcmd')
subdir('snippets')
@@ -193,6 +194,7 @@ status += [
'Quick Highlight ....... : @0@'.format(get_option('plugin_quick_highlight')),
'Retab ................. : @0@'.format(get_option('plugin_retab')),
'RLS ................... : @0@'.format(get_option('plugin_rls')),
+ 'Rubocop ............... : @0@'.format(get_option('plugin_rubocop')),
'Rust Analyzer ......... : @0@'.format(get_option('plugin_rust_analyzer')),
'Spellcheck ............ : @0@'.format(get_option('plugin_spellcheck')),
'Stylelint ............. : @0@'.format(get_option('plugin_stylelint')),
diff --git a/src/plugins/rubocop/meson.build b/src/plugins/rubocop/meson.build
new file mode 100644
index 000000000..b81d09370
--- /dev/null
+++ b/src/plugins/rubocop/meson.build
@@ -0,0 +1,16 @@
+if get_option('plugin_rubocop')
+
+install_data('rubocop_plugin.py', install_dir: plugindir)
+
+install_data('org.gnome.builder.plugins.rubocop.gschema.xml',
+ install_dir: schema_dir)
+
+configure_file(
+ input: 'rubocop.plugin',
+ output: 'rubocop.plugin',
+ configuration: config_h,
+ install: true,
+ install_dir: plugindir,
+)
+
+endif
diff --git a/src/plugins/rubocop/rubocop.plugin b/src/plugins/rubocop/rubocop.plugin
new file mode 100644
index 000000000..17dd393f2
--- /dev/null
+++ b/src/plugins/rubocop/rubocop.plugin
@@ -0,0 +1,11 @@
+[Plugin]
+Authors=Jeremy Wilkins <jeb jdwilkins co uk>
+Copyright=Copyright © 2021 Jeremy Wilkins <jeb jdwilkins co uk>
+Description=Provides Ruby linting using Rubocop
+Loader=python3
+Hidden=true
+Module=rubocop_plugin
+Name=rubocop
+X-Diagnostic-Provider-Languages-Priority=100
+X-Diagnostic-Provider-Languages=ruby
+X-Builder-ABI=@PACKAGE_ABI@
diff --git a/src/plugins/rubocop/rubocop_plugin.py b/src/plugins/rubocop/rubocop_plugin.py
new file mode 100644
index 000000000..b6c530ee0
--- /dev/null
+++ b/src/plugins/rubocop/rubocop_plugin.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+
+#
+# __init__.py
+#
+# Copyright 2021 Jeremy Wilkins <jeb jdwilkins co uk>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import gi
+import json
+import threading
+
+from gi.repository import GLib
+from gi.repository import GObject
+from gi.repository import Gio
+from gi.repository import Gtk
+from gi.repository import Ide
+
+_ = Ide.gettext
+
+
+SEVERITY_MAP = {
+ 'info': Ide.DiagnosticSeverity.NOTE,
+ 'refactor': Ide.DiagnosticSeverity.NOTE,
+ 'convention': Ide.DiagnosticSeverity.NOTE,
+ 'warning': Ide.DiagnosticSeverity.WARNING,
+ 'error': Ide.DiagnosticSeverity.ERROR,
+ 'fatal': Ide.DiagnosticSeverity.FATAL
+}
+
+class RubocopDiagnosticProvider(Ide.Object, Ide.DiagnosticProvider):
+ def create_launcher(self):
+ context = self.get_context()
+ srcdir = context.ref_workdir().get_path()
+ launcher = None
+
+ if context.has_project():
+ build_manager = Ide.BuildManager.from_context(context)
+ pipeline = build_manager.get_pipeline()
+ if pipeline is not None:
+ srcdir = pipeline.get_srcdir()
+ runtime = pipeline.get_config().get_runtime()
+ launcher = runtime.create_launcher()
+
+ if launcher is None:
+ launcher = Ide.SubprocessLauncher.new(0)
+
+ launcher.set_flags(Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE)
+ launcher.set_cwd(srcdir)
+
+ return launcher
+
+ def do_diagnose_async(self, file, file_content, lang_id, cancellable, callback, user_data):
+ self.diagnostics_list = []
+ task = Gio.Task.new(self, cancellable, callback)
+ task.diagnostics_list = []
+
+ launcher = self.create_launcher()
+ srcdir = launcher.get_cwd()
+
+ threading.Thread(target=self.execute, args=(task, launcher, srcdir, file, file_content),
+ name='rubocop-thread').start()
+
+ def execute(self, task, launcher, srcdir, file, file_content):
+ try:
+ launcher.push_args(('rubocop', '--format', 'json'))
+
+ if file_content:
+ launcher.push_argv('--stdin')
+
+ launcher.push_argv(file.get_path())
+
+ sub_process = launcher.spawn()
+ stdin = file_content.get_data().decode('UTF-8')
+ success, stdout, stderr = sub_process.communicate_utf8(stdin, None)
+
+ results = json.loads(stdout)
+
+ for result in results.get('files', []):
+ for offense in result.get('offenses', []):
+ if 'location' not in offense:
+ continue
+
+ location = offense['location']
+
+ if 'start_line' not in location or 'start_column' not in location:
+ continue
+
+ start_line = max(location['start_line'] - 1, 0)
+ start_col = max(location['start_column'] - 1, 0)
+ start = Ide.Location.new(file, start_line, start_col)
+
+ end = None
+ if 'last_line' in location:
+ end_line = max(location['last_line'] - 1, 0)
+ end_col = max(location['last_column'], 0)
+ end = Ide.Location.new(file, end_line, end_col)
+ elif 'length' in location:
+ end_line = start_line
+ end_col = start_col + location['length']
+ end = Ide.Location.new(file, end_line, end_col)
+
+ if file_content:
+ message = offense['cop_name'] + ': ' + offense['message']
+ else:
+ message = offense['message'] # Already prefixed when not --stdin
+
+ severity = SEVERITY_MAP[offense['severity']]
+ diagnostic = Ide.Diagnostic.new(severity, message, start)
+ if end is not None:
+ range_ = Ide.Range.new(start, end)
+ diagnostic.add_range(range_)
+
+ 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 rubocop json: {}'.format(e)))
+ else:
+ task.return_boolean(True)
+
+ def do_diagnose_finish(self, result):
+ if result.propagate_boolean():
+ diagnostics = Ide.Diagnostics()
+ for diag in result.diagnostics_list:
+ diagnostics.add(diag)
+ return diagnostics
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]