Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
ab9af89
Fixed binding redirect exception for when ValueTuple 4.0.3 is not in …
mitchcapper Nov 26, 2025
d50b814
More specific version error exception type to assist with ignoring
mitchcapper Nov 26, 2025
58e4271
Added editorconfig matching what the project seems to follow
mitchcapper Nov 26, 2025
e47bfe8
Added app.manifest for DPI control and defaults
mitchcapper Nov 26, 2025
0fac73d
Move to a central backend config class and added central exception/br…
mitchcapper Nov 26, 2025
83fb49e
Moved to centralized Directory.Build.props for .net target
mitchcapper Nov 26, 2025
302dd37
Added the .net 9 fluent theme for basic stylizing
mitchcapper Nov 26, 2025
8eb2715
Added load text from file button and basic CLI handling for doing the…
mitchcapper Nov 26, 2025
d609685
Add ability to only load certain engines
mitchcapper Nov 27, 2025
5fb484b
Fix style overrides to be based on fluent styles, added bool converter
mitchcapper Nov 27, 2025
03df1eb
New AI Assist pane
mitchcapper Nov 27, 2025
cfc478a
Add ability to specify multiple only-engine-dll's on the command line
mitchcapper Dec 10, 2025
f9d3ca8
Only load CLI text for the first empty tab
mitchcapper Dec 10, 2025
11098d2
Add ability to inspect a capture/group in a new tab
mitchcapper Dec 10, 2025
9710f03
Fix for matches window wrapping and proper length calculation for tru…
mitchcapper Dec 10, 2025
ca1afe7
Prevent combo box growth on dropdown expanding forever
mitchcapper Dec 10, 2025
8e2b2a5
Prevent session state corruption on fast exit
mitchcapper Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = crlf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.json]
indent_size = 2

[*.{cs,cpp,h,c,cc,cxx,hpp,hxx}]
indent_size = 4

[*.{cpp,h,c,cc,cxx,hpp,hxx}]
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = statement_begin
cpp_new_line_before_open_brace_namespace = new_line
cpp_new_line_before_open_brace_type = new_line
cpp_new_line_before_open_brace_function = new_line
cpp_new_line_before_open_brace_block = new_line
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_finally = true
cpp_space_before_function_open_parenthesis = false
cpp_space_within_parameter_list_parentheses = true
cpp_space_between_empty_parameter_list_parentheses = true
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = true
cpp_space_before_semicolon_in_for_statement = false
cpp_space_after_semicolon_in_for_statement = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert

[*.xaml]
charset = utf-8-bom

[*.cs]
charset = utf-8-bom
# New line settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

# Indentation settings
csharp_indent_case_contents = true
csharp_indent_switch_labels = false
csharp_indent_labels = one_less_than_current

# Spacing settings
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_between_method_call_parameter_list_parentheses = true
csharp_space_between_method_declaration_parameter_list_parentheses = true
csharp_space_between_method_call_empty_parameter_list_parentheses = true
csharp_space_between_method_declaration_empty_parameter_list_parentheses = true
csharp_space_between_parentheses = control_flow_statements, expressions

# Style settings
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_prefer_braces = false:silent
csharp_preserve_single_line_blocks = true
csharp_using_directive_placement = outside_namespace:silent
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "PilotAIAssistantControl"]
path = PilotAIAssistantControl
url = https://github.com/mitchcapper/PilotAIAssistantControl
1 change: 1 addition & 0 deletions PilotAIAssistantControl
5 changes: 5 additions & 0 deletions RegExpressWPFNET/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0-windows7.0</TargetFramework>
</PropertyGroup>
</Project>
25 changes: 20 additions & 5 deletions RegExpressWPFNET/RegExpressLibrary/IRegexEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,27 @@ namespace RegExpressLibrary

public delegate void RegexEngineOptionsChanged( IRegexEngine sender, RegexEngineOptionsChangedArgs args );

