~ubuntu-branches/ubuntu/vivid/kate/vivid-proposed

« back to all changes in this revision

Viewing changes to addons/kate/pate/src/plugins/js_utils/js_lint.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-12-04 16:49:41 UTC
  • mfrom: (1.6.6)
  • Revision ID: package-import@ubuntu.com-20141204164941-l3qbvsly83hhlw2v
Tags: 4:14.11.97-0ubuntu1
* New upstream release
* Update build-deps and use pkg-kde v3 for Qt 5 build
* kate-data now kate5-data for co-installability

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
# Copyright (c) 2013 by Pablo Martín <goinnn@gmail.com> and
3
 
# Alejandro Blanco <alejandro.b.e@gmail.com>
4
 
#
5
 
# This software is free software: you can redistribute it and/or modify
6
 
# it under the terms of the GNU Lesser General Public License as published by
7
 
# the Free Software Foundation, either version 3 of the License, or
8
 
# (at your option) any later version.
9
 
#
10
 
# This software is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU Lesser General Public License for more details.
14
 
#
15
 
# You should have received a copy of the GNU Lesser General Public License
16
 
# along with this software.  If not, see <http://www.gnu.org/licenses/>.
17
 
 
18
 
# This file originally was in this repository:
19
 
# <https://github.com/goinnn/Kate-plugins/blob/master/kate_plugins/jste_plugins/jslint_plugins.py>
20
 
 
21
 
 
22
 
"""
23
 
format of errors:
24
 
{
25
 
    line      : The line (relative to 0) at which the lint was found
26
 
    character : The character (relative to 0) at which the lint was found
27
 
    reason    : The problem
28
 
    evidence  : The text line in which the problem occurred
29
 
    raw       : The raw message before the details were inserted
30
 
    a         : The first detail
31
 
    b         : The second detail
32
 
    c         : The third detail
33
 
    d         : The fourth detail
34
 
}
35
 
"""
36
 
 
37
 
from __future__ import absolute_import
38
 
 
39
 
from os import path as p
40
 
from functools import partial
41
 
 
42
 
import kate
43
 
 
44
 
from PyKDE4.kdecore import i18nc, KGlobal, KUrl
45
 
from PyKDE4.kdeui import KMessageBox
46
 
from PyKDE4.kio import KIO
47
 
 
48
 
from .js_settings import SETTING_LINT_ON_SAVE, SETTING_LINTER
49
 
from .js_engine import PyJSEngine, JSModule
50
 
from libkatepate.errors import clearMarksOfError, showErrors, showOk, showError
51
 
 
52
 
 
53
 
JS_ENGINE = PyJSEngine()
54
 
 
55
 
# If doug crockford wasn’t special, we could do e.g.:
56
 
# LINTERS = { 'JSLint': JSModule(JS_ENGINE, p.join(p.dirname(__file__), 'jslint.js'), 'JSLINT') }
57
 
 
58
 
LINTERS = {}  # keys() == SETTING_LINTER.choices
59
 
 
60
 
_DOUG_LICENSE = 'The Software shall be used for Good, not Evil.'
61
 
NEEDS_LICENSE = {
62
 
    'JSLint': (_DOUG_LICENSE, 'JSLINT', 'https://raw.github.com/douglascrockford/JSLint/master/jslint.js'),
63
 
    'JSHint': (_DOUG_LICENSE, 'JSHINT', 'https://raw.github.com/jshint/jshint/2.x/dist/jshint.js'),
64
 
}
65
 
 
66
 
CACHE_DIR = KGlobal.dirs().locateLocal('appdata', 'pate/js_utils/', True)  # trailing slash necessary
67
 
 
68
 
 
69
 
def license_accepted(license):
70
 
    """asks to accept a license"""
