From ee650b60adf66f330cb04e1f72a1be5229a73d09 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 24 Sep 2017 15:51:57 -0700 Subject: [PATCH 1/7] Fix toggle on-save checking command. This also changes the command to change the setting for the entire window instead of the current view. --- toggle_setting.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/toggle_setting.py b/toggle_setting.py index 15a9eba1..741092ea 100644 --- a/toggle_setting.py +++ b/toggle_setting.py @@ -1,9 +1,19 @@ -import sublime, sublime_plugin +import sublime_plugin +from .rust import (util, messages) + class ToggleRustSyntaxSettingCommand(sublime_plugin.TextCommand): - def run(self, setting): - # Grab the setting and reserse it - current_state = self.view.settings().get('rust_syntax_checking') - self.view.settings().set('rust_syntax_checking', not current_state) - self.view.window().status_message("Rust syntax checking is now " + ("inactive" if current_state else "active")) + """Toggles on-save checking for the current window.""" + + def run(self, edit): + # Grab the setting and reverse it. + window = self.view.window() + current_state = util.get_setting('rust_syntax_checking', True) + new_state = not current_state + pdata = window.project_data() + pdata.setdefault('settings', {})['rust_syntax_checking'] = new_state + if not new_state: + messages.clear_messages(window) + window.status_message("Rust syntax checking is now " + ("inactive" if current_state else "active")) + window.set_project_data(pdata) From 973c2e911bf831e4d015cbff10deb13e9270de5d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 31 Oct 2017 18:48:46 -0700 Subject: [PATCH 2/7] Add context menu and a few context-sensitive commands. --- Context.sublime-menu | 116 ++++++++++++ RustEnhanced.sublime-commands | 22 ++- cargo_build.py | 180 +++++++++++++++++++ rust/messages.py | 106 ++++++++--- tests/multi-targets/benches/bench_context.rs | 17 ++ tests/multi-targets/tests/test_context.rs | 38 ++++ tests/rust_test_common.py | 5 + tests/test_cargo_build.py | 7 +- tests/test_context.py | 159 ++++++++++++++++ tests/test_target_detect.py | 3 +- tests/test_toggle_setting.py | 21 +++ toggle_setting.py | 9 +- 12 files changed, 651 insertions(+), 32 deletions(-) create mode 100644 Context.sublime-menu create mode 100644 tests/multi-targets/benches/bench_context.rs create mode 100644 tests/multi-targets/tests/test_context.rs create mode 100644 tests/test_context.py create mode 100644 tests/test_toggle_setting.py diff --git a/Context.sublime-menu b/Context.sublime-menu new file mode 100644 index 00000000..6238a6d1 --- /dev/null +++ b/Context.sublime-menu @@ -0,0 +1,116 @@ +// XXX +// run/test/bench with args? +// +[ + { + "caption": "Rust", + "id": "rust_context", + "children": [ + { + "caption": "Cargo", + "id": "rust_context_cargo", + "children": [ + { + "caption": "Clean", + "command": "cargo_exec", + "args": { + "command": "clean" + } + }, + { + "caption": "Check", + "command": "cargo_exec", + "args": { + "command": "check" + } + }, + { + "caption": "-", + }, + { + "caption": "Test Here", + "command": "cargo_test_here", + }, + { + "caption": "Test Current File", + "command": "cargo_test_current_file", + }, + { + "caption": "Test All", + "command": "cargo_exec", + "args": { + "command": "test" + } + }, + { + "caption": "-", + }, + { + "caption": "Bench Here", + "command": "cargo_bench_here", + }, + { + "caption": "Bench Current File", + "command": "cargo_bench_current_file", + }, + { + "caption": "Bench All", + "command": "cargo_exec", + "args": { + "command": "bench" + } + }, + { + "caption": "-", + }, + { + "caption": "Run This File", + "command": "cargo_run_current_file", + }, + { + "caption": "Doc", + "command": "cargo_exec", + "args": { + "command": "doc", + } + }, + { + "caption": "Cancel Build", + "command": "rust_cancel" + } + ] + }, + { + "caption": "-", + }, + { + "caption": "Clear Messages", + "command": "rust_dismiss_messages", + }, + { + "caption": "List All Messages", + "command": "rust_list_messages", + }, + { + "caption": "-", + }, + { + "caption": "Open Settings", + "command": "edit_settings", + "args": + { + "base_file": "${packages}/Rust Enhanced/RustEnhanced.sublime-settings", + "default": "{\n\t$0\n}\n" + } + }, + { + "caption": "Configure Cargo Build", + "command": "cargo_configure", + }, + { + "caption": "On-Save Checking", + "command": "toggle_rust_syntax_setting", + }, + ] + } +] diff --git a/RustEnhanced.sublime-commands b/RustEnhanced.sublime-commands index 40410573..f9206b9c 100644 --- a/RustEnhanced.sublime-commands +++ b/RustEnhanced.sublime-commands @@ -31,5 +31,25 @@ "base_file": "${packages}/Rust Enhanced/RustEnhanced.sublime-settings", "default": "{\n\t$0\n}\n" } - } + }, + { + "caption": "Rust: List All Messages", + "command": "rust_list_messages" + }, + { + "caption": "Rust: Run Test At Cursor", + "command": "cargo_test_at_cursor" + }, + { + "caption": "Rust: Run Tests In Current File", + "command": "cargo_test_current_file" + }, + { + "caption": "Rust: Run Benchmark At Cursor", + "command": "cargo_bench_at_cursor" + }, + { + "caption": "Rust: Run Benchmarks In Current File", + "command": "cargo_bench_current_file" + }, ] diff --git a/cargo_build.py b/cargo_build.py index 50e3c415..495bc38c 100644 --- a/cargo_build.py +++ b/cargo_build.py @@ -284,3 +284,183 @@ class RustDismissMessagesCommand(sublime_plugin.WindowCommand): def run(self): messages.clear_messages(self.window) + + +class RustListMessagesCommand(sublime_plugin.WindowCommand): + + """Shows a quick panel with a list of all messages.""" + + def run(self): + messages.list_messages(self.window) + + +# Patterns used to help find test function names. +# This is far from perfect, but should be good enough. +SPACE = r'[ \t]' +OPT_COMMENT = r"""(?: + (?: [ \t]* //.*) + | (?: [ \t]* /\*.*\*/ [ \t]* ) +)?""" +IDENT = r"""(?: + [a-z A-Z] [a-z A-Z 0-9 _]* + | _ [a-z A-Z 0-9 _]+ +)""" +TEST_PATTERN = r"""(?x) + {SPACE}* \# {SPACE}* \[ {SPACE}* {WHAT} {SPACE}* \] {SPACE}* + (?: + (?: {SPACE}* \#\[ [^]]+ \] {OPT_COMMENT} \n ) + | (?: {OPT_COMMENT} \n ) + )* + .* fn {SPACE}+ ({IDENT}+) +""" + + +def _target_to_test(what, view, on_done): + """Helper used to determine build target from given view.""" + td = target_detect.TargetDetector(view.window()) + targets = td.determine_targets(view.file_name()) + if len(targets) == 0: + sublime.error_message('Error: Could not determine target to %s.' % what) + elif len(targets) == 1: + on_done(' '.join(targets[0][1])) + else: + # Can't determine a single target, let the user choose one. + display_items = [' '.join(x[1]) for x in targets] + + def quick_on_done(idx): + on_done(targets[idx][1]) + + view.window().show_quick_panel(display_items, quick_on_done) + + +def _pt_to_test_name(what, pt, view): + """Helper used to convert Sublime point to a test/bench function name.""" + fn_names = [] + pat = TEST_PATTERN.format(WHAT=what, **globals()) + regions = view.find_all(pat, 0, r'\1', fn_names) + if not regions: + sublime.error_message('Could not find a Rust %s function.' % what) + return None + # Assuming regions are in ascending order. + indices = [i for (i, r) in enumerate(regions) if r.a <= pt] + if not indices: + sublime.error_message('No %s functions found about the current point.' % what) + return None + return fn_names[indices[-1]] + + +def _cargo_test_pt(what, pt, view): + """Helper used to run a test for a given point in the given view.""" + def do_test(target): + test_fn_name = _pt_to_test_name(what, pt, view) + if test_fn_name: + view.window().run_command('cargo_exec', args={ + 'command': what, + 'settings': { + 'target': target, + 'extra_run_args': test_fn_name + } + }) + + _target_to_test(what, view, do_test) + + +class CargoHere(sublime_plugin.WindowCommand): + + """Base class for mouse-here commands. + + Subclasses set `what` attribute. + """ + + what = None + + def run(self, event): + view = self.window.active_view() + if not view: + return + pt = view.window_to_text((event['x'], event['y'])) + _cargo_test_pt(self.what, pt, view) + + def want_event(self): + return True + + +class CargoTestHereCommand(CargoHere): + + """Determines the test name at the current mouse position, and runs just + that test.""" + + what = 'test' + + +class CargoBenchHereCommand(CargoHere): + + """Determines the benchmark at the current mouse position, and runs just + that benchmark.""" + + what = 'bench' + + +class CargoTestAtCursorCommand(sublime_plugin.TextCommand): + + """Determines the test name at the current cursor position, and runs just + that test.""" + + def run(self, edit): + pt = self.view.sel()[0].begin() + _cargo_test_pt('test', pt, self.view) + + +class CargoCurrentFile(sublime_plugin.WindowCommand): + + """Base class for current file commands. + + Subclasses set `what` attribute. + """ + + what = None + + def run(self): + print('current file') + def _test_file(target): + print('target is %r' % target) + self.window.run_command('cargo_exec', args={ + 'command': self.what, + 'settings': { + 'target': target + } + }) + + view = self.window.active_view() + _target_to_test(self.what, view, _test_file) + + +class CargoTestCurrentFileCommand(CargoCurrentFile): + + """Runs all tests in the current file.""" + + what = 'test' + + +class CargoBenchCurrentFileCommand(CargoCurrentFile): + + """Runs all benchmarks in the current file.""" + + what = 'bench' + + +class CargoRunCurrentFileCommand(CargoCurrentFile): + + """Runs the current file.""" + + what = 'run' + + +class CargoBenchAtCursorCommand(sublime_plugin.TextCommand): + + """Determines the benchmark name at the current cursor position, and runs + just that benchmark.""" + + def run(self, edit): + pt = self.view.sel()[0].begin() + _cargo_test_pt('bench', pt, self.view) diff --git a/rust/messages.py b/rust/messages.py index 8fabf599..dbc98195 100644 --- a/rust/messages.py +++ b/rust/messages.py @@ -19,10 +19,18 @@ # } # `path` is the absolute path to the file. # Each msg_dict has the following: -# - `level` -# - `span` -# - `is_main` -# - `message` +# - `level`: Message level as a string such as "error", or "info". +# - `span`: Location of the message (0-based): +# `((line_start, col_start), (line_end, col_end))` +# May be `None` to indicate no particular spot. +# - `is_main`: If True, this is a top-level message. False is used for +# attached detailed diagnostic information, child notes, etc. +# - `path`: Absolute path to the file. +# - `text`: The raw text of the message without any minihtml markup. +# - `phantom_text`: The string used for showing phantoms that includes the +# minihtml markup. +# - `output_panel_region`: Optional Sublime Region object that indicates the +# region in the build output panel that corresponds with this message. WINDOW_MESSAGES = {} @@ -317,15 +325,15 @@ def _sort_messages(window): def show_next_message(window, levels): current_idx = _advance_next_message(window, levels) - _show_message(window, levels, current_idx) + _show_message(window, current_idx) def show_prev_message(window, levels): current_idx = _advance_prev_message(window, levels) - _show_message(window, levels, current_idx) + _show_message(window, current_idx) -def _show_message(window, levels, current_idx): +def _show_message(window, current_idx, transient=False, force_open=False): if current_idx is None: return try: @@ -334,26 +342,39 @@ def _show_message(window, levels, current_idx): return paths = window_info['paths'] path, messages = _ith_iter_item(paths.items(), current_idx[0]) - view = window.find_open_file(path) msg = messages[current_idx[1]] _scroll_build_panel(window, msg) - if view: - _scroll_to_message(view, msg) - else: - # 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] + view = None + if not transient and not force_open: + view = window.find_open_file(path) + if view: + _scroll_to_message(view, msg, transient) + if not view: + flags = sublime.ENCODED_POSITION + if transient: + # FORCE_GROUP is undocumented. It forces the view to open in the + # current group, even if the view is already open in another + # group. This is necessary to prevent the quick panel from losing + # focus. See: + # https://github.com/SublimeTextIssues/Core/issues/1041 + flags |= sublime.TRANSIENT | sublime.FORCE_GROUP + if msg['span']: + # 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] + else: + row, col = (999999999, 1) view = window.open_file('%s:%d:%d' % (path, row + 1, col + 1), - sublime.ENCODED_POSITION) + flags) # Block until the view is loaded. - _show_message_wait(view, levels, messages, current_idx) + _show_message_wait(view, messages, current_idx) -def _show_message_wait(view, levels, messages, current_idx): +def _show_message_wait(view, messages, current_idx): if view.is_loading(): def f(): - _show_message_wait(view, levels, messages, current_idx) + _show_message_wait(view, messages, current_idx) sublime.set_timeout(f, 10) # The on_load event handler will call show_messages_for_view which # should handle displaying the messages. @@ -376,9 +397,10 @@ def _scroll_build_panel(window, message): view.erase_regions('bug') -def _scroll_to_message(view, message): +def _scroll_to_message(view, message, transient): """Scroll view to the message.""" - view.window().focus_view(view) + if not transient: + view.window().focus_view(view) r = _span_to_region(view, message['span']) view.sel().clear() view.sel().add(r.a) @@ -504,6 +526,48 @@ def _is_matching_level(levels, msg_dict): return False +def _relative_path(window, path): + """Convert an absolute path to a relative path used for a truncated + display.""" + for folder in window.folders(): + if path.startswith(folder): + return os.path.relpath(path, folder) + return path + + +def list_messages(window): + """Show a list of all messages.""" + try: + win_info = WINDOW_MESSAGES[window.id()] + except KeyError: + # XXX: Or dialog? + window.show_quick_panel(["No messages available"], None) + return + panel_items = [] + jump_to = [] + for path_idx, (path, msgs) in enumerate(win_info['paths'].items()): + for msg_idx, msg_dict in enumerate(msgs): + if not msg_dict['is_main']: + continue + jump_to.append((path_idx, msg_idx)) + if msg_dict['span']: + path_label = '%s:%s' % ( + _relative_path(window, path), + msg_dict['span'][0][0] + 1) + else: + path_label = _relative_path(window, path) + item = [msg_dict['text'], path_label] + panel_items.append(item) + + def on_done(idx): + _show_message(window, jump_to[idx], force_open=True) + + def on_highlighted(idx): + _show_message(window, jump_to[idx], transient=True) + + window.show_quick_panel(panel_items, on_done, 0, 0, on_highlighted) + + def add_rust_messages(window, cwd, info, target_path, msg_cb): """Add messages from Rust JSON to Sublime views. diff --git a/tests/multi-targets/benches/bench_context.rs b/tests/multi-targets/benches/bench_context.rs new file mode 100644 index 00000000..e9260885 --- /dev/null +++ b/tests/multi-targets/benches/bench_context.rs @@ -0,0 +1,17 @@ +// Tests for "bench here" commands. + +#![feature(test)] + +extern crate test; + +use test::Bencher; + + #[bench] // comment +fn bench1(b: &mut Bencher) { + b.iter(|| 1); +} + +#[bench] +fn bench2(b: &mut Bencher) { + b.iter(|| 2); +} diff --git a/tests/multi-targets/tests/test_context.rs b/tests/multi-targets/tests/test_context.rs new file mode 100644 index 00000000..844eb74d --- /dev/null +++ b/tests/multi-targets/tests/test_context.rs @@ -0,0 +1,38 @@ +// Tests for "test here" command. + + #[test] +fn test1() { + +} + +# [ test ] //comment + +#[should_panic(expected="xyz")] /* comment */ + +pub fn expected_panic1() { + panic!("xyz"); +} + +#[test] +fn test2() { + fn inner() { + + } + inner(); +}#[test] +fn test3() { + +} + +// #[test] +// fn test4() { +// } + +/*#[test] +fn test5() { +} +*/ + +#[test] fn test6() { + +} diff --git a/tests/rust_test_common.py b/tests/rust_test_common.py index 1afe28a6..100148db 100644 --- a/tests/rust_test_common.py +++ b/tests/rust_test_common.py @@ -99,6 +99,11 @@ def _run_build_wait(self, command='build', **kwargs): # Wait for it to finish. self._get_rust_thread().join() + def _get_build_output(self, window): + opanel = window.find_output_panel(plugin.rust.opanel.PANEL_NAME) + output = opanel.substr(sublime.Region(0, opanel.size())) + return output + def _with_open_file(self, filename, f, **kwargs): """Opens filename (relative to the plugin) in a new view, calls f(view) to perform the tests. diff --git a/tests/test_cargo_build.py b/tests/test_cargo_build.py index 1ff82ba0..852027e1 100644 --- a/tests/test_cargo_build.py +++ b/tests/test_cargo_build.py @@ -21,11 +21,6 @@ def exe(s): class TestCargoBuild(TestBase): - def _get_build_output(self, window): - opanel = window.find_output_panel(plugin.rust.opanel.PANEL_NAME) - output = opanel.substr(sublime.Region(0, opanel.size())) - return output - def setUp(self): super(TestCargoBuild, self).setUp() self._cargo_clean(multi_target_root) @@ -430,7 +425,7 @@ def _quick_panel(self, items, on_done, flags=0, def _test_ambiguous_auto_build2(self, view): window = view.window() - self.quick_panel_items = ['--test test1', '--test test2'] + self.quick_panel_items = ['--test test1', '--test test2', '--test test_context'] self.quick_panel_index = 0 self._run_build_wait('auto') output = self._get_build_output(window) diff --git a/tests/test_context.py b/tests/test_context.py new file mode 100644 index 00000000..2d0170a3 --- /dev/null +++ b/tests/test_context.py @@ -0,0 +1,159 @@ +"""Tests for the context commands.""" + + +from rust_test_common import * + + +class TestContext(TestBase): + + def test_pt_to_test_name(self): + self._with_open_file('tests/multi-targets/tests/test_context.rs', + self._test_pt_to_test_name) + + def _test_pt_to_test_name(self, view): + expected = [ + ('test1', (3, 1), (7, 1)), + ('expected_panic1', (8, 1), (15, 1)), + ('test2', (16, 1), (22, 1)), + ('test3', (22, 2), (26, 1)), + ('test6', (36, 1), (39, 1)), + ] + for fn_name, (start_row, start_col), (end_row, end_col) in expected: + start_pt = view.text_point(start_row - 1, start_col - 1) + end_pt = view.text_point(end_row - 1, end_col - 1) + for pt in range(start_pt, end_pt): + name = plugin.cargo_build._pt_to_test_name('test', pt, view) + self.assertEqual(name, fn_name, + 'rowcol=%r' % (view.rowcol(pt),)) + + def test_cargo_test_here(self): + self._with_open_file('tests/multi-targets/tests/test_context.rs', + self._test_cargo_test_here) + + def _test_cargo_test_here(self, view): + pt = view.text_point(4, 0) + x, y = view.text_to_window(pt) + view.window().run_command('cargo_test_here', args={ + 'event': {'x': x, 'y': y} + }) + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo test --test test_context --message-format=json -- test1\]') + + def test_cargo_test_at_cursor(self): + self._with_open_file('tests/multi-targets/tests/test_context.rs', + self._test_cargo_test_at_cursor) + + def _test_cargo_test_at_cursor(self, view): + pt = view.text_point(12, 0) + sel = view.sel() + sel.clear() + sel.add(sublime.Region(pt)) + view.run_command('cargo_test_at_cursor') + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo test --test test_context --message-format=json -- expected_panic1\]') + + def test_cargo_test_current_file(self): + self._with_open_file('tests/multi-targets/tests/test_context.rs', + self._test_cargo_test_current_file) + + def _test_cargo_test_current_file(self, view): + view.window().run_command('cargo_test_current_file') + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo test --test test_context --message-format=json\]') + + def test_cargo_bench_here(self): + self._with_open_file('tests/multi-targets/benches/bench_context.rs', + self._test_cargo_bench_here) + + def _test_cargo_bench_here(self, view): + pt = view.text_point(15, 0) + x, y = view.text_to_window(pt) + view.window().run_command('cargo_bench_here', args={ + 'event': {'x': x, 'y': y} + }) + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo bench --bench bench_context --message-format=json -- bench2\]') + + def test_cargo_bench_at_cursor(self): + self._with_open_file('tests/multi-targets/benches/bench_context.rs', + self._test_cargo_bench_at_cursor) + + def _test_cargo_bench_at_cursor(self, view): + pt = view.text_point(15, 0) + sel = view.sel() + sel.clear() + sel.add(sublime.Region(pt)) + view.run_command('cargo_bench_at_cursor') + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo bench --bench bench_context --message-format=json -- bench2\]') + + def test_cargo_bench_current_file(self): + self._with_open_file('tests/multi-targets/benches/bench_context.rs', + self._test_cargo_bench_current_file) + + def _test_cargo_bench_current_file(self, view): + view.window().run_command('cargo_bench_current_file') + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo bench --bench bench_context --message-format=json\]') + + def test_cargo_run_current_file(self): + self._with_open_file('tests/multi-targets/examples/ex1.rs', + self._test_cargo_run_current_file) + + def _test_cargo_run_current_file(self, view): + view.window().run_command('cargo_run_current_file') + self._get_rust_thread().join() + output = self._get_build_output(view.window()) + self.assertRegex(output, + r'\[Running: cargo run --example ex1 --message-format=json\]') + + def test_rust_list_messages(self): + self._with_open_file('tests/message-order/examples/ex_warning1.rs', + self._test_rust_list_messages) + + def _test_rust_list_messages(self, view): + window = view.window() + self._cargo_clean(view) + window.run_command('cargo_exec', args={'command': 'auto'}) + self._get_rust_thread().join() + sqp = window.__class__.show_quick_panel + window.__class__.show_quick_panel = self._quick_panel + try: + self._test_rust_list_messages2(view) + finally: + window.__class__.show_quick_panel = sqp + + def _quick_panel(self, items, on_done, flags=0, + selected_index=-1, on_highlighted=None): + self.assertEqual(items, self.quick_panel_items) + on_done(self.quick_panel_index) + + def _test_rust_list_messages2(self, view): + window = view.window() + self.quick_panel_items = [ + ['function is never used: `unused_a`', + os.path.join('tests', 'message-order', 'examples', 'warning1.rs') + ':1'], + ['function is never used: `unused_b`', + os.path.join('tests', 'message-order', 'examples', 'warning1.rs') + ':5'], + ['function is never used: `unused_in_2`', + os.path.join('tests', 'message-order', 'examples', 'warning2.rs') + ':82'], + ] + self.quick_panel_index = 2 + window.run_command('rust_list_messages') + new_view = window.active_view() + expected_path = os.path.normpath( + os.path.join(plugin_path, 'tests/message-order/examples/warning2.rs')) + self.assertEqual(new_view.file_name(), expected_path) + new_view.run_command('close_file') diff --git a/tests/test_target_detect.py b/tests/test_target_detect.py index 83ec4650..2a65744d 100644 --- a/tests/test_target_detect.py +++ b/tests/test_target_detect.py @@ -32,7 +32,8 @@ def test_multi_targets(self): # Shared module in test, not possible to easily determine which # test it belongs to. ('tests/common/helpers.rs', [('tests/test1.rs', '--test test1'), - ('tests/test2.rs', '--test test2')]), + ('tests/test2.rs', '--test test2'), + ('tests/test_context.rs', '--test test_context')]), # proc-macro kind ('pmacro/src/lib.rs', [('pmacro/src/lib.rs', '--lib')]), # Different lib types. diff --git a/tests/test_toggle_setting.py b/tests/test_toggle_setting.py new file mode 100644 index 00000000..5b42d69d --- /dev/null +++ b/tests/test_toggle_setting.py @@ -0,0 +1,21 @@ +"""Tests for toggle command.""" + + +from rust_test_common import * + + +class TestToggle(TestBase): + + def test_toggle(self): + window = sublime.active_window() + self.assertEqual( + util.get_setting('rust_syntax_checking', True), + True) + window.run_command('toggle_rust_syntax_setting') + self.assertEqual( + util.get_setting('rust_syntax_checking', True), + False) + window.run_command('toggle_rust_syntax_setting') + self.assertEqual( + util.get_setting('rust_syntax_checking', True), + True) diff --git a/toggle_setting.py b/toggle_setting.py index 741092ea..7e5dd67d 100644 --- a/toggle_setting.py +++ b/toggle_setting.py @@ -2,13 +2,13 @@ from .rust import (util, messages) -class ToggleRustSyntaxSettingCommand(sublime_plugin.TextCommand): +class ToggleRustSyntaxSettingCommand(sublime_plugin.WindowCommand): """Toggles on-save checking for the current window.""" - def run(self, edit): + def run(self): # Grab the setting and reverse it. - window = self.view.window() + window = self.window current_state = util.get_setting('rust_syntax_checking', True) new_state = not current_state pdata = window.project_data() @@ -17,3 +17,6 @@ def run(self, edit): messages.clear_messages(window) window.status_message("Rust syntax checking is now " + ("inactive" if current_state else "active")) window.set_project_data(pdata) + + def is_checked(self): + return util.get_setting('rust_syntax_checking', True) From d253ce3fc791be629bfbbab3cfe4a77802172a5e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Nov 2017 10:56:09 -0700 Subject: [PATCH 3/7] Remove the nested context menu. --- Context.sublime-menu | 138 +++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/Context.sublime-menu b/Context.sublime-menu index 6238a6d1..3b07ef92 100644 --- a/Context.sublime-menu +++ b/Context.sublime-menu @@ -7,78 +7,72 @@ "id": "rust_context", "children": [ { - "caption": "Cargo", - "id": "rust_context_cargo", - "children": [ - { - "caption": "Clean", - "command": "cargo_exec", - "args": { - "command": "clean" - } - }, - { - "caption": "Check", - "command": "cargo_exec", - "args": { - "command": "check" - } - }, - { - "caption": "-", - }, - { - "caption": "Test Here", - "command": "cargo_test_here", - }, - { - "caption": "Test Current File", - "command": "cargo_test_current_file", - }, - { - "caption": "Test All", - "command": "cargo_exec", - "args": { - "command": "test" - } - }, - { - "caption": "-", - }, - { - "caption": "Bench Here", - "command": "cargo_bench_here", - }, - { - "caption": "Bench Current File", - "command": "cargo_bench_current_file", - }, - { - "caption": "Bench All", - "command": "cargo_exec", - "args": { - "command": "bench" - } - }, - { - "caption": "-", - }, - { - "caption": "Run This File", - "command": "cargo_run_current_file", - }, - { - "caption": "Doc", - "command": "cargo_exec", - "args": { - "command": "doc", - } - }, - { - "caption": "Cancel Build", - "command": "rust_cancel" - } - ] + "caption": "Clean", + "command": "cargo_exec", + "args": { + "command": "clean" + } + }, + { + "caption": "Check", + "command": "cargo_exec", + "args": { + "command": "check" + } + }, + { + "caption": "-", + }, + { + "caption": "Test Here", + "command": "cargo_test_here", + }, + { + "caption": "Test Current File", + "command": "cargo_test_current_file", + }, + { + "caption": "Test All", + "command": "cargo_exec", + "args": { + "command": "test" + } + }, + { + "caption": "-", + }, + { + "caption": "Bench Here", + "command": "cargo_bench_here", + }, + { + "caption": "Bench Current File", + "command": "cargo_bench_current_file", + }, + { + "caption": "Bench All", + "command": "cargo_exec", + "args": { + "command": "bench" + } + }, + { + "caption": "-", + }, + { + "caption": "Run This File", + "command": "cargo_run_current_file", + }, + { + "caption": "Doc", + "command": "cargo_exec", + "args": { + "command": "doc", + } + }, + { + "caption": "Cancel Build", + "command": "rust_cancel" }, { "caption": "-", From 68ae40b829852740bd59878f2e06700eeaa20319 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Nov 2017 12:02:00 -0700 Subject: [PATCH 4/7] Add Clippy to context menu. --- Context.sublime-menu | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Context.sublime-menu b/Context.sublime-menu index 3b07ef92..b7c8fbcc 100644 --- a/Context.sublime-menu +++ b/Context.sublime-menu @@ -20,6 +20,13 @@ "command": "check" } }, + { + "caption": "Clippy", + "command": "cargo_exec", + "args": { + "command": "clippy" + } + }, { "caption": "-", }, From aaf6567c496bc50cdd0b8234c40e188d5182404c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Nov 2017 12:02:47 -0700 Subject: [PATCH 5/7] Fix duplicate messages when building multiple targets that share the same source files. --- rust/messages.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rust/messages.py b/rust/messages.py index dbc98195..31f76801 100644 --- a/rust/messages.py +++ b/rust/messages.py @@ -136,7 +136,7 @@ def add_message(window, path, span, level, is_main, text, markup_text, msg_cb): 'text': text, 'phantom_text': phantom_text, } - if to_add in messages: + if _is_duplicate(to_add, messages): # Don't add duplicates. return messages.append(to_add) @@ -147,6 +147,17 @@ def add_message(window, path, span, level, is_main, text, markup_text, msg_cb): msg_cb(to_add) +def _is_duplicate(to_add, messages): + # Primarily to avoid comparing the `output_panel_region` key. + for message in messages: + for key, value in to_add.items(): + if message[key] != value: + break + else: + return True + return False + + def has_message_for_path(window, path): paths = WINDOW_MESSAGES.get(window.id(), {}).get('paths', {}) return path in paths From e06cd360a48c44548c9e71fb8528adb85dd6f628 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 2 Nov 2017 08:24:42 -0700 Subject: [PATCH 6/7] Context menu docs. --- README.md | 4 ++++ docs/context.md | 44 ++++++++++++++++++++++++++++++++++++++++++ docs/rust_context.png | Bin 0 -> 13165 bytes 3 files changed, 48 insertions(+) create mode 100644 docs/context.md create mode 100644 docs/rust_context.png diff --git a/README.md b/README.md index 7d3f094a..85840114 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,10 @@ Projects with multiple build targets are supported too (--lib, --bin, --example, } ``` +## Context Menu +The Sublime context menu includes a Rust entry with a variety of commands. +See [context menu docs](docs/context.md) for more information. + ## Settings To customize the settings, use the command from the Sublime menu: diff --git a/docs/context.md b/docs/context.md new file mode 100644 index 00000000..4b8ebaab --- /dev/null +++ b/docs/context.md @@ -0,0 +1,44 @@ +# Rust Context Menu + +You can access Sublime's context menu with a right click. + +![Rust Context Menu](rust_context.png "Rust Context Menu") + +## Cargo Commands +A variety of Cargo commands are available here for quick access so you don't +have to frequently switch your build system variant. Some of them are +context-sensitive, based on where you click the mouse. + +* **Clean**: `cargo clean` to remove build artifacts. +* **Check**: `cargo check` to quickly check your package for errors. +* **Clippy**: `cargo clippy` to run + [Clippy](https://github.com/rust-lang-nursery/rust-clippy) on your source. +--- +* **Test Here**: Runs just the one test underneath the cursor. A similar + command is also available in the Sublime Command Palette as "Rust: Run Test + At Cursor". +* **Test Current File**: Runs all tests in the current file. +* **Test All**: Runs all tests in the package. +--- +* **Bench Here**: Runs just the one benchmark underneath the cursor. +* **Bench Current File**: Runs all benchmarks in the current file. +* **Bench All**: Runs all benchmarks in the package. +--- +* **Run This File**: `cargo run` the current file. +* **Doc**: `cargo doc` to generate documentation. +* **Cancel Build**: Cancel the current build. Also available with keyboard + shortcuts, see [build docs](build.md). + +## Message Commands +* **Clear Messages**: Remove inline error/warning messages. Also available + with the Esc key, or click the × symbol in the message. +* **List All Messages**: Show a quick panel popup with a list of all current + messages. + +## Settings Commands +* **Open Settings**: Open the Rust Enhanced settings. +* **Configure Cargo Build**: Run the command to interactively configure Cargo + build settings stored in your Sublime project file. See + [Configure Command](build.md#configure-command). +* **On-Save Checking**: Toggle `cargo check` running every time you save a + Rust file. diff --git a/docs/rust_context.png b/docs/rust_context.png new file mode 100644 index 0000000000000000000000000000000000000000..bac4311cdbe0b8e33e89454f81cce44157580d21 GIT binary patch literal 13165 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 E0@Yfq$p8QV literal 0 HcmV?d00001 From 5d59fbd61f28a7bb59dc41aca4e884f1d11ce792 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 4 Nov 2017 14:49:29 -0700 Subject: [PATCH 7/7] Add --exact for running specific tests. --- cargo_build.py | 2 +- tests/test_context.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cargo_build.py b/cargo_build.py index 495bc38c..e7ac75b8 100644 --- a/cargo_build.py +++ b/cargo_build.py @@ -358,7 +358,7 @@ def do_test(target): 'command': what, 'settings': { 'target': target, - 'extra_run_args': test_fn_name + 'extra_run_args': '--exact ' + test_fn_name } }) diff --git a/tests/test_context.py b/tests/test_context.py index 2d0170a3..d0b37847 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -39,7 +39,7 @@ def _test_cargo_test_here(self, view): self._get_rust_thread().join() output = self._get_build_output(view.window()) self.assertRegex(output, - r'\[Running: cargo test --test test_context --message-format=json -- test1\]') + r'\[Running: cargo test --test test_context --message-format=json -- --exact test1\]') def test_cargo_test_at_cursor(self): self._with_open_file('tests/multi-targets/tests/test_context.rs', @@ -54,7 +54,7 @@ def _test_cargo_test_at_cursor(self, view): self._get_rust_thread().join() output = self._get_build_output(view.window()) self.assertRegex(output, - r'\[Running: cargo test --test test_context --message-format=json -- expected_panic1\]') + r'\[Running: cargo test --test test_context --message-format=json -- --exact expected_panic1\]') def test_cargo_test_current_file(self): self._with_open_file('tests/multi-targets/tests/test_context.rs', @@ -80,7 +80,7 @@ def _test_cargo_bench_here(self, view): self._get_rust_thread().join() output = self._get_build_output(view.window()) self.assertRegex(output, - r'\[Running: cargo bench --bench bench_context --message-format=json -- bench2\]') + r'\[Running: cargo bench --bench bench_context --message-format=json -- --exact bench2\]') def test_cargo_bench_at_cursor(self): self._with_open_file('tests/multi-targets/benches/bench_context.rs', @@ -95,7 +95,7 @@ def _test_cargo_bench_at_cursor(self, view): self._get_rust_thread().join() output = self._get_build_output(view.window()) self.assertRegex(output, - r'\[Running: cargo bench --bench bench_context --message-format=json -- bench2\]') + r'\[Running: cargo bench --bench bench_context --message-format=json -- --exact bench2\]') def test_cargo_bench_current_file(self): self._with_open_file('tests/multi-targets/benches/bench_context.rs',