public interface IBaseEngine
{
string Name { get; }
string? ExportOptions( ); // (JSON)
}
public interface IAIBase : IBaseEngine
{
string AIPatternType => "Regex";
string AIPatternCodeblockType => "regex";
string AIAdditionalSystemPrompt => "If the language supports named capture groups, use these by default. " +
"If the user has ignoring patterned whitespace enabled in the options, use multi-lines and minimal in-regex comments for complex regexes with nice whitespace formatting to make it more readable. ";

string ReferenceTextHeader => "Users current target text";
string GetSystemPrompt( ) => $"You are a {Name} {AIPatternType} expert assistant. The user has questions about their {AIPatternType} patterns and target text. " +
$"Provide {AIPatternType} patterns inside Markdown code blocks (```{AIPatternCodeblockType} ... ```). " +
"Explain how the pattern works briefly. " +
AIAdditionalSystemPrompt +
$"They currently have these engine options enabled:\n```json\n{ExportOptions( )}\n```";
}

public interface IRegexEngine
public interface IRegexEngine : IAIBase
{
event RegexEngineOptionsChanged? OptionsChanged;
event EventHandler? FeatureMatrixReady;
Expand All @@ -26,8 +45,6 @@ public interface IRegexEngine

(string Kind, string? Version) CombinedId => (Kind, Version);

string Name { get; }

string Subtitle { get; }

RegexEngineCapabilityEnum Capabilities { get; }
Expand All @@ -36,8 +53,6 @@ public interface IRegexEngine

Control GetOptionsControl( );

string? ExportOptions( ); // (JSON)

void ImportOptions( string? json );

RegexMatches GetMatches( ICancellable cnc, [StringSyntax( StringSyntaxAttribute.Regex )] string pattern, string text );
Expand Down
124 changes: 124 additions & 0 deletions RegExpressWPFNET/RegExpressLibrary/InternalConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows;

namespace RegExpressLibrary
{
public static class InternalConfig
{
public static bool SHOW_DEBUG_BUTTONS = false;
public static bool DEBUG_LOG_AI_MESSAGES = true;

/// <summary>
/// as the target text can be long lets not keep the old versions around two options are update the target text with the new text, or remove the old one add a note and add the new one
/// </summary>
public static bool DONT_UPDATE_OLD_AI_TEXT_MARK_REMOVED = true;
public static string[]? limited_engine_dlls;
[Flags]
public enum ON_EXCEPTION_ACTION
{
None,
MessageBox = 1 << 0,
DebuggerBreak = 1 << 1,
Rethrow = 1 << 2,
IncludeStackTrace = 1 << 3,
IncludeTraceDetails = 1 << 4,

}
public static ON_EXCEPTION_ACTION ON_EXCEPTION_DEBUGGER_ATTACHED = ON_EXCEPTION_ACTION.DebuggerBreak | ON_EXCEPTION_ACTION.IncludeTraceDetails | ON_EXCEPTION_ACTION.IncludeStackTrace;
public static ON_EXCEPTION_ACTION ON_EXCEPTION_STANDARD = ON_EXCEPTION_ACTION.MessageBox;
public static void HandleOtherCriticalError( String error, [System.Runtime.CompilerServices.CallerLineNumber] int source_line_number = 0, [System.Runtime.CompilerServices.CallerMemberName] string member_name = "", [System.Runtime.CompilerServices.CallerFilePath] string source_file_path = "" ) =>
_CriticalError( new StringBuilder( error ), source_line_number, member_name, source_file_path );
private static void _CriticalError( StringBuilder sb, [System.Runtime.CompilerServices.CallerLineNumber] int source_line_number = 0, [System.Runtime.CompilerServices.CallerMemberName] string member_name = "", [System.Runtime.CompilerServices.CallerFilePath] string source_file_path = "" )
{
var ON_EXCEPTION = Debugger.IsAttached ? ON_EXCEPTION_DEBUGGER_ATTACHED : ON_EXCEPTION_STANDARD;
if( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.IncludeTraceDetails ) )
{
sb.Append( "Member: " ).AppendLine( member_name );
sb.Append( "File: " ).AppendLine( source_file_path );
sb.Append( "Line: " ).AppendLine( source_line_number.ToString( ) );
}

string message = sb.ToString( );

// MessageBox (on UI thread if possible)
if( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.MessageBox ) )
{
try
{
if( Application.Current?.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess( ) )
Application.Current.Dispatcher.Invoke( ( ) => MessageBox.Show( message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error ) );
else
MessageBox.Show( message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error );

}
catch
{
// Fallback to Debug output if UI unavailable
Debug.WriteLine( message );
}
}

// Break into debugger if requested and a debugger is attached
if( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.DebuggerBreak ) && Debugger.IsAttached )
Debugger.Break( );


// Always log to debug output for visibility
Debug.WriteLine( message );

}

