Skip to content

Commit 0f06274

Browse files
ehussJayflux
authored andcommitted
Update message handling for Rust 1.24. (#235)
* Remove Cargo.lock files in tests, not needed. * Update message handling for Rust 1.24.
1 parent 270fa6b commit 0f06274

30 files changed

+140
-175
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.cache
22
target/
3+
Cargo.lock

SyntaxCheckPlugin.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,10 @@ class RustSyntaxCheckThread(rust_thread.RustThread, rust_proc.ProcListener):
7373
view = None
7474
# Absolute path to the view that triggered the check.
7575
triggered_file_name = None
76-
# Directory of `triggered_file_name`.
76+
# Directory where cargo will be run.
7777
cwd = None
78+
# Base path for relative paths in messages.
79+
msg_rel_path = None
7880
# This flag is used to terminate early. In situations where we can't
7981
# auto-detect the appropriate Cargo target, we compile multiple targets.
8082
# If we receive any messages for the current view, we might as well stop.
@@ -125,7 +127,8 @@ def get_rustc_messages(self):
125127
# Clippy does not support cargo target filters, must be run for
126128
# all targets.
127129
cmd = settings.get_command(method, command_info, self.cwd,
128-
force_json=True)
130+
self.cwd, force_json=True)
131+
self.msg_rel_path = cmd['msg_rel_path']
129132
p = rust_proc.RustProc()
130133
p.run(self.window, cmd['command'], self.cwd, self, env=cmd['env'])
131134
p.wait()
@@ -135,9 +138,10 @@ def get_rustc_messages(self):
135138
td = target_detect.TargetDetector(self.window)
136139
targets = td.determine_targets(self.triggered_file_name)
137140
for (target_src, target_args) in targets:
138-
cmd = settings.get_command(method, command_info, self.cwd,
141+
cmd = settings.get_command(method, command_info, self.cwd, self.cwd,
139142
initial_settings={'target': ' '.join(target_args)},
140143
force_json=True)
144+
self.msg_rel_path = cmd['msg_rel_path']
141145
if method == 'no-trans':
142146
cmd['command'].extend(['--', '-Zno-trans', '-Zunstable-options'])
143147
if (util.get_setting('rust_syntax_checking_include_tests', True) and
@@ -173,7 +177,7 @@ def on_error(self, proc, message):
173177
print('Rust Error: %s' % message)
174178

175179
def on_json(self, proc, obj):
176-
messages.add_rust_messages(self.window, self.cwd, obj,
180+
messages.add_rust_messages(self.window, self.msg_rel_path, obj,
177181
self.current_target_src, msg_cb=None)
178182
if messages.has_message_for_path(self.window,
179183
self.triggered_file_name):

cargo_build.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,15 @@ def run(self):
191191
cmd = self.settings.get_command(self.command_name,
192192
self.command_info,
193193
self.settings_path,
194+
self.working_dir,
194195
self.initial_settings)
195196
if not cmd:
196197
return
197198
messages.clear_messages(self.window)
198199
p = rust_proc.RustProc()
199-
listener = opanel.OutputListener(self.window, self.working_dir,
200-
self.command_name)
200+
listener = opanel.OutputListener(self.window, cmd['msg_rel_path'],
201+
self.command_name,
202+
cmd['rustc_version'])
201203
decode_json = util.get_setting('show_errors_inline', True) and \
202204
self.command_info.get('allows_json', False)
203205
try:

rust/cargo_config.py

+12-42
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import sublime
1010
import sublime_plugin
1111
from .cargo_settings import CargoSettings, CARGO_COMMANDS
12-
from .util import index_with
12+
from .util import index_with, get_cargo_metadata
1313
from . import rust_proc, util
1414

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

5555
# Dictionary of choices passed into the command, instead of using
5656
# interactive UI.
57-
input = None
57+
cmd_input = None
5858

5959
# Sequence of questions to ask.
6060
sequence = None
@@ -90,7 +90,7 @@ def run(self, **kwargs):
9090
self.sequence_index = 0
9191
# Copy, since WindowCommand reuses objects.
9292
self._sequence = self.sequence[:]
93-
self.input = kwargs
93+
self.cmd_input = kwargs
9494
self.settings = CargoSettings(self.window)
9595
self.settings.load()
9696
self.show_next_question()
@@ -123,8 +123,8 @@ def make_choice(value):
123123
self._sequence[i:i] = next
124124
self.show_next_question()
125125

126-
if q in self.input:
127-
make_choice(self.input[q])
126+
if q in self.cmd_input:
127+
make_choice(self.cmd_input[q])
128128
else:
129129
try:
130130
item_info = getattr(self, 'items_' + q)()
@@ -286,11 +286,11 @@ def items_which(self):
286286
"""Choice to select at which level the setting should be saved at."""
287287
# This is a bit of a hack so that when called programmatically you
288288
# don't have to specify 'which'.
289-
if 'which' not in self.input:
290-
if 'variant' in self.input:
291-
self.input['which'] = 'project_package_variant'
292-
elif 'target' in self.input:
293-
self.input['which'] = 'project_package_target'
289+
if 'which' not in self.cmd_input:
290+
if 'variant' in self.cmd_input:
291+
self.cmd_input['which'] = 'project_package_variant'
292+
elif 'target' in self.cmd_input:
293+
self.cmd_input['which'] = 'project_package_target'
294294

295295
variant_extra = 'cargo build, cargo run, cargo test, etc.'
296296
target_extra = '--bin, --example, --test, etc.'
@@ -615,9 +615,9 @@ def done(self):
615615
// Enter environment variables here in JSON syntax.
616616
// Close this view when done to commit the settings.
617617
""")
618-
if 'contents' in self.input:
618+
if 'contents' in self.cmd_input:
619619
# Used when parsing fails to attempt to edit again.
620-
template = self.input['contents']
620+
template = self.cmd_input['contents']
621621
elif default:
622622
template += sublime.encode_value(default, True)
623623
else:
@@ -948,33 +948,3 @@ def _stock_build_system(self):
948948
pkg_name = __name__.split('.')[0]
949949
resource = 'Packages/%s/RustEnhanced.sublime-build' % pkg_name
950950
return sublime.decode_value(sublime.load_resource(resource))
951-
952-
953-
def get_cargo_metadata(window, cwd):
954-
"""Load Cargo metadata.
955-
956-
:returns: None on failure, otherwise a dictionary from Cargo:
957-
- packages: List of packages:
958-
- name
959-
- manifest_path: Path to Cargo.toml.
960-
- targets: List of target dictionaries:
961-
- name: Name of target.
962-
- src_path: Path of top-level source file. May be a
963-
relative path.
964-
- kind: List of kinds. May contain multiple entries if
965-
`crate-type` specifies multiple values in Cargo.toml.
966-
Lots of different types of values:
967-
- Libraries: 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib',
968-
'proc-macro'
969-
- Executables: 'bin', 'test', 'example', 'bench'
970-
- build.rs: 'custom-build'
971-
972-
:raises ProcessTermiantedError: Process was terminated by another thread.
973-
"""
974-
output = rust_proc.slurp_json(window,
975-
'cargo metadata --no-deps'.split(),
976-
cwd=cwd)
977-
if output:
978-
return output[0]
979-
else:
980-
return None

rust/cargo_settings.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -350,22 +350,29 @@ def get_merged(self, settings_path, variant, target, key,
350350
return result
351351

352352
def get_command(self, cmd_name, cmd_info,
353-
settings_path, initial_settings={}, force_json=False):
353+
settings_path, working_dir,
354+
initial_settings={}, force_json=False):
354355
"""Generates the command arguments for running Cargo.
355356
356357
:param cmd_name: The name of the command, the key used to select a
357358
"variant".
358359
:param cmd_info: Dictionary from `CARGO_COMMANDS` with rules on how to
359360
construct the command.
360361
:param settings_path: The absolute path to the Cargo project root
361-
directory.
362+
directory or script.
363+
:param working_dir: The directory where Cargo is to be run (typically
364+
the project root).
362365
:keyword initial_settings: Initial settings to inject which override
363366
all other settings.
364367
:keyword force_json: If True, will force JSON output.
365368
366369
:Returns: A dictionary with the keys:
367370
- `command`: The command to run as a list of strings.
368371
- `env`: Dictionary of environment variables (or None).
372+
- `msg_rel_path`: The root path to use for relative paths in
373+
messages.
374+
- `rustc_version`: The version of rustc being used as a string,
375+
such as '1.25.0-nightly'.
369376
370377
Returns None if the command cannot be constructed.
371378
"""
@@ -453,7 +460,22 @@ def expand(s):
453460
if not env:
454461
env = None
455462

463+
# Determine the base path for paths in messages.
464+
#
465+
# Starting in Rust 1.24, all messages and symbols are relative to the
466+
# workspace root instead of the package root.
467+
metadata = util.get_cargo_metadata(self.window, working_dir, toolchain)
468+
if metadata and 'workspace_root' in metadata:
469+
# 'workspace_root' key added in 1.24.
470+
msg_rel_path = metadata['workspace_root']
471+
else:
472+
msg_rel_path = working_dir
473+
474+
rustc_version = util.get_rustc_version(self.window, working_dir, toolchain=toolchain)
475+
456476
return {
457477
'command': result,
458478
'env': env,
479+
'msg_rel_path': msg_rel_path,
480+
'rustc_version': rustc_version,
459481
}

rust/messages.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,11 @@ def on_highlighted(idx):
636636
window.show_quick_panel(panel_items, on_done, 0, 0, on_highlighted)
637637

638638

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

687-
_collect_rust_messages(window, cwd, info, target_path, msg_cb, {},
687+
_collect_rust_messages(window, base_path, info, target_path, msg_cb, {},
688688
main_message, additional_messages)
689689

690690
messages = _create_cross_links(main_message, additional_messages)
@@ -750,7 +750,7 @@ def escape_and_link(i_txt):
750750
False, None, content, None)
751751

752752

753-
def _collect_rust_messages(window, cwd, info, target_path,
753+
def _collect_rust_messages(window, base_path, info, target_path,
754754
msg_cb, parent_info,
755755
main_message, additional_messages):
756756
"""
@@ -831,7 +831,7 @@ def _collect_rust_messages(window, cwd, info, target_path,
831831
return
832832

833833
def make_span_path(span):
834-
return os.path.realpath(os.path.join(cwd, span['file_name']))
834+
return os.path.realpath(os.path.join(base_path, span['file_name']))
835835

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

982982
# Recurse into children (which typically hold notes).
983983
for child in info['children']:
984-
_collect_rust_messages(window, cwd, child, target_path,
984+
_collect_rust_messages(window, base_path, child, target_path,
985985
msg_cb, parent_info.copy(),
986986
main_message, additional_messages)
987987

rust/opanel.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
import os
66
import re
7-
from . import rust_proc, messages, util
7+
from . import rust_proc, messages, util, semver
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
1111
# this would be a problem. If it is, it's a simple matter of changing this.
1212
PANEL_NAME = 'exec'
1313

1414

15-
def create_output_panel(window, cwd):
15+
def create_output_panel(window, base_dir):
1616
output_view = window.create_output_panel(PANEL_NAME)
1717
s = output_view.settings()
1818
if util.get_setting('show_errors_inline', True):
@@ -25,7 +25,7 @@ def create_output_panel(window, cwd):
2525
pattern = '(?|%s|%s)' % (build_pattern, test_pattern)
2626
s.set('result_file_regex', pattern)
2727
# Used for resolving relative paths.
28-
s.set('result_base_dir', cwd)
28+
s.set('result_base_dir', base_dir)
2929
s.set('word_wrap', True) # XXX Or False?
3030
s.set('line_numbers', False)
3131
s.set('gutter', False)
@@ -58,10 +58,11 @@ class OutputListener(rust_proc.ProcListener):
5858
# Sublime view used for output.
5959
output_view = None
6060

61-
def __init__(self, window, base_path, command_name):
61+
def __init__(self, window, base_path, command_name, rustc_version):
6262
self.window = window
6363
self.base_path = base_path
6464
self.command_name = command_name
65+
self.rustc_version = rustc_version
6566

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

106110
def on_json(self, proc, obj):
107111
if 'message' in obj:
108-
messages.add_rust_messages(self.window, proc.cwd, obj['message'],
112+
messages.add_rust_messages(self.window, self.base_path, obj['message'],
109113
None, self.msg_cb)
110114

111115
def msg_cb(self, message):

rust/util.py

+35
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,38 @@ def active_view_is_rust(window=None, view=None):
110110
if not view.file_name():
111111
return False
112112
return 'source.rust' in view.scope_name(0)
113+
114+
115+
def get_cargo_metadata(window, cwd, toolchain=None):
116+
"""Load Cargo metadata.
117+
118+
:returns: None on failure, otherwise a dictionary from Cargo:
119+
- packages: List of packages:
120+
- name
121+
- manifest_path: Path to Cargo.toml.
122+
- targets: List of target dictionaries:
123+
- name: Name of target.
124+
- src_path: Path of top-level source file. May be a
125+
relative path.
126+
- kind: List of kinds. May contain multiple entries if
127+
`crate-type` specifies multiple values in Cargo.toml.
128+
Lots of different types of values:
129+
- Libraries: 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib',
130+
'proc-macro'
131+
- Executables: 'bin', 'test', 'example', 'bench'
132+
- build.rs: 'custom-build'
133+
134+
:raises ProcessTermiantedError: Process was terminated by another thread.
135+
"""
136+
from . import rust_proc
137+
cmd = ['cargo']
138+
if toolchain:
139+
cmd.append('+' + toolchain)
140+
cmd.extend(['metadata', '--no-deps'])
141+
output = rust_proc.slurp_json(window,
142+
cmd,
143+
cwd=cwd)
144+
if output:
145+
return output[0]
146+
else:
147+
return None

tests/error-tests/Cargo.lock

-11
This file was deleted.

tests/error-tests/dcrate/Cargo.lock

-4
This file was deleted.

tests/error-tests/tests/arg-count-mismatch.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
// error-pattern: parameters were supplied
1212

1313
/*BEGIN*/fn f(x: isize) {
14+
// ^^^^^^^^^^^^^^ERR(>=1.24.0-beta) defined here
1415
}/*END*/
15-
// ~ERR defined here
16+
// ~ERR(<1.24.0-beta) defined here
1617

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

0 commit comments

Comments
 (0)