Skip to content

Commit dd99693

Browse files
committed
On-save check: Show result in window status when done.
Includes minor cleanup for tracking message levels.
1 parent fae26a0 commit dd99693

File tree

7 files changed

+123
-38
lines changed

7 files changed

+123
-38
lines changed

SyntaxCheckPlugin.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,31 @@ def run(self):
7878

7979
self.update_status()
8080
self.this_view_found = False
81+
CHECK_FAIL_MSG = 'Rust check failed, see console or debug log.'
8182
try:
8283
messages.clear_messages(self.window)
8384
try:
84-
self.get_rustc_messages()
85+
rc = self.get_rustc_messages()
8586
except rust_proc.ProcessTerminatedError:
87+
self.window.status_message('')
8688
return
87-
messages.messages_finished(self.window)
89+
except Exception as e:
90+
self.window.status_message(CHECK_FAIL_MSG)
91+
raise
8892
finally:
8993
self.done = True
90-
self.window.status_message('')
94+
messages.messages_finished(self.window)
95+
counts = messages.message_counts(self.window)
96+
if counts:
97+
msg = []
98+
for key, value in sorted(counts.items(), key=lambda x: x[0]):
99+
level = key.plural if value > 1 else key.name
100+
msg.append('%i %s' % (value, level))
101+
self.window.status_message('Rust check: %s' % (', '.join(msg,)))
102+
elif rc:
103+
self.window.status_message(CHECK_FAIL_MSG)
104+
else:
105+
self.window.status_message('Rust check: success')
91106

