Skip to content

Commit

Permalink
Message updates.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
ehuss committed Sep 5, 2018
1 parent 5480b64 commit d9f00c4
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 66 deletions.
4 changes: 4 additions & 0 deletions RustEnhanced.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@
"caption": "Rust: Open Debug Log",
"command": "rust_open_log"
},
{
"caption": "Rust: Popup Message At Cursor",
"command": "rust_message_popup"
}
]
6 changes: 6 additions & 0 deletions RustEnhanced.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@

// For errors/warnings, how to highlight the region of the error.
// "outline" - Outlines the region.
// "solid_underline" - A solid underline.
// "stippled_underline" - A stippled underline.
// "squiggly_underline" - A squiggly underline.
// "none" - No outlining.
"rust_region_style": "outline",

Expand All @@ -51,6 +54,9 @@
// "solid" - Solid background color.
"rust_message_theme": "clear",

// If `true`, displays diagnostic messages under the cursor in the status bar.
"rust_message_status_bar": false,

// If your cargo project has several build targets, it's possible to specify mapping of
// source code filenames to the target names to enable syntax checking.
// "projects": {
Expand Down
52 changes: 35 additions & 17 deletions SyntaxCheckPlugin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import sublime
import sublime_plugin
import os
import time
from .rust import (messages, rust_proc, rust_thread, util, target_detect,
cargo_settings, semver, log)
from pprint import pprint


"""On-save syntax checking.
Expand All @@ -13,26 +13,31 @@
"""


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

# Beware: This gets called multiple times if the same buffer is opened in
# multiple views (with the same view passed in each time). See:
# https://github.com/SublimeTextIssues/Core/issues/289
last_save = 0

def on_post_save(self, view):
# Are we in rust scope and is it switched on?
# We use phantoms which were added in 3118
if int(sublime.version()) < 3118:
enabled = util.get_setting('rust_syntax_checking', True)
if not enabled or not util.active_view_is_rust(view=view):
return
prev_save = self.last_save
self.last_save = time.time()
if self.last_save - prev_save < 0.25:
# This is a guard for a few issues.
# * `on_post_save` gets called multiple times if the same buffer
# is opened in multiple views (with the same view passed in each
# time). See:
# https://github.com/SublimeTextIssues/Core/issues/289
# * When using "Save All" we want to avoid launching a bunch of
# threads and then immediately killing them.
return
log.clear_log(view.window())

enabled = util.get_setting('rust_syntax_checking', True)
if enabled and util.active_view_is_rust(view=view):
t = RustSyntaxCheckThread(view)
t.start()
elif not enabled:
# If the user has switched OFF the plugin, remove any phantom
# lines.
messages.clear_messages(view.window())
messages.erase_status(view)
t = RustSyntaxCheckThread(view)
t.start()


class RustSyntaxCheckThread(rust_thread.RustThread, rust_proc.ProcListener):
Expand Down Expand Up @@ -87,7 +92,20 @@ def run(self):
messages.messages_finished(self.window)
finally:
self.done = True
self.window.status_message('')
messages.messages_finished(self.window)
if util.get_setting('rust_message_status_bar', False):
messages.update_status(self.view)
counts = messages.message_counts(self.window)
if counts:
msg = []
for key, value in sorted(counts.items(), key=lambda x: x[0]):
level = key.plural if value > 1 else key.name
msg.append('%i %s' % (value, level))
self.window.status_message('Rust check: %s' % (', '.join(msg,)))
elif rc:
self.window.status_message(CHECK_FAIL_MSG)
else:
self.window.status_message('Rust check: success')

def update_status(self, count=0):
if self.done:
Expand Down
100 changes: 77 additions & 23 deletions cargo_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,32 +222,22 @@ def run(self):
ON_LOAD_MESSAGES_ENABLED = True


class CargoEventListener(sublime_plugin.EventListener):
class MessagesViewEventListener(sublime_plugin.ViewEventListener):

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

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

def on_query_context(self, view, key, operator, operand, match_all):
# Used by the Escape-key keybinding to dismiss inline phantoms.
if key == 'rust_has_messages':
try:
winfo = messages.WINDOW_MESSAGES[view.window().id()]
has_messages = not winfo['hidden']
except KeyError:
has_messages = False
if operator == sublime.OP_EQUAL:
return operand == has_messages
elif operator == sublime.OP_NOT_EQUAL:
return operand != has_messages
return None
@classmethod
def applies_to_primary_view_only(cls):
return False

