Files
BeWoAdmin/DBToolControls/HighlightingRichTextBox.cs
2016-06-27 02:24:18 +02:00

142 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Text.RegularExpressions;
[assembly: CLSCompliant(true)]
namespace DBToolControls {
public class HighlightingRichTextBox : RichTextBox {
private bool textHandlingInProgress;
private bool pasting;
private string lineStartOffset;
private SyntaxProvider syntaxProvider = new SyntaxProvider();
public SyntaxProvider SyntaxProvider {
get { return syntaxProvider; }
}
public string Text {
set {
Document.Blocks.Clear();
if (value.Length > 2) {
Document.Blocks.Add(new Paragraph(new Run(value.Substring(0, value.Length - 2))));
RebuildContent();
SelectAll();
}
}
get { return new TextRange(Document.ContentStart, Document.ContentEnd).Text; }
}
public HighlightingRichTextBox() {
Document.LineHeight = 1;
DataObject.AddPastingHandler(this, (sender, e) => pasting = true);
}
// keep indentation in new lines
protected override void OnPreviewKeyDown(KeyEventArgs e) {
if (e.Key == Key.Tab) {
CaretPosition.InsertTextInRun("\t");
if(CaretPosition.GetOffsetToPosition(Document.ContentEnd) != 0)
CaretPosition = CaretPosition.GetPositionAtOffset(1);
e.Handled = true;
} else if (e.Key == Key.Enter) {
TextRange range = new TextRange(CaretPosition.GetLineStartPosition(0), CaretPosition);
string s = range.Text;
lineStartOffset = s.Substring(0, s.Length - s.TrimStart().Length);
if (new List<string> { ")", ");", "}", "};" }.Contains(s.Trim())) { // unindent
if (lineStartOffset.EndsWith("\t")) {
lineStartOffset = lineStartOffset.Remove(lineStartOffset.Length - 1);
} else if (lineStartOffset.EndsWith(" ")) {
lineStartOffset = lineStartOffset.Remove(lineStartOffset.Length - 2);
}
range.Text = lineStartOffset + range.Text.Trim();
CaretPosition = range.End;
} else if (CaretPosition.GetPositionAtOffset(-1) != null) { // indent if line ends with ( or {
s = new TextRange(CaretPosition.GetPositionAtOffset(-1), CaretPosition).Text;
if (s.Length > 0 && new List<char> { '(', '{' }.Contains(s[0]))
lineStartOffset += " ";
}
}
base.OnPreviewKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e) {
if (e.Key == Key.Enter)
CaretPosition.InsertTextInRun(lineStartOffset);
base.OnKeyUp(e);
}
// Syntax Highlighting
protected override void OnTextChanged(TextChangedEventArgs e) {
if (pasting) {
pasting = false;
RebuildContent();
} else if (!textHandlingInProgress) {
FormatTextAt(CaretPosition);
}
base.OnTextChanged(e);
}
private void FormatTextAt(TextPointer pointer) {
textHandlingInProgress = true;
TextRange range = WordBreaker.GetWordRange(pointer);
TextPointer temp = range.End.GetNextInsertionPosition(LogicalDirection.Backward);
if (temp != null) {
TextRange lastInput = new TextRange(range.End, temp);
if (SyntaxProvider.Delimiters.Contains(lastInput.Text[0]))
lastInput.ClearAllProperties();
}
ApplyFormatting(range);
temp = CaretPosition.GetPositionAtOffset(-3);
if (temp != null && !range.Contains(temp)) ApplyFormatting(WordBreaker.GetWordRange(temp));
textHandlingInProgress = false;
}
private void RebuildContent() {
textHandlingInProgress = true;
string s = new TextRange(Document.ContentStart, Document.ContentEnd).Text;
Paragraph p = new Paragraph();
string[] words = Regex.Split(s, SyntaxProvider.DelimitersAsRegExPattern);
if (words.Length < 2) return;
foreach (string word in words.Take(words.Length - 2).Where(w => w.Length > 0))
p.Inlines.Add(word.Trim().Length > 0 ? ApplyFormatting(new Run(word)) : new Run(word));
Document.Blocks.Clear();
Document.Blocks.Add(p);
CaretPosition = Document.ContentEnd;
textHandlingInProgress = false;
}
private void ApplyFormatting(TextRange range) {
Dictionary<DependencyProperty, object> formatting = SyntaxProvider.GetFormattingFor(range.Text);
if (formatting != null)
foreach (KeyValuePair<DependencyProperty, object> pv in formatting)
range.ApplyPropertyValue(pv.Key, pv.Value);
else
range.ClearAllProperties();
}
private Run ApplyFormatting(Run r) {
Dictionary<DependencyProperty, object> formatting = SyntaxProvider.GetFormattingFor(r.Text);
if (formatting != null)
foreach (KeyValuePair<DependencyProperty, object> pv in formatting)
r.SetValue(pv.Key, pv.Value);
return r;
}
}
}