Skip to content

Commit dfb7530

Browse files
committed
Message updates.
- Add `rust_message_status_bar` option to display the message under the cursor in the window status bar. - Add `rust_message_popup` command to manually show a popup under the cursor. - Add underline styles to `rust_region_style`. - Fix various issues with multiple views into the same file. - Fix on-save checking being triggered multiple times with "Save All" and the build command when the buffer is unsaved. - Fix Next/Prev when a message is hidden (such as a completed suggestion). - Fix hitting Esc in the middle of the build to hide/dismiss future messages.
1 parent 5480b64 commit dfb7530

14 files changed

+227
-65
lines changed

RustEnhanced.sublime-commands

+4
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,8 @@
5656
"caption": "Rust: Open Debug Log",
5757
"command": "rust_open_log"
5858
},
59+
{
60+
"caption": "Rust: Popup Message At Cursor",
61+
"command": "rust_message_popup"
62+
}
5963
]

RustEnhanced.sublime-settings

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737

3838
// For errors/warnings, how to highlight the region of the error.
3939
// "outline" - Outlines the region.
40+
// "solid_underline" - A solid underline.
41+
// "stippled_underline" - A stippled underline.
42+
// "squiggly_underline" - A squiggly underline.
4043
// "none" - No outlining.
4144
"rust_region_style": "outline",
4245

@@ -51,6 +54,9 @@
5154
// "solid" - Solid background color.
5255
"rust_message_theme": "clear",
5356

57+
// If `true`, displays diagnostic messages under the cursor in the status bar.
58+
"rust_message_status_bar": false,
59+
5460
// If your cargo project has several build targets, it's possible to specify mapping of
5561
// source code filenames to the target names to enable syntax checking.
5662
// "projects": {

SyntaxCheckPlugin.py

+21-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import sublime
22
import sublime_plugin
33
import os
4+
import time
45
from .rust import (messages, rust_proc, rust_thread, util, target_detect,
56
cargo_settings, semver, log)
6-
from pprint import pprint
77

88

99
"""On-save syntax checking.
@@ -13,26 +13,31 @@
1313
"""
1414

1515

16+
# TODO: Use ViewEventListener if
17+
# https://github.com/SublimeTextIssues/Core/issues/2411 is fixed.
1618
class RustSyntaxCheckEvent(sublime_plugin.EventListener):
1719

18-
# Beware: This gets called multiple times if the same buffer is opened in
19-
# multiple views (with the same view passed in each time). See:
20-
# https://github.com/SublimeTextIssues/Core/issues/289
20+
last_save = 0
21+
2122
def on_post_save(self, view):
22-
# Are we in rust scope and is it switched on?
23-
# We use phantoms which were added in 3118
24-
if int(sublime.version()) < 3118:
23+
enabled = util.get_setting('rust_syntax_checking', True)
24+
if not enabled or not util.active_view_is_rust(view=view):
25+
return
26+
prev_save = self.last_save
27+
self.last_save = time.time()
28+
if self.last_save - prev_save < 0.25:
29+
# This is a guard for a few issues.
30+
# * `on_post_save` gets called multiple times if the same buffer
31+
# is opened in multiple views (with the same view passed in each
32+
# time). See:
33+
# https://github.com/SublimeTextIssues/Core/issues/289
34+
# * When using "Save All" we want to avoid launching a bunch of
35+
# threads and then immediately killing them.
2536
return
2637
log.clear_log(view.window())
27-
28-
enabled = util.get_setting('rust_syntax_checking', True)
29-
if enabled and util.active_view_is_rust(view=view):
30-
t = RustSyntaxCheckThread(view)
31-
t.start()
32-
elif not enabled:
33-
# If the user has switched OFF the plugin, remove any phantom
34-
# lines.
35-
messages.clear_messages(view.window())
38+
messages.erase_status(view)
39+
t = RustSyntaxCheckThread(view)
40+
t.start()
3641