def on_load_async(self):
messages.show_messages_for_view(self.view)


class NextPrevBase(sublime_plugin.WindowCommand):
Expand Down Expand Up @@ -486,15 +476,79 @@ class CargoMessageHover(sublime_plugin.ViewEventListener):

@classmethod
def is_applicable(cls, settings):
s = settings.get('syntax')
package_name = __package__.split('.')[0]
return s == 'Packages/%s/RustEnhanced.sublime-syntax' % (package_name,)
return util.is_rust_view(settings)

@classmethod
def applies_to_primary_view_only(cls):
return False

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


class RustMessagePopupCommand(sublime_plugin.TextCommand):

"""Manually display a popup for any message under the cursor."""

def run(self, edit):
for r in self.view.sel():
messages.message_popup(self.view, r.begin(), sublime.HOVER_TEXT)


class RustMessageStatus(sublime_plugin.ViewEventListener):

"""Display message under cursor in status bar."""

@classmethod
def is_applicable(cls, settings):
return (util.is_rust_view(settings)
and util.get_setting('rust_message_status_bar', False))

@classmethod
def applies_to_primary_view_only(cls):
return False

def on_selection_modified_async(self):
# https://github.com/SublimeTextIssues/Core/issues/289
# Only works with the primary view, get the correct view.
# (Also called for each view, unfortunately.)
active_view = self.view.window().active_view()
if active_view and active_view.buffer_id() == self.view.buffer_id():
view = active_view
else:
view = self.view
messages.update_status(view)


class RustEventListener(sublime_plugin.EventListener):

def on_activated_async(self, view):
# This is a workaround for this bug:
# https://github.com/SublimeTextIssues/Core/issues/2411
# It would be preferable to use ViewEventListener, but it doesn't work
# on duplicate views created with Goto Anything.
if not util.active_view_is_rust(view=view):
return
if util.get_setting('rust_message_status_bar', False):
messages.update_status(view)
messages.draw_regions_if_missing(view)

def on_query_context(self, view, key, operator, operand, match_all):
# Used by the Escape-key keybinding to dismiss inline phantoms.
if key == 'rust_has_messages':
try:
winfo = messages.WINDOW_MESSAGES[view.window().id()]
has_messages = not winfo['hidden']
except KeyError:
has_messages = False
if operator == sublime.OP_EQUAL:
return operand == has_messages
elif operator == sublime.OP_NOT_EQUAL:
return operand != has_messages
return None


class RustAcceptSuggestedReplacement(sublime_plugin.TextCommand):

"""Used for suggested replacements issued by the compiler to apply the
Expand Down
Binary file modified docs/img/region_style_none.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/region_style_outline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/region_style_solid_underline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/region_style_squiggly_underline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/region_style_stippled_underline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions docs/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ hovers over an error (either the gutter icon or the error outline). The

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

### Popup Command
You can bind the `rust_message_popup` command to a keyboard shortcut to force
a popup to open if there is a message under the cursor. Example:

```json
{"keys": ["f8"], "command": "rust_message_popup", "context":
[
{"key": "selector", "operator":"equal", "operand": "source.rust"}
]
}
```

## Phantom Themes

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

## Gutter Images
Expand All @@ -105,3 +120,4 @@ A few other settings are available for controlling messages:
| :------ | :------ | :---------- |
| `show_panel_on_build` | `true` | If true, an output panel is displayed at the bottom of the window showing the compiler output. |
| `rust_syntax_hide_warnings` | `false` | If true, will not display warning messages. |
| `rust_message_status_bar` | `false` | If true, will display the message under the cursor in the window status bar. |
6 changes: 4 additions & 2 deletions rust/batch.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Classes used for aggregating messages that are on the same line."""

from . import util


class MessageBatch:

Expand Down Expand Up @@ -48,8 +50,8 @@ def _dismiss(self, window):
# (user has to close and reopen the file). I don't know of any good
# workarounds.
for msg in self:
view = window.find_open_file(msg.path)
if view:
views = util.open_views_for_file(window, msg.path)
for view in views:
view.erase_regions(msg.region_key)
view.erase_phantoms(msg.region_key)

Expand Down
Loading

0 comments on commit d9f00c4

Please sign in to comment.