Commit 548fef64 authored by Georg Vienna's avatar Georg Vienna Committed by Christian Hergert

eslint plugin: add javascript linting using eslint

This adds support for linting javascript files using eslint.
An eslint configuration file must be present in the project directory.

http://eslint.org/

https://bugzilla.gnome.org/show_bug.cgi?id=779624
parent 5f2ba22f
......@@ -304,6 +304,7 @@ m4_include([plugins/comment-code/configure.ac])
m4_include([plugins/create-project/configure.ac])
m4_include([plugins/ctags/configure.ac])
m4_include([plugins/devhelp/configure.ac])
m4_include([plugins/eslint/configure.ac])
m4_include([plugins/file-search/configure.ac])
m4_include([plugins/flatpak/configure.ac])
m4_include([plugins/fpaste/configure.ac])
......@@ -588,6 +589,7 @@ echo " Command Bar .......................... : ${enable_command_bar_plugin}"
echo " Comment Code.......................... : ${enable_comment_code_plugin}"
echo " Ctags ................................ : ${enable_ctags_plugin}"
echo " Devhelp .............................. : ${enable_devhelp_plugin}"
echo " ESLint ............................... : ${enable_eslint_plugin}"
echo " Editorconfig ......................... : ${enable_editorconfig}"
echo " Flatpak .............................. : ${enable_flatpak_plugin}"
echo " Fpaste.org ........................... : ${enable_fpaste_plugin}"
......
......@@ -28,6 +28,7 @@ option('with_comment_code', type: 'boolean')
option('with_create_project', type: 'boolean')
option('with_ctags', type: 'boolean')
option('with_devhelp', type: 'boolean')
option('with_eslint', type: 'boolean')
option('with_file_search', type: 'boolean')
option('with_flatpak', type: 'boolean')
option('with_fpaste', type: 'boolean')
......
......@@ -12,6 +12,7 @@ SUBDIRS = \
create-project \
ctags \
devhelp \
eslint \
file-search \
flatpak \
fpaste \
......
if ENABLE_ESLINT_PLUGIN
plugindir = $(libdir)/gnome-builder/plugins
dist_plugin_DATA = eslint.plugin
moduledir = $(libdir)/gnome-builder/plugins/eslint_plugin
dist_module_DATA = eslint_plugin/__init__.py
gsettings_SCHEMAS = org.gnome.builder.plugins.eslint.gschema.xml
.PRECIOUS: $(gsettings_SCHEMAS)
@GSETTINGS_RULES@
EXTRA_DIST = $(gsettings_SCHEMAS) $(plugin_DATA)
endif
-include $(top_srcdir)/git.mk
# --enable-eslint-plugin=yes/no
AC_ARG_ENABLE([eslint-plugin],
[AS_HELP_STRING([--enable-eslint-plugin=@<:@yes/no@:>@],
[Build with support for eslint integration.])],
[enable_eslint_plugin=$enableval],
[enable_eslint_plugin=yes])
# for if ENABLE_ESLINT_PLUGIN in Makefile.am
AM_CONDITIONAL(ENABLE_ESLINT_PLUGIN, test x$enable_eslint_plugin = xyes)
# Ensure our makefile is generated by autoconf
AC_CONFIG_FILES([plugins/eslint/Makefile])
[Plugin]
Module=eslint_plugin
Name=eslint
Loader=python3
Description=Provides javascript lints
Authors=Georg Vienna <georg.vienna@himbarsoft.com>
Copyright=Copyright © 2017 Georg Vienna <georg.vienna@himbarsoft.com>
X-Diagnostic-Provider-Languages=js
X-Diagnostic-Provider-Languages-Priority=100
#!/usr/bin/env python3
#
# __init__.py
#
# Copyright (C) 2017 Georg Vienna <georg.vienna@himbarsoft.com>
#
# 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 gi
import re
gi.require_version('Ide', '1.0')
from gi.repository import Egg
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from gi.repository import Ide
import threading
_ = 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 = []
def do_diagnose_async(self, file, buffer, cancellable, callback, user_data):
self.diagnostics_list = []
task = Gio.Task.new(self, cancellable, callback)
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)
else:
threading.Thread(target=self.execute, args=[task, file, file_content], name='eslint-thread').start()
def execute(self, task, 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)
def do_diagnose_finish(self, result):
return Ide.Diagnostics.new(self.diagnostics_list)
class ESLintPreferencesAddin(GObject.Object, Ide.PreferencesAddin):
def do_load(self, preferences):
self.eslint = preferences.add_switch("code-insight",
"diagnostics",
"org.gnome.builder.plugins.eslint",
"enable-eslint",
None,
"false",
_("ESlint"),
_("Enable the use of ESLint, which may execute code in your project"),
# 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)
if get_option('with_eslint')
eslint_dir = join_paths(plugindir, 'eslint_plugin')
install_data('eslint.plugin', install_dir: plugindir)
install_data('eslint_plugin/__init__.py', install_dir: eslint_dir)
install_data('org.gnome.builder.plugins.eslint.gschema.xml',
install_dir: schema_dir)
endif
<schemalist>
<schema id="org.gnome.builder.plugins.eslint" path="/org/gnome/builder/plugins/eslint/" gettext-domain="gnome-builder">
<key name="enable-eslint" type="b">
<default>false</default>
<summary>Enable ESLint</summary>
<description>Enable the use of eslint to find additional diagnostics in JavaScript files. This may result in the execution of code in your project.</description>
</key>
</schema>
</schemalist>
......@@ -23,6 +23,7 @@ subdir('comment-code')
subdir('create-project')
subdir('ctags')
subdir('devhelp')
subdir('eslint')
subdir('file-search')
subdir('flatpak')
subdir('fpaste')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment