Skip to content

Commit 37d4ba4

Browse files
authored
Add debug logging feature. (#291)
Fixes #275
1 parent 3663f1e commit 37d4ba4

13 files changed

+167
-45
lines changed

Context.sublime-menu

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@
8181
"caption": "Cancel Build",
8282
"command": "rust_cancel"
8383
},
84+
{
85+
"caption": "Open Debug Log",
86+
"command": "rust_open_log"
87+
},
8488
{
8589
"caption": "-",
8690
},

RustEnhanced.sublime-commands

+4
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,8 @@
5252
"caption": "Rust: Run Benchmarks In Current File",
5353
"command": "cargo_bench_current_file"
5454
},
55+
{
56+
"caption": "Rust: Open Debug Log",
57+
"command": "rust_open_log"
58+
},
5559
]

SyntaxCheckPlugin.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sublime_plugin
33
import os
44
from .rust import (messages, rust_proc, rust_thread, util, target_detect,
5-
cargo_settings, semver)
5+
cargo_settings, semver, log)
66
from pprint import pprint
77

88

@@ -23,6 +23,7 @@ def on_post_save(self, view):
2323
# We use phantoms which were added in 3118
2424
if int(sublime.version()) < 3118:
2525
return
26+
log.clear_log(view.window())
2627

2728
enabled = util.get_setting('rust_syntax_checking', True)
2829
if enabled and util.active_view_is_rust(view=view):
@@ -68,9 +69,11 @@ def run(self):
6869
self.cwd = util.find_cargo_manifest(self.triggered_file_name)
6970
if self.cwd is None:
7071
# A manifest is required.
71-
print('Rust Enhanced skipping on-save syntax check.')
72-
print('Failed to find Cargo.toml from %r' % self.triggered_file_name)
73-
print('A Cargo.toml manifest is required.')
72+
log.critical(self.window, util.multiline_fix("""
73+
Rust Enhanced skipping on-save syntax check.
74+
Failed to find Cargo.toml from %r
75+
A Cargo.toml manifest is required.
76+
"""), self.triggered_file_name)
7477
return
7578

7679
self.update_status()
@@ -158,14 +161,10 @@ def on_begin(self, proc):
158161
pass
159162

160163
def on_data(self, proc, data):
161-
# Debugging on-save checking problems requires viewing output here,
162-
# but it is difficult to segregate useful messages (like "thread
163-
# 'main' panicked") from all the other output. Perhaps make a debug
164-
# print setting?
165-
pass
164+
log.log(self.window, data)
166165

167166
def on_error(self, proc, message):
168-
print('Rust Error: %s' % message)
167+
log.critical(self.window, 'Rust Error: %s', message)
169168

170169
def on_json(self, proc, obj):
171170
messages.add_rust_messages(self.window, self.msg_rel_path, obj,
@@ -175,7 +174,7 @@ def on_json(self, proc, obj):
175174
self.this_view_found = True
176175

177176
def on_finished(self, proc, rc):
178-
pass
177+
log.log(self.window, 'On-save check finished.')
179178

180179
def on_terminated(self, proc):
181-
pass
180+
log.log(self.window, 'Process Interrupted')

cargo_build.py

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .rust import (rust_proc, rust_thread, opanel, util, messages,
88
cargo_settings, target_detect)
99
from .rust.cargo_config import *
10+
from .rust.log import (log, clear_log, RustOpenLog, RustLogEvent)
1011

1112
# Maps command to an input string. Used to pre-populate the input panel with
1213
# the last entered value.
@@ -44,6 +45,7 @@ class CargoExecCommand(sublime_plugin.WindowCommand):
4445
def run(self, command=None, command_info=None, settings=None):
4546
if command is None:
4647
return self.window.run_command('build', {'select': True})
48+
clear_log(self.window)
4749
self.initial_settings = settings if settings else {}
4850
self.settings = cargo_settings.CargoSettings(self.window)
4951
self.settings.load()

docs/context.md

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ context-sensitive, based on where you click the mouse.
2828
* **Doc**: `cargo doc` to generate documentation.
2929
* **Cancel Build**: Cancel the current build. Also available with keyboard
3030
shortcuts, see [build docs](build.md).
31+
* **Open Debug Log**: Open a view to display debug messages generated by the
32+
Rust Enhanced plugin.
3133

3234
## Message Commands
3335
* **Clear Messages**: Remove inline error/warning messages. Also available

rust/cargo_config.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import sublime_plugin
1111
from .cargo_settings import CargoSettings, CARGO_COMMANDS
1212
from .util import index_with, get_cargo_metadata
13-
from . import rust_proc, util
13+
from . import rust_proc, util, log
1414

1515
# Keep track of recent choices to set the default value.
1616
RECENT_CHOICES = {}
@@ -212,7 +212,8 @@ def items_package(self):
212212
self.packages[manifest_dir] = package
213213
else:
214214
# Manifest load failure, let it slide.
215-
print('Failed to load Cargo manifest in %r' % dirpath)
215+
log.critical(self.window,
216+
'Failed to load Cargo manifest in %r', dirpath)
216217

217218
if len(self.packages) == 0:
218219
sublime.error_message(util.multiline_fix("""
@@ -252,7 +253,8 @@ def items_target(self):
252253
# build.rs, can't be built explicitly.
253254
pass
254255
else:
255-
print('Rust: Unsupported target found: %s' % kind)
256+
log.critical(self.window,
257+
'Rust: Unsupported target found: %s', kind)
256258
items = []
257259
for kind, values in kinds.items():
258260
allowed = True

rust/cargo_settings.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import sublime
2020
import os
2121
import shlex
22-
from . import util, target_detect
22+
from . import util, target_detect, log
2323

2424
CARGO_COMMANDS = {
2525
'auto': {
@@ -269,7 +269,7 @@ def _set_project_data(self):
269269
if self.window.project_file_name() is None:
270270
# XXX: Better way to display a warning? Is
271271
# sublime.error_message() reasonable?
272-
print(util.multiline_fix("""
272+
log.critical(self.window, util.multiline_fix("""
273273
Rust Enhanced Warning: This window does not have an associated sublime-project file.
274274
Any changes to the Cargo build settings will be lost if you close the window."""))
275275
self.window.set_project_data(self.project_data)

rust/log.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"""Debug logging support."""
2+
3+
import sublime_plugin
4+
import time
5+
6+
7+
logs = {}
8+
9+
10+
class WindowLog:
11+
12+
"""Collection of log messages tied to a window."""
13+
14+
view = None
15+
16+
def __init__(self):
17+
self.messages = []
18+
19+
def clear(self):
20+
self.messages.clear()
21+
if self.view:
22+
self.view.run_command("select_all")
23+
self.view.run_command("right_delete")
24+
25+
def add_message(self, msg, args):
26+
if self.messages:
27+
previous_time = self.messages[-1].time
28+
else:
29+
previous_time = None
30+
lm = LogMessage(msg, args, previous_time)
31+
self.messages.append(lm)
32+
self._display_message(lm)
33+
34+
def _display_message(self, msg):
35+
if self.view:
36+
text = msg.render()
37+
self.view.run_command('append', {'characters': text,
38+
'scroll_to_end': True})
39+
40+
def open_view(self, window):
41+
view = window.new_file()
42+
view.set_scratch(True)
43+
view.settings().set('rust_log_view', window.id())
44+
view.settings().set('word_wrap', True)
45+
view.set_name('Rust Enhanced Debug Log')
46+
self.view = view
47+
for m in self.messages:
48+
self._display_message(m)
49+
50+
51+
class LogMessage:
52+
def __init__(self, msg, args, previous_time):
53+
self.msg = msg
54+
self.args = args
55+
self.previous_time = previous_time
56+
self.time = time.time()
57+
58+
def render(self):
59+
if self.previous_time is None:
60+
last_time = '+0.000'
61+
else:
62+
last_time = '+%.3f' % (self.time - self.previous_time,)
63+
if self.args:
64+
rendered = self.msg % self.args
65+
else:
66+
rendered = self.msg
67+
return '%s %s\n' % (last_time, rendered.rstrip())
68+
69+
70+
def critical(window, msg, *args):
71+
"""Add a log message and display it to the console."""
72+
log(window, msg, *args)
73+
if args:
74+
print(msg % args)
75+
else:
76+
print(msg)
77+
78+
79+
def log(window, msg, *args):
80+
"""Add a log message."""
81+
global logs
82+
wlog = logs.setdefault(window.id(), WindowLog())
83+
wlog.add_message(msg, args)
84+
85+
86+
def clear_log(window):
87+
"""Clear log messages."""
88+
try:
89+
logs[window.id()].clear()
90+
except KeyError:
91+
pass
92+
93+
94+
class RustOpenLog(sublime_plugin.WindowCommand):
95+
96+
"""Opens a view to display log messages generated by the Rust Enhanced
97+
plugin."""
98+
99+
def run(self):
100+
wlog = logs.setdefault(self.window.id(), WindowLog())
101+
if wlog.view:
102+
self.window.focus_view(wlog.view)
103+
else:
104+
wlog.open_view(self.window)
105+
106+
107+
class RustLogEvent(sublime_plugin.ViewEventListener):
108+
109+
@classmethod
110+
def is_applicable(cls, settings):
111+
return settings.has('rust_log_view')
112+
113+
def on_pre_close(self):
114+
try:
115+
wlog = logs[self.view.settings().get('rust_log_view')]
116+
except KeyError:
117+
return
118+
else:
119+
wlog.view = None

rust/messages.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import uuid
1414
import webbrowser
1515

16-
from . import util, themes
16+
from . import util, themes, log
1717
from .batch import *
1818

1919
# Key is window id.
@@ -266,7 +266,9 @@ def _draw_region_highlights(view, batch):
266266
for msg in batch:
267267
region = msg.sublime_region(view)
268268
if msg.level not in regions:
269-
print('RustEnhanced: Unknown message level %r encountered.' % msg.level)
269+
log.critical(view.window(),
270+
'RustEnhanced: Unknown message level %r encountered.',
271+
msg.level)
270272
msg.level = 'error'
271273
regions[msg.level].append((msg.region_key, region))
272274

@@ -370,7 +372,8 @@ def batch_and_msg():
370372
# since the messages were generated).
371373
regions = view.get_regions(msg.region_key)
372374
if not regions:
373-
print('Rust Enhanced internal error: Could not find region for suggestion.')
375+
log.critical(view.window(),
376+
'Rust Enhanced internal error: Could not find region for suggestion.')
374377
return
375378
region = (regions[0].a, regions[0].b)
376379
view.run_command('rust_accept_suggested_replacement', {

rust/opanel.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import os
66
import re
7-
from . import rust_proc, messages, util, semver
7+
from . import rust_proc, messages, util, semver, log
88

99
# Use the same panel name that Sublime's build system uses so that "Show Build
1010
# Results" will open the same panel. I don't see any particular reason why
@@ -157,6 +157,6 @@ def _append(self, message, nl=True):
157157

158158
def _display_debug(self, proc):
159159
# Display some information to help the user debug any build problems.
160-
self._append('[dir: %s]' % (proc.cwd,))
160+
log.log(self.window, 'cwd: %s', proc.cwd)
161161
# TODO: Fix this when adding PATH/env support.
162-
self._append('[path: %s]' % (proc.env.get('PATH'),))
162+
log.log(self.window, 'path: %s', proc.env.get('PATH'))

rust/rust_proc.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
import threading
1313
import time
1414
import shellenv
15+
import sublime
1516
import traceback
1617

17-
from . import util
18+
from . import util, log
1819

1920
# Map Sublime window ID to RustProc.
2021
PROCS = {}
@@ -43,7 +44,7 @@ def on_data(self, proc, data):
4344

4445
def on_error(self, proc, message):
4546
"""Called when there is an error, such as failure to decode utf-8."""
46-
print('Rust Error: %s' % message)
47+
log.critical(sublime.active_window(), 'Rust Error: %s', message)
4748

4849
def on_json(self, proc, obj):
4950
"""Parsed JSON output from the command."""
@@ -93,8 +94,8 @@ def slurp_json(window, cmd, cwd):
9394
"""
9495
rc, listener = _slurp(window, cmd, cwd)
9596
if not listener.json and rc:
96-
print('Failed to run: %s' % cmd)
97-
print(''.join(listener.data))
97+
log.critical(window, 'Failed to run: %s', cmd)
98+
log.critical(window, ''.join(listener.data))
9899
return listener.json
99100

100101

@@ -198,8 +199,7 @@ def run(self, window, cmd, cwd, listener, env=None,
198199
if env:
199200
self.env.update(env)
200201

201-
# XXX: Debug config.
202-
util.debug('Rust running: %s', self.cmd)
202+
log.log(window, 'Running: %s', ' '.join(self.cmd))
203203

204204
if sys.platform == 'win32':
205205
# Prevent a console window from popping up.

rust/target_detect.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88

99
import os
10-
from . import rust_proc, util
10+
from . import rust_proc, util, log
1111

1212

1313
class TargetDetector(object):
@@ -58,7 +58,8 @@ def determine_targets(self, file_name):
5858
if result:
5959
return result
6060

61-
print('Rust Enhanced: Failed to find target for %r' % file_name)
61+
log.critical(self.window,
62+
'Rust Enhanced: Failed to find target for %r', file_name)
6263
return []
6364

6465
def _targets_manual_config(self, file_name):

0 commit comments

Comments
 (0)