71
 
    return KMessageBox.Yes == KMessageBox.warningYesNo(kate.mainWindow(),
72
 
        i18nc('@info:status', '''<p>
73
 
            Additionally to free software licenses like GPL and MIT,
74
 
            this functionality requires you to accept the following conditions:
75
 
            </p><p>%1</p><p>
76
 
            Do you want to accept and download the functionality?
77
 
            </p>''', license),
78
 
        i18nc('@title:window', 'Accept license?'))
79
 
 
80
 
 
81
 
def get_linter(linter_name, callback):
82
 
    """tries to retrieve a linter and calls `callback` on it on success"""
83
 
    if linter_name in LINTERS:
84
 
        callback(LINTERS[linter_name])
85
 
        return
86
 
 
87
 
    if linter_name not in NEEDS_LICENSE:
88
 
        showError(i18nc('@info:status', 'No acceptable linter named %1!', linter_name))
89
 
        return
90
 
 
91
 
    license, objname, url = NEEDS_LICENSE[linter_name]
92
 
    cache_path = p.join(CACHE_DIR, linter_name + '.js')
93
 
 
94
 
    def success():
95
 
        """store newly created linter and “return” it"""
96
 
        LINTERS[linter_name] = JSModule(JS_ENGINE, cache_path, objname)
97
 
        callback(LINTERS[linter_name])
98
 
 
99
 
    if p.exists(cache_path):
100
 
        success()
101
 
        return
102
 
 
103
 
    # the user doesn’t have the file. ask to accept its license
104
 
    if not license_accepted(license):
105
 
        return
106
 
 
107
 
    download = KIO.file_copy(KUrl(url), KUrl.fromPath(cache_path))
108
 
    @download.result.connect
109
 
    def _call(job):
110
 
        if job.error():
111
 
            showError(i18nc('@info:status', 'Download failed'))
112
 
        else:
113
 
            success()
114
 
    download.start()
115
 
 
116
 
 
117
 
def lint_js(document, move_cursor=False):
118
 
    """Check your js code with the jslint tool"""
119
 
    mark_iface = document.markInterface()
120
 
    clearMarksOfError(document, mark_iface)
121
 
 
122
 
    linter_name = SETTING_LINTER.choices[SETTING_LINTER.lookup()]  # lookup() gives index of choices
123
 
    get_linter(linter_name, partial(_lint, document, move_cursor, linter_name))
124
 
 
125
 
 
126
 
def _lint(document, move_cursor, linter_name, linter):
127
 
    """extracted part of lint_js that has to be called after the linter is ready"""
128
 
    ok = linter(document.text(), {})
129
 
    if ok:
130
 
        showOk(i18nc('@info:status', '<application>%1</application> OK', linter_name))
131
 
        return
132
 
 
133
 
    errors = [error for error in linter['errors'] if error]  # sometimes None
134
 
 
135
 
    # Prepare errors found for painting
136
 
    for error in errors:
137
 
        error['message'] = error.pop('reason')  # rename since showErrors has 'message' hardcoded
138
 
        error.pop('raw', None)  # Only reason, line, and character are always there
139
 
        error.pop('a', None)
140
 
        error.pop('b', None)
141
 
        error.pop('c', None)
142
 
        error.pop('d', None)
143
 
 
144
 
    mark_key = '{}-{}'.format(document.url().path(), linter_name)
145
 
 
146
 
    showErrors(i18nc('@info:status', '<application>%1</application> Errors:', linter_name),
147
 
               errors,
148
 
               mark_key, document,
149
 
               key_column='character',
150
 
               move_cursor=move_cursor)
151
 
 
152
 
 
153
 
def lint_on_save(document):
154
 
    """Tests for multiple Conditions and lints if they are met"""
155
 
    if (not document.isModified() and
156
 
        document.mimeType() == 'application/javascript' and
157
 
        SETTING_LINT_ON_SAVE.lookup()):
158
 
        lint_js(document)
159
 
 
160
 
 
161
 
def init_js_lint(view=None):
162
 
    doc = view.document() if view else kate.activeDocument()
163
 
    doc.modifiedChanged.connect(lint_on_save)
164
 
 
165
 
# kate: space-indent on; indent-width 4;