3742

3843
class RustSyntaxCheckThread(rust_thread.RustThread, rust_proc.ProcListener):

cargo_build.py

+77-23
Original file line numberDiff line numberDiff line change
@@ -222,32 +222,22 @@ def run(self):
222222
ON_LOAD_MESSAGES_ENABLED = True
223223

224224

225-
class CargoEventListener(sublime_plugin.EventListener):
225+
class MessagesViewEventListener(sublime_plugin.ViewEventListener):
226226

227227
"""Every time a new file is loaded, check if is a Rust file with messages,
228228
and if so, display the messages.
229229
"""
230230

231-
def on_load(self, view):
232-
if ON_LOAD_MESSAGES_ENABLED and util.active_view_is_rust(view=view):
233-
# For some reason, view.window() returns None here.
234-
# Use set_timeout to give it time to attach to a window.
235-
sublime.set_timeout(
236-
lambda: messages.show_messages_for_view(view), 1)
231+
@classmethod
232+
def is_applicable(cls, settings):
233+
return ON_LOAD_MESSAGES_ENABLED and util.is_rust_view(settings)
237234

238-
def on_query_context(self, view, key, operator, operand, match_all):
239-
# Used by the Escape-key keybinding to dismiss inline phantoms.
240-
if key == 'rust_has_messages':
241-
try:
242-
winfo = messages.WINDOW_MESSAGES[view.window().id()]
243-
has_messages = not winfo['hidden']
244-
except KeyError:
245-
has_messages = False
246-
if operator == sublime.OP_EQUAL:
247-
return operand == has_messages
248-
elif operator == sublime.OP_NOT_EQUAL:
249-
return operand != has_messages
250-
return None
235+
@classmethod
236+
def applies_to_primary_view_only(cls):
237+
return False
238+
239+
def on_load_async(self):
240+
messages.show_messages_for_view(self.view)
251241

252242

253243
class NextPrevBase(sublime_plugin.WindowCommand):
@@ -486,15 +476,79 @@ class CargoMessageHover(sublime_plugin.ViewEventListener):
486476

487477
@classmethod
488478
def is_applicable(cls, settings):
489-
s = settings.get('syntax')
490-
package_name = __package__.split('.')[0]
491-
return s == 'Packages/%s/RustEnhanced.sublime-syntax' % (package_name,)
479+
return util.is_rust_view(settings)
480+
481+
@classmethod
482+
def applies_to_primary_view_only(cls):
483+
return False
492484

493485
def on_hover(self, point, hover_zone):
494486
if util.get_setting('rust_phantom_style', 'normal') == 'popup':
495487
messages.message_popup(self.view, point, hover_zone)
496488

497489

