Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On-save check: Show result in window status when done. #345

Merged
merged 1 commit into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions SyntaxCheckPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,31 @@ def run(self):

self.update_status()
self.this_view_found = False
CHECK_FAIL_MSG = 'Rust check failed, see console or debug log.'
try:
messages.clear_messages(self.window)
try:
self.get_rustc_messages()
rc = self.get_rustc_messages()
except rust_proc.ProcessTerminatedError:
self.window.status_message('')
return
messages.messages_finished(self.window)
except Exception as e:
self.window.status_message(CHECK_FAIL_MSG)
raise
finally:
self.done = True
self.window.status_message('')
messages.messages_finished(self.window)
counts = messages.message_counts(self.window)
if counts:
msg = []
for key, value in sorted(counts.items(), key=lambda x: x[0]):
level = key.plural if value > 1 else key.name
msg.append('%i %s' % (value, level))
self.window.status_message('Rust check: %s' % (', '.join(msg,)))
elif rc:
self.window.status_message(CHECK_FAIL_MSG)
else:
self.window.status_message('Rust check: success')

def update_status(self, count=0):
if self.done:
Expand All @@ -105,6 +120,9 @@ def get_rustc_messages(self):
filename.

:raises rust_proc.ProcessTerminatedError: Check was canceled.
:raises OSError: Failed to launch the child process.

:returns: Returns the process return code.
"""
method = util.get_setting('rust_syntax_checking_method', 'check')
settings = cargo_settings.CargoSettings(self.window)
Expand All @@ -119,8 +137,7 @@ def get_rustc_messages(self):
self.msg_rel_path = cmd['msg_rel_path']
p = rust_proc.RustProc()
p.run(self.window, cmd['command'], self.cwd, self, env=cmd['env'])
p.wait()
return
return p.wait()

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

if method != 'check':
print('Unknown setting for `rust_syntax_checking_method`: %r' % (method,))
return
return -1

td = target_detect.TargetDetector(self.window)
targets = td.determine_targets(self.triggered_file_name)
if not targets:
return -1
rc = 0
for (target_src, target_args) in targets:
cmd = settings.get_command(method, command_info, self.cwd, self.cwd,
initial_settings={'target': ' '.join(target_args)},
Expand All @@ -149,9 +169,10 @@ def get_rustc_messages(self):
p = rust_proc.RustProc()
self.current_target_src = target_src
p.run(self.window, cmd['command'], self.cwd, self, env=cmd['env'])
p.wait()
rc = p.wait()
if self.this_view_found:
break
return rc
return rc

#########################################################################
# ProcListner methods
Expand Down
57 changes: 57 additions & 0 deletions rust/levels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import sublime
from . import log


class Level:

def __init__(self, order, name, plural):
self.order = order
self.name = name
self.plural = plural

def __hash__(self):
return hash(self.name)

def __eq__(self, other):
if isinstance(other, Level):
return self.name == other.name
elif isinstance(other, str):
return self.name == other
else:
return False

def __lt__(self, other):
return self.order < other.order

def __le__(self, other):
return self.order <= other.order

def __gt__(self, other):
return self.order > other.order

def __ge__(self, other):
return self.order >= other.order

def __repr__(self):
return self.name


LEVELS = {
'error': Level(0, 'error', 'errors'),
'warning': Level(1, 'warning', 'warnings'),
'note': Level(2, 'note', 'notes'),
'help': Level(3, 'help', 'help'),
}


def level_from_str(level):
if level.startswith('error:'):
# ICE
level = 'error'
try:
return LEVELS[level]
except KeyError:
log.critical(sublime.active_window(),
'RustEnhanced: Unknown message level %r encountered.',
level)
return LEVELS['error']
51 changes: 25 additions & 26 deletions rust/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

from . import util, themes, log
from .batch import *
from .levels import *

# Key is window id.
# Value is a dictionary: {
Expand Down Expand Up @@ -42,7 +43,7 @@ class Message:
be None if the content is raw markup (such as a minihtml link) or if
it is an outline-only region (which happens with things such as
dual-region messages added in 1.21).
:ivar level: Message level as a string such as "error", or "info".
:ivar level: Message level as a `Level` object.
:ivar span: Location of the message (0-based):
`((line_start, col_start), (line_end, col_end))`
May be `None` to indicate no particular spot.
Expand Down Expand Up @@ -258,27 +259,17 @@ def messages_finished(window):
def _draw_region_highlights(view, batch):
if util.get_setting('rust_region_style') == 'none':
return

# Collect message regions by level.
regions = {
'error': [],
'warning': [],
'note': [],
'help': [],
}
if batch.hidden:
return

# Collect message regions by level.
regions = {level: [] for level in LEVELS.values()}
for msg in batch:
region = msg.sublime_region(view)
if msg.level not in regions:
log.critical(view.window(),
'RustEnhanced: Unknown message level %r encountered.',
msg.level)
msg.level = 'error'
regions[msg.level].append((msg.region_key, region))

# Do this in reverse order so that errors show on-top.
for level in ['help', 'note', 'warning', 'error']:
for level in reversed(sorted(list(LEVELS.values()))):
# Use scope names from color themes to drive the color of the outline.
# 'invalid' typically is red. We use 'info' for all other levels, which
# is usually not defined in any color theme, and will end up showing as
Expand All @@ -293,7 +284,7 @@ def _draw_region_highlights(view, batch):
scope = 'invalid'
else:
scope = 'info'
icon = util.icon_path(level)
icon = util.icon_path(level.name)
for key, region in regions[level]:
_sublime_add_regions(
view, key, [region], scope, icon,
Expand Down Expand Up @@ -468,13 +459,8 @@ def _sort_messages(window):
items = []
for path, batches in batches_by_path.items():
for batch in batches:
level = {
'error': 0,
'warning': 1,
'note': 2,
'help': 3,
}.get(batch.first().level, 0)
items.append((level, path, batch.first().lineno(), batch))
first = batch.first()
items.append((first.level, path, first.lineno(), batch))
items.sort(key=lambda x: x[:3])
batches_by_path = collections.OrderedDict()
for _, path, _, batch in items:
Expand Down Expand Up @@ -737,6 +723,19 @@ def on_highlighted(idx):
window.show_quick_panel(panel_items, on_done, 0, 0, on_highlighted)


def message_counts(window):
result = collections.Counter()
try:
win_info = WINDOW_MESSAGES[window.id()]
except KeyError:
return result
for batches in win_info['paths'].values():
for batch in batches:
if isinstance(batch, PrimaryBatch):
result[batch.first().level] += 1
return result


def add_rust_messages(window, base_path, info, target_path, msg_cb):
"""Add messages from Rust JSON to Sublime views.

