Skip to content

Commit

Permalink
Update message handling for Rust 1.24. (#235)
Browse files Browse the repository at this point in the history
* Remove Cargo.lock files in tests, not needed.

* Update message handling for Rust 1.24.
  • Loading branch information
ehuss authored and Jason Williams committed Jan 27, 2018
1 parent 270fa6b commit 0f06274
Show file tree
Hide file tree
Showing 30 changed files with 140 additions and 175 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,2 +1,3 @@
*.cache
target/
Cargo.lock
12 changes: 8 additions & 4 deletions SyntaxCheckPlugin.py
Expand Up @@ -73,8 +73,10 @@ class RustSyntaxCheckThread(rust_thread.RustThread, rust_proc.ProcListener):
view = None
# Absolute path to the view that triggered the check.
triggered_file_name = None
# Directory of `triggered_file_name`.
# Directory where cargo will be run.
cwd = None
# Base path for relative paths in messages.
msg_rel_path = None
# This flag is used to terminate early. In situations where we can't
# auto-detect the appropriate Cargo target, we compile multiple targets.
# If we receive any messages for the current view, we might as well stop.
Expand Down Expand Up @@ -125,7 +127,8 @@ def get_rustc_messages(self):
# Clippy does not support cargo target filters, must be run for
# all targets.
cmd = settings.get_command(method, command_info, self.cwd,
force_json=True)
self.cwd, force_json=True)
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()
Expand All @@ -135,9 +138,10 @@ def get_rustc_messages(self):
td = target_detect.TargetDetector(self.window)
targets = td.determine_targets(self.triggered_file_name)
for (target_src, target_args) in targets:
cmd = settings.get_command(method, command_info, self.cwd,
cmd = settings.get_command(method, command_info, self.cwd, self.cwd,
initial_settings={'target': ' '.join(target_args)},
force_json=True)
self.msg_rel_path = cmd['msg_rel_path']
if method == 'no-trans':
cmd['command'].extend(['--', '-Zno-trans', '-Zunstable-options'])
if (util.get_setting('rust_syntax_checking_include_tests', True) and
Expand Down Expand Up @@ -173,7 +177,7 @@ def on_error(self, proc, message):
print('Rust Error: %s' % message)

def on_json(self, proc, obj):
messages.add_rust_messages(self.window, self.cwd, obj,
messages.add_rust_messages(self.window, self.msg_rel_path, obj,
self.current_target_src, msg_cb=None)
if messages.has_message_for_path(self.window,
self.triggered_file_name):
Expand Down
6 changes: 4 additions & 2 deletions cargo_build.py
Expand Up @@ -191,13 +191,15 @@ def run(self):
cmd = self.settings.get_command(self.command_name,
self.command_info,
self.settings_path,
self.working_dir,
self.initial_settings)
if not cmd:
return
messages.clear_messages(self.window)
p = rust_proc.RustProc()
listener = opanel.OutputListener(self.window, self.working_dir,
self.command_name)
listener = opanel.OutputListener(self.window, cmd['msg_rel_path'],
self.command_name,
cmd['rustc_version'])
decode_json = util.get_setting('show_errors_inline', True) and \
self.command_info.get('allows_json', False)
try:
Expand Down
54 changes: 12 additions & 42 deletions rust/cargo_config.py
Expand Up @@ -9,7 +9,7 @@
import sublime
import sublime_plugin
from .cargo_settings import CargoSettings, CARGO_COMMANDS
from .util import index_with
from .util import index_with, get_cargo_metadata
from . import rust_proc, util

# Keep track of recent choices to set the default value.
Expand Down Expand Up @@ -54,7 +54,7 @@ class CargoConfigBase(sublime_plugin.WindowCommand):

# Dictionary of choices passed into the command, instead of using
# interactive UI.
input = None
cmd_input = None

# Sequence of questions to ask.
sequence = None
Expand Down Expand Up @@ -90,7 +90,7 @@ def run(self, **kwargs):
self.sequence_index = 0
# Copy, since WindowCommand reuses objects.
self._sequence = self.sequence[:]
self.input = kwargs
self.cmd_input = kwargs
self.settings = CargoSettings(self.window)
self.settings.load()
self.show_next_question()
Expand Down Expand Up @@ -123,8 +123,8 @@ def make_choice(value):
self._sequence[i:i] = next
self.show_next_question()

if q in self.input:
make_choice(self.input[q])
if q in self.cmd_input:
make_choice(self.cmd_input[q])
else:
try:
item_info = getattr(self, 'items_' + q)()
Expand Down Expand Up @@ -286,11 +286,11 @@ def items_which(self):
"""Choice to select at which level the setting should be saved at."""
# This is a bit of a hack so that when called programmatically you
# don't have to specify 'which'.
if 'which' not in self.input:
if 'variant' in self.input:
self.input['which'] = 'project_package_variant'
elif 'target' in self.input:
self.input['which'] = 'project_package_target'
if 'which' not in self.cmd_input:
if 'variant' in self.cmd_input:
self.cmd_input['which'] = 'project_package_variant'
elif 'target' in self.cmd_input:
self.cmd_input['which'] = 'project_package_target'

variant_extra = 'cargo build, cargo run, cargo test, etc.'
target_extra = '--bin, --example, --test, etc.'
Expand Down Expand Up @@ -615,9 +615,9 @@ def done(self):
// Enter environment variables here in JSON syntax.
// Close this view when done to commit the settings.
""")
if 'contents' in self.input:
if 'contents' in self.cmd_input:
# Used when parsing fails to attempt to edit again.
template = self.input['contents']
template = self.cmd_input['contents']
elif default:
template += sublime.encode_value(default, True)
else:
Expand Down Expand Up @@ -948,33 +948,3 @@ def _stock_build_system(self):
pkg_name = __name__.split('.')[0]
resource = 'Packages/%s/RustEnhanced.sublime-build' % pkg_name
return sublime.decode_value(sublime.load_resource(resource))


def get_cargo_metadata(window, cwd):
"""Load Cargo metadata.
:returns: None on failure, otherwise a dictionary from Cargo:
- packages: List of packages:
- name
- manifest_path: Path to Cargo.toml.
- targets: List of target dictionaries:
- name: Name of target.
- src_path: Path of top-level source file. May be a
relative path.
- kind: List of kinds. May contain multiple entries if
`crate-type` specifies multiple values in Cargo.toml.
Lots of different types of values:
- Libraries: 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib',
'proc-macro'
- Executables: 'bin', 'test', 'example', 'bench'
- build.rs: 'custom-build'
:raises ProcessTermiantedError: Process was terminated by another thread.
"""
output = rust_proc.slurp_json(window,
'cargo metadata --no-deps'.split(),
cwd=cwd)
if output:
return output[0]
else:
return None
26 changes: 24 additions & 2 deletions rust/cargo_settings.py
Expand Up @@ -350,22 +350,29 @@ def get_merged(self, settings_path, variant, target, key,
return result

def get_command(self, cmd_name, cmd_info,
settings_path, initial_settings={}, force_json=False):
settings_path, working_dir,
initial_settings={}, force_json=False):
"""Generates the command arguments for running Cargo.
:param cmd_name: The name of the command, the key used to select a
"variant".
:param cmd_info: Dictionary from `CARGO_COMMANDS` with rules on how to
construct the command.
:param settings_path: The absolute path to the Cargo project root
directory.
directory or script.
:param working_dir: The directory where Cargo is to be run (typically
the project root).
:keyword initial_settings: Initial settings to inject which override
all other settings.
:keyword force_json: If True, will force JSON output.
:Returns: A dictionary with the keys:
- `command`: The command to run as a list of strings.
- `env`: Dictionary of environment variables (or None).
- `msg_rel_path`: The root path to use for relative paths in
messages.
- `rustc_version`: The version of rustc being used as a string,
such as '1.25.0-nightly'.
Returns None if the command cannot be constructed.
"""
Expand Down Expand Up @@ -453,7 +460,22 @@ def expand(s):
if not env:
env = None

# Determine the base path for paths in messages.
#
# Starting in Rust 1.24, all messages and symbols are relative to the
# workspace root instead of the package root.
metadata = util.get_cargo_metadata(self.window, working_dir, toolchain)
if metadata and 'workspace_root' in metadata:
# 'workspace_root' key added in 1.24.
msg_rel_path = metadata['workspace_root']
else:
msg_rel_path = working_dir

rustc_version = util.get_rustc_version(self.window, working_dir, toolchain=toolchain)

return {
'command': result,
'env': env,
'msg_rel_path': msg_rel_path,
'rustc_version': rustc_version,
}
12 changes: 6 additions & 6 deletions rust/messages.py
Expand Up @@ -636,11 +636,11 @@ def on_highlighted(idx):
window.show_quick_panel(panel_items, on_done, 0, 0, on_highlighted)


def add_rust_messages(window, cwd, info, target_path, msg_cb):
def add_rust_messages(window, base_path, info, target_path, msg_cb):
"""Add messages from Rust JSON to Sublime views.
- `window`: Sublime Window object.
- `cwd`: Directory where cargo/rustc was run.
- `base_path`: Base path used for resolving relative paths from Rust.
- `info`: Dictionary of messages from rustc or cargo.
- `target_path`: Absolute path to the top-level source file of the target
(lib.rs, main.rs, etc.). May be None if it is not known.
Expand Down Expand Up @@ -684,7 +684,7 @@ def add_rust_messages(window, cwd, info, target_path, msg_cb):
# List of message dictionaries, belonging to the main message.
additional_messages = []

_collect_rust_messages(window, cwd, info, target_path, msg_cb, {},
_collect_rust_messages(window, base_path, info, target_path, msg_cb, {},
main_message, additional_messages)

messages = _create_cross_links(main_message, additional_messages)
Expand Down Expand Up @@ -750,7 +750,7 @@ def escape_and_link(i_txt):
False, None, content, None)


def _collect_rust_messages(window, cwd, info, target_path,
def _collect_rust_messages(window, base_path, info, target_path,
msg_cb, parent_info,
main_message, additional_messages):
"""
Expand Down Expand Up @@ -831,7 +831,7 @@ def _collect_rust_messages(window, cwd, info, target_path,
return

def make_span_path(span):
return os.path.realpath(os.path.join(cwd, span['file_name']))
return os.path.realpath(os.path.join(base_path, span['file_name']))

def make_span_region(span):
# Sublime text is 0 based whilst the line/column info from
Expand Down Expand Up @@ -981,7 +981,7 @@ def find_span_r(span, expansion=None):

# Recurse into children (which typically hold notes).
for child in info['children']:
_collect_rust_messages(window, cwd, child, target_path,
_collect_rust_messages(window, base_path, child, target_path,
msg_cb, parent_info.copy(),
main_message, additional_messages)

Expand Down
14 changes: 9 additions & 5 deletions rust/opanel.py
Expand Up @@ -4,15 +4,15 @@

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

# 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
# this would be a problem. If it is, it's a simple matter of changing this.
PANEL_NAME = 'exec'


def create_output_panel(window, cwd):
def create_output_panel(window, base_dir):
output_view = window.create_output_panel(PANEL_NAME)
s = output_view.settings()
if util.get_setting('show_errors_inline', True):
Expand All @@ -25,7 +25,7 @@ def create_output_panel(window, cwd):
pattern = '(?|%s|%s)' % (build_pattern, test_pattern)
s.set('result_file_regex', pattern)
# Used for resolving relative paths.
s.set('result_base_dir', cwd)
s.set('result_base_dir', base_dir)
s.set('word_wrap', True) # XXX Or False?
s.set('line_numbers', False)
s.set('gutter', False)
Expand Down Expand Up @@ -58,10 +58,11 @@ class OutputListener(rust_proc.ProcListener):
# Sublime view used for output.
output_view = None

def __init__(self, window, base_path, command_name):
def __init__(self, window, base_path, command_name, rustc_version):
self.window = window
self.base_path = base_path
self.command_name = command_name
self.rustc_version = rustc_version

def on_begin(self, proc):
self.output_view = create_output_panel(self.window, self.base_path)
Expand All @@ -87,6 +88,9 @@ def on_data(self, proc, data):
lineno = int(m.group(2)) - 1
# Region columns appear to the left, so this is +1.
col = int(m.group(3))
# Rust 1.24 changed column numbering to be 1-based.
if semver.match(self.rustc_version, '>=1.24.0-beta'):
col -= 1
span = ((lineno, col), (lineno, col))
# +2 to skip ", "
build_region = sublime.Region(region_start + m.start() + 2,
Expand All @@ -105,7 +109,7 @@ def on_error(self, proc, message):

def on_json(self, proc, obj):
if 'message' in obj:
messages.add_rust_messages(self.window, proc.cwd, obj['message'],
messages.add_rust_messages(self.window, self.base_path, obj['message'],
None, self.msg_cb)

def msg_cb(self, message):
Expand Down
35 changes: 35 additions & 0 deletions rust/util.py
Expand Up @@ -110,3 +110,38 @@ def active_view_is_rust(window=None, view=None):
if not view.file_name():
return False
return 'source.rust' in view.scope_name(0)


def get_cargo_metadata(window, cwd, toolchain=None):
"""Load Cargo metadata.
:returns: None on failure, otherwise a dictionary from Cargo:
- packages: List of packages:
- name
- manifest_path: Path to Cargo.toml.
- targets: List of target dictionaries:
- name: Name of target.
- src_path: Path of top-level source file. May be a
relative path.
- kind: List of kinds. May contain multiple entries if
`crate-type` specifies multiple values in Cargo.toml.
Lots of different types of values:
- Libraries: 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib',
'proc-macro'
- Executables: 'bin', 'test', 'example', 'bench'
- build.rs: 'custom-build'
:raises ProcessTermiantedError: Process was terminated by another thread.
"""
from . import rust_proc
cmd = ['cargo']
if toolchain:
cmd.append('+' + toolchain)
cmd.extend(['metadata', '--no-deps'])
output = rust_proc.slurp_json(window,
cmd,
cwd=cwd)
if output:
return output[0]
else:
return None
11 changes: 0 additions & 11 deletions tests/error-tests/Cargo.lock

This file was deleted.

4 changes: 0 additions & 4 deletions tests/error-tests/dcrate/Cargo.lock

This file was deleted.

3 changes: 2 additions & 1 deletion tests/error-tests/tests/arg-count-mismatch.rs
Expand Up @@ -11,8 +11,9 @@
// error-pattern: parameters were supplied

/*BEGIN*/fn f(x: isize) {
// ^^^^^^^^^^^^^^ERR(>=1.24.0-beta) defined here
}/*END*/
// ~ERR defined here
// ~ERR(<1.24.0-beta) defined here

// children without spans, spans with no labels
// Should display error (with link) and a note of expected type.
Expand Down

0 comments on commit 0f06274

Please sign in to comment.