public static bool HandleException( String msg, Exception exception, [System.Runtime.CompilerServices.CallerLineNumber] int source_line_number = 0, [System.Runtime.CompilerServices.CallerMemberName] string member_name = "", [System.Runtime.CompilerServices.CallerFilePath] string source_file_path = "", [CallerArgumentExpression( "exception" )] string exceptionName = "" )
{
if( exception == null ) return false;
var ON_EXCEPTION = Debugger.IsAttached ? ON_EXCEPTION_DEBUGGER_ATTACHED : ON_EXCEPTION_STANDARD;

// Build a diagnostic message
StringBuilder sb = new( );

sb.AppendLine( "Exception! " );
if( !String.IsNullOrWhiteSpace( msg ) )
sb.AppendLine( msg + " " );
if( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.IncludeTraceDetails ) )
{
sb.Append( "Member: " ).AppendLine( member_name );
sb.Append( "File: " ).AppendLine( source_file_path );
sb.Append( "Line: " ).AppendLine( source_line_number.ToString( ) );
}
sb.Append( "Exception Var: " ).AppendLine( exceptionName );
sb.Append( "Type: " ).AppendLine( exception.GetType( ).FullName );
sb.Append( "Message: " ).AppendLine( exception.Message );

if( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.IncludeStackTrace ) )
{
var st = exception.StackTrace;
if( !string.IsNullOrWhiteSpace( st ) )
{
sb.AppendLine( "StackTrace:" );
sb.AppendLine( st );
}
}
_CriticalError( sb, source_line_number, member_name, source_file_path );

return ( ON_EXCEPTION.HasFlag( ON_EXCEPTION_ACTION.Rethrow ) );
}
/// <summary>
/// Returns true if caller should rethrow the exception
/// </summary>
/// <param name="exception"></param>
/// <param name="source_line_number"></param>
/// <param name="member_name"></param>
/// <param name="source_file_path"></param>
/// <param name="exceptionName"></param>
/// <returns></returns>
public static bool HandleException( Exception exception, [System.Runtime.CompilerServices.CallerLineNumber] int source_line_number = 0, [System.Runtime.CompilerServices.CallerMemberName] string member_name = "", [System.Runtime.CompilerServices.CallerFilePath] string source_file_path = "", [CallerArgumentExpression( "exception" )] string exceptionName = "" ) =>
HandleException( string.Empty, exception, source_line_number, member_name, source_file_path, exceptionName );

}
}
21 changes: 12 additions & 9 deletions RegExpressWPFNET/RegExpressLibrary/PluginUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@ public static class PluginLoader
}
catch( Exception exc )
{
if( Debugger.IsAttached ) Debugger.Break( );

MessageBox.Show( ownerWindow, $"Failed to load plugins using '{enginesJsonPath}'.\r\n\r\n{exc.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation );
if (InternalConfig.HandleException($"Failed to load plugins using '{enginesJsonPath}'", exc ))
throw;

return (null, null);
}
Expand All @@ -81,6 +80,11 @@ public static class PluginLoader
{
foreach( EngineData engine_data in engines_data.engines )
{
if ( InternalConfig.limited_engine_dlls?.Length > 0 && !InternalConfig.limited_engine_dlls.Any( dll => engine_data.path.Contains(dll, StringComparison.CurrentCultureIgnoreCase) ) )
{
Debug.WriteLine( $"Skipping plugin due to limited_engine_dlls \"{engine_data.path}\"..." );
continue;
}
string plugin_absolute_path = Path.Combine( plugin_root_folder, engine_data.path! );

try
Expand All @@ -106,18 +110,17 @@ public static class PluginLoader
}
catch( Exception exc )
{
if( Debugger.IsAttached ) Debugger.Break( );
if (InternalConfig.HandleException( $"Failed to create plugin \"{engine_data.path}\"", exc ))
throw;

MessageBox.Show( ownerWindow, $"Failed to create plugin \"{engine_data.path}\".\r\n\r\n{exc.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation );
}
}
}
}
catch( Exception exc )
{
if( Debugger.IsAttached ) Debugger.Break( );

MessageBox.Show( $"Failed to load plugin \"{engine_data.path}\".\r\n\r\n{exc.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation );
if (InternalConfig.HandleException( $"Failed to create plugin \"{engine_data.path}\"", exc ))
throw;
}
}
}
Expand All @@ -142,4 +145,4 @@ public static class PluginLoader

