ruber 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +42 -1
- data/lib/ruber/application/application.rb +25 -5
- data/lib/ruber/application/plugin.yaml +2 -10
- data/lib/ruber/component_manager.rb +2 -2
- data/lib/ruber/document_project.rb +5 -3
- data/lib/ruber/editor/document.rb +5 -4
- data/lib/ruber/editor/ktexteditor_wrapper.rb +1 -1
- data/lib/ruber/exception_widgets.rb +1 -1
- data/lib/ruber/main_window/main_window.rb +4 -3
- data/lib/ruber/main_window/main_window_actions.rb +2 -2
- data/lib/ruber/main_window/main_window_internal.rb +1 -1
- data/lib/ruber/output_widget.rb +17 -5
- data/lib/ruber/project.rb +34 -3
- data/lib/ruber/project_dir_scanner.rb +171 -0
- data/lib/ruber/settings_container.rb +7 -7
- data/lib/ruber/settings_dialog.rb +24 -24
- data/lib/ruber/version.rb +1 -1
- data/lib/ruber/world/environment.rb +1 -0
- data/lib/ruber/world/plugin.yaml +7 -2
- data/lib/ruber/{application → world}/project_files_widget.rb +0 -0
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.ui +0 -0
- data/lib/ruber/{application → world}/ui/project_files_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_widget.ui +0 -0
- data/plugins/auto_end/auto_end.rb +21 -18
- data/plugins/autosave/autosave.rb +1 -1
- data/plugins/find_in_files/find_in_files.rb +1 -1
- data/plugins/irb/irb.png +0 -0
- data/plugins/irb/irb.rb +142 -0
- data/plugins/irb/irb.svg +240 -0
- data/plugins/irb/irb_controller.rb +541 -0
- data/plugins/irb/irbrc.rb +21 -0
- data/plugins/irb/plugin.yaml +19 -0
- data/plugins/irb/ui/irb_config_widget.rb +151 -0
- data/plugins/irb/ui/irb_config_widget.ui +123 -0
- data/plugins/irb/ui/irb_tool_widget.rb +97 -0
- data/plugins/irb/ui/irb_tool_widget.ui +86 -0
- data/plugins/project_browser/project_browser.rb +1 -1
- data/plugins/rspec/plugin.yaml +6 -3
- data/plugins/rspec/rspec.rb +172 -473
- data/plugins/rspec/tool_widget.rb +462 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +58 -38
- data/plugins/rspec/ui/rspec_project_widget.ui +68 -64
- data/plugins/ruberri/class_formatter.rb +126 -0
- data/plugins/ruberri/method_formatter.rb +90 -0
- data/plugins/ruberri/plugin.yaml +13 -0
- data/plugins/ruberri/ruberri.rb +226 -0
- data/plugins/ruberri/search.rb +111 -0
- data/plugins/ruberri/ui/tool_widget.rb +73 -0
- data/plugins/ruberri/ui/tool_widget.ui +49 -0
- data/plugins/ruby_runner/ruby_runner.rb +2 -2
- data/plugins/ruby_syntax_checker/plugin.yaml +11 -0
- data/plugins/ruby_syntax_checker/ruby_syntax_checker.rb +147 -0
- data/plugins/syntax_checker/plugin.yaml +10 -6
- data/plugins/syntax_checker/syntax_checker.rb +216 -520
- data/plugins/syntax_checker/ui/config_widget.rb +61 -0
- data/plugins/syntax_checker/ui/config_widget.ui +44 -0
- data/plugins/yaml_syntax_checker/plugin.yaml +11 -0
- data/plugins/yaml_syntax_checker/yaml_syntax_checker.rb +62 -0
- data/ruber.desktop +0 -0
- data/spec/auto_end_spec.rb +224 -186
- data/spec/document_project_spec.rb +9 -1
- data/spec/document_spec.rb +9 -0
- data/spec/environment_spec.rb +12 -0
- data/spec/output_widget_spec.rb +69 -2
- data/spec/project_dir_scanner_spec.rb +195 -0
- data/spec/project_spec.rb +43 -73
- data/spec/ruby_syntax_checker_spec.rb +361 -0
- data/spec/syntax_checker_spec.rb +1132 -0
- data/spec/yaml_syntax_checker_spec.rb +130 -0
- metadata +232 -225
- data/lib/ruber/application/project_files_list.rb +0 -320
- data/spec/project_files_list_spec.rb +0 -411
@@ -0,0 +1,49 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<ui version="4.0">
|
3
|
+
<class>RIToolWidget</class>
|
4
|
+
<widget class="QWidget" name="RIToolWidget">
|
5
|
+
<property name="geometry">
|
6
|
+
<rect>
|
7
|
+
<x>0</x>
|
8
|
+
<y>0</y>
|
9
|
+
<width>676</width>
|
10
|
+
<height>300</height>
|
11
|
+
</rect>
|
12
|
+
</property>
|
13
|
+
<property name="windowTitle">
|
14
|
+
<string>Form</string>
|
15
|
+
</property>
|
16
|
+
<layout class="QGridLayout" name="gridLayout">
|
17
|
+
<item row="0" column="0">
|
18
|
+
<widget class="QLabel" name="label">
|
19
|
+
<property name="text">
|
20
|
+
<string>Find</string>
|
21
|
+
</property>
|
22
|
+
<property name="buddy">
|
23
|
+
<cstring>search_term</cstring>
|
24
|
+
</property>
|
25
|
+
</widget>
|
26
|
+
</item>
|
27
|
+
<item row="0" column="1">
|
28
|
+
<widget class="KLineEdit" name="search_term"/>
|
29
|
+
</item>
|
30
|
+
<item row="0" column="2">
|
31
|
+
<widget class="QPushButton" name="search">
|
32
|
+
<property name="text">
|
33
|
+
<string>&Search</string>
|
34
|
+
</property>
|
35
|
+
</widget>
|
36
|
+
</item>
|
37
|
+
<item row="1" column="0" colspan="3">
|
38
|
+
<widget class="QTextBrowser" name="content"/>
|
39
|
+
</item>
|
40
|
+
</layout>
|
41
|
+
</widget>
|
42
|
+
<tabstops>
|
43
|
+
<tabstop>search_term</tabstop>
|
44
|
+
<tabstop>search</tabstop>
|
45
|
+
<tabstop>content</tabstop>
|
46
|
+
</tabstops>
|
47
|
+
<resources/>
|
48
|
+
<connections/>
|
49
|
+
</ui>
|
@@ -346,7 +346,7 @@ object
|
|
346
346
|
current project, even if _target_ is a {Document} or the name of a file belonging
|
347
347
|
to it
|
348
348
|
@param [Boolean] abs it has the same meaning as in {SettingsContainer#[]}
|
349
|
-
@raise
|
349
|
+
@raise [IndexError] if the option can't be found
|
350
350
|
=end
|
351
351
|
def option_for target, group, name, ignore_project = false, abs = false
|
352
352
|
cont = []
|
@@ -363,7 +363,7 @@ to it
|
|
363
363
|
abs = :abs if abs
|
364
364
|
cont.each_with_index do |c, i|
|
365
365
|
begin return c[group, name, abs]
|
366
|
-
rescue
|
366
|
+
rescue IndexError
|
367
367
|
raise if i == cont.size - 1
|
368
368
|
end
|
369
369
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
name: ruby_syntax_checker
|
2
|
+
version: 0.0.1
|
3
|
+
about:
|
4
|
+
authors: [Stefano Crocco, stefano.crocco@alice.it]
|
5
|
+
license: gpl
|
6
|
+
description: Syntax checker for ruby documents. Requires the syntax checker plugin
|
7
|
+
bug_address: http://github.com/stcrocco/ruber/issues
|
8
|
+
icon: tools-check-spelling
|
9
|
+
deps: [syntax_checker, ruby_development]
|
10
|
+
class: Ruber::RubySyntaxChecker::Plugin
|
11
|
+
require: ruby_syntax_checker
|
@@ -0,0 +1,147 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright (C) 2010, 2011 by Stefano Crocco
|
3
|
+
stefano.crocco@alice.it
|
4
|
+
|
5
|
+
This program is free software; you can redistribute it andor modify
|
6
|
+
it under the terms of the GNU General Public License as published by
|
7
|
+
the Free Software Foundation; either version 2 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program 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 General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with this program; if not, write to the
|
17
|
+
Free Software Foundation, Inc.,
|
18
|
+
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19
|
+
=end
|
20
|
+
|
21
|
+
module Ruber
|
22
|
+
|
23
|
+
module RubySyntaxChecker
|
24
|
+
|
25
|
+
SyntaxError = Struct.new :line, :column, :message, :formatted_message, :error_type
|
26
|
+
|
27
|
+
class Plugin < Ruber::Plugin
|
28
|
+
|
29
|
+
def initialize psf
|
30
|
+
super
|
31
|
+
Ruber[:syntax_checker].register_syntax_checker RubySyntaxChecker::Checker, ['application/x-ruby'],
|
32
|
+
%w[*.rb rakefile Rakefile]
|
33
|
+
end
|
34
|
+
|
35
|
+
def unload
|
36
|
+
Ruber[:syntax_checker].remove_syntax_checker RubySyntaxChecker::Checker
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class Checker
|
42
|
+
|
43
|
+
SPECIAL_ERROR_STRINGS = [
|
44
|
+
'unmatched close parenthesis:',
|
45
|
+
'end pattern with unmatched parenthesis:',
|
46
|
+
'unknown regexp option -',
|
47
|
+
'class|module definition in method body',
|
48
|
+
'dynamic constant assignment',
|
49
|
+
'unterminated string meets end of file',
|
50
|
+
'premature end of char-class:',
|
51
|
+
'embedded document meets end of file',
|
52
|
+
'can\'t find string "[^"]+" anywhere before EOF'
|
53
|
+
]
|
54
|
+
|
55
|
+
ERROR_TYPES=[
|
56
|
+
[/\bunexpected \$end,\s+expecting (?:keyword_end|kEND)/, :missing_end],
|
57
|
+
[/\bunexpected (?:keyword_end|kEND),\s+expecting \$end/, :extra_end],
|
58
|
+
[/\bexpecting '\)/, :missing_close_paren],
|
59
|
+
[/\bunexpected '\)/, :extra_close_paren],
|
60
|
+
[/\bexpecting '\]'/, :missing_close_bracket],
|
61
|
+
[/\bunexpected '\]/, :extra_close_bracket],
|
62
|
+
[/\bexpecting '\}'/, :missing_close_brace],
|
63
|
+
[/\bunexpected '\}/, :extra_close_brace],
|
64
|
+
[/\bunexpected (?:keyword_else|kELSE)/, :extra_else],
|
65
|
+
[/\bunexpected (?:keyword_when|kWHEN)/, :extra_when],
|
66
|
+
[/\bunexpected (?:keyword_rescue|kRESCUE)/, :extra_rescue],
|
67
|
+
[/\bunexpected (?:keyword_ensure|kENSURE)/, :extra_ensure],
|
68
|
+
[/\bunterminated string/, :missing_quote],
|
69
|
+
[/\bunexpected (?:keyword_end|kEND)/, :misplaced_end],
|
70
|
+
[/end pattern with unmatched parenthesis/, :missing_regexp_close_paren],
|
71
|
+
[/unmatched close parenthesis/, :extra_regexp_close_paren],
|
72
|
+
[/premature end of char-class/, :missing_regexp_close_bracket],
|
73
|
+
[/unknown regexp option/, :unknown_regexp_option],
|
74
|
+
[/dynamic constant assignment/, :dynamic_constant_assignment],
|
75
|
+
[/embedded document meets end of file/, :missing_block_comment_end],
|
76
|
+
[/can't find string "[^"]+" anywhere before EOF/, :missing_heredoc_end]
|
77
|
+
]
|
78
|
+
|
79
|
+
def initialize doc
|
80
|
+
@doc = doc
|
81
|
+
@regexp = %r{^-e:(\d+):\s+(?:syntax error,|(#{SPECIAL_ERROR_STRINGS.join '|'}))(?:\s+(.*)|$)}
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_syntax text, formatted
|
85
|
+
ruby = Ruber[:ruby_development].interpreter_for @doc
|
86
|
+
begin
|
87
|
+
msg = Open3.popen3(ruby, '-c', '-e', text) do |in_s, out_s, err_s|
|
88
|
+
error = err_s.read
|
89
|
+
out_s.read.strip != 'Syntax OK' ? error : ''
|
90
|
+
end
|
91
|
+
rescue SystemCallError
|
92
|
+
raise Ruber::SyntaxChecker::SyntaxNotChecked
|
93
|
+
end
|
94
|
+
parse_output msg, formatted
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def parse_output str, formatted
|
100
|
+
# The inner array is needed in case the first message doesn\'t use a
|
101
|
+
# recognized format (for example, regexp syntax errors don\'t have a standard
|
102
|
+
# format). Without this, in the lins cycle, the else clause would be
|
103
|
+
# executed and would fail because the error_lines array is empty.
|
104
|
+
error_lines = [ [ [] ] ]
|
105
|
+
lines = str.split_lines
|
106
|
+
return if lines.empty?
|
107
|
+
lines.each do |l|
|
108
|
+
if l.match @regexp
|
109
|
+
error = [[$2 ? "#{$2} #{$3}" : $3], $1.to_i - 1]
|
110
|
+
error_type = ERROR_TYPES.find{|a| a[0] =~ l}
|
111
|
+
error << error_type[1] if error_type
|
112
|
+
error_lines << error
|
113
|
+
else error_lines[-1][0] << l
|
114
|
+
end
|
115
|
+
end
|
116
|
+
error_lines.shift if error_lines.first.first.empty?
|
117
|
+
errors = error_lines.map do |a, number, type|
|
118
|
+
error = SyntaxError.new number, nil, a.shift, nil, type
|
119
|
+
a.each_with_index do |l, i|
|
120
|
+
if l.match %r{^\s*\^\s*$}
|
121
|
+
error.column = l.index '^'
|
122
|
+
previous_line = a[i-1]
|
123
|
+
if previous_line and previous_line.match /^\.{3}/
|
124
|
+
offset = ( @doc.line(error.line) =~ /#{Regexp.quote(previous_line[3..-1])}/)
|
125
|
+
error.column += offset if offset
|
126
|
+
end
|
127
|
+
else error.message << "\n" << l
|
128
|
+
end
|
129
|
+
end
|
130
|
+
if formatted
|
131
|
+
msg = error.message.dup
|
132
|
+
msg.gsub! /expect(ed|ing)\s+\$end/, 'expect\1 end of file'
|
133
|
+
msg.gsub! /expect(ed|ing)\s+kEND/, 'expect\1 `end` keyword'
|
134
|
+
msg.gsub! /expect(ed|ing)\s+keyword_end/, 'expect\1 `end` keyword'
|
135
|
+
error.formatted_message = msg
|
136
|
+
else error.formatted_message = error.message.dup
|
137
|
+
end
|
138
|
+
error
|
139
|
+
end
|
140
|
+
errors
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -3,16 +3,20 @@ version: 0.0.1
|
|
3
3
|
about:
|
4
4
|
authors: [Stefano Crocco, stefano.crocco@alice.it]
|
5
5
|
license: :gpl
|
6
|
-
description:
|
6
|
+
description: Infrastructure to check the syntax of documents (needs other plugins to perform the actual syntax check)
|
7
7
|
icon: tools-check-spelling
|
8
8
|
bug_address: http://github.com/stcrocco/ruber/issues
|
9
|
-
class: Ruber::SyntaxChecker::
|
9
|
+
class: Ruber::SyntaxChecker::Plugin
|
10
10
|
require: syntax_checker
|
11
|
-
deps: ruby_development
|
12
11
|
config_options:
|
13
12
|
syntax_checker:
|
14
|
-
|
13
|
+
time_interval: {default: 1}
|
14
|
+
project_options:
|
15
|
+
syntax_checker:
|
16
|
+
auto_check: {scope: document, default: true}
|
15
17
|
config_widgets:
|
16
|
-
{caption: Syntax,
|
18
|
+
{caption: Syntax, class: Ruber::SyntaxChecker::ConfigWidget, pixmap: tools-check-spelling.png}
|
19
|
+
project_widgets:
|
20
|
+
{caption: Syntax, code: 'Qt::CheckBox.new("&Automatically check syntax for this document"){self.object_name = "_syntax_checker__auto_check"}', pixmap: tools-check-spelling.png, scope: document}
|
17
21
|
extensions:
|
18
|
-
syntax_checker: {class: Ruber::SyntaxChecker::
|
22
|
+
syntax_checker: {class: Ruber::SyntaxChecker::Extension, scope: document}
|
@@ -22,6 +22,7 @@ require 'tempfile'
|
|
22
22
|
require 'open3'
|
23
23
|
|
24
24
|
require 'facets/boolean'
|
25
|
+
require_relative 'ui/config_widget'
|
25
26
|
|
26
27
|
module Ruber
|
27
28
|
|
@@ -61,604 +62,299 @@ syntax checks after one second of inactivity
|
|
61
62
|
=end
|
62
63
|
module SyntaxChecker
|
63
64
|
|
65
|
+
# SyntaxError = Struct.new :line, :column, :message, :formatted_message
|
66
|
+
|
67
|
+
class SyntaxNotChecked < Exception
|
68
|
+
end
|
69
|
+
#
|
70
|
+
# class SyntaxError
|
71
|
+
#
|
72
|
+
# def format
|
73
|
+
# res = ""
|
74
|
+
# res << KDE.i18n("Line %d") % (line + 1) if line
|
75
|
+
# res << KDE.i18n(", column %d") % (column + 1) if line and column
|
76
|
+
# msg = formatted_message || message
|
77
|
+
# res << ": " if msg and !res.empty?
|
78
|
+
# res << msg
|
79
|
+
# res
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# end
|
83
|
+
|
64
84
|
=begin rdoc
|
65
|
-
Plugin object for the @
|
85
|
+
Plugin object for the @syntax_checker@ feature
|
66
86
|
|
67
87
|
@api class SyntaxChecker::SyntaxCheckerPlugin
|
68
88
|
@api_method #register_syntax_checker
|
69
89
|
@api_method #remove_syntax_checker
|
70
90
|
=end
|
71
|
-
class
|
91
|
+
class Plugin < Ruber::Plugin
|
72
92
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
1, while Document and EditorView count lines from 0)
|
77
|
-
message:= a string describing the syntax error
|
78
|
-
code:= a string with the code around the point where the syntax error occurred
|
79
|
-
column:= the column at which the syntax error occurred
|
80
|
-
|
81
|
-
This class'constructor can take up to four parameters, corresponding (in
|
82
|
-
the same order) to the four attributes described above.
|
83
|
-
=end
|
84
|
-
ErrorDescription = Struct.new(:line, :message, :code, :column)
|
93
|
+
attr_reader :current_status
|
94
|
+
|
95
|
+
attr_reader :current_errors
|
85
96
|
|
86
|
-
=begin rdoc
|
87
|
-
Colors used to display the different states of the document
|
88
|
-
=end
|
89
97
|
COLORS = {
|
90
98
|
:correct => Qt::Color.new(Qt.green),
|
91
|
-
:
|
92
|
-
:
|
93
|
-
|
99
|
+
:unknown => Qt::Color.new(Qt.gray),
|
100
|
+
:incorrect => Qt::Color.new(Qt.red)
|
101
|
+
}
|
94
102
|
|
95
|
-
=
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
=begin rdoc
|
101
|
-
Creates an instance of the plugin
|
102
|
-
|
103
|
-
It also registers the two built-in syntax checkers
|
103
|
+
MESSAGES = {
|
104
|
+
:correct => 'No syntax errors',
|
105
|
+
:unknown => 'Unknown document type',
|
106
|
+
:incorrect => 'There are syntax errors'
|
107
|
+
}
|
104
108
|
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
class Led < KDE::Led
|
110
|
+
|
111
|
+
signals 'context_menu_requested(QPoint)'
|
112
|
+
|
113
|
+
signals :left_clicked
|
114
|
+
|
115
|
+
def contextMenuEvent e
|
116
|
+
emit context_menu_requested(e.global_pos)
|
117
|
+
end
|
118
|
+
|
119
|
+
def mouseReleaseEvent e
|
120
|
+
emit left_clicked if e.button == Qt::LeftButton
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
signals :settings_changed
|
126
|
+
|
127
|
+
signals :syntax_checker_added
|
128
|
+
|
129
|
+
signals :syntax_checker_removed
|
130
|
+
|
108
131
|
def initialize psf
|
109
132
|
super
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@led =
|
133
|
+
self.connect(SIGNAL('extension_added(QString, QObject*)')) do |name, prj|
|
134
|
+
connect prj.extension(name.to_sym), SIGNAL('syntax_checked(QObject*)'), self, SLOT('document_checked(QObject*)')
|
135
|
+
end
|
136
|
+
@syntax_checkers = {}
|
137
|
+
@led = Led.new
|
138
|
+
connect @led, SIGNAL('context_menu_requested(QPoint)'), self, SLOT('display_context_menu(QPoint)')
|
139
|
+
connect @led, SIGNAL(:left_clicked), self, SLOT(:jump_to_first_error)
|
115
140
|
Ruber[:main_window].status_bar.add_permanent_widget @led
|
116
|
-
|
141
|
+
set_current_status :unknown
|
117
142
|
end
|
118
143
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
@return [Object,nil] a syntax checker suitable for _doc_ or *nil* if _doc_ is not
|
124
|
-
associated with a file or no syntax checker has been registered for <i>doc</i>'s extension
|
125
|
-
or mimetype
|
126
|
-
=end
|
127
|
-
def syntax_checker_for doc
|
128
|
-
checker_cls = @availlable_syntax_checkers.find! do |cls, data|
|
129
|
-
doc.file_type_match?(*data) ? cls : nil
|
130
|
-
end
|
131
|
-
checker_cls ? checker_cls.new(doc) : nil
|
144
|
+
def unload
|
145
|
+
Ruber[:main_window].status_bar.remove_widget @led
|
146
|
+
super
|
147
|
+
self
|
132
148
|
end
|
133
149
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
@param [Array<SyntaxCheckerPlugin::ErrorDescription>] errors an array containing
|
140
|
-
instances of class {SyntaxCheckerPlugin::ErrorDescription} describing each of the
|
141
|
-
syntax error which where found in the document. This argument is only used if
|
142
|
-
_status_ is @:error@
|
143
|
-
@return [SyntaxCheckerPlugin] *self*
|
144
|
-
=end
|
145
|
-
def mark_document_as status, errors = []
|
146
|
-
msg = case status
|
147
|
-
when :correct then 'Syntax OK'
|
148
|
-
when :unknown then 'Document type unknown'
|
149
|
-
when :error then errors.map{|e| format_error_message e}.join "\n"
|
150
|
+
def format_error error
|
151
|
+
msg = ''
|
152
|
+
if error.line
|
153
|
+
msg << KDE.i18n("Line %d") % (error.line + 1)
|
154
|
+
msg << (error.column ? (KDE.i18n(", column %d: ")) % (error.column + 1) : ': ')
|
150
155
|
end
|
151
|
-
|
156
|
+
msg << KDE.i18n(error.formatted_message || error.message || 'UNKNOWN ERROR')
|
157
|
+
msg
|
158
|
+
end
|
159
|
+
|
160
|
+
def set_current_status status, errors = []
|
152
161
|
@led.color = COLORS[status]
|
153
|
-
|
162
|
+
if status == :incorrect and !errors.empty?
|
163
|
+
tool_tip = errors.map do |e|
|
164
|
+
format_error e
|
165
|
+
end.join "\n"
|
166
|
+
@led.tool_tip = tool_tip
|
167
|
+
else @led.tool_tip = i18n(MESSAGES[status])
|
168
|
+
end
|
169
|
+
@current_status = status
|
170
|
+
if @current_status == :incorrect
|
171
|
+
@current_errors = errors.dup
|
172
|
+
else @current_errors = nil
|
173
|
+
end
|
154
174
|
end
|
155
175
|
|
156
|
-
=begin rdoc
|
157
|
-
Registers a new syntax checker.
|
158
|
-
|
159
|
-
A syntax checker is an object which analyzes the contents of a document and tells
|
160
|
-
whether its syntax is correct or not. To register it with the plugin, you need
|
161
|
-
to pass the object's class, toghether with the mimetypes and file patterns it
|
162
|
-
should be used to check syntax for, to this method. When a new document with the
|
163
|
-
appropriate mimetype or file name is created, a new instances of the syntax checker
|
164
|
-
class will be created.
|
165
|
-
|
166
|
-
The syntax checker class must have the following characteristics:
|
167
|
-
* its constructor should take the document as only parameter
|
168
|
-
* it should have a @check@ method which takes a string (corresponding to the text
|
169
|
-
of the document) and performs the syntax check on it. It must return a string
|
170
|
-
with all the information needed to retrieve the information about the single
|
171
|
-
errors.
|
172
|
-
* it should have a @convert_check_result@ method, which takes the string
|
173
|
-
returned by the @check@ method and converts it to an array of {ErrorDescription}
|
174
|
-
objects, with each object containing the information about a single error. If
|
175
|
-
the document doesn't contain any syntax error, this method should return an
|
176
|
-
empty array.
|
177
|
-
|
178
|
-
|
179
|
-
@param [Class] cls the class to instantiate to create the syntax checker
|
180
|
-
@param [String, <String>] mimetypes the mimetypes to use the new syntax checker
|
181
|
-
for. It has the format described in {Document#file_type_match?}
|
182
|
-
@param [String, <String>] patterns the file patterns to use the new syntax checker
|
183
|
-
for. It has the format described in {Document#file_type_match?}
|
184
|
-
@return [SyntaxCheckerPlugin] *self*
|
185
|
-
@raise ArgumentError if _cls_ had already been registered as a syntax checker.
|
186
|
-
=end
|
187
176
|
def register_syntax_checker cls, mimetypes, patterns = []
|
188
|
-
if @
|
189
|
-
raise ArgumentError, "
|
190
|
-
|
191
|
-
|
177
|
+
if @syntax_checkers.include? cls
|
178
|
+
raise ArgumentError, "#{cls} has already been registered as syntax checker"
|
179
|
+
end
|
180
|
+
@syntax_checkers[cls] = [mimetypes, patterns]
|
181
|
+
emit syntax_checker_added
|
192
182
|
end
|
193
183
|
|
194
|
-
=begin rdoc
|
195
|
-
Removes a registered syntax checker.
|
196
|
-
|
197
|
-
Nothing is done if the syntax checker hadn't been registered.
|
198
|
-
|
199
|
-
@param [Class] cls the class of the syntax checker to remove
|
200
|
-
@return [Boolean] *true* if the syntax checker was removed and *false* if it wasn't
|
201
|
-
registered
|
202
|
-
=end
|
203
184
|
def remove_syntax_checker cls
|
204
|
-
|
205
|
-
res.to_bool
|
206
|
-
end
|
207
|
-
|
208
|
-
=begin rdoc
|
209
|
-
Prepares the plugin for application shutdown
|
210
|
-
@return [SyntaxCheckerPlugin] *self*
|
211
|
-
=end
|
212
|
-
def shutdown
|
213
|
-
@timer.stop
|
214
|
-
self
|
185
|
+
emit syntax_checker_removed if @syntax_checkers.delete cls
|
215
186
|
end
|
216
187
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
Ruber[:main_window].status_bar.remove_widget @led
|
224
|
-
super
|
225
|
-
self
|
188
|
+
def syntax_checker_for doc
|
189
|
+
cls = @syntax_checkers.find do |_, rules|
|
190
|
+
doc.file_type_match?(rules[0], rules[1])
|
191
|
+
end
|
192
|
+
return unless cls
|
193
|
+
cls[0]
|
226
194
|
end
|
227
195
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
The returned string contains the error message together with information about
|
232
|
-
the line and the column (if known) where the error happened
|
233
|
-
|
234
|
-
@param [ErrorDescription] error the object containing the error message
|
235
|
-
@return [String] a string containing the error message, including line and row
|
236
|
-
where the error happened, formatted in a standard way
|
237
|
-
=end
|
238
|
-
def format_error_message error
|
239
|
-
res = "Line #{error.line}"
|
240
|
-
res += " Col #{error.column}" if error.column
|
241
|
-
res += ": #{error.message}"
|
242
|
-
res
|
196
|
+
def load_settings
|
197
|
+
emit settings_changed
|
243
198
|
end
|
244
199
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
@timer.stop
|
253
|
-
@timer.start
|
200
|
+
private
|
201
|
+
|
202
|
+
def display_context_menu pt
|
203
|
+
return if @current_status == :unknown
|
204
|
+
if !@current_errors || @current_errors.empty?
|
205
|
+
actions = [KDE::Action.new(i18n(MESSAGES[@current_status]), @led)]
|
206
|
+
else actions = @current_errors.map{|e| KDE::Action.new format_error(e), @led}
|
254
207
|
end
|
255
|
-
|
208
|
+
choice = Qt::Menu.exec actions, pt
|
209
|
+
return if !choice or !@current_errors or @current_errors.empty?
|
210
|
+
error = @current_errors[actions.index(choice)]
|
211
|
+
line = error.line
|
212
|
+
col = error.column || 0
|
213
|
+
Ruber[:world].active_environment.active_editor.go_to line, col if line
|
256
214
|
end
|
215
|
+
slots 'display_context_menu(QPoint)'
|
257
216
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
self
|
217
|
+
def jump_to_first_error
|
218
|
+
return unless @current_errors and !@current_errors.empty?
|
219
|
+
e = @current_errors[0]
|
220
|
+
col = e.column || 0
|
221
|
+
if e.line
|
222
|
+
Ruber[:world].active_environment.active_editor.go_to e.line, col
|
223
|
+
end
|
266
224
|
end
|
225
|
+
slots :jump_to_first_error
|
267
226
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
the timer is destroyed
|
273
|
-
|
274
|
-
@return [nil]
|
275
|
-
=end
|
276
|
-
def load_settings
|
277
|
-
auto_check = Ruber[:config][:syntax_checker, :automatic_check]
|
278
|
-
if auto_check and !@timer
|
279
|
-
@timer = Qt::Timer.new self
|
280
|
-
@timer.interval = 1000
|
281
|
-
connect @timer, SIGNAL(:timeout), self, SIGNAL(:timeout)
|
282
|
-
@timer.start if Ruber[:main_window].current_document
|
283
|
-
elsif !auto_check
|
284
|
-
@timer.disconnect self
|
285
|
-
@timer.dispose
|
286
|
-
@timer = nil
|
287
|
-
end
|
288
|
-
nil
|
227
|
+
def document_checked doc
|
228
|
+
return unless doc.active?
|
229
|
+
ext = doc.extension(:syntax_checker)
|
230
|
+
set_current_status ext.status, ext.errors
|
289
231
|
end
|
232
|
+
slots 'document_checked(QObject*)'
|
290
233
|
|
291
234
|
end
|
292
|
-
|
293
|
-
|
294
|
-
Document extension which checks the syntax for a document. The syntax check happens:
|
295
|
-
* when the document becomes active
|
296
|
-
* when the document is saved
|
297
|
-
* one second after the last modification (if the user has enabled automatic checks)
|
298
|
-
|
299
|
-
The check can only be done if a syntax checker for the document's mimetype
|
300
|
-
or file extension exists. New syntax checkers must be added to the syntax checker
|
301
|
-
plugin using the {SyntaxCheckerPlugin#register_syntax_checker} method,
|
302
|
-
and can be removed using {SyntaxCheckerPlugin#remove_syntax_checker}.
|
303
|
-
|
304
|
-
The appropriate syntax checker for the document is chosen when the extension is
|
305
|
-
added to the document, and is changed (if needed) whenever the @document_name@
|
306
|
-
of the document changes.
|
307
|
-
|
308
|
-
*Note:* in the documentation of this class, the term _document_ will refer
|
309
|
-
to the Document passed as argument to the constructor.
|
310
|
-
=end
|
311
|
-
class SyntaxCheckerExtension < Qt::Object
|
235
|
+
|
236
|
+
class Extension < Qt::Object
|
312
237
|
|
313
|
-
include Extension
|
314
|
-
|
315
|
-
=begin rdoc
|
316
|
-
Signal emitted after a syntax check has been completed
|
317
|
-
|
318
|
-
@param [String] result a string containing the results of the syntax check
|
319
|
-
=end
|
320
|
-
signals 'check_done(QString)'
|
238
|
+
include Ruber::Extension
|
321
239
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
=begin rdoc
|
326
|
-
A list of the syntax errors found in the document
|
240
|
+
SyntaxErrorMark = KTextEditor::MarkInterface.markType09
|
241
|
+
|
242
|
+
DEFAULT_CHECK_OPTIONS = {:format => true, :update => true}
|
327
243
|
|
328
|
-
The list is empty if the document doesn't contain syntax errors or if it hasn't
|
329
|
-
been checked yet
|
330
|
-
|
331
|
-
@return [<SyntaxCheckerPlugin::ErrorDescription>] the syntax errors found in the
|
332
|
-
document
|
333
|
-
=end
|
334
244
|
attr_reader :errors
|
335
245
|
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
=end
|
246
|
+
attr_reader :status
|
247
|
+
|
248
|
+
signals 'syntax_checked(QObject*)'
|
249
|
+
|
341
250
|
def initialize prj
|
342
251
|
super
|
343
|
-
@
|
252
|
+
@status = :unknown
|
253
|
+
@errors = nil
|
344
254
|
@doc = prj.document
|
345
|
-
@
|
346
|
-
@
|
255
|
+
@project = prj
|
256
|
+
connect @doc, SIGNAL('document_url_changed(QObject*)'), self, SLOT(:create_syntax_checker)
|
257
|
+
connect @doc, SIGNAL('document_saved_or_uploaded(QObject*, bool)'), self,
|
258
|
+
SLOT(:auto_check)
|
259
|
+
connect @doc, SIGNAL('text_changed(QObject*)'), self, SLOT(:start_waiting)
|
260
|
+
create_syntax_checker
|
347
261
|
connect @doc, SIGNAL(:activated), self, SLOT(:document_activated)
|
348
|
-
connect @doc, SIGNAL(:deactivated), self, SLOT(:
|
349
|
-
|
350
|
-
|
262
|
+
connect @doc, SIGNAL(:deactivated), self, SLOT(:delete_timer)
|
263
|
+
connect Ruber[:syntax_checker], SIGNAL(:settings_changed), self, SLOT(:load_settings)
|
264
|
+
connect Ruber[:syntax_checker], SIGNAL(:syntax_checker_added), self, SLOT(:create_syntax_checker_if_needed)
|
265
|
+
connect Ruber[:syntax_checker], SIGNAL(:syntax_checker_removed), self, SLOT(:create_syntax_checker)
|
266
|
+
load_settings
|
267
|
+
document_activated false if @doc.active?
|
268
|
+
end
|
269
|
+
|
270
|
+
def check_syntax options = DEFAULT_CHECK_OPTIONS
|
271
|
+
options = DEFAULT_CHECK_OPTIONS.merge options
|
272
|
+
if @checker
|
273
|
+
begin
|
274
|
+
errors = @checker.check_syntax @doc.text, options[:format]
|
275
|
+
res = {:errors => errors, :result => errors ? :incorrect : :correct}
|
276
|
+
rescue SyntaxNotChecked
|
277
|
+
res = {:result => :unknown, :errors => nil}
|
278
|
+
end
|
279
|
+
else res = {:result => :unknown, :errors => nil}
|
351
280
|
end
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
281
|
+
if options[:format] and options[:update]
|
282
|
+
@errors = errors
|
283
|
+
@status = res[:result]
|
284
|
+
if errors
|
285
|
+
#Uncomment the following lines when KTextEditor::MarkInterface#marks works
|
286
|
+
# iface = @doc.interface('mark_interface')
|
287
|
+
# errors.each do |e|
|
288
|
+
# iface.add_mark e.line, SyntaxErrorMark if e.line
|
289
|
+
# end
|
357
290
|
end
|
291
|
+
emit syntax_checked(@doc) if options[:format]
|
358
292
|
end
|
359
|
-
|
360
|
-
create_syntax_checker
|
293
|
+
res
|
361
294
|
end
|
295
|
+
slots :check_syntax
|
362
296
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
It marks the current document as having correct or incorrect syntax depending on
|
367
|
-
the contents of _str_.
|
368
|
-
|
369
|
-
@param [String] str the string containing the results of the syntax check (such as
|
370
|
-
the one that a syntax checker's @check@ method). It is passed to the syntax checker's
|
371
|
-
@convert_check_result@ method
|
372
|
-
@return [nil]
|
373
|
-
=end
|
374
|
-
def update_ui str
|
375
|
-
@errors = @checker.convert_check_result str
|
376
|
-
if @errors.empty? then @plugin.mark_document_as :correct
|
377
|
-
else @plugin.mark_document_as :error, @errors
|
378
|
-
end
|
379
|
-
nil
|
297
|
+
def remove_from_project
|
298
|
+
super
|
299
|
+
@timer.stop if @timer
|
380
300
|
end
|
381
301
|
|
382
|
-
|
383
|
-
|
384
|
-
end
|
302
|
+
private
|
385
303
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
The syntax check can be synchronous or asynchronous, according to the value of
|
390
|
-
the argument. In the first case, this method won't return until the syntax check
|
391
|
-
has finished and the UI has been updated. In the second case, the method will
|
392
|
-
start the syntax check in a new thread and return immediately. The {#check_done}
|
393
|
-
signal will be emitted when the syntax check has been finished.
|
394
|
-
|
395
|
-
Nothing will be done if no checker exists for the document.
|
396
|
-
|
397
|
-
*Note:* while an asynchronous syntax check avoids freezing the UI if it takes
|
398
|
-
a long time, it seems that it takes much longer than a synchronous check.
|
399
|
-
|
400
|
-
@param [Boolean] async whether the syntax check should or not be asynchronous
|
401
|
-
@todo the decision on whether the check should be synchronous or asynchronous
|
402
|
-
should be delegated to the checker
|
403
|
-
@return [nil]
|
404
|
-
=end
|
405
|
-
def check async = false
|
406
|
-
return unless @checker
|
407
|
-
@plugin.stop_timer
|
408
|
-
if async
|
409
|
-
@threak.kill if @thread
|
410
|
-
@thread = Thread.new(@doc.text) do |str|
|
411
|
-
res = @checker.check @doc.text
|
412
|
-
emit check_done res
|
413
|
-
end
|
414
|
-
else
|
415
|
-
res = @checker.check @doc.text
|
416
|
-
update_ui res
|
304
|
+
def create_syntax_checker_if_needed
|
305
|
+
unless @checker
|
306
|
+
create_syntax_checker
|
417
307
|
end
|
418
|
-
nil
|
419
308
|
end
|
309
|
+
slots :create_syntax_checker_if_needed
|
420
310
|
|
421
|
-
private
|
422
|
-
|
423
|
-
=begin rdoc
|
424
|
-
Creates a syntax checker for the document
|
425
|
-
|
426
|
-
If needed, it also removes the old one and immediately performs a syntax check
|
427
|
-
|
428
|
-
@return [nil]
|
429
|
-
=end
|
430
311
|
def create_syntax_checker
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
@checker = nil
|
435
|
-
if new_checker
|
436
|
-
@checker = new_checker
|
437
|
-
connect self, SIGNAL('check_done(QString)'), self, SLOT('update_ui(QString)')
|
438
|
-
end
|
439
|
-
check if @doc.active?
|
440
|
-
end
|
441
|
-
nil
|
312
|
+
checker_cls = Ruber[:syntax_checker].syntax_checker_for @doc
|
313
|
+
@checker = checker_cls ? checker_cls.new(@doc) : nil
|
314
|
+
auto_check
|
442
315
|
end
|
316
|
+
slots :create_syntax_checker
|
443
317
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
@return [nil]
|
448
|
-
=end
|
449
|
-
def document_deactivated
|
450
|
-
@thread.kill if @thread
|
451
|
-
@plugin.stop_timer
|
452
|
-
@plugin.disconnect SIGNAL(:timeout), self, SLOT(:check)
|
453
|
-
Ruber[:syntax_checker].mark_document_as :unknown
|
454
|
-
nil
|
318
|
+
def auto_check
|
319
|
+
check_syntax if @project[:syntax_checker, :auto_check]
|
455
320
|
end
|
321
|
+
slots :auto_check
|
456
322
|
|
457
|
-
=
|
458
|
-
|
459
|
-
|
460
|
-
@
|
461
|
-
|
462
|
-
def document_activated
|
463
|
-
connect @plugin, SIGNAL(:timeout), self, SLOT(:check)
|
464
|
-
check
|
465
|
-
nil
|
323
|
+
def document_activated check_syntax = true
|
324
|
+
@timer = Qt::Timer.new self
|
325
|
+
@timer.singleShot = true
|
326
|
+
connect @timer, SIGNAL(:timeout), self, SLOT(:auto_check)
|
327
|
+
auto_check if check_syntax
|
466
328
|
end
|
329
|
+
slots :document_activated
|
467
330
|
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
To do so, it runs a separate ruby process (using the ruby interpreter set by the
|
474
|
-
Ruby Runner plugin) passing it the @-c@ and the @-e@ options with the document's
|
475
|
-
content as argument.
|
476
|
-
|
477
|
-
The process is executed using @Open3.popen3@
|
478
|
-
=end
|
479
|
-
class RubySyntaxChecker
|
480
|
-
|
481
|
-
=begin rdoc
|
482
|
-
Creates a new instance.
|
483
|
-
|
484
|
-
@param [Document] doc the document to check
|
485
|
-
=end
|
486
|
-
def initialize doc
|
487
|
-
@doc = doc
|
331
|
+
def delete_timer
|
332
|
+
@timer.stop
|
333
|
+
@timer.delete_later
|
334
|
+
@timer = nil
|
488
335
|
end
|
336
|
+
slots :delete_timer
|
489
337
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
@param [String] str the string to check (usually, it'll be the document's text)
|
494
|
-
@return [String] a string containing the lines of output produced by ruby concerning
|
495
|
-
syntax errors or an empty string if there were no syntax error
|
496
|
-
=end
|
497
|
-
def check str
|
498
|
-
ruby = Ruber[:ruby_development].interpreter_for @doc
|
499
|
-
Open3.popen3(ruby, '-c', '-e', str) do |in_s, out_s, err_s|
|
500
|
-
error = err_s.read
|
501
|
-
error.gsub! %r{^-e(?=:\d+:\s+syntax error,)}, @doc.path
|
502
|
-
out_s.read.strip != 'Syntax OK' ? error : ''
|
503
|
-
end
|
338
|
+
def load_settings
|
339
|
+
@time_interval = Ruber[:config][:syntax_checker, :time_interval]
|
504
340
|
end
|
341
|
+
slots :load_settings
|
505
342
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
@param [String] str the string to parse.
|
510
|
-
@return [<SyntaxCheckerPlugin::ErrorDescription>] a list of {SyntaxCheckerPlugin::ErrorDescription ErrorDescription}s
|
511
|
-
corresponding to the syntax errors mentioned in _str_
|
512
|
-
=end
|
513
|
-
def convert_check_result str
|
514
|
-
groups = [[]]
|
515
|
-
lines = str.split "\n"
|
516
|
-
lines.each do |l|
|
517
|
-
if l.match(/^#{Regexp.quote(@doc.path||'')}:\d+:\s+syntax error,\s+/) then groups << [l]
|
518
|
-
else groups[-1] << l
|
519
|
-
end
|
520
|
-
end
|
521
|
-
groups.delete_if{|g| g.empty?}
|
522
|
-
groups.map do |a|
|
523
|
-
a.shift.match(/^#{Regexp.quote(@doc.path||'')}:(\d+):\s+syntax error,\s+(.*)/)
|
524
|
-
msgs = [$2]
|
525
|
-
error = SyntaxCheckerPlugin::ErrorDescription.new $1.to_i
|
526
|
-
if a[-1] and a[-1].match(/^\s*\^\s*$/)
|
527
|
-
error.code = a[-2]
|
528
|
-
# Sometimes, ruby doesn't report the whole line where the error occurs, but only
|
529
|
-
# the part nearest it. In this case, the beginning of the line is replaced with ... .
|
530
|
-
# In this case, to obtain the correct column number, we try a regexp match
|
531
|
-
# between the part of code reported by ruby and the whole line. If it works, we
|
532
|
-
# add that position to the one returned by ruby. If it doesn't (for example because
|
533
|
-
# the user changed the document in the meantime), we'll just report what ruby reports
|
534
|
-
col = a[-1].index('^')
|
535
|
-
if a[-2].match(/^\.\.\./)
|
536
|
-
lines = @doc.text.split("\n")
|
537
|
-
# error.line is 1-based
|
538
|
-
l = lines[error.line-1] || ''
|
539
|
-
pos = (l =~ /#{Regexp.quote(a[-2][3..-1])}/)
|
540
|
-
error.column = pos ? col + pos - 1 : col
|
541
|
-
else error.column = col
|
542
|
-
end
|
543
|
-
a.pop 2
|
544
|
-
end
|
545
|
-
a.each{|l| msgs << l}
|
546
|
-
error.message = msgs.join ' '
|
547
|
-
error
|
548
|
-
end
|
343
|
+
def start_waiting
|
344
|
+
@timer.start 1_000 * @time_interval if @time_interval > 0 and @doc.active?
|
549
345
|
end
|
346
|
+
slots :start_waiting
|
550
347
|
|
551
348
|
end
|
552
|
-
|
553
|
-
|
554
|
-
Class which checks the syntax of a ruby file.
|
555
|
-
|
556
|
-
It calls the @YAML.load@ method on the document's content within a begin/rescue
|
557
|
-
block, rescuing any ArgumentError exception. The message of the exception is used
|
558
|
-
to find information about the error
|
559
|
-
=end
|
560
|
-
class YamlSyntaxChecker
|
561
|
-
|
562
|
-
=begin rdoc
|
563
|
-
Creates a new instance
|
564
|
-
|
565
|
-
@param [Document] doc the document to check
|
566
|
-
=end
|
567
|
-
def initialize doc
|
568
|
-
end
|
569
|
-
|
570
|
-
=begin rdoc
|
571
|
-
Checks the syntax of the given string.
|
572
|
-
|
573
|
-
@param [String] str the string to check (usually, it'll be the document's text)
|
574
|
-
@return [String] a string containing the lines of output produced by @YAML.load@
|
575
|
-
concerning syntax errors or an empty string if there were no syntax error
|
576
|
-
=end
|
577
|
-
def check str
|
578
|
-
begin
|
579
|
-
YAML.load str
|
580
|
-
''
|
581
|
-
rescue ArgumentError => e
|
582
|
-
e.message
|
583
|
-
end
|
584
|
-
end
|
349
|
+
|
350
|
+
class ConfigWidget < Qt::Widget
|
585
351
|
|
586
|
-
=
|
587
|
-
|
588
|
-
|
589
|
-
@
|
590
|
-
@return [<SyntaxCheckerPlugin::ErrorDescription>] a list of {SyntaxCheckerPlugin::ErrorDescription ErrorDescription}s
|
591
|
-
corresponding to the syntax errors mentioned in _str_
|
592
|
-
=end
|
593
|
-
def convert_check_result str
|
594
|
-
return [] if str.empty?
|
595
|
-
str.match(/^syntax error on line (\d+), col (\d+): `(.*)'$/)
|
596
|
-
error = SyntaxCheckerPlugin::ErrorDescription.new $1.to_i, 'Syntax error', $3.to_s, $2.to_i
|
597
|
-
[error]
|
352
|
+
def initialize parent = nil
|
353
|
+
super
|
354
|
+
@ui = Ui::SyntaxCheckerConfigWidget.new
|
355
|
+
@ui.setup_ui self
|
598
356
|
end
|
599
357
|
|
600
|
-
end
|
601
|
-
|
602
|
-
=begin rdoc
|
603
|
-
@KDE::Led@ with the ability to jump to the first syntax error on left or middle mouse
|
604
|
-
click and to popup a menu with a list of all syntax errors in the current document
|
605
|
-
on right click
|
606
|
-
=end
|
607
|
-
class SyntaxResultWidget < KDE::Led
|
608
|
-
|
609
|
-
=begin rdoc
|
610
|
-
Override of @Qt::Widget#mouseReleaseEvent@
|
611
|
-
|
612
|
-
If the event refers to the left button and the current document contains syntax
|
613
|
-
errors, it moves the cursor in the editor view to the position of the first error
|
614
|
-
|
615
|
-
@return [nil]
|
616
|
-
=end
|
617
|
-
def mouseReleaseEvent e
|
618
|
-
return unless e.button == Qt::LeftButton or e.button == Qt::MidButton
|
619
|
-
doc = Ruber[:main_window].current_document
|
620
|
-
view = Ruber[:main_window].active_editor
|
621
|
-
return unless view and doc and doc.extension(:syntax_checker)
|
622
|
-
checker = doc.extension(:syntax_checker)
|
623
|
-
err = checker.errors.first
|
624
|
-
if err
|
625
|
-
view.go_to err.line - 1, (err.column || 0)
|
626
|
-
Ruber[:main_window].status_bar.show_message Ruber[:syntax_checker].format_error_message(err), 4000
|
627
|
-
end
|
628
|
-
nil
|
629
|
-
end
|
630
|
-
|
631
|
-
=begin rdoc
|
632
|
-
Override of @Qt::Widget#contextMenuEvent@
|
633
|
-
|
634
|
-
If the current document contains syntax errors, it displays a menu listing them.
|
635
|
-
Each action in the menu moves the cursor in the editor view to display to the line
|
636
|
-
and column of the corresponding error.
|
637
|
-
|
638
|
-
If the current document doesn't contain syntax errors, the menu will only contain
|
639
|
-
an entry with text @Syntax OK@ which does nothing when activated.
|
640
|
-
|
641
|
-
@return [nil]
|
642
|
-
=end
|
643
|
-
def contextMenuEvent event
|
644
|
-
doc = Ruber[:main_window].current_document
|
645
|
-
view = Ruber[:main_window].active_editor
|
646
|
-
return unless doc and view and (checker = doc.extension :syntax_checker)
|
647
|
-
errors = checker.errors
|
648
|
-
actions = errors.map do |e|
|
649
|
-
a = KDE::Action.new Ruber[:syntax_checker].format_error_message(e), self
|
650
|
-
end
|
651
|
-
actions << KDE::Action.new('Syntax OK', self) if actions.empty?
|
652
|
-
res = Qt::Menu.exec(actions, event.global_pos)
|
653
|
-
return if !res or errors.empty?
|
654
|
-
idx = actions.index res
|
655
|
-
return unless idx
|
656
|
-
error = errors[idx]
|
657
|
-
view.go_to error.line - 1, (error.column || 0)
|
658
|
-
Ruber[:main_window].status_bar.show_message res.text, 4000
|
659
|
-
nil
|
660
|
-
end
|
661
|
-
|
662
358
|
end
|
663
359
|
|
664
360
|
end
|