92107
def update_status(self, count=0):
93108
if self.done:
@@ -105,6 +120,9 @@ def get_rustc_messages(self):
105120
filename.
106121
107122
:raises rust_proc.ProcessTerminatedError: Check was canceled.
123+
:raises OSError: Failed to launch the child process.
124+
125+
:returns: Returns the process return code.
108126
"""
109127
method = util.get_setting('rust_syntax_checking_method', 'check')
110128
settings = cargo_settings.CargoSettings(self.window)
@@ -119,8 +137,7 @@ def get_rustc_messages(self):
119137
self.msg_rel_path = cmd['msg_rel_path']
120138
p = rust_proc.RustProc()
121139
p.run(self.window, cmd['command'], self.cwd, self, env=cmd['env'])
122-
p.wait()
123-
return
140+
return p.wait()
124141

125142
if method == 'no-trans':
126143
print('rust_syntax_checking_method == "no-trans" is no longer supported.')
@@ -129,10 +146,13 @@ def get_rustc_messages(self):
129146

130147
if method != 'check':
131148
print('Unknown setting for `rust_syntax_checking_method`: %r' % (method,))
132-
return
149+
return -1
133150

134151
td = target_detect.TargetDetector(self.window)
135152
targets = td.determine_targets(self.triggered_file_name)
153+
if not targets:
154+
return -1
155+
rc = 0
136156
for (target_src, target_args) in targets:
137157
cmd = settings.get_command(method, command_info, self.cwd, self.cwd,
138158
initial_settings={'target': ' '.join(target_args)},
@@ -149,9 +169,10 @@ def get_rustc_messages(self):
149169
p = rust_proc.RustProc()
150170
self.current_target_src = target_src
151171
p.run(self.window, cmd['command'], self.cwd, self, env=cmd['env'])
152-
p.wait()
172+
rc = p.wait()
153173
if self.this_view_found:
154-
break
174+
return rc
175+
return rc
155176

156177
#########################################################################
157178
# ProcListner methods

rust/levels.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import sublime
2+
from . import log
3+
4+
5+
class Level:
6+
7+
def __init__(self, order, name, plural):
8+
self.order = order
9+
self.name = name
10+
self.plural = plural
11+
12+
def __hash__(self):
13+
return hash(self.name)
14+
15+
def __eq__(self, other):
16+
if isinstance(other, Level):
17+
return self.name == other.name
18+
elif isinstance(other, str):
19+
return self.name == other
20+
else:
21+
return False
22+
23+
def __lt__(self, other):
24+
return self.order < other.order
25+
26+
def __le__(self, other):
27+
return self.order <= other.order
28+
29+
def __gt__(self, other):
30+
return self.order > other.order
31+
32+
def __ge__(self, other):
33+
return self.order >= other.order
34+
35+
def __repr__(self):
36+
return self.name
37+
38+
39+
LEVELS = {
40+
'error': Level(0, 'error', 'errors'),
41+
'warning': Level(1, 'warning', 'warnings'),
42+
'note': Level(2, 'note', 'notes'),
43+
'help': Level(3, 'help', 'help'),
44+
}
45+
46+
47+
def level_from_str(level):
48+
if level.startswith('error:'):
49+
# ICE
50+
level = 'error'
51+
try:
52+
return LEVELS[level]
53+
except KeyError:
54+
log.critical(sublime.active_window(),
55+
'RustEnhanced: Unknown message level %r encountered.',
56+
level)
57+
return LEVELS['error']

rust/messages.py

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from . import util, themes, log
1717
from .batch import *
18+
from .levels import *
1819

1920
# Key is window id.
2021
# Value is a dictionary: {
@@ -42,7 +43,7 @@ class Message:
4243
be None if the content is raw markup (such as a minihtml link) or if
4344
it is an outline-only region (which happens with things such as
4445
dual-region messages added in 1.21).
45-
:ivar level: Message level as a string such as "error", or "info".
46+
:ivar level: Message level as a `Level` object.
4647
:ivar span: Location of the message (0-based):
4748
`((line_start, col_start), (line_end, col_end))`
4849
May be `None` to indicate no particular spot.
@@ -258,27 +259,17 @@ def messages_finished(window):
258259
def _draw_region_highlights(view, batch):
259260
if util.get_setting('rust_region_style') == 'none':
260261
return
261-
262-
# Collect message regions by level.
263-
regions = {
264-
'error': [],
265-
'warning': [],
266-
'note': [],
267-
'help': [],
268-
}
269262
if batch.hidden:
270263
return
264+
265+
# Collect message regions by level.
266+
regions = {level: [] for level in LEVELS.values()}
271267
for msg in batch:
272268
region = msg.sublime_region(view)
273-
if msg.level not in regions:
274-
log.critical(view.window(),
275-
'RustEnhanced: Unknown message level %r encountered.',
276-
msg.level)
277-
msg.level = 'error'
278269
regions[msg.level].append((msg.region_key, region))
279270

280271
# Do this in reverse order so that errors show on-top.
281-
for level in ['help', 'note', 'warning', 'error']:
272+
for level in reversed(sorted(list(LEVELS.values()))):
282273
# Use scope names from color themes to drive the color of the outline.
283274
# 'invalid' typically is red. We use 'info' for all other levels, which
284275
# is usually not defined in any color theme, and will end up showing as
@@ -293,7 +284,7 @@ def _draw_region_highlights(view, batch):
293284
scope = 'invalid'
294285
else:
295286
scope = 'info'
296-
icon = util.icon_path(level)
287+
icon = util.icon_path(level.name)
297288
for key, region in regions[level]:
298289
_sublime_add_regions(
299290
view, key, [region], scope, icon,
@@ -468,13 +459,8 @@ def _sort_messages(window):
468459
items = []
469460
for path, batches in batches_by_path.items():
470461
for batch in batches:
471-
level = {
472-
'error': 0,
473-
'warning': 1,
474-
'note': 2,
475-
'help': 3,
476-
}.get(batch.first().level, 0)
477-
items.append((level, path, batch.first().lineno(), batch))
462+
first = batch.first()
463+
items.append((first.level, path, first.lineno(), batch))
478464
items.sort(key=lambda x: x[:3])
479465
batches_by_path = collections.OrderedDict()
480466
for _, path, _, batch in items:
@@ -737,6 +723,19 @@ def on_highlighted(idx):
737723
window.show_quick_panel(panel_items, on_done, 0, 0, on_highlighted)
738724

739725

726+
def message_counts(window):
727+
result = collections.Counter()
728+
try:
729+
win_info = WINDOW_MESSAGES[window.id()]
730+
except KeyError:
731+
return result
732+
for batches in win_info['paths'].values():
733+
for batch in batches:
734+
if isinstance(batch, PrimaryBatch):
735+
result[batch.first().level] += 1
736+
return result
737+
738+
740739
def add_rust_messages(window, base_path, info, target_path, msg_cb):
741740
"""Add messages from Rust JSON to Sublime views.
742741
@@ -876,13 +875,13 @@ def set_primary_message(span, text):
876875
message.path = make_span_path(span)
877876
message.span = make_span_region(span)
878877
message.text = text
879-
message.level = info['level']
878+
message.level = level_from_str(info['level'])
880879

