diff --git a/AndroidLogViewer/AndroidLogViewer.csproj b/AndroidLogViewer/AndroidLogViewer.csproj
index 8a4eb94..b311a3c 100644
--- a/AndroidLogViewer/AndroidLogViewer.csproj
+++ b/AndroidLogViewer/AndroidLogViewer.csproj
@@ -58,6 +58,7 @@
MSBuild:Compile
Designer
+
diff --git a/AndroidLogViewer/Command/BindingRedirector.cs b/AndroidLogViewer/Command/BindingRedirector.cs
new file mode 100644
index 0000000..ddb9808
--- /dev/null
+++ b/AndroidLogViewer/Command/BindingRedirector.cs
@@ -0,0 +1,36 @@
+using System.Windows;
+
+namespace AndroidLogViewer.Command
+{
+ public class BindingRedirector : DependencyObject
+ {
+ public static readonly DependencyProperty LeftProperty = DependencyProperty.Register(
+ "Left", typeof(object), typeof(BindingRedirector), new PropertyMetadata(default(object), LeftChanged));
+
+ private static void LeftChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((BindingRedirector) d).Right = e.NewValue;
+ }
+
+ public object Left
+ {
+ get { return (object) GetValue(LeftProperty); }
+ set { SetValue(LeftProperty, value); }
+ }
+
+ public static readonly DependencyProperty RightProperty = DependencyProperty.Register(
+ "Right", typeof(object), typeof(BindingRedirector), new PropertyMetadata(default(object) , RightChanged));
+
+ private static void RightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((BindingRedirector) d).Left = e.NewValue;
+ }
+
+ public object Right
+ {
+ get { return (object) GetValue(RightProperty); }
+ set { SetValue(RightProperty, value); }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/AndroidLogViewer/Dialogs/Export/ExportDialogViewModel.cs b/AndroidLogViewer/Dialogs/Export/ExportDialogViewModel.cs
index 00c0823..d0d0d25 100644
--- a/AndroidLogViewer/Dialogs/Export/ExportDialogViewModel.cs
+++ b/AndroidLogViewer/Dialogs/Export/ExportDialogViewModel.cs
@@ -97,7 +97,7 @@ private void ExecuteConfirmCommand()
}
else
{
- lines = _entries.Select(x=> $"{x.Time} {x.Process} {x.Thread} {x.Level} {x.Tag}: {x.Message}");
+ lines = _entries.Select(FormatLogEntry);
}
@@ -105,5 +105,10 @@ private void ExecuteConfirmCommand()
Done(null);
}
+
+ public static string FormatLogEntry(LogEntry x)
+ {
+ return $"{x.Time} {x.Process} {x.Thread} {x.Level} {x.Tag}: {x.Message}";
+ }
}
}
\ No newline at end of file
diff --git a/AndroidLogViewer/LogcatParser.cs b/AndroidLogViewer/LogcatParser.cs
index 70cf05d..ab271fb 100644
--- a/AndroidLogViewer/LogcatParser.cs
+++ b/AndroidLogViewer/LogcatParser.cs
@@ -14,12 +14,13 @@ public class LogcatParser
private const string TagRegularExpression = "(?[^:]+):";
private const string MessageRegularExpression = "(?.*)";
private static readonly string TrailingLineRegularExpression =$"(?\\s+?){MessageRegularExpression}";
- private static readonly string DefaultLogcatRegularExpression = $"(?{DateTimeRegularExpression}\\s+{PidRegularExpression}\\s+{TidRegularExpression}\\s+{LogLevelRegularExpression}\\s+{TagRegularExpression}\\s+?){MessageRegularExpression}";
- private static readonly string AndroidStudioRegularExpression = $"(?{DateTimeRegularExpression}\\s+{PidRegularExpression}-{TidRegularExpression}[^\\s]+\\s+{LogLevelRegularExpression}/{TagRegularExpression}\\s+?){MessageRegularExpression}";
+ private static readonly string DefaultLogcatRegularExpression = $"(?{DateTimeRegularExpression}\\s+{PidRegularExpression}\\s+{TidRegularExpression}\\s+{LogLevelRegularExpression}\\s*{TagRegularExpression}\\s+?){MessageRegularExpression}";
+ private static readonly string AndroidStudioRegularExpression = $"(?{DateTimeRegularExpression}\\s+{PidRegularExpression}-{TidRegularExpression}[^\\s]+\\s*{LogLevelRegularExpression}/{TagRegularExpression}\\s+?){MessageRegularExpression}";
+ private static readonly string StartOfLogExpression = "(?\\s*---+)(?.*)";
- private static readonly string[] RecognizedRegularExpressions = {DefaultLogcatRegularExpression, AndroidStudioRegularExpression, TrailingLineRegularExpression};
- private static readonly string Pattern = $"^{string.Join("|", RecognizedRegularExpressions.Select(x => $"({x})"))}$";
+ private static readonly string[] RecognizedRegularExpressions = {DefaultLogcatRegularExpression, AndroidStudioRegularExpression, TrailingLineRegularExpression, StartOfLogExpression};
+ private static readonly string Pattern = $"{string.Join("|", RecognizedRegularExpressions.Select(x => $"^({x})$"))}";
private static readonly Regex RegularExpression = new Regex(Pattern, RegexOptions.Compiled);
static LogcatParser()
@@ -41,6 +42,7 @@ public static ObservableCollection ReadLogEntries(TextReader reader)
if (match.Success)
{
LogEntry newEntry = null;
+
if (match.Groups["datetime"].Success)
{
newEntry = new LogEntry
@@ -56,6 +58,13 @@ public static ObservableCollection ReadLogEntries(TextReader reader)
pivotEntry = newEntry;
}
+ else if (match.Groups["startoflog"].Success)
+ {
+ newEntry = new LogEntry
+ {
+ Message = $"--- {match.Groups["message"].Value.Trim()}"
+ };
+ }
else if (match.Groups["trailingline"].Success && pivotEntry != null)
{
var trimmedMessage = match.Groups["message"].Value.Trim();
@@ -72,6 +81,7 @@ public static ObservableCollection ReadLogEntries(TextReader reader)
Time = pivotEntry.Time,
};
}
+
if (newEntry != null) result.Add(newEntry);
}
diff --git a/AndroidLogViewer/MainWindow.xaml b/AndroidLogViewer/MainWindow.xaml
index fed21e8..20732a1 100644
--- a/AndroidLogViewer/MainWindow.xaml
+++ b/AndroidLogViewer/MainWindow.xaml
@@ -212,6 +212,9 @@
Style="{StaticResource MonospaceFont}"
SelectedIndex="{Binding SelectedLogEntryIndex}"
SelectedItem="{Binding Path=SelectedLogEntry, Mode=OneWayToSource}">
+
+
+
+
+
diff --git a/AndroidLogViewer/MainWindow.xaml.cs b/AndroidLogViewer/MainWindow.xaml.cs
index aa8cc3f..8954dcb 100644
--- a/AndroidLogViewer/MainWindow.xaml.cs
+++ b/AndroidLogViewer/MainWindow.xaml.cs
@@ -1,17 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
+using System.Windows;
using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
namespace AndroidLogViewer
{
@@ -31,5 +19,10 @@ private void CloseWindow(object sender, RoutedEventArgs e)
{
Close();
}
+
+ private void ExecuteCopyLogItems(object sender, ExecutedRoutedEventArgs e)
+ {
+ (DataContext as MainWindowViewModel)?.CopySelectionCommand?.Execute(LogItems.SelectedItems);
+ }
}
}
diff --git a/AndroidLogViewer/MainWindowViewModel.cs b/AndroidLogViewer/MainWindowViewModel.cs
index d6e9f73..6ea03d2 100644
--- a/AndroidLogViewer/MainWindowViewModel.cs
+++ b/AndroidLogViewer/MainWindowViewModel.cs
@@ -49,6 +49,8 @@ public MainWindowViewModel()
ExportCommand = new DelegateCommand(
() => ShowDialog(new ExportDialogViewModel(_defaultView.OfType().ToArray())).FireAndForget(),
() => !string.IsNullOrEmpty(FileName)).ObservesProperty(() => FileName);
+ ExportSelectionCommand = new DelegateCommand>(x => ShowDialog(new ExportDialogViewModel(x.OfType().ToArray())).FireAndForget());
+ CopySelectionCommand = new DelegateCommand>(items => Clipboard.SetText(string.Join("\n", items.OfType().Select(ExportDialogViewModel.FormatLogEntry))));
OpenFileCommand = new DelegateCommand(OpenFile);
OpenUrlCommand = new DelegateCommand(OpenUrl);
@@ -149,6 +151,10 @@ private bool FilterLogEntries(object x)
public ICommand ExportCommand { get; }
+ public ICommand ExportSelectionCommand { get; }
+
+ public ICommand CopySelectionCommand { get; }
+
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;