490+
class RustMessagePopupCommand(sublime_plugin.TextCommand):
491+
492+
"""Manually display a popup for any message under the cursor."""
493+
494+
def run(self, edit):
495+
for r in self.view.sel():
496+
messages.message_popup(self.view, r.begin(), sublime.HOVER_TEXT)
497+
498+
499+
class RustMessageStatus(sublime_plugin.ViewEventListener):
500+
501+
"""Display message under cursor in status bar."""
502+
503+
@classmethod
504+
def is_applicable(cls, settings):
505+
return (util.is_rust_view(settings)
506+
and util.get_setting('rust_message_status_bar', False))
507+
508+
@classmethod
509+
def applies_to_primary_view_only(cls):
510+
return False
511+
512+
def on_selection_modified_async(self):
513+
# https://github.com/SublimeTextIssues/Core/issues/289
514+
# Only works with the primary view, get the correct view.
515+
# (Also called for each view, unfortunately.)
516+
active_view = self.view.window().active_view()
517+
if active_view and active_view.buffer_id() == self.view.buffer_id():
518+
view = active_view
519+
else:
520+
view = self.view
521+
messages.update_status(view)
522+
523+
524+
class RustEventListener(sublime_plugin.EventListener):
525+
526+
def on_activated_async(self, view):
527+
# This is a workaround for this bug:
528+
# https://github.com/SublimeTextIssues/Core/issues/2411
529+
# It would be preferable to use ViewEventListener, but it doesn't work
530+
# on duplicate views created with Goto Anything.
531+
if not util.active_view_is_rust(view=view):
532+
return
533+
if util.get_setting('rust_message_status_bar', False):
534+
messages.update_status(view)
535+
messages.draw_regions_if_missing(view)
536+
537+
def on_query_context(self, view, key, operator, operand, match_all):
538+
# Used by the Escape-key keybinding to dismiss inline phantoms.
539+
if key == 'rust_has_messages':
540+
try:
541+
winfo = messages.WINDOW_MESSAGES[view.window().id()]
542+
has_messages = not winfo['hidden']
543+
except KeyError:
544+
has_messages = False
545+
if operator == sublime.OP_EQUAL:
546+
return operand == has_messages
547+
elif operator == sublime.OP_NOT_EQUAL:
548+
return operand != has_messages
549+
return None
550+
551+
498552
class RustAcceptSuggestedReplacement(sublime_plugin.TextCommand):
499553

500554
"""Used for suggested replacements issued by the compiler to apply the

docs/img/region_style_none.png

-589 Bytes
Loading

docs/img/region_style_outline.png

-474 Bytes
Loading
1.95 KB
Loading
1.96 KB
Loading
1.94 KB
Loading

docs/messages.md

+16
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ hovers over an error (either the gutter icon or the error outline). The
4040

4141
<img src="img/messages_popup.gif">
4242

43+
### Popup Command
44+
You can bind the `rust_message_popup` command to a keyboard shortcut to force
45+
a popup to open if there is a message under the cursor. Example:
46+
47+
```json
48+
{"keys": ["f8"], "command": "rust_message_popup", "context":
49+
[
50+
{"key": "selector", "operator":"equal", "operand": "source.rust"}
51+
]
52+
}
53+
```
54+
4355
## Phantom Themes
4456

4557
The style of the phantom messages is controlled with the `rust_message_theme`
@@ -81,6 +93,9 @@ outline.
8193
| Value | Example | Description |
8294
| :---- | :------ | :---------- |
8395
| `outline` | <img src="img/region_style_outline.png"> | Regions are highlighted with an outline. |
96+
| `solid_underline` | <img src="img/region_style_solid_underline.png"> | Solid underline. |
97+
| `stippled_underline` | <img src="img/region_style_stippled_underline.png"> | Stippled underline. |
98+
| `squiggly_underline` | <img src="img/region_style_squiggly_underline.png"> | Squiggly underline. |
8499
| `none` | <img src="img/region_style_none.png"> | Regions are not highlighted. |
85100

86101
## Gutter Images
@@ -105,3 +120,4 @@ A few other settings are available for controlling messages:
105120
| :------ | :------ | :---------- |
106121
| `show_panel_on_build` | `true` | If true, an output panel is displayed at the bottom of the window showing the compiler output. |
107122
| `rust_syntax_hide_warnings` | `false` | If true, will not display warning messages. |
123+
| `rust_message_status_bar` | `false` | If true, will display the message under the cursor in the window status bar. |

rust/batch.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Classes used for aggregating messages that are on the same line."""
22

3+
from . import util
4+
35

46
class MessageBatch:
57

@@ -48,8 +50,8 @@ def _dismiss(self, window):
4850
# (user has to close and reopen the file). I don't know of any good
4951
# workarounds.
5052
for msg in self:
51-
view = window.find_open_file(msg.path)
52-
if view:
53+
views = util.open_views_for_file(window, msg.path)
54+
for view in views:
5355
view.erase_regions(msg.region_key)
5456
view.erase_phantoms(msg.region_key)
5557

0 commit comments

Comments
 (0)