return (plugins, no_fm_plugins);
}
}
}
12 changes: 8 additions & 4 deletions RegExpressWPFNET/RegExpressLibrary/ProcessHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ public bool Start( ICancellable cnc )
catch( Exception exc )
{
_ = exc;
if( Debugger.IsAttached ) Debugger.Break( );
if (InternalConfig.HandleException( exc ))
throw;
}
} )
{
Expand All @@ -155,7 +156,8 @@ public bool Start( ICancellable cnc )
catch( Exception exc )
{
_ = exc;
if( Debugger.IsAttached ) Debugger.Break( );
if (InternalConfig.HandleException( exc ))
throw;
}
} )
{
Expand All @@ -174,7 +176,8 @@ public bool Start( ICancellable cnc )
catch( Exception exc )
{
_ = exc;
if( Debugger.IsAttached ) Debugger.Break( );
if (InternalConfig.HandleException( exc ))
throw;
}
} )
{
Expand Down Expand Up @@ -222,7 +225,8 @@ public bool Start( ICancellable cnc )
if( unchecked((uint)exc.HResult) != 0x80004005 && // 'E_ACCESSDENIED'
unchecked((uint)exc.HResult) != 0x80131509 ) // -2146233079, "Cannot process request because the process (<PID>) has exited."
{
if( Debugger.IsAttached ) Debugger.Break( );
if (InternalConfig.HandleException( exc ))
throw;
}

// ignore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
x:Name="userControl" DataContextChanged="userControl_DataContextChanged"
>
<CheckBox IsChecked="{Binding IsChecked, ElementName=userControl}" HorizontalAlignment="Left">
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap">
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" VerticalAlignment="Center" TextWrapping="Wrap">
<Run x:Name="run" Text="Sample text"/>
<Run>
<Run.Style>
Expand Down
4 changes: 4 additions & 0 deletions RegExpressWPFNET/RegExpressWPFNET.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
<Platform Name="Any CPU" />
<Platform Name="x64" />
</Configurations>
<Folder Name="/AIAssist/">
<Project Path="../PilotAIAssistantControl/PilotAIAssistantControl/PilotAIAssistantControl.shproj" Id="6cd62ff6-5bd0-41d0-a512-a6587e4846da" />
<Project Path="../PilotAIAssistantControl/PilotAIAssistantControlWPF/PilotAIAssistantControlWPF.csproj" />
</Folder>
<Folder Name="/RegexEngines/" />
<Folder Name="/RegexEngines/Ada/">
<Project Path="RegexEngines/Ada/AdaPlugin/AdaPlugin.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ public void SetRangesToUnderline( IReadOnlyList<(TextPointer start, TextPointer
// TODO: 'ExecutionEngineException' is now obsolete.

_ = exc;
if( Debugger.IsAttached ) Debugger.Break( );
if (RegExpressLibrary.InternalConfig.HandleException( exc ))
throw;
// ignore and accept the ranges
}
}
Expand Down
Loading