142 lines
5.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|