From ce5bb8b457479878f4a56563386ba09eab584e52 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 21 Jul 2019 10:21:35 -0700 Subject: [PATCH] Next/prev jump to end of span. This changes the next/prev commands to jump to the end of a message span instead of the beginning. When using inline phantoms, jumping to the beginning can be hard to see the message for a multi-line message. I've flip-flopped over time which I like better. I've been using "end" for a while now, and it seems to work better for me. If anyone objects, we can always add a config setting. This also changes how the test works, since the old test didn't handle this new format very well. --- rust/messages.py | 4 +- tests/message-order/examples/warning1.rs | 4 +- tests/message-order/examples/warning2.rs | 2 +- tests/message-order/tests/test_all_levels.rs | 4 +- tests/message-order/tests/test_test_output.rs | 12 +- tests/test_message_order.py | 160 ++++++++---------- 6 files changed, 85 insertions(+), 101 deletions(-) diff --git a/rust/messages.py b/rust/messages.py index 40f9f23e..9e9634ef 100644 --- a/rust/messages.py +++ b/rust/messages.py @@ -551,7 +551,7 @@ def _show_message(window, current_idx, transient=False, force_open=False): # show_at_center is buggy with newly opened views (see # https://github.com/SublimeTextIssues/Core/issues/538). # ENCODED_POSITION is 1-based. - row, col = msg.span[0] + row, col = msg.span[1] else: row, col = (999999999, 1) view = window.open_file('%s:%d:%d' % (path, row + 1, col + 1), @@ -586,7 +586,7 @@ def _scroll_to_message(view, message, transient): if not transient: view.window().focus_view(view) r = message.sublime_region(view) - view.run_command('rust_scroll_to_region', {'region': (r.a, r.a)}) + view.run_command('rust_scroll_to_region', {'region': (r.end(), r.end())}) def redraw_all_open_views(window): diff --git a/tests/message-order/examples/warning1.rs b/tests/message-order/examples/warning1.rs index 8132bf29..867b1f5c 100644 --- a/tests/message-order/examples/warning1.rs +++ b/tests/message-order/examples/warning1.rs @@ -1,7 +1,7 @@ -/*WARN 1 "examples/warning1.rs:1" " --> examples/warning1.rs:1:69"*/fn unused_a() { +fn unused_a() { } -/*WARN 2 "examples/warning1.rs:5" " --> examples/warning1.rs:5:69"*/fn unused_b() { +fn unused_b() { } diff --git a/tests/message-order/examples/warning2.rs b/tests/message-order/examples/warning2.rs index 69771a84..9dc0c062 100644 --- a/tests/message-order/examples/warning2.rs +++ b/tests/message-order/examples/warning2.rs @@ -79,6 +79,6 @@ -/*WARN 3 "examples/warning2.rs:82" " --> examples/warning2.rs:82:72"*/fn unused_in_2() { +fn unused_in_2() { } diff --git a/tests/message-order/tests/test_all_levels.rs b/tests/message-order/tests/test_all_levels.rs index e9324a64..35abe663 100644 --- a/tests/message-order/tests/test_all_levels.rs +++ b/tests/message-order/tests/test_all_levels.rs @@ -1,10 +1,10 @@ trait Trait {} // This triggers a warning about lifetimes with help. -fn f2 tests/test_all_levels.rs:4:85"*/'a: 'static>(_: &'a i32) {} +fn f2<'a: 'static>(_: &'a i32) {} pub fn f() { let x = Box::new(0u32); // This is an error with a note and help. - let y: &dyn Trait = /*ERR 1,2 "tests/test_all_levels.rs:9" " --> tests/test_all_levels.rs:9:103"*/x; + let y: &dyn Trait = x; } diff --git a/tests/message-order/tests/test_test_output.rs b/tests/message-order/tests/test_test_output.rs index 3bcf1927..501df044 100644 --- a/tests/message-order/tests/test_test_output.rs +++ b/tests/message-order/tests/test_test_output.rs @@ -6,29 +6,27 @@ fn passing() { #[test] fn basic_error1() { - // . is used for the column because Rust 1.24 changed the column indexing - // to be 1-based. - /*ERR 1 "tests/test_test_output.rs:11:4."*/assert!(false); + assert!(false); } #[test] fn basic_error2() { - /*ERR 2 "tests/test_test_output.rs:16:4."*/assert_eq!(1, 0); + assert_eq!(1, 0); } #[test] fn basic_error3() { - /*ERR 3 "tests/test_test_output.rs:21:4."*/assert_ne!(1, 1); + assert_ne!(1, 1); } #[test] fn custom_message() { - /*ERR 4 "tests/test_test_output.rs:26:4."*/assert!(false, "Custom message"); + assert!(false, "Custom message"); } #[test] fn manual_panic() { - /*ERR 5 "tests/test_test_output.rs:31:4."*/panic!("manual panic"); + panic!("manual panic"); } #[test] diff --git a/tests/test_message_order.py b/tests/test_message_order.py index 8cf8deef..9e0f0a0d 100644 --- a/tests/test_message_order.py +++ b/tests/test_message_order.py @@ -5,14 +5,65 @@ from rust_test_common import * +# Test data for message order tests. +# +# 'command': The command to run. +# 'path': The path to open. +# 'messages': List of expected messages. Tuples of: +# (sequence, path, level, rowcol, inline_highlight, raw_highlight) +# +# sequence: The order the messages should be visited. The messages should +# be listed in the order that they are emitted by rustc. The number +# indicates the order that the Rust Enhanced plugin will visit them. +# This is different because we visit based by level (warnings first). +# path: The file that this message is for. +# level: The message level ('WARN', 'ERR', etc.) +# rowcol: The 0-based row/col where the cursor should appear. +# inline_highlight: The message that is displayed in the build output when +# `show_inline_messages` is True. +# raw_highlight: The message that is displayed in the build output when +# `show_inline_messages` is False. +# +# The highlight messages are regular expressions. +TEST_DATA = [ + {'command': 'build', + 'path': 'examples/ex_warning1.rs', + 'messages': [ + (1, 'examples/warning1.rs', 'WARN', (0, 13), 'examples/warning1.rs:1', ' --> examples/warning1.rs:1:1'), + (2, 'examples/warning1.rs', 'WARN', (4, 13), 'examples/warning1.rs:5', ' --> examples/warning1.rs:5:1'), + (3, 'examples/warning2.rs', 'WARN', (81, 16), 'examples/warning2.rs:82', ' --> examples/warning2.rs:82:1'), + ] + }, + + {'command': 'build', + 'path': 'tests/test_all_levels.rs', + 'messages': [ + (2, 'tests/test_all_levels.rs', 'WARN', (3, 17), 'tests/test_all_levels.rs:4', ' --> tests/test_all_levels.rs:4:7'), + (1, 'tests/test_all_levels.rs', 'ERR', (8, 25), 'tests/test_all_levels.rs:9', ' --> tests/test_all_levels.rs:9:25'), + ] + }, + + {'command': 'test', + 'path': 'tests/test_test_output.rs', + 'messages': [ + (1, 'tests/test_test_output.rs', 'ERR', (8, 4), 'tests/test_test_output.rs:9:5', 'tests/test_test_output.rs:9:5'), + (2, 'tests/test_test_output.rs', 'ERR', (13, 4), 'tests/test_test_output.rs:14:5', 'tests/test_test_output.rs:14:5'), + (3, 'tests/test_test_output.rs', 'ERR', (18, 4), 'tests/test_test_output.rs:19:5', 'tests/test_test_output.rs:19:5'), + (4, 'tests/test_test_output.rs', 'ERR', (23, 4), 'tests/test_test_output.rs:24:5', 'tests/test_test_output.rs:24:5'), + (5, 'tests/test_test_output.rs', 'ERR', (28, 4), 'tests/test_test_output.rs:29:5', 'tests/test_test_output.rs:29:5'), + ] + } +] + + class TestMessageOrder(TestBase): def setUp(self): super(TestMessageOrder, self).setUp() # Set a base version for these tests. version = util.get_rustc_version(sublime.active_window(), plugin_path) - if semver.match(version, '<1.20.0'): - self.skipTest('Tests require rust 1.20 or newer.') + if semver.match(version, '<1.27.0'): + self.skipTest('Tests require rust 1.27 or newer.') # Make it so that the build target is automatically determined from # the active view so each test doesn't have to specify it. @@ -31,40 +82,19 @@ def test_message_order(self): This opens a file and runs the build command on it. It then verifies that next/prev message goes to the correct message in order. + """ + for data in TEST_DATA: + path = os.path.join('tests/message-order', data['path']) - The files are annotated with comments to indicate where each message - should appear and in which order. The annotations should look like: - - /*ERR 1 "build_output_selection_inline" "build_output_selection_raw"*/ - /*WARN 1 "build_output_selection_inline" "build_output_selection_raw"*/ - - The number is the order the message should appear. Two numbers can be - specified separated with a comma, where the second number is the - "unsorted" sequence (the order the message is emitted from rustc). + # rust_next_message sorts based on error level. + inline_sort = [x[1:] for x in sorted(data['messages'])] + # Sublime's built-in next/prev message goes in source order. + unsorted = [x[1:] for x in data['messages']] - The "inline" message is the message in the build output panel that - should be displayed when inline phantoms are being used. The "raw" - version is what is displayed when inline phantoms are not being used. - These value is a regular expressions tested against region in the - output panel. - """ - to_test = [ - ('build', 'examples/ex_warning1.rs', - 'examples/warning1.rs', 'examples/warning2.rs'), - ('build', 'tests/test_all_levels.rs',), - ('test', 'tests/test_test_output.rs',), - ] - for command, *paths in to_test: - rel_paths = [os.path.join('tests/message-order', path) - for path in paths] - sorted_msgs, unsorted_msgs = self._collect_message_order(rel_paths) - self.assertTrue(sorted_msgs) - self.assertTrue(unsorted_msgs) - self._with_open_file(rel_paths[0], self._test_message_order, - messages=sorted_msgs, inline=True, command=command) - self._with_open_file(rel_paths[0], - self._test_message_order, messages=unsorted_msgs, - inline=False, command=command) + self._with_open_file(path, self._test_message_order, + messages=inline_sort, inline=True, command=data['command']) + self._with_open_file(path, self._test_message_order, + messages=unsorted, inline=False, command=data['command']) def _test_message_order(self, view, messages, inline, command): self._override_setting('show_errors_inline', inline) @@ -83,6 +113,8 @@ def check_sequence(direction): for _ in range(times): for (next_filename, next_level, next_row_col, inline_highlight, raw_highlight) in omsgs: + next_filename = os.path.join(plugin_path, + 'tests', 'message-order', next_filename) if inline and ( (level == 'error' and next_level != 'ERR') or (level == 'warning' and next_level != 'WARN')): @@ -98,7 +130,13 @@ def check_sequence(direction): self.assertEqual(next_view.file_name(), next_filename) region = next_view.sel()[0] rowcol = next_view.rowcol(region.begin()) - self.assertEqual(rowcol, next_row_col) + if inline: + self.assertEqual(rowcol, next_row_col) + else: + # When inline is disabled, we use Sublime's + # built-in next/prev, which goes to the beginning. + # Just validate the row is correct. + self.assertEqual(rowcol[0], next_row_col[0]) # Verify the output panel is highlighting the correct # thing. build_panel = window.find_output_panel( @@ -126,58 +164,6 @@ def check_sequence(direction): window.focus_view(close_view) window.run_command('close_file') - def _collect_message_order(self, paths): - """Scan test files for comments that indicate the order of messages. - - :param paths: List of paths relative to the plugin. - - :returns: Returns a tuple of two lists. The first list is the sorted - order of messages. The first list is the unsorted order of - messages. Each list has tuples (path, level, (row, col), - inline_highlight, raw_highlight). - """ - result = [] - for path in paths: - self._with_open_file(path, self._collect_message_order_view, - result=result) - # Sort the result. - sorted_result = sorted(result, key=lambda x: x[0]) - unsorted_result = sorted(result, key=lambda x: x[1]) - # Verify that the markup was entered correctly. - self.assertEqual([x[0] for x in sorted_result], - list(range(1, len(sorted_result) + 1))) - # Strip the sequence number. - return ([x[2:] for x in sorted_result], - [x[2:] for x in unsorted_result]) - - def _collect_message_order_view(self, view, result): - pattern = r'/\*(ERR|WARN) ([0-9,]+) "([^"]+)"(?: "([^"]+)")?\*/' - regions = view.find_all(pattern) - - def path_fixup(p): - if sys.platform == 'win32': - # Double backslash since it is a regex. - return p.replace('/', '\\\\') - else: - return p - - for region in regions: - text = view.substr(region) - m = re.match(pattern, text) - rowcol = view.rowcol(region.end()) - if ',' in m.group(2): - sort_index, unsorted = map(int, m.group(2).split(',')) - else: - sort_index = int(m.group(2)) - unsorted = sort_index - inline_highlight = path_fixup(m.group(3)) - if m.group(4): - raw_highlight = path_fixup(m.group(4)) - else: - raw_highlight = inline_highlight - result.append((sort_index, unsorted, view.file_name(), - m.group(1), rowcol, inline_highlight, raw_highlight)) - def test_no_messages(self): self._with_open_file('tests/message-order/examples/ex_no_messages.rs', self._test_no_messages)