Update UIX and rename disassembly as log view

This commit is contained in:
Yoshi Askharoun
2024-01-20 20:33:30 -06:00
parent 47b4208cd3
commit 5c1469313e
12 changed files with 250 additions and 53 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

@@ -0,0 +1,28 @@
using Gemini.Framework.Commands;
using System;
using System.ComponentModel.Composition;
using System.Windows.Input;
namespace ZuneUIXTools.Modules.Shell.Commands;
[CommandDefinition]
public class ContinueDebuggerCommandDefinition : CommandDefinition
{
private const string Text_Stop = "Continue";
private const string ToolTip_Stop = "Continues execution until the next breakpoint is hit.";
private static readonly Uri IconSource_Stop = new("pack://application:,,,/ZuneUIXTools;component/Images/DebugContinue_16x.png");
public const string CommandName = "Debugger.Continue";
public override string Name => CommandName;
public override string Text => Text_Stop;
public override string ToolTip => ToolTip_Stop;
public override Uri IconSource => IconSource_Stop;
[Export]
public static CommandKeyboardShortcut KeyGesture
= new CommandKeyboardShortcut<ContinueDebuggerCommandDefinition>(new KeyGesture(Key.F11));
}
@@ -0,0 +1,28 @@
using Gemini.Framework.Commands;
using System;
using System.ComponentModel.Composition;
using System.Windows.Input;
namespace ZuneUIXTools.Modules.Shell.Commands;
[CommandDefinition]
public class StepOverDebuggerCommandDefinition : CommandDefinition
{
private const string Text_Stop = "Step Over";
private const string ToolTip_Stop = "Executes the current instruction and breaks at the next.";
private static readonly Uri IconSource_Stop = new("pack://application:,,,/ZuneUIXTools;component/Images/StepOver_16x.png");
public const string CommandName = "Debugger.StepOver";
public override string Name => CommandName;
public override string Text => Text_Stop;
public override string ToolTip => ToolTip_Stop;
public override Uri IconSource => IconSource_Stop;
[Export]
public static CommandKeyboardShortcut KeyGesture
= new CommandKeyboardShortcut<StepOverDebuggerCommandDefinition>(new KeyGesture(Key.F10));
}
@@ -30,5 +30,13 @@ namespace ZuneUIXTools.Modules.Shell
[Export]
public static ToolBarItemDefinition StartStopDebuggerToolBarItem = new CommandToolBarItemDefinition<StartStopDebuggerCommandDefinition>(
UIXDebuggerToolBarGroup, 0, ToolBarItemDisplay.IconOnly);
[Export]
public static ToolBarItemDefinition StepOverDebuggerToolBarItem = new CommandToolBarItemDefinition<StepOverDebuggerCommandDefinition>(
UIXDebuggerToolBarGroup, 4, ToolBarItemDisplay.IconOnly);
[Export]
public static ToolBarItemDefinition ContinueDebuggerToolBarItem = new CommandToolBarItemDefinition<ContinueDebuggerCommandDefinition>(
UIXDebuggerToolBarGroup, 1, ToolBarItemDisplay.IconOnly);
}
}
+27 -17
View File
@@ -16,8 +16,7 @@ namespace ZuneUIXTools.Modules.UIX;
public class DebuggerService
{
private readonly IOutput _output;
private readonly ConcurrentDictionary<string, ConcurrentBag<InterpreterEntry>> _entriesByFile = new();
private IDebuggerClient _client;
private readonly ConcurrentDictionary<string, ConcurrentBag<InterpreterInstruction>> _entriesByFile = new();
public event Action Stopped;
@@ -27,33 +26,37 @@ public class DebuggerService
_output = output;
}
public bool IsRunning => _client != null;
public bool IsRunning => Client != null;
public IDebuggerClient Client => _client;
public IDebuggerClient Client { get; private set; }
public IReadOnlyDictionary<string, ConcurrentBag<InterpreterEntry>> ConstructedFiles => _entriesByFile;
public IReadOnlyDictionary<string, ConcurrentBag<InterpreterInstruction>> ConstructedFiles => _entriesByFile;
public bool IsInBreakMode { get; private set; }
public void Start(string connectionUri = null)
{
Stop();
_client = new NetDebuggerClient(connectionUri);
_client.InterpreterStep += Client_InterpreterStep;
Client = new NetDebuggerClient(connectionUri);
Client.InterpreterDecode += ClientInterpreterDecode;
Client.InterpreterExecute += ClientInterpreterExecute;
_output.AppendLine($"Debugger connected to {_client.ConnectionUri}");
_output.AppendLine($"Debugger listening on {Client.ConnectionUri}");
}
public void Stop()
{
_entriesByFile.Clear();
if (_client is null)
if (Client is null)
return;
else if (_client is IDisposable disposable)
else if (Client is IDisposable disposable)
disposable.Dispose();
_client.InterpreterStep -= Client_InterpreterStep;
_client = null;
Client.InterpreterDecode -= ClientInterpreterDecode;
Client.InterpreterExecute -= ClientInterpreterExecute;
Client = null;
Stopped?.Invoke();
_output.AppendLine("Debugger disconnected");
@@ -67,16 +70,23 @@ public class DebuggerService
var sortedEntries = entries.ToImmutableSortedSet();
StringBuilder sb = new();
sb.AppendJoin(Environment.NewLine, sortedEntries.Select(e => e.ToInstructionString()));
sb.AppendJoin(Environment.NewLine, sortedEntries.Select(e => e.ToString()));
return sb.ToString();
}
private void Client_InterpreterStep(object sender, InterpreterEntry currentEntry)
private void ClientInterpreterDecode(object sender, InterpreterInstruction currentInstruction)
{
var entries = _entriesByFile.GetOrAdd(currentEntry.LoadUri, _ => new ConcurrentBag<InterpreterEntry>());
_output.AppendLine("[UIX Dec] " + currentInstruction.ToString());
if (entries.Any(e => e.Offset == currentEntry.Offset))
var entries = _entriesByFile.GetOrAdd(currentInstruction.LoadUri, _ => new());
if (entries.Any(e => e.Offset == currentInstruction.Offset))
return;
entries.Add(currentEntry);
entries.Add(currentInstruction);
}
private void ClientInterpreterExecute(object sender, InterpreterEntry entry)
{
_output.AppendLine("[UIX Exe] " + entry.ToString());
}
}
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ZuneUIXTools.Modules.UIXCompiled"
xmlns:uixDebugData="clr-namespace:Microsoft.Iris.Debug.Data"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:UIBDisassemblyViewModel}">
@@ -36,14 +36,14 @@ public class UIBDisassemblyViewModel : Document
public UIBDisassemblyViewModel(DebuggerService debuggerService, IShell shell)
{
_debuggerService = debuggerService;
_debuggerService.Client.InterpreterStep += Client_InterpreterStep;
_debuggerService.Client.InterpreterExecute += ClientInterpreterExecute;
_shell = shell;
DisplayName = $"UIB Disassembler ('{_debuggerService.Client.ConnectionUri}')";
}
private void Client_InterpreterStep(object sender, InterpreterEntry entry)
private void ClientInterpreterExecute(object sender, InterpreterEntry entry)
{
_view?.Dispatcher.Invoke(() =>
{
@@ -0,0 +1,42 @@
<UserControl x:Class="ZuneUIXTools.Modules.UIXCompiled.UIXLogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ZuneUIXTools.Modules.UIXCompiled"
xmlns:uixDebugData="clr-namespace:Microsoft.Iris.Debug.Data"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:UIBDisassemblyViewModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CheckBox Content="Auto-scroll" IsChecked="{Binding AutoScroll}" Padding="4"/>
<DataGrid x:Name="InstructionListView" IsReadOnly="True" AutoGenerateColumns="False"
ItemsSource="{Binding Instructions}" SelectionChanged="InstructionListView_SelectionChanged"
Grid.Row="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Source" Binding="{Binding LoadUri}"/>
<DataGridTextColumn Header="Instruction" Binding="{Binding InstructionString}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate DataType="uixDebugData:InterpreterEntry">
<Border Padding="8">
<StackPanel Orientation="Vertical">
<TextBlock Text="Parameters:"/>
<ItemsControl ItemsSource="{Binding Parameters}"/>
<Border Height="1" Background="Gray" Margin="0,8"/>
<TextBlock Text="Return values:"/>
<ItemsControl ItemsSource="{Binding ReturnValues}"/>
</StackPanel>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</UserControl>
@@ -0,0 +1,38 @@
using System.Windows;
using System.Windows.Controls;
using MahApps.Metro.Controls;
using Microsoft.Iris.Debug.Data;
namespace ZuneUIXTools.Modules.UIXCompiled;
public partial class UIXLogView : UserControl
{
public UIBDisassemblyViewModel ViewModel => (UIBDisassemblyViewModel)DataContext;
public UIXLogView()
{
InitializeComponent();
InstructionListView.Loaded += InstructionListView_Loaded;
}
private void InstructionListView_Loaded(object sender, RoutedEventArgs e)
{
InstructionListView.Loaded -= InstructionListView_Loaded;
InstructionListView.FindChild<ScrollViewer>().ScrollChanged += InstructionListView_ScrollChanged;
}
private void InstructionListView_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (ViewModel.AutoScroll && e.ExtentHeightChange != 0)
((ScrollViewer)sender).ScrollToBottom();
}
private void InstructionListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count <= 0)
return;
ViewModel.SetInspector(e.AddedItems[0] as InterpreterEntry);
}
}
@@ -1,6 +1,7 @@
using Caliburn.Micro;
using Gemini.Framework.Commands;
using Gemini.Framework.Threading;
using Gemini.Modules.ErrorList;
using Gemini.Modules.Output;
using Microsoft.Iris;
using Microsoft.Iris.Debug.SystemNet;
@@ -12,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using ZuneUIXTools.Modules.Shell.Commands;
using ZuneUIXTools.Modules.UIX;
using Application = Microsoft.Iris.Application;
using Command = Gemini.Framework.Commands.Command;
@@ -19,10 +21,14 @@ namespace ZuneUIXTools.Modules.UIXSource
{
[Export(typeof(UIXSourceEditorViewModel))]
#pragma warning disable 659
public class UIXSourceEditorViewModel : UIX.UIXEditorViewModelBase, ICommandHandler<BuildAndRunCommandDefinition>, ICommandHandler<BuildAndDebugCommandDefinition>
public class UIXSourceEditorViewModel : UIXEditorViewModelBase, ICommandHandler<BuildAndRunCommandDefinition>, ICommandHandler<BuildAndDebugCommandDefinition>,
ICommandHandler<StepOverDebuggerCommandDefinition>, ICommandHandler<ContinueDebuggerCommandDefinition>
#pragma warning restore 659
{
private readonly IOutput _output = IoC.Get<IOutput>();
private readonly IErrorList _errorList = IoC.Get<IErrorList>();
private readonly DebuggerService _debuggerService = IoC.Get<DebuggerService>();
private UIXSourceEditorView _view;
private string _originalText;
private string _debuggerConnectionUri = App.DEFAULT_DEBUG_URI;
@@ -83,15 +89,34 @@ namespace ZuneUIXTools.Modules.UIXSource
private void BuildAndRun(object parameter)
{
string sourceFile = FilePath;
string compiledFile = Path.ChangeExtension(sourceFile, "uib");
bool attachDebugger = (bool)parameter;
if (attachDebugger)
{
// Set up debugger client
var debuggerService = IoC.Get<DebuggerService>();
debuggerService.Start(_debuggerConnectionUri);
debuggerService.Client.UpdateBreakpoint(new($"file://{compiledFile}", 1));
debuggerService.Client.DebuggerCommand = Microsoft.Iris.Debug.Data.InterpreterCommand.Continue;
debuggerService.Client.RequestLineNumberTable($"file://{sourceFile}", entries =>
{
foreach (var entry in entries)
_output.AppendLine($"{entry.Offset} => {entry.Line}, {entry.Column}");
});
// Set up debugger server
Application.DebugSettings.DebugConnectionUri = _debuggerConnectionUri;
Application.DebuggerServerReady += OnDebuggerServerReady;
Application.Initialized += () =>
{
// Server is ready, run the application
Run(sourceFile, compiledFile);
};
}
_output.AppendLine($"Compiling '{sourceFile}'...");
string sourceFile = FilePath;
string compiledFile = Path.ChangeExtension(sourceFile, "uib");
bool isSuccess = false;
try
{
@@ -109,20 +134,13 @@ namespace ZuneUIXTools.Modules.UIXSource
}
catch (Exception ex)
{
//Dispatcher.Invoke(() =>
//{
// ErrorPanel.Children.Add(new TextBlock
// {
// Text = $"Build failed: {ex.Message}",
// Margin = new Thickness(0, 0, 0, 4)
// });
//});
_errorList.AddItem(ErrorListItemType.Error, "Compiling failed: " + ex.Message, sourceFile, null, null);
}
if (!isSuccess)
{
var dialogResult = MessageBox.Show(
"There were build errors. Would you like to contine and run the last successful build?",
"There were build errors. Would you like to continue and run the last successful build?",
"Zune UIX Tools", MessageBoxButton.YesNo, MessageBoxImage.Information
);
if (dialogResult != MessageBoxResult.Yes)
@@ -135,41 +153,39 @@ namespace ZuneUIXTools.Modules.UIXSource
}
catch { }
// No need to wait for the debugger to start
if (!attachDebugger)
Run(sourceFile, compiledFile);
}
private void Run(string sourceFile, string compiledFile)
{
try
{
string uiRoot = null;// (IrisProject.SelectedDocument as UIXDocumentViewModel)?.UIRoot;
string uiRoot = string.IsNullOrEmpty(UIRoot) ? "Default" : UIRoot;
_output.AppendLine($"Loading UI '{uiRoot}' from '{compiledFile}'...");
Application.Window.SetBackgroundColor(new WindowColor(0xE6, 0xE6, 0xE6));
Application.Window.RequestLoad("file://" + compiledFile + (string.IsNullOrEmpty(uiRoot) ? string.Empty : "#" + uiRoot));
Application.Window.RequestLoad($"file://{compiledFile}#{uiRoot}");
Application.Window.CloseRequested += (object sender, WindowCloseRequestedEventArgs args) =>
{
args.BlockCloseRequest();
Application.Window.Visible = false;
if (sender is Microsoft.Iris.Window window)
_output.AppendLine($"Window '{window.Handle}' closed");
};
_output.AppendLine($"Application is running...");
Application.Run();
_output.AppendLine("Application exited");
}
catch (Exception ex)
{
//Dispatcher.Invoke(() =>
//{
// ErrorPanel.Children.Add(new TextBlock
// {
// Text = $"Load failed: {ex.Message}",
// Margin = new Thickness(0, 0, 0, 4)
// });
//});
_errorList.AddItem(ErrorListItemType.Error, "Load failed: " + ex.Message, sourceFile, null, null);
}
}
private void OnDebuggerServerReady(object sender, EventArgs e)
{
// Set up the debugger client
NetDebuggerClient debuggerClient = new(_debuggerConnectionUri);
debuggerClient.DispatcherStep += message =>
{
_output.AppendLine($"[{DisplayName}] [Dispatcher] {message}");
};
}
void ICommandHandler<BuildAndRunCommandDefinition>.Update(Command command) => command.Enabled = CanBuild;
Task ICommandHandler<BuildAndRunCommandDefinition>.Run(Command command)
@@ -185,5 +201,31 @@ namespace ZuneUIXTools.Modules.UIXSource
StartBuildAndRun(true);
return TaskUtility.Completed;
}
void ICommandHandler<StepOverDebuggerCommandDefinition>.Update(Command command)
{
command.Visible = _debuggerService.Client != null;
command.Enabled = _debuggerService.Client != null
&& _debuggerService.Client.DebuggerCommand == Microsoft.Iris.Debug.Data.InterpreterCommand.Break;
}
Task ICommandHandler<StepOverDebuggerCommandDefinition>.Run(Command command)
{
_debuggerService.Client.DebuggerCommand = Microsoft.Iris.Debug.Data.InterpreterCommand.Step;
return Task.CompletedTask;
}
void ICommandHandler<ContinueDebuggerCommandDefinition>.Update(Command command)
{
command.Visible = _debuggerService.Client != null;
command.Enabled = _debuggerService.Client != null
&& _debuggerService.Client.DebuggerCommand != Microsoft.Iris.Debug.Data.InterpreterCommand.Continue;
}
Task ICommandHandler<ContinueDebuggerCommandDefinition>.Run(Command command)
{
_debuggerService.Client.DebuggerCommand = Microsoft.Iris.Debug.Data.InterpreterCommand.Continue;
return Task.CompletedTask;
}
}
}