Expand Down Expand Up @@ -876,13 +875,13 @@ def set_primary_message(span, text):
message.path = make_span_path(span)
message.span = make_span_region(span)
message.text = text
message.level = info['level']
message.level = level_from_str(info['level'])

def add_additional(span, text, level, suggested_replacement=None):
child = Message()
child.text = text
child.suggested_replacement = suggested_replacement
child.level = level
child.level = level_from_str(level)
child.primary = False
if 'macros>' in span['file_name']:
# Nowhere to display this, just send it to the console via msg_cb.
Expand Down Expand Up @@ -925,7 +924,7 @@ def add_additional(span, text, level, suggested_replacement=None):
# put it.
if msg_cb:
tmp_msg = Message()
tmp_msg.level = info['level']
tmp_msg.level = level_from_str(info['level'])
tmp_msg.text = imsg
msg_cb(tmp_msg)

Expand Down
6 changes: 3 additions & 3 deletions rust/opanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import os
import re
from . import rust_proc, messages, util, semver, log
from . import rust_proc, messages, util, semver, levels, log

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

def on_error(self, proc, message):
Expand All @@ -118,7 +118,7 @@ def msg_cb(self, message):
if not message.text:
# Region-only messages can be ignored.
return
region_start = self.output_view.size() + len(message.level) + 2
region_start = self.output_view.size() + len(message.level.name) + 2
path = message.path
if path:
if self.base_path and path.startswith(self.base_path):
Expand Down
7 changes: 7 additions & 0 deletions rust/rust_proc.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def slurp_json(window, cmd, cwd):
:returns: List of parsed JSON objects.

:raises ProcessTermiantedError: Process was terminated by another thread.
:raises OSError: Failed to launch the child process. `FileNotFoundError`
is a typical example if the executable is not found.
"""
rc, listener = _slurp(window, cmd, cwd)
if not listener.json and rc:
Expand All @@ -109,6 +111,8 @@ def check_output(window, cmd, cwd):
:returns: A string of the command's output.

:raises ProcessTermiantedError: Process was terminated by another thread.
:raises OSError: Failed to launch the child process. `FileNotFoundError`
is a typical example if the executable is not found.
:raises subprocess.CalledProcessError: The command returned a nonzero exit
status.
"""
Expand Down Expand Up @@ -160,6 +164,9 @@ def run(self, window, cmd, cwd, listener, env=None,

:raises ProcessTermiantedError: Process was terminated by another
thread.
:raises OSError: Failed to launch the child process.
`FileNotFoundError` is a typical example if the executable is not
found.
"""
self.cmd = cmd
self.cwd = cwd
Expand Down
2 changes: 1 addition & 1 deletion rust/themes.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def render(self, view, batch, for_popup=False):
level_text = ''
else:
if msg.level == last_level:
level_text = '&nbsp;' * (len(msg.level) + 2)
level_text = '&nbsp;' * (len(str(msg.level)) + 2)
else:
level_text = '%s: ' % (msg.level,)
last_level = msg.level
Expand Down
1 change: 1 addition & 0 deletions rust/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def get_cargo_metadata(window, cwd, toolchain=None):

def icon_path(level, res=None):
"""Return a path to a message-level icon."""
level = str(level)
if level not in ('error', 'warning', 'note', 'help', 'none'):
return ''
gutter_style = get_setting('rust_gutter_style', 'shape')
Expand Down