Skip to content

Add context menu #222

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

Merged
merged 8 commits into from
Nov 26, 2017
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
117 changes: 117 additions & 0 deletions Context.sublime-menu
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// XXX
// run/test/bench with args?
//
[
{
"caption": "Rust",
"id": "rust_context",
"children": [
{
"caption": "Clean",
"command": "cargo_exec",
"args": {
"command": "clean"
}
},
{
"caption": "Check",
"command": "cargo_exec",
"args": {
"command": "check"
}
},
{
"caption": "Clippy",
"command": "cargo_exec",
"args": {
"command": "clippy"
}
},
{
"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",
},
]
}
]
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
22 changes: 21 additions & 1 deletion RustEnhanced.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
]
180 changes: 180 additions & 0 deletions cargo_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': '--exact ' + 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)
44 changes: 44 additions & 0 deletions docs/context.md
Original file line number Diff line number Diff line change
@@ -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 &#xd7; 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.
Binary file added docs/rust_context.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading