Skip to content

Commit

Permalink
Updated protocol logging to use a window and show each sessions log s…
Browse files Browse the repository at this point in the history
…eparately
  • Loading branch information
daveleroy committed Jan 28, 2024
1 parent 656518b commit 50f7b00
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 82 deletions.
2 changes: 1 addition & 1 deletion modules/adapters/ruby.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def stdout(data: str):
def stderr(data: str):
hidden = data.startswith('DEBUGGER: ')
if hidden:
log('transport', dap.TransportStderrOutputLog(data))
log('transport', dap.TransportOutputLog('stderr', data))
else:
log('stderr',data)

Expand Down
13 changes: 7 additions & 6 deletions modules/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from .ansi import ansi_colorize

from .protocol import ProtocolPanel
from .protocol import ProtocolWindow
from .output_panel import OutputPanel


Expand All @@ -25,7 +25,8 @@ def __init__(self, debugger: Debugger) -> None:
self.on_navigate = core.Event[dap.SourceLocation]()
self.debugger = debugger

self.protocol = ProtocolPanel(debugger)
self.protocol = ProtocolWindow()
self.dispose_add(self.protocol)

self.view.assign_syntax(core.package_path_relative('contributes/Syntax/DebuggerConsole.sublime-syntax'))
self.color: str|None = None
Expand Down Expand Up @@ -466,9 +467,9 @@ def autofill(self, offset: int):



def log(self, type: str, value: Any, source: dap.SourceLocation|None = None):
def log(self, type: str, value: Any, source: dap.SourceLocation|None = None, session: dap.Session|None = None):
if type == 'transport':
self.protocol.log('transport', value)
self.protocol.log('transport', value, session)
elif type == 'error-no-open':
self.write(str(value).rstrip('\n'), 'red', ensure_new_line=True)
elif type == 'error':
Expand All @@ -483,10 +484,10 @@ def log(self, type: str, value: Any, source: dap.SourceLocation|None = None):
if value is not None:
self.write(str(value), None, ensure_new_line=True)
elif type == 'stdout':
self.protocol.log('stdout', value)
self.protocol.log('stdout', value, session)
self.write(str(value), None)
elif type == 'stderr':
self.protocol.log('stderr', value)
self.protocol.log('stderr', value, session)
self.write(str(value), 'red')
elif type == 'stdout':
self.write(str(value), None)
Expand Down
8 changes: 4 additions & 4 deletions modules/dap/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .import dap

from ..watch import Watch
from .debugger import Console, Debugger
from .debugger import Console, ConsoleSessionBound, Debugger
from .error import Error

from ..breakpoints import Breakpoints, SourceBreakpoint, Breakpoint
Expand Down Expand Up @@ -67,7 +67,7 @@ def __init__(self,
breakpoints: Breakpoints,
watch: Watch,
listener: SessionListener,
log: Console,
console: Console,
debugger: Debugger,
parent: Session|None = None
) -> None:
Expand All @@ -85,7 +85,7 @@ def __init__(self,
if parent:
parent.children.append(self)

self.log = log
self.log = ConsoleSessionBound(self, console)
self.state_changed = core.Event[int]()

self.breakpoints = breakpoints
Expand Down Expand Up @@ -179,7 +179,7 @@ async def _launch(self) -> None:

self._change_state_status('Starting')
try:
self.log.log('transport', f'-- adapter: type={self.adapter_configuration.type} version={installed_version}')
self.log('transport', f'-- adapter: type={self.adapter_configuration.type} version={installed_version}')
transport = await self.adapter_configuration.start(log=self.log, configuration=self.configuration)
except TransportConnectionError as e:
self.stopped_unexpectedly = True
Expand Down
11 changes: 3 additions & 8 deletions modules/dap/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,11 @@ def on_transport_closed(self) -> Any: ...


@dataclass
class TransportStdoutOutputLog:
class TransportOutputLog:
type: str
output: str
def __str__(self) -> str:
return '-> stdout :: ' + self.output

@dataclass
class TransportStderrOutputLog:
output: str
def __str__(self) -> str:
return '-> stderr !! ' + self.output
return f'-> {type} :: {self.output}'

@dataclass
class TransportDataLog:
Expand Down
8 changes: 4 additions & 4 deletions modules/dap/transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import IO, Any, Callable

from ..import core
from .transport import Transport, TransportListener, TransportStderrOutputLog, TransportStdoutOutputLog, TransportConnectionError, TransportStream
from .transport import Transport, TransportListener, TransportOutputLog, TransportConnectionError, TransportStream

import socket
import os
Expand Down Expand Up @@ -133,7 +133,7 @@ async def setup(self):
self.process.on_stderr(self._log_stderr)

def _log_stderr(self, data: str):
self.log('transport', TransportStderrOutputLog(data))
self.log('transport', TransportOutputLog('stderr', data))
if stderr := self.stderr:
stderr(data)

Expand Down Expand Up @@ -205,8 +205,8 @@ async def setup(self):


if self.process:
self.process.on_stdout(self.stdout or (lambda data: self.log('transport', TransportStdoutOutputLog(data))))
self.process.on_stderr(self.stderr or (lambda data: self.log('transport', TransportStderrOutputLog(data))))
self.process.on_stdout(self.stdout or (lambda data: self.log('transport', TransportOutputLog('stdout', data))))
self.process.on_stderr(self.stderr or (lambda data: self.log('transport', TransportOutputLog('stderr', data))))

self.socket_stdin = self.socket.makefile('wb')
self.socket_stdout = self.socket.makefile('rb')
Expand Down
17 changes: 12 additions & 5 deletions modules/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ async def launch(self, breakpoints: Breakpoints, adapter: dap.AdapterConfigurati
listener=self,
debugger=self,
parent=parent,
log=self.console,
console=self.console,
)

self.add_session(session)
Expand Down Expand Up @@ -410,15 +410,22 @@ def remove_session(self, session: dap.Session):


if session.stopped_unexpectedly:
for data in self.console.protocol.pending:
if isinstance(data, dap.TransportStderrOutputLog):
found_error = False
for data in self.console.protocol.logs:
if isinstance(data, dap.TransportOutputLog):
found_error = True
self.console.error(data.output)

self.console.error('Debugging session ended unexpectedly')
# color the end prompt as an error if there were no errors found
if not found_error:
self.console.error('Debugging ended unexpectedly')
else:
self.console.info('Debugging ended unexpectedly')

if not self.sessions:
elif not self.sessions:
self.console.info('Debugging ended')

if not self.sessions:
# if the debugger panel is open switch to the console.
# note: We could be on a pre debug step panel which we want to remain on so only do this if we are on the callstack panel
if self.callstack.is_open():
Expand Down
112 changes: 58 additions & 54 deletions modules/protocol.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,62 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from typing import Any

import sublime

from .import core
from .output_panel import OutputPanel
from .import dap

if TYPE_CHECKING:
from .debugger import Debugger
class ProtocolWindow:
def __init__(self) -> None:
window = None

class ProtocolPanel(core.Logger):
def __init__(self, debugger: Debugger):
self.debugger = debugger
self.output: OutputPanel|None = None
self.pending: list[Any] = []
for w in sublime.windows():
if w.settings().has('debugger.window.protocol'):
window = w

self.window = window
self.views: dict[dap.Session|None, sublime.View] = {}
self.logs = []

def open(self):
if self.window and self.window.is_valid():
self.window.bring_to_front()
else:
sublime.run_command('new_window')
self.window = sublime.active_window()
settings = self.window.settings()
settings.set('debugger', True)
settings.set('debugger.window', True)
settings.set('debugger.window.protocol', True)

self.window.run_command('show_panel', {'panel': 'console'})

def clear(self):
for view in self.views.values():
view.close()

self.views.clear()
self.logs.clear()

def dispose(self):
self.clear()

def view_for_session(self, session: dap.Session|None):
if view := self.views.get(session):
return view

assert self.window
view = self.window.new_file(flags=sublime.ADD_TO_SELECTION)
view.assign_syntax(core.package_path_relative('contributes/Syntax/DebuggerProtocol.sublime-syntax'))
view.set_scratch(True)

settings = view.settings()
settings.set('word_wrap', False)
settings.set('scroll_past_end', False)

self.views[session] = view
view.set_name(session and session.name or 'General')
return view

def platform_info(self):
settings = sublime.load_settings("Preferences.sublime-settings")
Expand All @@ -27,53 +70,14 @@ def platform_info(self):
output += '\n'
return output

def write_pending(self):
if not self.output:
self.output = OutputPanel(self.debugger, 'Debugger Protocol', 'Protocol')
self.output.on_opened = lambda: self.write_pending_if_needed()
self.output.view.assign_syntax(core.package_path_relative('contributes/Syntax/DebuggerProtocol.sublime-syntax'))
settings = self.output.view.settings()
settings.set('word_wrap', False)
settings.set('scroll_past_end', False)
def log(self, type: str, value: Any, session: dap.Session|None = None):
if not self.window:
return

self.output.view.run_command('append', {
'characters': self.platform_info(),
'force': True,
'scroll_to_end': True,
})
self.logs.append(value)


text = ''
for pending in self.pending:
text += f'{pending}\n'

self.pending.clear()

self.output.view.run_command('append', {
'characters': text,
self.view_for_session(session).run_command('append', {
'characters': f'{value}\n',
'force': True,
'scroll_to_end': True,
})

def write_pending_if_needed(self):
if self.output and self.output.is_open():
self.write_pending()

def log(self, type: str, value: Any):
self.pending.append(value)
self.write_pending_if_needed()

def open(self):
self.write_pending()
if self.output:
self.output.open()

def clear(self):
self.pending.clear()
if self.output:
self.output.dispose()
self.output = None

def dispose(self):
if self.output:
self.output.dispose()

0 comments on commit 50f7b00

Please sign in to comment.