diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/AvalonEditUtility.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/AvalonEditUtility.cs new file mode 100644 index 0000000..9f461e0 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/AvalonEditUtility.cs @@ -0,0 +1,34 @@ +using ICSharpCode.AvalonEdit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + public static class AvalonEditUtility + { + public static void DeleteLine( TextEditor editor, int lineNumber) + { + var editorLine = editor.Document.GetLineByNumber(lineNumber); + // remove the line from AvalonEdit + + if( editorLine.NextLine != null && editorLine.PreviousLine == null) + { + // has no previous but has next + editor.Document.Remove(editorLine.Offset, editorLine.NextLine.Offset - editorLine.Offset); + } + else if( editorLine.PreviousLine != null ) + { + // has previous (Having a next either way doesn't matter) + editor.Document.Remove(editorLine.PreviousLine.EndOffset, editorLine.EndOffset - editorLine.PreviousLine.EndOffset); + } + else + { + // has no next or previous + editor.Document.Remove(editorLine); // this just clears contents of the line + } + } + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineInfo.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineInfo.cs new file mode 100644 index 0000000..269d185 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineInfo.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + public class LineInfo + { + public int Number { get; set; } + public double LineHeight { get; set; } + + + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml new file mode 100644 index 0000000..ebbe5a8 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml.cs new file mode 100644 index 0000000..3e4454b --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplay.xaml.cs @@ -0,0 +1,133 @@ +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.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + /// + /// Interaction logic for LineNumberDisplay.xaml + /// + public partial class LineNumberDisplay : UserControl + { + + #region Model DP + + public static readonly DependencyProperty ModelProperty = DependencyProperty.Register("Model", typeof(LineNumberDisplayModel), typeof(LineNumberDisplay), new PropertyMetadata { PropertyChangedCallback = new PropertyChangedCallback( OnModelChanged) }); + + public LineNumberDisplayModel Model + { + get { return (LineNumberDisplayModel)this.GetValue(ModelProperty); } + set { this.SetValue(ModelProperty, value); } + } + + private static void OnModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) + { + var ctrl = d as LineNumberDisplay; + ctrl.InitModel(); + } + + #endregion + + public LineNumberDisplay() + { + InitializeComponent(); + + } + + + public void InitModel() + { + // hookup events and other things + var model = this.DataContext as LineNumberDisplayModel; + + // different things can signal us to turn on command mode + model.OnSignalToTurnOnCommandMode += Model_OnSignalToTurnOnCommandMode; + } + + private void Model_OnSignalToTurnOnCommandMode(object arg1, EventArgs arg2) + { + var model = this.DataContext as LineNumberDisplayModel; + model.IsCommandEntryVisible = true; + // focus the textbox + lineNumberCommandTextBox.Focus(); + } + + private void lineNumberTextBlock_MouseUp(object sender, MouseButtonEventArgs e) + { + // clicked line number so go to command mode + var context = this.DataContext as LineNumberDisplayModel; + context.IsCommandEntryVisible = true; + lineNumberCommandTextBox.Focus(); + } + + private void lineNumberCommandTextBox_LostFocus(object sender, RoutedEventArgs e) + { + var context = this.DataContext as LineNumberDisplayModel; + // they may have entered a command that got rid of the line + if( context != null) + { + context.IsCommandEntryVisible = false; + } + + } + + private void lineNumberCommandTextBlock_MouseUp(object sender, MouseButtonEventArgs e) + { + // clicked a command area so go to command mode + var context = this.DataContext as LineNumberDisplayModel; + context.IsCommandEntryVisible = true; + lineNumberCommandTextBox.Focus(); + } + + private void lineNumberCommandTextBox_KeyDown(object sender, KeyEventArgs e) + { + var model = this.DataContext as LineNumberDisplayModel; + if( e.Key == Key.Return) + { + // signal command submitted + model.signalSubmitAllCommands(); + } + } + + private void lineNumberCommandTextBox_PreviewKeyDown(object sender, KeyEventArgs e) + { + var model = this.DataContext as LineNumberDisplayModel; + //arrow keys only available on this event. They don't show up on KeyDown + if (e.Key == Key.Right && + ( lineNumberCommandTextBox.Text.Length == 0 || + lineNumberCommandTextBox.CaretIndex == lineNumberCommandTextBox.Text.Length - 1 + ) + ) + { + // signal that we should move to avalonedit + model.IsCommandEntryVisible = false; + model.signalCommandModeArrowKeyShouldCauseCursorToBeOnAvalonEdit();// I bet we need to pass line number later + } else if( e.Key == Key.Up) + { + // signal that we should move up a line number command + model.IsCommandEntryVisible = false; + model.signalUpArrowKeyPressedInCommandTextBox(); + } else if( e.Key == Key.Down) + { + // signal that we should move down a line number command + model.IsCommandEntryVisible = false; + model.signalDownArrowKeyPressedInCommandTextBox(); + } + } + } + + + +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplayModel.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplayModel.cs new file mode 100644 index 0000000..dcf0009 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberDisplayModel.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + public class LineNumberDisplayModel : WPFHelpers.ViewModelBase + { + + public event Action SubmitAllLineNumberCommands; + + public class LineNumberEventArgs : EventArgs + { + public int LineNumber { get; set; } + } + + public event Action OnSignalToTurnOnCommandMode; + public event Action CommandModeKeyPressShouldCauseTransitionToAvalonEditLine; + + public event Action OnSignalToTurnOnCommandModeForPreviousLineNumber; + public event Action OnSignalToTurnOnCommandModeForNextLineNumber; + + + public int LineNumber + { + get { return this.GetValue(() => this.LineNumber); } + set { this.SetValue(() => this.LineNumber, value); } + } + + public string CommandText + { + get { return this.GetValue(() => this.CommandText); } + set { + this.SetValue(() => this.CommandText, value); + OnPropertyChanged(nameof(HasCommandText)); + } + } + + public bool HasCommandText + { + get + { + return !string.IsNullOrWhiteSpace(CommandText); + } + } + + // each line number is a specific height + public double ControlHeight + { + get { return this.GetValue(() => this.ControlHeight); } + set { this.SetValue(() => this.ControlHeight, value); } + } + + + public bool IsInView + { + get { return this.GetValue(() => this.IsInView); } + set { this.SetValue(() => this.IsInView, value); } + } + + // this decided wether to show textbox or label for command + public bool IsCommandEntryVisible + { + get { return this.GetValue(() => this.IsCommandEntryVisible); } + set { this.SetValue(() => this.IsCommandEntryVisible, value); } + } + + + + + + public void signalSubmitAllCommands() + { + if( this.SubmitAllLineNumberCommands != null) + { + this.SubmitAllLineNumberCommands(this, new EventArgs()); + } + } + + + + public void signalTurnOnCommandMode() + { + // user is on a line and they've used the arrow key all the way to the left which should make the cursor jump to command mode + if( this.OnSignalToTurnOnCommandMode != null) + { + this.OnSignalToTurnOnCommandMode(this, new EventArgs()); + } + } + + public void signalCommandModeArrowKeyShouldCauseCursorToBeOnAvalonEdit() + { + // user was in command mode and they'ved arrowed all the way to the right which should cause command mode to end + // - then the cursor should go to the avalonedit line + if( this.CommandModeKeyPressShouldCauseTransitionToAvalonEditLine != null) + { + this.CommandModeKeyPressShouldCauseTransitionToAvalonEditLine(this, new LineNumberEventArgs + { + LineNumber = this.LineNumber + }); + } + } + + + public void signalUpArrowKeyPressedInCommandTextBox() + { + if( this.OnSignalToTurnOnCommandModeForPreviousLineNumber != null) + { + this.OnSignalToTurnOnCommandModeForPreviousLineNumber(this, new LineNumberEventArgs + { + LineNumber = this.LineNumber + }); + } + } + + public void signalDownArrowKeyPressedInCommandTextBox() + { + if( this.OnSignalToTurnOnCommandModeForNextLineNumber != null) + { + this.OnSignalToTurnOnCommandModeForNextLineNumber(this, new LineNumberEventArgs + { + LineNumber = this.LineNumber + }); + } + } + + + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginAdorner.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginAdorner.cs new file mode 100644 index 0000000..ce6686d --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginAdorner.cs @@ -0,0 +1,219 @@ +using ICSharpCode.AvalonEdit; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + public class LineNumberMarginAdorner : Adorner + { + + private TextEditor editor; + + public LineNumberMarginAdorner(LineNumberMarginWithCommands marginElement, TextEditor _editor) + : base(marginElement) + { + this.editor = _editor; + this.listView = new LineNumbersListView(); + this.AddVisualChild(this.listView); // this has to be there for events and interaction to work + + this.listView.SizeChanged += (_sender, _args) => + { + trackListViewWidth(); + }; + + + // update the adorner layer + AdornerLayer.GetAdornerLayer(marginElement).Update(); + + // setup events that we will need to use to modify our list of line numbers + marginElement.LineNumbersChangedDelayedEvent += MarginElement_LineNumbersChangedDelayedEvent; + + // need to initially populate line numbers that are already there + populateLineNumbers(marginElement.uiLineInfoList, this.listView.LineNumbers); + + + // some command manipulation occurs because of keypresses in the editor + _editor.PreviewKeyDown += _editor_PreviewKeyDown; + } + + private void _editor_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e) + { + if( e.Key == System.Windows.Input.Key.Left) + { + // get current line then find out if we are at the first character of the line + var line = editor.Document.GetLineByOffset(editor.CaretOffset); + if( line.Offset == editor.CaretOffset) + { + // signal + var model = listView.LineNumbers.Single(m => m.LineNumber == line.LineNumber); + model.signalTurnOnCommandMode(); + } + } + } + + private void populateLineNumbers(List textLineInfoList, + ObservableCollection visualLines) + { + // determine what needs to be created and what needs hidden + var nonExistantTextLines = from t in textLineInfoList + where !visualLines.Any(v => v.LineNumber == t.Number) + select t; + + var visualsToHide = from v in visualLines + where !textLineInfoList.Any(t => t.Number == v.LineNumber) + select v; + + var visualsToShow = from v in visualLines + where textLineInfoList.Any(t => t.Number == v.LineNumber) + select v; + + // create + foreach( var t in nonExistantTextLines) + { + var entry = new LineNumberDisplayModel + { + IsInView = true, + LineNumber = t.Number, + ControlHeight = t.LineHeight + }; + + entry.SubmitAllLineNumberCommands += (_sender, _args) => + { + if(this.listView.LineNumbers.Any(l => l.HasCommandText)) + { + try + { + SEUCommands.SEUCommandHandler.ExecuteCommands(this.listView.LineNumbers, editor); + } + catch(Exception ex) + { + // command execution failed, redo all the line numbers so it just clears everything? + System.Windows.MessageBox.Show($"Hey change this to just clear out everything. Exception Occured: {ex}"); + } + } + + }; + + + entry.CommandModeKeyPressShouldCauseTransitionToAvalonEditLine += (_sender, _args) => + { + var line = editor.Document.GetLineByNumber(_args.LineNumber); + editor.Focus(); + editor.CaretOffset = line.Offset; + }; + + entry.OnSignalToTurnOnCommandModeForNextLineNumber += (_sender, _args) => + { + // next line number + var nextLineModel = listView.LineNumbers.FirstOrDefault(m => m.LineNumber == _args.LineNumber + 1); + + if( nextLineModel != null && nextLineModel.IsInView == true) + { + // signal it + nextLineModel.signalTurnOnCommandMode(); + } + }; + + entry.OnSignalToTurnOnCommandModeForPreviousLineNumber += (_sender, _args) => + { + // previous line number + var previousLineNumber = listView.LineNumbers.FirstOrDefault(m => m.LineNumber == _args.LineNumber - 1); + + if( previousLineNumber != null && previousLineNumber.IsInView == true) + { + // signal it + previousLineNumber.signalTurnOnCommandMode(); + } + }; + + visualLines.Add(entry); + } + + // hide + foreach( var v in visualsToHide) + { + v.IsInView = false; + } + + // show + foreach(var v in visualsToShow) + { + v.IsInView = true; + } + } + + private void MarginElement_LineNumbersChangedDelayedEvent(object sendor, EventArgs args) + { + var margin = sendor as LineNumberMarginWithCommands; + populateLineNumbers(margin.uiLineInfoList, this.listView.LineNumbers); + } + + + private LineNumbersListView listView; + + + + protected override int VisualChildrenCount + { + get + { + return 1; + } + } + + protected override Visual GetVisualChild(int index) + { + if (index != 0) throw new ArgumentOutOfRangeException(); + return listView; + } + + double previousListViewWidth = 0; + + public event Action LineNumberListViewWidthChanged; + + public class LineNumberMarginListViewWidthChangedEventArgs : EventArgs + { + public double Width { get; set; } + } + + + private void trackListViewWidth() + { + if (listView.DesiredSize.Width != previousListViewWidth) + { + previousListViewWidth = listView.DesiredSize.Width; + // fire off that width of listview changed + if (this.LineNumberListViewWidthChanged != null) + { + this.LineNumberListViewWidthChanged(this, new LineNumberMarginListViewWidthChangedEventArgs + { + Width = previousListViewWidth + }); + } + } + } + + protected override Size MeasureOverride(Size constraint) + { + listView.Measure(constraint); + + return listView.DesiredSize; + } + + + protected override Size ArrangeOverride(Size finalSize) + { + listView.Arrange(new Rect(new Point(0, 0), finalSize)); + return new Size(listView.ActualWidth, listView.ActualHeight); + } + + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginWithCommands.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginWithCommands.cs new file mode 100644 index 0000000..9af5040 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumberMarginWithCommands.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Editing; +using ICSharpCode.AvalonEdit.Rendering; +using System.Windows; +using System.Windows.Controls; +using System.Globalization; +using System.Windows.Threading; +using System.Windows.Documents; +using System.Windows.Shapes; +using System.Windows.Data; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + + // idea from: http://community.icsharpcode.net/forums/t/11706.aspx + public class LineNumberMarginWithCommands : LineNumberMargin + { + + + public static void Install(TextEditor _editor) + { + var me = new LineNumberMarginWithCommands(_editor); + + me.Loaded += (_sender, args) => + { + var adorner1 = new LineNumberMarginAdorner(me, _editor); + // it's got to be displayed before adorning I think + // adorn it + adorner1.LineNumberListViewWidthChanged += (_sender2, _args2) => + { + me.UpdateLineNumberListWidthFromAdorner(_args2.Width); + }; + + AdornerLayer.GetAdornerLayer(me).Add(adorner1); + }; + + _editor.ShowLineNumbers = false; // turn off the built in + + addLineNumberMarching(_editor, me); + + } + + + private static void addLineNumberMarching(TextEditor _editor, LineNumberMargin lineNumbers) + { + var leftMargins = _editor.TextArea.LeftMargins; + + Line line = (Line)DottedLineMargin.Create(); + leftMargins.Insert(0, lineNumbers); + leftMargins.Insert(1, line); + var lineNumbersForeground = new Binding("LineNumbersForeground") { Source = _editor }; + line.SetBinding(Line.StrokeProperty, lineNumbersForeground); + lineNumbers.SetBinding(Control.ForegroundProperty, lineNumbersForeground); + + } + + public LineNumberMarginWithCommands(TextEditor _editor) + { + + } + + private double lineNumberListViewWidth = 0; + public void UpdateLineNumberListWidthFromAdorner(double width) + { + if (width != lineNumberListViewWidth) + { + this.lineNumberListViewWidth = width; + this.InvalidateMeasure(); + } + } + + + + protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize) + { + return new Size(this.lineNumberListViewWidth, 0); + } + + + + + public List uiLineInfoList { get; set; } = new List(); + + + // do a delayed event when the line info list is updated + public event Action LineNumbersChangedDelayedEvent; + + private bool doWeNeedToRedoLineNumberDisplay(IReadOnlyCollection visualLines, + List linesDisplayed) + { + var firstVisual = visualLines.FirstOrDefault(); + var lastVisual = visualLines.LastOrDefault(); + + var firstLine = linesDisplayed.FirstOrDefault(); + var lastLine = linesDisplayed.LastOrDefault(); + + if(firstVisual?.FirstDocumentLine?.LineNumber == firstLine?.Number + && lastVisual?.FirstDocumentLine?.LineNumber == lastLine?.Number + ) + { + return false; + } + + return true; + } + + protected override void OnRender(DrawingContext drawingContext) + { + + TextView textView = this.TextView; + if (textView != null + && textView.VisualLinesValid + && doWeNeedToRedoLineNumberDisplay(textView.VisualLines, this.uiLineInfoList) + ) + { + + // repopulate the ui list + this.uiLineInfoList.Clear(); + foreach (VisualLine line in textView.VisualLines) + { + var info = new LineInfo(); + info.Number = line.FirstDocumentLine.LineNumber; + info.LineHeight = line.Height; + + this.uiLineInfoList.Add(info); + } + + // finished processing line numbers + + if (this.LineNumbersChangedDelayedEvent != null) + { + this.LineNumbersChangedDelayedEvent(this, new EventArgs()); + } + + + } + } + + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml new file mode 100644 index 0000000..fc7a3b1 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml.cs new file mode 100644 index 0000000..90d74bd --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/LineNumbersListView.xaml.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +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.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + /// + /// Interaction logic for LineNumbersListView.xaml + /// + public partial class LineNumbersListView : UserControl + { + + #region LineNumbers DP + + public static readonly DependencyProperty LineNumbersProperty = DependencyProperty.Register("LineNumbers", typeof(ObservableCollection), typeof(LineNumbersListView)); + + public ObservableCollection LineNumbers + { + get { return (ObservableCollection)this.GetValue(LineNumbersProperty); } + set { this.SetValue(LineNumbersProperty, value); } + } + + #endregion + + public LineNumbersListView() + { + InitializeComponent(); + this.LineNumbers = new ObservableCollection(); + } + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/MaxLineNumberLengthChangedEventArgs.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/MaxLineNumberLengthChangedEventArgs.cs new file mode 100644 index 0000000..4b9d322 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/MaxLineNumberLengthChangedEventArgs.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin +{ + public class MaxLineNumberLengthChangedEventArgs : EventArgs + { + public System.Windows.Size NewSize { get; set; } + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ICommand.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ICommand.cs new file mode 100644 index 0000000..c3fd826 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ICommand.cs @@ -0,0 +1,15 @@ +using ICSharpCode.AvalonEdit; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin.SEUCommands +{ + public interface ICommand + { + void Execute(ObservableCollection commands, TextEditor editor); + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/SEUCommandHandler.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/SEUCommandHandler.cs new file mode 100644 index 0000000..8351f42 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/SEUCommandHandler.cs @@ -0,0 +1,27 @@ +using ICSharpCode.AvalonEdit; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin.SEUCommands +{ + public static class SEUCommandHandler + { + + public static void ExecuteCommands(ObservableCollection possibleCommands, TextEditor editor) + { + var d = new dCommand(); + d.Execute(possibleCommands, editor); + var dd = new ddCommand(); + dd.Execute(possibleCommands, editor); + } + + + + + + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/dCommand.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/dCommand.cs new file mode 100644 index 0000000..f0ba5f7 --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/dCommand.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.AvalonEdit; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin.SEUCommands +{ + public class dCommand : ICommand + { + public void Execute(ObservableCollection commands, TextEditor editor) + { + var cmds = (from c in commands + where string.Equals(c.CommandText, "d", StringComparison.OrdinalIgnoreCase) + select c + ).ToList();// make a copy of it + + + + foreach( var c in cmds) + { + int commandsIndex = commands.IndexOf(c); // it's being removed from commands so grab it's index prior to that + commands.Remove(c); // remove it from the margin since it's line is about to be deleted + + AvalonEditUtility.DeleteLine(editor, c.LineNumber); + + + // we've deleted a line so we have to renumber all lines after it in the custom margin + int lineNumber = c.LineNumber; + + // things will shift down so we want to renumber starting with the old index of our removed line + for( int i = commandsIndex; i < commands.Count; ++i ) + { + var cmdToRenumber = commands[i]; + cmdToRenumber.LineNumber = lineNumber++; // assign current line number then incriment it + } + } + } + } +} diff --git a/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ddCommand.cs b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ddCommand.cs new file mode 100644 index 0000000..031deec --- /dev/null +++ b/ILEditor/Classes/AvalonEdit.LineNumberCommandMargin/SEUCommands/ddCommand.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.AvalonEdit; + +namespace ILEditor.Classes.AvalonEdit.LineNumberCommandMargin.SEUCommands +{ + public class ddCommand : ICommand + { + public void Execute(ObservableCollection commands, TextEditor editor) + { + var firstDD = commands.OrderBy(c => c.LineNumber).FirstOrDefault(c => string.Equals(c.CommandText, "dd", StringComparison.OrdinalIgnoreCase)); + var lastDD = commands.OrderBy(c => c.LineNumber).LastOrDefault(c => string.Equals(c.CommandText, "dd", StringComparison.OrdinalIgnoreCase)); + + if( firstDD != null && lastDD != null) + { + // delete the lines + int posOfFirstShiftedLineCommand = commands.IndexOf(firstDD); // this is the pos of the first shifted because a bunch are now gone + var commandsToDelete = commands.Where(c => c.LineNumber >= firstDD.LineNumber && c.LineNumber <= lastDD.LineNumber); + + // delete out the line number commands + commandsToDelete.ToList().ForEach(c => commands.Remove(c)); + // delete out the line from AvalonEdit + commandsToDelete.ToList().ForEach(c => AvalonEditUtility.DeleteLine(editor, c.LineNumber)); + + // starting from line after lastDD shift the line numbers + int lineNumber = firstDD.LineNumber; // this is the new line number to start with for everything shifted + + for( int i = posOfFirstShiftedLineCommand; i < commands.Count; ++i) + { + var commandToRenumber = commands[i]; + commandToRenumber.LineNumber = lineNumber++; // use the line number then incriment it + } + } + + } + } +} diff --git a/ILEditor/Classes/WPFHelpers/ViewModelBase.cs b/ILEditor/Classes/WPFHelpers/ViewModelBase.cs new file mode 100644 index 0000000..7cb93b3 --- /dev/null +++ b/ILEditor/Classes/WPFHelpers/ViewModelBase.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace ILEditor.Classes.WPFHelpers +{ + /** + * This was included with some other code I got: http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/ + */ + public abstract class ViewModelBase : INotifyPropertyChanged + { + + + /// + /// Internal store for the property values. + /// + private Dictionary values; + + public ViewModelBase() + { + this.values = new Dictionary(); + } + + + #region INotifyPropertyChanged Members + + /// + /// Occurs when a property value changes. + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Called when [property changed]. + /// + /// Name of the property. + protected void OnPropertyChanged(string propertyName) + { + PropertyChangedEventHandler handler = this.PropertyChanged; + if (handler != null) + { + // root event source first + PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); + handler(this, args); + } + } + + #endregion + + // Unfortunately, C# currently does not support property delegates, in other words, a reference to a property. + private PropertyInfo GetPropertyInfo(LambdaExpression lambda) + { + MemberExpression memberExpression; + if (lambda.Body is UnaryExpression) + { + var unaryExpression = lambda.Body as UnaryExpression; + memberExpression = unaryExpression.Operand as MemberExpression; + } + else + { + memberExpression = lambda.Body as MemberExpression; + } + var constantExpression = memberExpression.Expression as ConstantExpression; + var propertyInfo = memberExpression.Member as PropertyInfo; + return propertyInfo; + } + + protected void SetValue(Expression> property, T value) + { + LambdaExpression lambda = property as LambdaExpression; + + if (lambda == null) + throw new ArgumentException("Invalid view model property definition."); + + PropertyInfo propertyInfo = this.GetPropertyInfo(lambda); + + T existingValue = GetValueInternal(propertyInfo.Name); + + if (!object.Equals(existingValue, value)) + { + this.values[propertyInfo.Name] = value; + this.OnPropertyChanged(propertyInfo.Name); + } + } + + /// + /// This very will allways fire OnPropertyChanged + /// - Should not be used unless you know what your doing + /// + /// + /// + /// + protected void SetValueAllwaysNotify(Expression> property, T value) + { + LambdaExpression lambda = property as LambdaExpression; + + if (lambda == null) + throw new ArgumentException("Invalid view model property definition."); + + PropertyInfo propertyInfo = this.GetPropertyInfo(lambda); + + T existingValue = GetValueInternal(propertyInfo.Name); + + this.values[propertyInfo.Name] = value; + this.OnPropertyChanged(propertyInfo.Name); + } + + + + + protected T GetValue(Expression> property) + { + LambdaExpression lambda = property as LambdaExpression; + + if (lambda == null) + throw new ArgumentException("Invalid view model property definition."); + + PropertyInfo propertyInfo = this.GetPropertyInfo(lambda); + + T value = GetValueInternal(propertyInfo.Name); + + // auto create instance for common list types + if (value == null && !propertyInfo.CanWrite) + { + if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ObservableCollection<>)) + { + value = (T)Activator.CreateInstance(propertyInfo.PropertyType); + } + else if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) + { + value = (T)Activator.CreateInstance(propertyInfo.PropertyType); + } + else if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + { + Type observableCollectionType = typeof(ObservableCollection<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments()); + value = (T)Activator.CreateInstance(observableCollectionType); + } + else if (propertyInfo.PropertyType == typeof(System.Collections.IEnumerable)) + { + Type observableCollectionType = typeof(ObservableCollection<>).MakeGenericType(typeof(object)); + value = (T)Activator.CreateInstance(observableCollectionType); + } + + this.values[propertyInfo.Name] = value; + } + + return value; + + } + + internal T GetValueInternal(string propertyName) + { + object value; + if (values.TryGetValue(propertyName, out value)) + return (T)value; + else + return default(T); + } + + }// end of view model base class + + +} diff --git a/ILEditor/ILEditor.csproj b/ILEditor/ILEditor.csproj index 8cc9db9..70cf928 100644 --- a/ILEditor/ILEditor.csproj +++ b/ILEditor/ILEditor.csproj @@ -130,6 +130,22 @@ + + + + LineNumberDisplay.xaml + + + + + + LineNumbersListView.xaml + + + + + + @@ -142,6 +158,7 @@ + @@ -623,6 +640,14 @@ + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/ILEditor/ILEditor.csproj.orig b/ILEditor/ILEditor.csproj.orig new file mode 100644 index 0000000..8b1748c --- /dev/null +++ b/ILEditor/ILEditor.csproj.orig @@ -0,0 +1,586 @@ + + + + + Debug + AnyCPU + {9F66C8A3-C1D9-4CF0-B6F4-A7B9B8E802BB} + WinExe + ILEditor + ILEditor + v4.6.1 + 512 + true + true + + ftp://ftp.worksofbarry.com/ + true + Web + true + Foreground + 7 + Days + false + false + true + http://worksofbarry.com/ileditor/installer/ + http://worksofbarry.com/ileditor/installer/ + en-GB + ILEditor + Works Of Barry + true + index.html + 73 + 2.0.0.%2a + true + true + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + worksofbarry_mOq_icon.ico + + + DA92B763BFFCE5314360B97F39EDAACE53632514 + + + Idle.pfx + + + true + + + true + + + false + + + LocalIntranet + + + Properties\app.manifest + + + Idle.pfx + + + + ..\packages\FluentFTP.19.1.2\lib\net45\FluentFTP.dll + + + ..\packages\AvalonEdit.5.0.4\lib\Net40\ICSharpCode.AvalonEdit.dll + + + + + + + + + + + + + + + + + + + + + + + Resources\TabControlExtra.dll + + + + + + + + + + + LineNumberDisplay.xaml + + + + + + LineNumbersListView.xaml + + + + + + + + + + + + + + + + + + + +<<<<<<< HEAD + +======= + + Form + + + About.cs + +>>>>>>> master + + Form + + + CloneWindow.cs + + + Form + + + EditCommand.cs + + + Form + + + NewType.cs + + + Form + + + FirewallHelp.cs + + + Form + + + FirewallPrompt.cs + + + Form + + + LibraryList.cs + + + Form + + + Connection.cs + + + Form + + + MemberCompareDisplay.cs + + + Form + + + MemberCompareSelect.cs + + + Form + + + MemberSearch.cs + + + Form + + + NewMember.cs + + + Form + + + NewSPF.cs + + + Form + + + ObjectInformation.cs + + + Form + + + FileSelect.cs + + + Form + + + OpenMember.cs + + + Form + + + HelpWindow.cs + + + Form + + + PushWindow.cs + + + Form + + + QuickMemberSearch.cs + + + Form + + + SaveAs.cs + + + Form + + + ServiceGenerator.cs + + + Form + + + SPFSelect.cs + + + UserControl + + + BindingDirectory.cs + + + UserControl + + + CompileOptions.cs + + + UserControl + + + ErrorListing.cs + + + Form + + + Editor.cs + + + Form + + + HostSelect.cs + + + Form + + + NewSystem.cs + + + + + UserControl + + + MemberSearchListing.cs + + + UserControl + + + ObjectBrowse.cs + + + UserControl + + + SourceEditor.cs + + + UserControl + + + MemberBrowse.cs + + + UserControl + + + SpoolListing.cs + + + UserControl + + + SpoolViewer.cs + + + UserControl + + + TreeBrowse.cs + + + UserControl + + + UserToolList.cs + + + UserControl + + + Welcome.cs + + + Editor.cs + + + About.cs + + + CloneWindow.cs + + + EditCommand.cs + + + NewType.cs + + + FirewallHelp.cs + + + FirewallPrompt.cs + + + HostSelect.cs + + + LibraryList.cs + + + MemberCompareDisplay.cs + + + MemberCompareSelect.cs + + + MemberSearch.cs + + + NewMember.cs + + + NewSPF.cs + + + NewSystem.cs + + + Connection.cs + + + ObjectInformation.cs + + + FileSelect.cs + + + OpenMember.cs + + + PushWindow.cs + + + QuickMemberSearch.cs + + + SaveAs.cs + + + ServiceGenerator.cs + + + SPFSelect.cs + + + PublicResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + HelpWindow.cs + + + BindingDirectory.cs + + + CompileOptions.cs + + + ErrorListing.cs + + + MemberBrowse.cs + + + MemberSearchListing.cs + + + ObjectBrowse.cs + + + SourceEditor.cs + + + SpoolListing.cs + + + SpoolViewer.cs + + + TreeBrowse.cs + + + UserToolList.cs + + + Welcome.cs + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + + False + Microsoft .NET Framework 4.5.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + + + Designer + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + \ No newline at end of file diff --git a/ILEditor/UserTools/SourceEditor.cs b/ILEditor/UserTools/SourceEditor.cs index 3f6bca9..35c053a 100644 --- a/ILEditor/UserTools/SourceEditor.cs +++ b/ILEditor/UserTools/SourceEditor.cs @@ -113,6 +113,8 @@ public void CreateForm() else SearchReplacePanel.Install(textEditor); + Classes.AvalonEdit.LineNumberCommandMargin.LineNumberMarginWithCommands.Install(textEditor); + string lang = ""; if (Editor.DarkMode)