881880
def add_additional(span, text, level, suggested_replacement=None):
882881
child = Message()
883882
child.text = text
884883
child.suggested_replacement = suggested_replacement
885-
child.level = level
884+
child.level = level_from_str(level)
886885
child.primary = False
887886
if 'macros>' in span['file_name']:
888887
# Nowhere to display this, just send it to the console via msg_cb.
@@ -925,7 +924,7 @@ def add_additional(span, text, level, suggested_replacement=None):
925924
# put it.
926925
if msg_cb:
927926
tmp_msg = Message()
928-
tmp_msg.level = info['level']
927+
tmp_msg.level = level_from_str(info['level'])
929928
tmp_msg.text = imsg
930929
msg_cb(tmp_msg)
931930

rust/opanel.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import os
66
import re
7-
from . import rust_proc, messages, util, semver, log
7+
from . import rust_proc, messages, util, semver, levels, log
88

99
# Use the same panel name that Sublime's build system uses so that "Show Build
1010
# Results" will open the same panel. I don't see any particular reason why
@@ -98,7 +98,7 @@ def on_data(self, proc, data):
9898
region_start + m.end())
9999
message.output_panel_region = build_region
100100
message.path = path
101-
message.level = 'error'
101+
message.level = levels.level_from_str('error')
102102
messages.add_message(self.window, message)
103103

104104
def on_error(self, proc, message):
@@ -118,7 +118,7 @@ def msg_cb(self, message):
118118
if not message.text:
119119
# Region-only messages can be ignored.
120120
return
121-
region_start = self.output_view.size() + len(message.level) + 2
121+
region_start = self.output_view.size() + len(message.level.name) + 2
122122
path = message.path
123123
if path:
124124
if self.base_path and path.startswith(self.base_path):

rust/rust_proc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ def slurp_json(window, cmd, cwd):
9191
:returns: List of parsed JSON objects.
9292
9393
:raises ProcessTermiantedError: Process was terminated by another thread.
94+
:raises OSError: Failed to launch the child process. `FileNotFoundError`
95+
is a typical example if the executable is not found.
9496
"""
9597
rc, listener = _slurp(window, cmd, cwd)
9698
if not listener.json and rc:
@@ -109,6 +111,8 @@ def check_output(window, cmd, cwd):
109111
:returns: A string of the command's output.
110112
111113
:raises ProcessTermiantedError: Process was terminated by another thread.
114+
:raises OSError: Failed to launch the child process. `FileNotFoundError`
115+
is a typical example if the executable is not found.
112116
:raises subprocess.CalledProcessError: The command returned a nonzero exit
113117
status.
114118
"""
@@ -160,6 +164,9 @@ def run(self, window, cmd, cwd, listener, env=None,
160164
161165
:raises ProcessTermiantedError: Process was terminated by another
162166
thread.
167+
:raises OSError: Failed to launch the child process.
168+
`FileNotFoundError` is a typical example if the executable is not
169+
found.
163170
"""
164171
self.cmd = cmd
165172
self.cwd = cwd

rust/themes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def render(self, view, batch, for_popup=False):
104104
level_text = ''
105105
else:
106106
if msg.level == last_level:
107-
level_text = '&nbsp;' * (len(msg.level) + 2)
107+
level_text = '&nbsp;' * (len(str(msg.level)) + 2)
108108
else:
109109
level_text = '%s: ' % (msg.level,)
110110
last_level = msg.level

rust/util.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def get_cargo_metadata(window, cwd, toolchain=None):
135135

136136
def icon_path(level, res=None):
137137
"""Return a path to a message-level icon."""
138+
level = str(level)
138139
if level not in ('error', 'warning', 'note', 'help', 'none'):
139140
return ''
140141
gutter_style = get_setting('rust_gutter_style', 'shape')

0 commit comments

Comments
 (0)