Compare commits

...

5 commits

Author SHA1 Message Date
Wydy
a8148855a9
Merge 7816c1dcca into dc4611a258 2025-09-26 21:18:30 +08:00
2dust
dc4611a258 Adjust qrcode width
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-09-26 20:36:27 +08:00
2dust
03d5b7a05b Bug fix
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2025-09-26 17:11:48 +08:00
2dust
a652fd879b Added simple highlight function to the message view 2025-09-26 15:29:46 +08:00
Wydy
7816c1dcca Update pac 2025-09-21 18:17:48 +08:00
7 changed files with 291 additions and 202 deletions

View file

@ -449,6 +449,14 @@ public class Global
"none" "none"
]; ];
public static readonly Dictionary<string, string> LogLevelColors = new()
{
{ "debug", "#6C757D" },
{ "info", "#2ECC71" },
{ "warning", "#FFA500" },
{ "error", "#E74C3C" },
};
public static readonly List<string> InboundTags = public static readonly List<string> InboundTags =
[ [
"socks", "socks",

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
using Avalonia.Media;
using AvaloniaEdit;
using AvaloniaEdit.Document;
using AvaloniaEdit.Rendering;
namespace v2rayN.Desktop.Common;
public class KeywordColorizer : DocumentColorizingTransformer
{
private readonly string[] _keywords;
private readonly Dictionary<string, IBrush> _brushMap;
public KeywordColorizer(IDictionary<string, IBrush> keywordBrushMap)
{
if (keywordBrushMap == null || keywordBrushMap.Count == 0)
{
throw new ArgumentException("keywordBrushMap must not be null or empty", nameof(keywordBrushMap));
}
_brushMap = new Dictionary<string, IBrush>(StringComparer.OrdinalIgnoreCase);
foreach (var kvp in keywordBrushMap)
{
if (string.IsNullOrEmpty(kvp.Key) || kvp.Value == null)
{
continue;
}
if (!_brushMap.ContainsKey(kvp.Key))
{
_brushMap[kvp.Key] = kvp.Value;
}
}
if (_brushMap.Count == 0)
{
throw new ArgumentException("keywordBrushMap must contain at least one non-empty key with a non-null brush", nameof(keywordBrushMap));
}
_keywords = _brushMap.Keys.ToArray();
}
protected override void ColorizeLine(DocumentLine line)
{
var text = CurrentContext.Document.GetText(line);
if (string.IsNullOrEmpty(text))
{
return;
}
foreach (var kw in _keywords)
{
if (string.IsNullOrEmpty(kw))
{
continue;
}
var searchStart = 0;
while (true)
{
var idx = text.IndexOf(kw, searchStart, StringComparison.OrdinalIgnoreCase);
if (idx < 0)
{
break;
}
var kwEndIndex = idx + kw.Length;
if (IsWordCharBefore(text, idx) || IsWordCharAfter(text, kwEndIndex))
{
searchStart = idx + Math.Max(1, kw.Length);
continue;
}
var start = line.Offset + idx;
var end = start + kw.Length;
if (_brushMap.TryGetValue(kw, out var brush) && brush != null)
{
ChangeLinePart(start, end, element => element.TextRunProperties.SetForegroundBrush(brush));
}
searchStart = idx + Math.Max(1, kw.Length);
}
}
}
private static bool IsWordCharBefore(string text, int idx)
{
if (idx <= 0)
{
return false;
}
var c = text[idx - 1];
return char.IsLetterOrDigit(c) || c == '_';
}
private static bool IsWordCharAfter(string text, int idx)
{
if (idx >= text.Length)
{
return false;
}
var c = text[idx];
return char.IsLetterOrDigit(c) || c == '_';
}
}
public static class TextEditorKeywordHighlighter
{
public static void Attach(TextEditor editor, IDictionary<string, IBrush> keywordBrushMap)
{
ArgumentNullException.ThrowIfNull(editor);
if (keywordBrushMap == null || keywordBrushMap.Count == 0)
{
return;
}
if (editor.TextArea?.TextView?.LineTransformers?.OfType<KeywordColorizer>().Any() == true)
{
return;
}
var colorizer = new KeywordColorizer(keywordBrushMap);
editor.TextArea.TextView.LineTransformers.Add(colorizer);
editor.TextArea.TextView.InvalidateVisual();
}
}

View file

@ -1,5 +1,6 @@
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
@ -21,6 +22,11 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
}); });
TextEditorKeywordHighlighter.Attach(txtMsg, Global.LogLevelColors.ToDictionary(
kv => kv.Key,
kv => (IBrush)new SolidColorBrush(Color.Parse(kv.Value))
));
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
@ -40,8 +46,6 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
private void ShowMsg(object msg) private void ShowMsg(object msg)
{ {
txtMsg.BeginChange();
//var lineCount = txtMsg.LineCount; //var lineCount = txtMsg.LineCount;
//if (lineCount > ViewModel?.NumMaxMsg) //if (lineCount > ViewModel?.NumMaxMsg)
//{ //{
@ -58,13 +62,11 @@ public partial class MsgView : ReactiveUserControl<MsgViewModel>
{ {
txtMsg.ScrollToEnd(); txtMsg.ScrollToEnd();
} }
txtMsg.EndChange();
} }
public void ClearMsg() public void ClearMsg()
{ {
txtMsg.Text = string.Empty; txtMsg.Clear();
txtMsg.AppendText("----- Message cleared -----\n"); txtMsg.AppendText("----- Message cleared -----\n");
} }

View file

@ -10,7 +10,7 @@
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<sys:Double x:Key="QrcodeWidth">500</sys:Double> <sys:Double x:Key="QrcodeWidth">400</sys:Double>
</UserControl.Resources> </UserControl.Resources>
<Grid Margin="32" RowDefinitions="Auto,Auto"> <Grid Margin="32" RowDefinitions="Auto,Auto">

View file

@ -47,8 +47,6 @@ public partial class MsgView
private void ShowMsg(object msg) private void ShowMsg(object msg)
{ {
txtMsg.BeginChange();
if (txtMsg.LineCount > ViewModel?.NumMaxMsg) if (txtMsg.LineCount > ViewModel?.NumMaxMsg)
{ {
ClearMsg(); ClearMsg();
@ -59,8 +57,6 @@ public partial class MsgView
{ {
txtMsg.ScrollToEnd(); txtMsg.ScrollToEnd();
} }
txtMsg.EndChange();
} }
public void ClearMsg() public void ClearMsg()

View file

@ -12,7 +12,7 @@
Style="{StaticResource ViewGlobal}" Style="{StaticResource ViewGlobal}"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<sys:Double x:Key="QrcodeWidth">500</sys:Double> <sys:Double x:Key="QrcodeWidth">400</sys:Double>
</UserControl.Resources> </UserControl.Resources>
<Grid Margin="32"> <Grid Margin="32">