first commit

This commit is contained in:
2026-01-07 11:33:05 +08:00
commit fc54ffd43b
215 changed files with 31856 additions and 0 deletions

View File

@@ -0,0 +1,917 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace ICSharpCode.TextEditor.Document
{
public class DefaultHighlightingStrategy : IHighlightingStrategyUsingRuleSets
{
string name;
List<HighlightRuleSet> rules = new List<HighlightRuleSet>();
Dictionary<string, HighlightColor> environmentColors = new Dictionary<string, HighlightColor>();
Dictionary<string, string> properties = new Dictionary<string, string>();
string[] extensions;
HighlightColor digitColor;
HighlightRuleSet defaultRuleSet = null;
public HighlightColor DigitColor {
get {
return digitColor;
}
set {
digitColor = value;
}
}
public IEnumerable<KeyValuePair<string, HighlightColor>> EnvironmentColors {
get {
return environmentColors;
}
}
protected void ImportSettingsFrom(DefaultHighlightingStrategy source)
{
if (source == null)
throw new ArgumentNullException("source");
properties = source.properties;
extensions = source.extensions;
digitColor = source.digitColor;
defaultRuleSet = source.defaultRuleSet;
name = source.name;
rules = source.rules;
environmentColors = source.environmentColors;
defaultTextColor = source.defaultTextColor;
}
public DefaultHighlightingStrategy() : this("Default")
{
}
public DefaultHighlightingStrategy(string name)
{
this.name = name;
digitColor = new HighlightColor(SystemColors.WindowText, false, false);
defaultTextColor = new HighlightColor(SystemColors.WindowText, false, false);
// set small 'default color environment'
environmentColors["Default"] = new HighlightBackground("WindowText", "Window", false, false);
environmentColors["Selection"] = new HighlightColor("HighlightText", "Highlight", false, false);
environmentColors["VRuler"] = new HighlightColor("ControlLight", "Window", false, false);
environmentColors["InvalidLines"] = new HighlightColor(Color.Red, false, false);
environmentColors["CaretMarker"] = new HighlightColor(Color.Yellow, false, false);
environmentColors["CaretLine"] = new HighlightBackground("ControlLight", "Window", false, false);
environmentColors["LineNumbers"] = new HighlightBackground("ControlDark", "Window", false, false);
environmentColors["FoldLine"] = new HighlightColor("ControlDark", false, false);
environmentColors["FoldMarker"] = new HighlightColor("WindowText", "Window", false, false);
environmentColors["SelectedFoldLine"] = new HighlightColor("WindowText", false, false);
environmentColors["EOLMarkers"] = new HighlightColor("ControlLight", "Window", false, false);
environmentColors["SpaceMarkers"] = new HighlightColor("ControlLight", "Window", false, false);
environmentColors["TabMarkers"] = new HighlightColor("ControlLight", "Window", false, false);
}
public Dictionary<string, string> Properties {
get {
return properties;
}
}
public string Name
{
get {
return name;
}
}
public string[] Extensions
{
set {
extensions = value;
}
get {
return extensions;
}
}
public List<HighlightRuleSet> Rules {
get {
return rules;
}
}
public HighlightRuleSet FindHighlightRuleSet(string name)
{
foreach(HighlightRuleSet ruleSet in rules) {
if (ruleSet.Name == name) {
return ruleSet;
}
}
return null;
}
public void AddRuleSet(HighlightRuleSet aRuleSet)
{
HighlightRuleSet existing = FindHighlightRuleSet(aRuleSet.Name);
if (existing != null) {
existing.MergeFrom(aRuleSet);
} else {
rules.Add(aRuleSet);
}
}
public void ResolveReferences()
{
// Resolve references from Span definitions to RuleSets
ResolveRuleSetReferences();
// Resolve references from RuleSet defintitions to Highlighters defined in an external mode file
ResolveExternalReferences();
}
void ResolveRuleSetReferences()
{
foreach (HighlightRuleSet ruleSet in Rules) {
if (ruleSet.Name == null) {
defaultRuleSet = ruleSet;
}
foreach (Span aSpan in ruleSet.Spans) {
if (aSpan.Rule != null) {
bool found = false;
foreach (HighlightRuleSet refSet in Rules) {
if (refSet.Name == aSpan.Rule) {
found = true;
aSpan.RuleSet = refSet;
break;
}
}
if (!found) {
aSpan.RuleSet = null;
throw new HighlightingDefinitionInvalidException("The RuleSet " + aSpan.Rule + " could not be found in mode definition " + this.Name);
}
} else {
aSpan.RuleSet = null;
}
}
}
if (defaultRuleSet == null) {
throw new HighlightingDefinitionInvalidException("No default RuleSet is defined for mode definition " + this.Name);
}
}
void ResolveExternalReferences()
{
foreach (HighlightRuleSet ruleSet in Rules) {
ruleSet.Highlighter = this;
if (ruleSet.Reference != null) {
IHighlightingStrategy highlighter = HighlightingManager.Manager.FindHighlighter (ruleSet.Reference);
if (highlighter == null)
throw new HighlightingDefinitionInvalidException("The mode defintion " + ruleSet.Reference + " which is refered from the " + this.Name + " mode definition could not be found");
if (highlighter is IHighlightingStrategyUsingRuleSets)
ruleSet.Highlighter = (IHighlightingStrategyUsingRuleSets)highlighter;
else
throw new HighlightingDefinitionInvalidException("The mode defintion " + ruleSet.Reference + " which is refered from the " + this.Name + " mode definition does not implement IHighlightingStrategyUsingRuleSets");
}
}
}
// internal void SetDefaultColor(HighlightBackground color)
// {
// return (HighlightColor)environmentColors[name];
// defaultColor = color;
// }
HighlightColor defaultTextColor;
public HighlightColor DefaultTextColor {
get {
return defaultTextColor;
}
}
public void SetColorFor(string name, HighlightColor color)
{
if (name == "Default")
defaultTextColor = new HighlightColor(color.Color, color.Bold, color.Italic);
environmentColors[name] = color;
}
public HighlightColor GetColorFor(string name)
{
HighlightColor color;
if (environmentColors.TryGetValue(name, out color))
return color;
else
return defaultTextColor;
}
public HighlightColor GetColor(IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)
{
return GetColor(defaultRuleSet, document, currentSegment, currentOffset, currentLength);
}
protected virtual HighlightColor GetColor(HighlightRuleSet ruleSet, IDocument document, LineSegment currentSegment, int currentOffset, int currentLength)
{
if (ruleSet != null) {
if (ruleSet.Reference != null) {
return ruleSet.Highlighter.GetColor(document, currentSegment, currentOffset, currentLength);
} else {
return (HighlightColor)ruleSet.KeyWords[document, currentSegment, currentOffset, currentLength];
}
}
return null;
}
public HighlightRuleSet GetRuleSet(Span aSpan)
{
if (aSpan == null) {
return this.defaultRuleSet;
} else {
if (aSpan.RuleSet != null)
{
if (aSpan.RuleSet.Reference != null) {
return aSpan.RuleSet.Highlighter.GetRuleSet(null);
} else {
return aSpan.RuleSet;
}
} else {
return null;
}
}
}
// Line state variable
protected LineSegment currentLine;
protected int currentLineNumber;
// Span stack state variable
protected SpanStack currentSpanStack;
public virtual void MarkTokens(IDocument document)
{
if (Rules.Count == 0) {
return;
}
int lineNumber = 0;
while (lineNumber < document.TotalNumberOfLines) {
LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null);
if (lineNumber >= document.LineSegmentCollection.Count) { // may be, if the last line ends with a delimiter
break; // then the last line is not in the collection :)
}
currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? previousLine.HighlightSpanStack.Clone() : null);
if (currentSpanStack != null) {
while (!currentSpanStack.IsEmpty && currentSpanStack.Peek().StopEOL)
{
currentSpanStack.Pop();
}
if (currentSpanStack.IsEmpty) currentSpanStack = null;
}
currentLine = (LineSegment)document.LineSegmentCollection[lineNumber];
if (currentLine.Length == -1) { // happens when buffer is empty !
return;
}
currentLineNumber = lineNumber;
List<TextWord> words = ParseLine(document);
// Alex: clear old words
if (currentLine.Words != null) {
currentLine.Words.Clear();
}
currentLine.Words = words;
currentLine.HighlightSpanStack = (currentSpanStack==null || currentSpanStack.IsEmpty) ? null : currentSpanStack;
++lineNumber;
}
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
document.CommitUpdate();
currentLine = null;
}
bool MarkTokensInLine(IDocument document, int lineNumber, ref bool spanChanged)
{
currentLineNumber = lineNumber;
bool processNextLine = false;
LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null);
currentSpanStack = ((previousLine != null && previousLine.HighlightSpanStack != null) ? previousLine.HighlightSpanStack.Clone() : null);
if (currentSpanStack != null) {
while (!currentSpanStack.IsEmpty && currentSpanStack.Peek().StopEOL) {
currentSpanStack.Pop();
}
if (currentSpanStack.IsEmpty) {
currentSpanStack = null;
}
}
currentLine = (LineSegment)document.LineSegmentCollection[lineNumber];
if (currentLine.Length == -1) { // happens when buffer is empty !
return false;
}
List<TextWord> words = ParseLine(document);
if (currentSpanStack != null && currentSpanStack.IsEmpty) {
currentSpanStack = null;
}
// Check if the span state has changed, if so we must re-render the next line
// This check may seem utterly complicated but I didn't want to introduce any function calls
// or allocations here for perf reasons.
if(currentLine.HighlightSpanStack != currentSpanStack) {
if (currentLine.HighlightSpanStack == null) {
processNextLine = false;
foreach (Span sp in currentSpanStack) {
if (!sp.StopEOL) {
spanChanged = true;
processNextLine = true;
break;
}
}
} else if (currentSpanStack == null) {
processNextLine = false;
foreach (Span sp in currentLine.HighlightSpanStack) {
if (!sp.StopEOL) {
spanChanged = true;
processNextLine = true;
break;
}
}
} else {
SpanStack.Enumerator e1 = currentSpanStack.GetEnumerator();
SpanStack.Enumerator e2 = currentLine.HighlightSpanStack.GetEnumerator();
bool done = false;
while (!done) {
bool blockSpanIn1 = false;
while (e1.MoveNext()) {
if (!((Span)e1.Current).StopEOL) {
blockSpanIn1 = true;
break;
}
}
bool blockSpanIn2 = false;
while (e2.MoveNext()) {
if (!((Span)e2.Current).StopEOL) {
blockSpanIn2 = true;
break;
}
}
if (blockSpanIn1 || blockSpanIn2) {
if (blockSpanIn1 && blockSpanIn2) {
if (e1.Current != e2.Current) {
done = true;
processNextLine = true;
spanChanged = true;
}
} else {
spanChanged = true;
done = true;
processNextLine = true;
}
} else {
done = true;
processNextLine = false;
}
}
}
} else {
processNextLine = false;
}
//// Alex: remove old words
if (currentLine.Words!=null) currentLine.Words.Clear();
currentLine.Words = words;
currentLine.HighlightSpanStack = (currentSpanStack != null && !currentSpanStack.IsEmpty) ? currentSpanStack : null;
return processNextLine;
}
public virtual void MarkTokens(IDocument document, List<LineSegment> inputLines)
{
if (Rules.Count == 0) {
return;
}
Dictionary<LineSegment, bool> processedLines = new Dictionary<LineSegment, bool>();
bool spanChanged = false;
int documentLineSegmentCount = document.LineSegmentCollection.Count;
foreach (LineSegment lineToProcess in inputLines) {
if (!processedLines.ContainsKey(lineToProcess)) {
int lineNumber = lineToProcess.LineNumber;
bool processNextLine = true;
if (lineNumber != -1) {
while (processNextLine && lineNumber < documentLineSegmentCount) {
processNextLine = MarkTokensInLine(document, lineNumber, ref spanChanged);
processedLines[currentLine] = true;
++lineNumber;
}
}
}
}
if (spanChanged || inputLines.Count > 20) {
// if the span was changed (more than inputLines lines had to be reevaluated)
// or if there are many lines in inputLines, it's faster to update the whole
// text area instead of many small segments
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.WholeTextArea));
} else {
// document.Caret.ValidateCaretPos();
// document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, document.GetLineNumberForOffset(document.Caret.Offset)));
//
foreach (LineSegment lineToProcess in inputLines) {
document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineToProcess.LineNumber));
}
}
document.CommitUpdate();
currentLine = null;
}
// Span state variables
protected bool inSpan;
protected Span activeSpan;
protected HighlightRuleSet activeRuleSet;
// Line scanning state variables
protected int currentOffset;
protected int currentLength;
protected bool isDelimiter = false;
void UpdateSpanStateVariables()
{
inSpan = (currentSpanStack != null && !currentSpanStack.IsEmpty);
activeSpan = inSpan ? currentSpanStack.Peek() : null;
activeRuleSet = GetRuleSet(activeSpan);
}
List<TextWord> ParseLine(IDocument document)
{
List<TextWord> words = new List<TextWord>();
HighlightColor markNext = null;
currentOffset = 0;
currentLength = 0;
UpdateSpanStateVariables();
int currentLineLength = currentLine.Length;
int currentLineOffset = currentLine.Offset;
for (int i = 0; i < currentLineLength; ++i) {
char ch = document.GetCharAt(currentLineOffset + i);
switch (ch) {
case '\n':
case '\r':
PushCurWord(document, ref markNext, words);
++currentOffset;
break;
case ' ':
PushCurWord(document, ref markNext, words);
if (activeSpan != null && activeSpan.Color.HasBackground) {
words.Add(new TextWord.SpaceTextWord(activeSpan.Color));
} else {
words.Add(TextWord.Space);
}
++currentOffset;
break;
case '\t':
PushCurWord(document, ref markNext, words);
if (activeSpan != null && activeSpan.Color.HasBackground) {
words.Add(new TextWord.TabTextWord(activeSpan.Color));
} else {
words.Add(TextWord.Tab);
}
++currentOffset;
break;
default:
{
// handle escape characters
char escapeCharacter = '\0';
if (activeSpan != null && activeSpan.EscapeCharacter != '\0') {
escapeCharacter = activeSpan.EscapeCharacter;
} else if (activeRuleSet != null) {
escapeCharacter = activeRuleSet.EscapeCharacter;
}
if (escapeCharacter != '\0' && escapeCharacter == ch) {
// we found the escape character
if (activeSpan != null && activeSpan.End != null && activeSpan.End.Length == 1
&& escapeCharacter == activeSpan.End[0])
{
// the escape character is a end-doubling escape character
// it may count as escape only when the next character is the escape, too
if (i + 1 < currentLineLength) {
if (document.GetCharAt(currentLineOffset + i + 1) == escapeCharacter) {
currentLength += 2;
PushCurWord(document, ref markNext, words);
++i;
continue;
}
}
} else {
// this is a normal \-style escape
++currentLength;
if (i + 1 < currentLineLength) {
++currentLength;
}
PushCurWord(document, ref markNext, words);
++i;
continue;
}
}
// highlight digits
if (!inSpan && (char.IsDigit(ch) || (ch == '.' && i + 1 < currentLineLength && char.IsDigit(document.GetCharAt(currentLineOffset + i + 1)))) && currentLength == 0) {
bool ishex = false;
bool isfloatingpoint = false;
if (ch == '0' && i + 1 < currentLineLength && char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'X') { // hex digits
const string hex = "0123456789ABCDEF";
++currentLength;
++i; // skip 'x'
++currentLength;
ishex = true;
while (i + 1 < currentLineLength && hex.IndexOf(char.ToUpper(document.GetCharAt(currentLineOffset + i + 1))) != -1) {
++i;
++currentLength;
}
} else {
++currentLength;
while (i + 1 < currentLineLength && char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) {
++i;
++currentLength;
}
}
if (!ishex && i + 1 < currentLineLength && document.GetCharAt(currentLineOffset + i + 1) == '.') {
isfloatingpoint = true;
++i;
++currentLength;
while (i + 1 < currentLineLength && char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) {
++i;
++currentLength;
}
}
if (i + 1 < currentLineLength && char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'E') {
isfloatingpoint = true;
++i;
++currentLength;
if (i + 1 < currentLineLength && (document.GetCharAt(currentLineOffset + i + 1) == '+' || document.GetCharAt(currentLine.Offset + i + 1) == '-')) {
++i;
++currentLength;
}
while (i + 1 < currentLine.Length && char.IsDigit(document.GetCharAt(currentLineOffset + i + 1))) {
++i;
++currentLength;
}
}
if (i + 1 < currentLine.Length) {
char nextch = char.ToUpper(document.GetCharAt(currentLineOffset + i + 1));
if (nextch == 'F' || nextch == 'M' || nextch == 'D') {
isfloatingpoint = true;
++i;
++currentLength;
}
}
if (!isfloatingpoint) {
bool isunsigned = false;
if (i + 1 < currentLineLength && char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'U') {
++i;
++currentLength;
isunsigned = true;
}
if (i + 1 < currentLineLength && char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'L') {
++i;
++currentLength;
if (!isunsigned && i + 1 < currentLineLength && char.ToUpper(document.GetCharAt(currentLineOffset + i + 1)) == 'U') {
++i;
++currentLength;
}
}
}
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, DigitColor, false));
currentOffset += currentLength;
currentLength = 0;
continue;
}
// Check for SPAN ENDs
if (inSpan) {
if (activeSpan.End != null && activeSpan.End.Length > 0) {
if (MatchExpr(currentLine, activeSpan.End, i, document, activeSpan.IgnoreCase)) {
PushCurWord(document, ref markNext, words);
string regex = GetRegString(currentLine, activeSpan.End, i, document);
currentLength += regex.Length;
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, activeSpan.EndColor, false));
currentOffset += currentLength;
currentLength = 0;
i += regex.Length - 1;
currentSpanStack.Pop();
UpdateSpanStateVariables();
continue;
}
}
}
// check for SPAN BEGIN
if (activeRuleSet != null) {
foreach (Span span in activeRuleSet.Spans) {
if ((!span.IsBeginSingleWord || currentLength == 0)
&& (!span.IsBeginStartOfLine.HasValue || span.IsBeginStartOfLine.Value == (currentLength == 0 && words.TrueForAll(delegate(TextWord textWord) { return textWord.Type != TextWordType.Word; })))
&& MatchExpr(currentLine, span.Begin, i, document, activeRuleSet.IgnoreCase)) {
PushCurWord(document, ref markNext, words);
string regex = GetRegString(currentLine, span.Begin, i, document);
if (!OverrideSpan(regex, document, words, span, ref i)) {
currentLength += regex.Length;
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, span.BeginColor, false));
currentOffset += currentLength;
currentLength = 0;
i += regex.Length - 1;
if (currentSpanStack == null) {
currentSpanStack = new SpanStack();
}
currentSpanStack.Push(span);
span.IgnoreCase = activeRuleSet.IgnoreCase;
UpdateSpanStateVariables();
}
goto skip;
}
}
}
// check if the char is a delimiter
if (activeRuleSet != null && (int)ch < 256 && activeRuleSet.Delimiters[(int)ch]) {
PushCurWord(document, ref markNext, words);
isDelimiter = true;
if (currentOffset + currentLength +1 < currentLine.Length) {
++currentLength;
PushCurWord(document, ref markNext, words);
goto skip;
}
}
++currentLength;
skip: continue;
}
}
}
PushCurWord(document, ref markNext, words);
OnParsedLine(document, currentLine, words);
return words;
}
protected virtual void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
}
protected virtual bool OverrideSpan(string spanBegin, IDocument document, List<TextWord> words, Span span, ref int lineOffset)
{
return false;
}
/// <summary>
/// pushes the curWord string on the word list, with the
/// correct color.
/// </summary>
void PushCurWord(IDocument document, ref HighlightColor markNext, List<TextWord> words)
{
// Svante Lidman : Need to look through the next prev logic.
if (currentLength > 0) {
if (words.Count > 0 && activeRuleSet != null) {
TextWord prevWord = null;
int pInd = words.Count - 1;
while (pInd >= 0) {
if (!((TextWord)words[pInd]).IsWhiteSpace) {
prevWord = (TextWord)words[pInd];
if (prevWord.HasDefaultColor) {
PrevMarker marker = (PrevMarker)activeRuleSet.PrevMarkers[document, currentLine, currentOffset, currentLength];
if (marker != null) {
prevWord.SyntaxColor = marker.Color;
// document.Caret.ValidateCaretPos();
// document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, document.GetLineNumberForOffset(document.Caret.Offset)));
}
}
break;
}
pInd--;
}
}
if (inSpan) {
HighlightColor c = null;
bool hasDefaultColor = true;
if (activeSpan.Rule == null) {
c = activeSpan.Color;
} else {
c = GetColor(activeRuleSet, document, currentLine, currentOffset, currentLength);
hasDefaultColor = false;
}
if (c == null) {
c = activeSpan.Color;
if (c.Color == Color.Transparent) {
c = this.DefaultTextColor;
}
hasDefaultColor = true;
}
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, markNext != null ? markNext : c, hasDefaultColor));
} else {
HighlightColor c = markNext != null ? markNext : GetColor(activeRuleSet, document, currentLine, currentOffset, currentLength);
if (c == null) {
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, this.DefaultTextColor, true) {
IsDelimiter = isDelimiter
});
} else {
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, c, false)
{
IsDelimiter = isDelimiter
});
}
isDelimiter = false;
}
if (activeRuleSet != null) {
NextMarker nextMarker = (NextMarker)activeRuleSet.NextMarkers[document, currentLine, currentOffset, currentLength];
if (nextMarker != null) {
if (nextMarker.MarkMarker && words.Count > 0) {
TextWord prevword = ((TextWord)words[words.Count - 1]);
prevword.SyntaxColor = nextMarker.Color;
}
markNext = nextMarker.Color;
} else {
markNext = null;
}
}
currentOffset += currentLength;
currentLength = 0;
}
}
#region Matching
/// <summary>
/// get the string, which matches the regular expression expr,
/// in string s2 at index
/// </summary>
static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document)
{
int j = 0;
StringBuilder regexpr = new StringBuilder();
for (int i = 0; i < expr.Length; ++i, ++j) {
if (index + j >= lineSegment.Length)
break;
switch (expr[i]) {
case '@': // "special" meaning
++i;
if (i == expr.Length)
throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");
switch (expr[i]) {
case '!': // don't match the following expression
StringBuilder whatmatch = new StringBuilder();
++i;
while (i < expr.Length && expr[i] != '@') {
whatmatch.Append(expr[i++]);
}
break;
case '@': // matches @
regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
break;
}
break;
default:
if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j)) {
return regexpr.ToString();
}
regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
break;
}
}
return regexpr.ToString();
}
/// <summary>
/// returns true, if the get the string s2 at index matches the expression expr
/// </summary>
static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase)
{
for (int i = 0, j = 0; i < expr.Length; ++i, ++j) {
switch (expr[i]) {
case '@': // "special" meaning
++i;
if (i == expr.Length)
throw new HighlightingDefinitionInvalidException("Unexpected end of @ sequence, use @@ to look for a single @.");
switch (expr[i]) {
case 'C': // match whitespace or punctuation
if (index + j == lineSegment.Offset || index + j >= lineSegment.Offset + lineSegment.Length) {
// nothing (EOL or SOL)
} else {
char ch = document.GetCharAt(lineSegment.Offset + index + j);
if (!char.IsWhiteSpace(ch) && !char.IsPunctuation(ch)) {
return false;
}
}
break;
case '!': // don't match the following expression
{
StringBuilder whatmatch = new StringBuilder();
++i;
while (i < expr.Length && expr[i] != '@') {
whatmatch.Append(expr[i++]);
}
if (lineSegment.Offset + index + j + whatmatch.Length < document.TextLength) {
int k = 0;
for (; k < whatmatch.Length; ++k) {
char docChar = ignoreCase ? char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j + k)) : document.GetCharAt(lineSegment.Offset + index + j + k);
char spanChar = ignoreCase ? char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
if (docChar != spanChar) {
break;
}
}
if (k >= whatmatch.Length) {
return false;
}
}
// --j;
break;
}
case '-': // don't match the expression before
{
StringBuilder whatmatch = new StringBuilder();
++i;
while (i < expr.Length && expr[i] != '@') {
whatmatch.Append(expr[i++]);
}
if (index - whatmatch.Length >= 0) {
int k = 0;
for (; k < whatmatch.Length; ++k) {
char docChar = ignoreCase ? char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k)) : document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k);
char spanChar = ignoreCase ? char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
if (docChar != spanChar)
break;
}
if (k >= whatmatch.Length) {
return false;
}
}
// --j;
break;
}
case '@': // matches @
if (index + j >= lineSegment.Length || '@' != document.GetCharAt(lineSegment.Offset + index + j)) {
return false;
}
break;
}
break;
default:
{
if (index + j >= lineSegment.Length) {
return false;
}
char docChar = ignoreCase ? char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j)) : document.GetCharAt(lineSegment.Offset + index + j);
char spanChar = ignoreCase ? char.ToUpperInvariant(expr[i]) : expr[i];
if (docChar != spanChar) {
return false;
}
break;
}
}
}
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,103 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Drawing;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// This class is used to generate bold, italic and bold/italic fonts out
/// of a base font.
/// </summary>
public class FontContainer
{
Font defaultFont;
Font regularfont, boldfont, italicfont, bolditalicfont;
/// <value>
/// The scaled, regular version of the base font
/// </value>
public Font RegularFont {
get {
return regularfont;
}
}
/// <value>
/// The scaled, bold version of the base font
/// </value>
public Font BoldFont {
get {
return boldfont;
}
}
/// <value>
/// The scaled, italic version of the base font
/// </value>
public Font ItalicFont {
get {
return italicfont;
}
}
/// <value>
/// The scaled, bold/italic version of the base font
/// </value>
public Font BoldItalicFont {
get {
return bolditalicfont;
}
}
static float twipsPerPixelY;
public static float TwipsPerPixelY {
get {
if (twipsPerPixelY == 0) {
using (Bitmap bmp = new Bitmap(1,1)) {
using (Graphics g = Graphics.FromImage(bmp)) {
twipsPerPixelY = 1440 / g.DpiY;
}
}
}
return twipsPerPixelY;
}
}
/// <value>
/// The base font
/// </value>
public Font DefaultFont {
get {
return defaultFont;
}
set {
// 1440 twips is one inch
float pixelSize = (float)Math.Round(value.SizeInPoints * 20 / TwipsPerPixelY);
defaultFont = value;
regularfont = new Font(value.FontFamily, pixelSize * TwipsPerPixelY / 20f, FontStyle.Regular);
boldfont = new Font(regularfont, FontStyle.Bold);
italicfont = new Font(regularfont, FontStyle.Italic);
bolditalicfont = new Font(regularfont, FontStyle.Bold | FontStyle.Italic);
}
}
public static Font ParseFont(string font)
{
string[] descr = font.Split(new char[]{',', '='});
return new Font(descr[1], float.Parse(descr[3]));
}
public FontContainer(Font defaultFont)
{
this.DefaultFont = defaultFont;
}
}
}

View File

@@ -0,0 +1,51 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Drawing;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// Extens the highlighting color with a background image.
/// </summary>
public class HighlightBackground : HighlightColor
{
Image backgroundImage;
/// <value>
/// The image used as background
/// </value>
public Image BackgroundImage {
get {
return backgroundImage;
}
}
/// <summary>
/// Creates a new instance of <see cref="HighlightBackground"/>
/// </summary>
public HighlightBackground(XmlElement el) : base(el)
{
if (el.Attributes["image"] != null) {
backgroundImage = new Bitmap(el.Attributes["image"].InnerText);
}
}
/// <summary>
/// Creates a new instance of <see cref="HighlightBackground"/>
/// </summary>
public HighlightBackground(Color color, Color backgroundcolor, bool bold, bool italic) : base(color, backgroundcolor, bold, italic)
{
}
public HighlightBackground(string systemColor, string systemBackgroundColor, bool bold, bool italic) : base(systemColor, systemBackgroundColor, bold, italic)
{
}
}
}

View File

@@ -0,0 +1,274 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// A color used for highlighting
/// </summary>
public class HighlightColor
{
Color color;
Color backgroundcolor = System.Drawing.Color.WhiteSmoke;
bool bold = false;
bool italic = false;
bool hasForeground = false;
bool hasBackground = false;
public bool HasForeground {
get {
return hasForeground;
}
}
public bool HasBackground {
get {
return hasBackground;
}
}
/// <value>
/// If true the font will be displayed bold style
/// </value>
public bool Bold {
get {
return bold;
}
}
/// <value>
/// If true the font will be displayed italic style
/// </value>
public bool Italic {
get {
return italic;
}
}
/// <value>
/// The background color used
/// </value>
public Color BackgroundColor {
get {
return backgroundcolor;
}
}
/// <value>
/// The foreground color used
/// </value>
public Color Color {
get {
return color;
}
}
/// <value>
/// The font used
/// </value>
public Font GetFont(FontContainer fontContainer)
{
if (Bold) {
return Italic ? fontContainer.BoldItalicFont : fontContainer.BoldFont;
}
return Italic ? fontContainer.ItalicFont : fontContainer.RegularFont;
}
Color ParseColorString(string colorName)
{
string[] cNames = colorName.Split('*');
PropertyInfo myPropInfo = typeof(System.Drawing.SystemColors).GetProperty(cNames[0], BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static);
Color c = (Color)myPropInfo.GetValue(null, null);
if (cNames.Length == 2) {
// hack : can't figure out how to parse doubles with '.' (culture info might set the '.' to ',')
double factor = double.Parse(cNames[1]) / 100;
c = Color.FromArgb((int)((double)c.R * factor), (int)((double)c.G * factor), (int)((double)c.B * factor));
}
return c;
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(XmlElement el)
{
Debug.Assert(el != null, "ICSharpCode.TextEditor.Document.SyntaxColor(XmlElement el) : el == null");
if (el.Attributes["bold"] != null) {
bold = bool.Parse(el.Attributes["bold"].InnerText);
}
if (el.Attributes["italic"] != null) {
italic = bool.Parse(el.Attributes["italic"].InnerText);
}
if (el.Attributes["color"] != null) {
string c = el.Attributes["color"].InnerText;
if (c[0] == '#') {
color = ParseColor(c);
} else if (c.StartsWith("SystemColors.")) {
color = ParseColorString(c.Substring("SystemColors.".Length));
} else {
color = (Color)(Color.GetType()).InvokeMember(c, BindingFlags.GetProperty, null, Color, new object[0]);
}
hasForeground = true;
} else {
color = Color.Transparent; // to set it to the default value.
}
if (el.Attributes["bgcolor"] != null) {
string c = el.Attributes["bgcolor"].InnerText;
if (c[0] == '#') {
backgroundcolor = ParseColor(c);
} else if (c.StartsWith("SystemColors.")) {
backgroundcolor = ParseColorString(c.Substring("SystemColors.".Length));
} else {
backgroundcolor = (Color)(Color.GetType()).InvokeMember(c, BindingFlags.GetProperty, null, Color, new object[0]);
}
hasBackground = true;
}
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(XmlElement el, HighlightColor defaultColor)
{
Debug.Assert(el != null, "ICSharpCode.TextEditor.Document.SyntaxColor(XmlElement el) : el == null");
if (el.Attributes["bold"] != null) {
bold = bool.Parse(el.Attributes["bold"].InnerText);
} else {
bold = defaultColor.Bold;
}
if (el.Attributes["italic"] != null) {
italic = bool.Parse(el.Attributes["italic"].InnerText);
} else {
italic = defaultColor.Italic;
}
if (el.Attributes["color"] != null) {
string c = el.Attributes["color"].InnerText;
if (c[0] == '#') {
color = ParseColor(c);
} else if (c.StartsWith("SystemColors.")) {
color = ParseColorString(c.Substring("SystemColors.".Length));
} else {
color = (Color)(Color.GetType()).InvokeMember(c, BindingFlags.GetProperty, null, Color, new object[0]);
}
hasForeground = true;
} else {
color = defaultColor.color;
}
if (el.Attributes["bgcolor"] != null) {
string c = el.Attributes["bgcolor"].InnerText;
if (c[0] == '#') {
backgroundcolor = ParseColor(c);
} else if (c.StartsWith("SystemColors.")) {
backgroundcolor = ParseColorString(c.Substring("SystemColors.".Length));
} else {
backgroundcolor = (Color)(Color.GetType()).InvokeMember(c, BindingFlags.GetProperty, null, Color, new object[0]);
}
hasBackground = true;
} else {
backgroundcolor = defaultColor.BackgroundColor;
}
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(Color color, bool bold, bool italic)
{
hasForeground = true;
this.color = color;
this.bold = bold;
this.italic = italic;
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(Color color, Color backgroundcolor, bool bold, bool italic)
{
hasForeground = true;
hasBackground = true;
this.color = color;
this.backgroundcolor = backgroundcolor;
this.bold = bold;
this.italic = italic;
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(string systemColor, string systemBackgroundColor, bool bold, bool italic)
{
hasForeground = true;
hasBackground = true;
this.color = ParseColorString(systemColor);
this.backgroundcolor = ParseColorString(systemBackgroundColor);
this.bold = bold;
this.italic = italic;
}
/// <summary>
/// Creates a new instance of <see cref="HighlightColor"/>
/// </summary>
public HighlightColor(string systemColor, bool bold, bool italic)
{
hasForeground = true;
this.color = ParseColorString(systemColor);
this.bold = bold;
this.italic = italic;
}
static Color ParseColor(string c)
{
int a = 255;
int offset = 0;
if (c.Length > 7) {
offset = 2;
a = int.Parse(c.Substring(1,2), NumberStyles.HexNumber);
}
int r = int.Parse(c.Substring(1 + offset,2), NumberStyles.HexNumber);
int g = int.Parse(c.Substring(3 + offset,2), NumberStyles.HexNumber);
int b = int.Parse(c.Substring(5 + offset,2), NumberStyles.HexNumber);
return Color.FromArgb(a, r, g, b);
}
/// <summary>
/// Converts a <see cref="HighlightColor"/> instance to string (for debug purposes)
/// </summary>
public override string ToString()
{
return "[HighlightColor: Bold = " + Bold +
", Italic = " + Italic +
", Color = " + Color +
", BackgroundColor = " + BackgroundColor + "]";
}
}
}

View File

@@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.TextEditor.Document
{
public class HighlightInfo
{
public bool BlockSpanOn = false;
public bool Span = false;
public Span CurSpan = null;
public HighlightInfo(Span curSpan, bool span, bool blockSpanOn)
{
this.CurSpan = curSpan;
this.Span = span;
this.BlockSpanOn = blockSpanOn;
}
}
}

View File

@@ -0,0 +1,182 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Xml;
using ICSharpCode.TextEditor.Util;
namespace ICSharpCode.TextEditor.Document
{
public class HighlightRuleSet
{
LookupTable keyWords;
ArrayList spans = new ArrayList();
LookupTable prevMarkers;
LookupTable nextMarkers;
char escapeCharacter;
bool ignoreCase = false;
string name = null;
bool[] delimiters = new bool[256];
string reference = null;
public ArrayList Spans {
get {
return spans;
}
}
internal IHighlightingStrategyUsingRuleSets Highlighter;
public LookupTable KeyWords {
get {
return keyWords;
}
}
public LookupTable PrevMarkers {
get {
return prevMarkers;
}
}
public LookupTable NextMarkers {
get {
return nextMarkers;
}
}
public bool[] Delimiters {
get {
return delimiters;
}
}
public char EscapeCharacter {
get {
return escapeCharacter;
}
}
public bool IgnoreCase {
get {
return ignoreCase;
}
}
public string Name {
get {
return name;
}
set {
name = value;
}
}
public string Reference {
get {
return reference;
}
}
public HighlightRuleSet()
{
keyWords = new LookupTable(false);
prevMarkers = new LookupTable(false);
nextMarkers = new LookupTable(false);
}
public HighlightRuleSet(XmlElement el)
{
XmlNodeList nodes;
if (el.Attributes["name"] != null) {
Name = el.Attributes["name"].InnerText;
}
if (el.HasAttribute("escapecharacter")) {
escapeCharacter = el.GetAttribute("escapecharacter")[0];
}
if (el.Attributes["reference"] != null) {
reference = el.Attributes["reference"].InnerText;
}
if (el.Attributes["ignorecase"] != null) {
ignoreCase = bool.Parse(el.Attributes["ignorecase"].InnerText);
}
for (int i = 0; i < Delimiters.Length; ++i) {
delimiters[i] = false;
}
if (el["Delimiters"] != null) {
string delimiterString = el["Delimiters"].InnerText;
foreach (char ch in delimiterString) {
delimiters[(int)ch] = true;
}
}
// Spans = new LookupTable(!IgnoreCase);
keyWords = new LookupTable(!IgnoreCase);
prevMarkers = new LookupTable(!IgnoreCase);
nextMarkers = new LookupTable(!IgnoreCase);
nodes = el.GetElementsByTagName("KeyWords");
foreach (XmlElement el2 in nodes) {
HighlightColor color = new HighlightColor(el2);
XmlNodeList keys = el2.GetElementsByTagName("Key");
foreach (XmlElement node in keys) {
keyWords[node.Attributes["word"].InnerText] = color;
}
}
nodes = el.GetElementsByTagName("Span");
foreach (XmlElement el2 in nodes) {
Spans.Add(new Span(el2));
/*
Span span = new Span(el2);
Spans[span.Begin] = span;*/
}
nodes = el.GetElementsByTagName("MarkPrevious");
foreach (XmlElement el2 in nodes) {
PrevMarker prev = new PrevMarker(el2);
prevMarkers[prev.What] = prev;
}
nodes = el.GetElementsByTagName("MarkFollowing");
foreach (XmlElement el2 in nodes) {
NextMarker next = new NextMarker(el2);
nextMarkers[next.What] = next;
}
}
/// <summary>
/// Merges spans etc. from the other rule set into this rule set.
/// </summary>
public void MergeFrom(HighlightRuleSet ruleSet)
{
for (int i = 0; i < delimiters.Length; i++) {
delimiters[i] |= ruleSet.delimiters[i];
}
// insert merged spans in front of old spans
ArrayList oldSpans = spans;
spans = (ArrayList)ruleSet.spans.Clone();
spans.AddRange(oldSpans);
//keyWords.MergeFrom(ruleSet.keyWords);
//prevMarkers.MergeFrom(ruleSet.prevMarkers);
//nextMarkers.MergeFrom(ruleSet.nextMarkers);
}
}
}

View File

@@ -0,0 +1,32 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Runtime.Serialization;
namespace ICSharpCode.TextEditor.Document
{
[Serializable()]
public class HighlightingColorNotFoundException : Exception
{
public HighlightingColorNotFoundException() : base()
{
}
public HighlightingColorNotFoundException(string message) : base(message)
{
}
public HighlightingColorNotFoundException(string message, Exception innerException) : base(message, innerException)
{
}
protected HighlightingColorNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@@ -0,0 +1,37 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Runtime.Serialization;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// Indicates that the highlighting definition that was tried to load was invalid.
/// You get this exception only once per highlighting definition, after that the definition
/// is replaced with the default highlighter.
/// </summary>
[Serializable()]
public class HighlightingDefinitionInvalidException : Exception
{
public HighlightingDefinitionInvalidException() : base()
{
}
public HighlightingDefinitionInvalidException(string message) : base(message)
{
}
public HighlightingDefinitionInvalidException(string message, Exception innerException) : base(message, innerException)
{
}
protected HighlightingDefinitionInvalidException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}

View File

@@ -0,0 +1,110 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
namespace ICSharpCode.TextEditor.Document
{
public static class HighlightingDefinitionParser
{
public static DefaultHighlightingStrategy Parse(SyntaxMode syntaxMode, XmlReader xmlReader)
{
return Parse(null, syntaxMode, xmlReader);
}
public static DefaultHighlightingStrategy Parse(DefaultHighlightingStrategy highlighter, SyntaxMode syntaxMode, XmlReader xmlReader)
{
if (syntaxMode == null)
throw new ArgumentNullException("syntaxMode");
if (xmlReader == null)
throw new ArgumentNullException("xmlTextReader");
try {
List<ValidationEventArgs> errors = null;
XmlReaderSettings settings = new XmlReaderSettings();
Stream shemaStream = typeof(HighlightingDefinitionParser).Assembly.GetManifestResourceStream("ICSharpCode.TextEditor.Resources.Mode.xsd");
settings.Schemas.Add("", new XmlTextReader(shemaStream));
settings.Schemas.ValidationEventHandler += delegate(object sender, ValidationEventArgs args) {
if (errors == null) {
errors = new List<ValidationEventArgs>();
}
errors.Add(args);
};
settings.ValidationType = ValidationType.Schema;
XmlReader validatingReader = XmlReader.Create(xmlReader, settings);
XmlDocument doc = new XmlDocument();
doc.Load(validatingReader);
if (highlighter == null)
highlighter = new DefaultHighlightingStrategy(doc.DocumentElement.Attributes["name"].InnerText);
if (doc.DocumentElement.HasAttribute("extends")) {
KeyValuePair<SyntaxMode, ISyntaxModeFileProvider> entry = HighlightingManager.Manager.FindHighlighterEntry(doc.DocumentElement.GetAttribute("extends"));
if (entry.Key == null) {
throw new HighlightingDefinitionInvalidException("Cannot find referenced highlighting source " + doc.DocumentElement.GetAttribute("extends"));
} else {
highlighter = Parse(highlighter, entry.Key, entry.Value.GetSyntaxModeFile(entry.Key));
if (highlighter == null) return null;
}
}
if (doc.DocumentElement.HasAttribute("extensions")) {
highlighter.Extensions = doc.DocumentElement.GetAttribute("extensions").Split(new char[] { ';', '|' });
}
XmlElement environment = doc.DocumentElement["Environment"];
if (environment != null) {
foreach (XmlNode node in environment.ChildNodes) {
if (node is XmlElement) {
XmlElement el = (XmlElement)node;
if (el.Name == "Custom") {
highlighter.SetColorFor(el.GetAttribute("name"), el.HasAttribute("bgcolor") ? new HighlightBackground(el) : new HighlightColor(el));
} else {
highlighter.SetColorFor(el.Name, el.HasAttribute("bgcolor") ? new HighlightBackground(el) : new HighlightColor(el));
}
}
}
}
// parse properties
if (doc.DocumentElement["Properties"]!= null) {
foreach (XmlElement propertyElement in doc.DocumentElement["Properties"].ChildNodes) {
highlighter.Properties[propertyElement.Attributes["name"].InnerText] = propertyElement.Attributes["value"].InnerText;
}
}
if (doc.DocumentElement["Digits"]!= null) {
highlighter.DigitColor = new HighlightColor(doc.DocumentElement["Digits"]);
}
XmlNodeList nodes = doc.DocumentElement.GetElementsByTagName("RuleSet");
foreach (XmlElement element in nodes) {
highlighter.AddRuleSet(new HighlightRuleSet(element));
}
xmlReader.Close();
if (errors != null) {
StringBuilder msg = new StringBuilder();
foreach (ValidationEventArgs args in errors) {
msg.AppendLine(args.Message);
}
throw new HighlightingDefinitionInvalidException(msg.ToString());
} else {
return highlighter;
}
} catch (Exception e) {
throw new HighlightingDefinitionInvalidException("Could not load mode definition file '" + syntaxMode.FileName + "'.\n", e);
}
}
}
}

View File

@@ -0,0 +1,166 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
namespace ICSharpCode.TextEditor.Document
{
public class HighlightingManager
{
ArrayList syntaxModeFileProviders = new ArrayList();
static HighlightingManager highlightingManager;
// hash table from extension name to highlighting definition,
// OR from extension name to Pair SyntaxMode,ISyntaxModeFileProvider
Hashtable highlightingDefs = new Hashtable();
Hashtable extensionsToName = new Hashtable();
public Hashtable HighlightingDefinitions {
get {
return highlightingDefs;
}
}
public static HighlightingManager Manager {
get {
return highlightingManager;
}
}
static HighlightingManager()
{
highlightingManager = new HighlightingManager();
highlightingManager.AddSyntaxModeFileProvider(new ResourceSyntaxModeProvider());
}
public HighlightingManager()
{
CreateDefaultHighlightingStrategy();
}
public void AddSyntaxModeFileProvider(ISyntaxModeFileProvider syntaxModeFileProvider)
{
foreach (SyntaxMode syntaxMode in syntaxModeFileProvider.SyntaxModes) {
highlightingDefs[syntaxMode.Name] = new DictionaryEntry(syntaxMode, syntaxModeFileProvider);
foreach (string extension in syntaxMode.Extensions) {
extensionsToName[extension.ToUpperInvariant()] = syntaxMode.Name;
}
}
if (!syntaxModeFileProviders.Contains(syntaxModeFileProvider)) {
syntaxModeFileProviders.Add(syntaxModeFileProvider);
}
}
public void AddHighlightingStrategy(IHighlightingStrategy highlightingStrategy)
{
highlightingDefs[highlightingStrategy.Name] = highlightingStrategy;
foreach (string extension in highlightingStrategy.Extensions)
{
extensionsToName[extension.ToUpperInvariant()] = highlightingStrategy.Name;
}
}
public void ReloadSyntaxModes()
{
highlightingDefs.Clear();
extensionsToName.Clear();
CreateDefaultHighlightingStrategy();
foreach (ISyntaxModeFileProvider provider in syntaxModeFileProviders) {
provider.UpdateSyntaxModeList();
AddSyntaxModeFileProvider(provider);
}
OnReloadSyntaxHighlighting(EventArgs.Empty);
}
void CreateDefaultHighlightingStrategy()
{
DefaultHighlightingStrategy defaultHighlightingStrategy = new DefaultHighlightingStrategy();
defaultHighlightingStrategy.Extensions = new string[] {};
defaultHighlightingStrategy.Rules.Add(new HighlightRuleSet());
highlightingDefs["Default"] = defaultHighlightingStrategy;
}
IHighlightingStrategy LoadDefinition(DictionaryEntry entry)
{
SyntaxMode syntaxMode = (SyntaxMode)entry.Key;
ISyntaxModeFileProvider syntaxModeFileProvider = (ISyntaxModeFileProvider)entry.Value;
DefaultHighlightingStrategy highlightingStrategy = null;
try {
var reader = syntaxModeFileProvider.GetSyntaxModeFile(syntaxMode);
if (reader == null)
throw new HighlightingDefinitionInvalidException("Could not get syntax mode file for " + syntaxMode.Name);
highlightingStrategy = HighlightingDefinitionParser.Parse(syntaxMode, reader);
if (highlightingStrategy.Name != syntaxMode.Name) {
throw new HighlightingDefinitionInvalidException("The name specified in the .xshd '" + highlightingStrategy.Name + "' must be equal the syntax mode name '" + syntaxMode.Name + "'");
}
} finally {
if (highlightingStrategy == null) {
highlightingStrategy = DefaultHighlighting;
}
highlightingDefs[syntaxMode.Name] = highlightingStrategy;
highlightingStrategy.ResolveReferences();
}
return highlightingStrategy;
}
public DefaultHighlightingStrategy DefaultHighlighting {
get {
return (DefaultHighlightingStrategy)highlightingDefs["Default"];
}
}
internal KeyValuePair<SyntaxMode, ISyntaxModeFileProvider> FindHighlighterEntry(string name)
{
foreach (ISyntaxModeFileProvider provider in syntaxModeFileProviders) {
foreach (SyntaxMode mode in provider.SyntaxModes) {
if (mode.Name == name) {
return new KeyValuePair<SyntaxMode, ISyntaxModeFileProvider>(mode, provider);
}
}
}
return new KeyValuePair<SyntaxMode, ISyntaxModeFileProvider>(null, null);
}
public IHighlightingStrategy FindHighlighter(string name)
{
object def = highlightingDefs[name];
if (def is DictionaryEntry) {
return LoadDefinition((DictionaryEntry)def);
}
return def == null ? DefaultHighlighting : (IHighlightingStrategy)def;
}
public IHighlightingStrategy FindHighlighterForFile(string fileName)
{
string highlighterName = (string)extensionsToName[Path.GetExtension(fileName).ToUpperInvariant()];
if (highlighterName != null) {
object def = highlightingDefs[highlighterName];
if (def is DictionaryEntry) {
return LoadDefinition((DictionaryEntry)def);
}
return def == null ? DefaultHighlighting : (IHighlightingStrategy)def;
} else {
return DefaultHighlighting;
}
}
protected virtual void OnReloadSyntaxHighlighting(EventArgs e)
{
if (ReloadSyntaxHighlighting != null) {
ReloadSyntaxHighlighting(this, e);
}
}
public event EventHandler ReloadSyntaxHighlighting;
}
}

View File

@@ -0,0 +1,40 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.TextEditor.Document
{
public class HighlightingStrategyFactory
{
public static IHighlightingStrategy CreateHighlightingStrategy()
{
return (IHighlightingStrategy)HighlightingManager.Manager.HighlightingDefinitions["Default"];
}
public static IHighlightingStrategy CreateHighlightingStrategy(string name)
{
IHighlightingStrategy highlightingStrategy = HighlightingManager.Manager.FindHighlighter(name);
if (highlightingStrategy == null)
{
return CreateHighlightingStrategy();
}
return highlightingStrategy;
}
public static IHighlightingStrategy CreateHighlightingStrategyForFile(string fileName)
{
IHighlightingStrategy highlightingStrategy = HighlightingManager.Manager.FindHighlighterForFile(fileName);
if (highlightingStrategy == null)
{
return CreateHighlightingStrategy();
}
return highlightingStrategy;
}
}
}

View File

@@ -0,0 +1,67 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// A highlighting strategy for a buffer.
/// </summary>
public interface IHighlightingStrategy
{
/// <value>
/// The name of the highlighting strategy, must be unique
/// </value>
string Name {
get;
}
/// <value>
/// The file extenstions on which this highlighting strategy gets
/// used
/// </value>
string[] Extensions {
get;
}
Dictionary<string, string> Properties {
get;
}
// returns special color. (BackGround Color, Cursor Color and so on)
/// <remarks>
/// Gets the color of an Environment element.
/// </remarks>
HighlightColor GetColorFor(string name);
/// <remarks>
/// Used internally, do not call
/// </remarks>
void MarkTokens(IDocument document, List<LineSegment> lines);
/// <remarks>
/// Used internally, do not call
/// </remarks>
void MarkTokens(IDocument document);
}
public interface IHighlightingStrategyUsingRuleSets : IHighlightingStrategy
{
/// <remarks>
/// Used internally, do not call
/// </remarks>
HighlightRuleSet GetRuleSet(Span span);
/// <remarks>
/// Used internally, do not call
/// </remarks>
HighlightColor GetColor(IDocument document, LineSegment keyWord, int index, int length);
}
}

View File

@@ -0,0 +1,63 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// Used for mark next token
/// </summary>
public class NextMarker
{
string what;
HighlightColor color;
bool markMarker = false;
/// <value>
/// String value to indicate to mark next token
/// </value>
public string What {
get {
return what;
}
}
/// <value>
/// Color for marking next token
/// </value>
public HighlightColor Color {
get {
return color;
}
}
/// <value>
/// If true the indication text will be marked with the same color
/// too
/// </value>
public bool MarkMarker {
get {
return markMarker;
}
}
/// <summary>
/// Creates a new instance of <see cref="NextMarker"/>
/// </summary>
public NextMarker(XmlElement mark)
{
color = new HighlightColor(mark);
what = mark.InnerText;
if (mark.Attributes["markmarker"] != null) {
markMarker = bool.Parse(mark.Attributes["markmarker"].InnerText);
}
}
}
}

View File

@@ -0,0 +1,63 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// Used for mark previous token
/// </summary>
public class PrevMarker
{
string what;
HighlightColor color;
bool markMarker = false;
/// <value>
/// String value to indicate to mark previous token
/// </value>
public string What {
get {
return what;
}
}
/// <value>
/// Color for marking previous token
/// </value>
public HighlightColor Color {
get {
return color;
}
}
/// <value>
/// If true the indication text will be marked with the same color
/// too
/// </value>
public bool MarkMarker {
get {
return markMarker;
}
}
/// <summary>
/// Creates a new instance of <see cref="PrevMarker"/>
/// </summary>
public PrevMarker(XmlElement mark)
{
color = new HighlightColor(mark);
what = mark.InnerText;
if (mark.Attributes["markmarker"] != null) {
markMarker = bool.Parse(mark.Attributes["markmarker"].InnerText);
}
}
}
}

View File

@@ -0,0 +1,157 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
public sealed class Span
{
bool stopEOL;
HighlightColor color;
HighlightColor beginColor;
HighlightColor endColor;
char[] begin;
char[] end;
string name;
string rule;
HighlightRuleSet ruleSet;
char escapeCharacter;
bool ignoreCase;
bool isBeginSingleWord;
bool? isBeginStartOfLine;
bool isEndSingleWord;
internal HighlightRuleSet RuleSet {
get {
return ruleSet;
}
set {
ruleSet = value;
}
}
public bool IgnoreCase {
get {
return ignoreCase;
}
set {
ignoreCase = value;
}
}
public bool StopEOL {
get {
return stopEOL;
}
}
public bool? IsBeginStartOfLine {
get {
return isBeginStartOfLine;
}
}
public bool IsBeginSingleWord {
get {
return isBeginSingleWord;
}
}
public bool IsEndSingleWord {
get {
return isEndSingleWord;
}
}
public HighlightColor Color {
get {
return color;
}
}
public HighlightColor BeginColor {
get {
if(beginColor != null) {
return beginColor;
} else {
return color;
}
}
}
public HighlightColor EndColor {
get {
return endColor!=null ? endColor : color;
}
}
public char[] Begin {
get { return begin; }
}
public char[] End {
get { return end; }
}
public string Name {
get { return name; }
}
public string Rule {
get { return rule; }
}
/// <summary>
/// Gets the escape character of the span. The escape character is a character that can be used in front
/// of the span end to make it not end the span. The escape character followed by another escape character
/// means the escape character was escaped like in @"a "" b" literals in C#.
/// The default value '\0' means no escape character is allowed.
/// </summary>
public char EscapeCharacter {
get { return escapeCharacter; }
}
public Span(XmlElement span)
{
color = new HighlightColor(span);
if (span.HasAttribute("rule")) {
rule = span.GetAttribute("rule");
}
if (span.HasAttribute("escapecharacter")) {
escapeCharacter = span.GetAttribute("escapecharacter")[0];
}
name = span.GetAttribute("name");
if (span.HasAttribute("stopateol")) {
stopEOL = bool.Parse(span.GetAttribute("stopateol"));
}
begin = span["Begin"].InnerText.ToCharArray();
beginColor = new HighlightColor(span["Begin"], color);
if (span["Begin"].HasAttribute("singleword")) {
this.isBeginSingleWord = bool.Parse(span["Begin"].GetAttribute("singleword"));
}
if (span["Begin"].HasAttribute("startofline")) {
this.isBeginStartOfLine = bool.Parse(span["Begin"].GetAttribute("startofline"));
}
if (span["End"] != null) {
end = span["End"].InnerText.ToCharArray();
endColor = new HighlightColor(span["End"], color);
if (span["End"].HasAttribute("singleword")) {
this.isEndSingleWord = bool.Parse(span["End"].GetAttribute("singleword"));
}
}
}
}
}

View File

@@ -0,0 +1,118 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace ICSharpCode.TextEditor.Document
{
/// <summary>
/// A stack of Span instances. Works like Stack&lt;Span&gt;, but can be cloned quickly
/// because it is implemented as linked list.
/// </summary>
public sealed class SpanStack : ICloneable, IEnumerable<Span>
{
internal sealed class StackNode
{
public readonly StackNode Previous;
public readonly Span Data;
public StackNode(StackNode previous, Span data)
{
this.Previous = previous;
this.Data = data;
}
}
StackNode top = null;
public Span Pop()
{
Span s = top.Data;
top = top.Previous;
return s;
}
public Span Peek()
{
return top.Data;
}
public void Push(Span s)
{
top = new StackNode(top, s);
}
public bool IsEmpty {
get {
return top == null;
}
}
public SpanStack Clone()
{
SpanStack n = new SpanStack();
n.top = this.top;
return n;
}
object ICloneable.Clone()
{
return this.Clone();
}
public Enumerator GetEnumerator()
{
return new Enumerator(new StackNode(top, null));
}
IEnumerator<Span> IEnumerable<Span>.GetEnumerator()
{
return this.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public struct Enumerator : IEnumerator<Span>
{
StackNode c;
internal Enumerator(StackNode node)
{
c = node;
}
public Span Current {
get {
return c.Data;
}
}
object System.Collections.IEnumerator.Current {
get {
return c.Data;
}
}
public void Dispose()
{
c = null;
}
public bool MoveNext()
{
c = c.Previous;
return c != null;
}
public void Reset()
{
throw new NotSupportedException();
}
}
}
}

View File

@@ -0,0 +1,84 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
public class FileSyntaxModeProvider : ISyntaxModeFileProvider
{
string directory;
List<SyntaxMode> syntaxModes = null;
public ICollection<SyntaxMode> SyntaxModes {
get {
return syntaxModes;
}
}
public FileSyntaxModeProvider(string directory)
{
this.directory = directory;
UpdateSyntaxModeList();
}
public void UpdateSyntaxModeList()
{
string syntaxModeFile = Path.Combine(directory, "SyntaxModes.xml");
if (File.Exists(syntaxModeFile)) {
Stream s = File.OpenRead(syntaxModeFile);
syntaxModes = SyntaxMode.GetSyntaxModes(s);
s.Close();
} else {
syntaxModes = ScanDirectory(directory);
}
}
public XmlTextReader GetSyntaxModeFile(SyntaxMode syntaxMode)
{
string syntaxModeFile = Path.Combine(directory, syntaxMode.FileName);
if (!File.Exists(syntaxModeFile)) {
throw new HighlightingDefinitionInvalidException("Can't load highlighting definition " + syntaxModeFile + " (file not found)!");
}
return new XmlTextReader(File.OpenRead(syntaxModeFile));
}
List<SyntaxMode> ScanDirectory(string directory)
{
string[] files = Directory.GetFiles(directory);
List<SyntaxMode> modes = new List<SyntaxMode>();
foreach (string file in files) {
if (Path.GetExtension(file).Equals(".XSHD", StringComparison.OrdinalIgnoreCase)) {
XmlTextReader reader = new XmlTextReader(file);
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element) {
switch (reader.Name) {
case "SyntaxDefinition":
string name = reader.GetAttribute("name");
string extensions = reader.GetAttribute("extensions");
modes.Add(new SyntaxMode(Path.GetFileName(file),
name,
extensions));
goto bailout;
default:
throw new HighlightingDefinitionInvalidException("Unknown root node in syntax highlighting file :" + reader.Name);
}
}
}
bailout:
reader.Close();
}
}
return modes;
}
}
}

View File

@@ -0,0 +1,23 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
public interface ISyntaxModeFileProvider
{
ICollection<SyntaxMode> SyntaxModes {
get;
}
XmlTextReader GetSyntaxModeFile(SyntaxMode syntaxMode);
void UpdateSyntaxModeList();
}
}

View File

@@ -0,0 +1,48 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
public class ResourceSyntaxModeProvider : ISyntaxModeFileProvider
{
List<SyntaxMode> syntaxModes = null;
public ICollection<SyntaxMode> SyntaxModes {
get {
return syntaxModes;
}
}
public ResourceSyntaxModeProvider()
{
Assembly assembly = typeof(SyntaxMode).Assembly;
Stream syntaxModeStream = assembly.GetManifestResourceStream("ICSharpCode.TextEditor.Resources.SyntaxModes.xml");
if (syntaxModeStream != null) {
syntaxModes = SyntaxMode.GetSyntaxModes(syntaxModeStream);
} else {
syntaxModes = new List<SyntaxMode>();
}
}
public XmlTextReader GetSyntaxModeFile(SyntaxMode syntaxMode)
{
Assembly assembly = typeof(SyntaxMode).Assembly;
return new XmlTextReader(assembly.GetManifestResourceStream("ICSharpCode.TextEditor.Resources." + syntaxMode.FileName));
}
public void UpdateSyntaxModeList()
{
// resources don't change during runtime
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.TextEditor.Src.Document.HighlightingStrategy.SyntaxModes
{
public class ResourceSyntaxModeProviderEx : ISyntaxModeFileProvider
{
private const string ResourcesDir = "ICSharpCode.TextEditor.Resources.";
readonly List<SyntaxMode> _syntaxModes;
public ICollection<SyntaxMode> SyntaxModes
{
get
{
return _syntaxModes;
}
}
public ResourceSyntaxModeProviderEx()
{
var syntaxModeStream = GetSyntaxModeStream("SyntaxModesEx.xml");
_syntaxModes = syntaxModeStream != null ? SyntaxMode.GetSyntaxModes(syntaxModeStream) : new List<SyntaxMode>();
}
public XmlTextReader GetSyntaxModeFile(SyntaxMode syntaxMode)
{
var stream = GetSyntaxModeStream(syntaxMode.FileName);
return stream != null ? new XmlTextReader(stream) : null;
}
public void UpdateSyntaxModeList()
{
// resources don't change during runtime
}
private Stream GetSyntaxModeStream(string filename)
{
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetManifestResourceStream(string.Format("{0}{1}", ResourcesDir, filename));
}
}
}

View File

@@ -0,0 +1,96 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml;
namespace ICSharpCode.TextEditor.Document
{
public class SyntaxMode
{
string fileName;
string name;
string[] extensions;
public string FileName {
get {
return fileName;
}
set {
fileName = value;
}
}
public string Name {
get {
return name;
}
set {
name = value;
}
}
public string[] Extensions {
get {
return extensions;
}
set {
extensions = value;
}
}
public SyntaxMode(string fileName, string name, string extensions)
{
this.fileName = fileName;
this.name = name;
this.extensions = extensions.Split(';', '|', ',');
}
public SyntaxMode(string fileName, string name, string[] extensions)
{
this.fileName = fileName;
this.name = name;
this.extensions = extensions;
}
public static List<SyntaxMode> GetSyntaxModes(Stream xmlSyntaxModeStream)
{
XmlTextReader reader = new XmlTextReader(xmlSyntaxModeStream);
List<SyntaxMode> syntaxModes = new List<SyntaxMode>();
while (reader.Read()) {
switch (reader.NodeType) {
case XmlNodeType.Element:
switch (reader.Name) {
case "SyntaxModes":
string version = reader.GetAttribute("version");
if (version != "1.0") {
throw new HighlightingDefinitionInvalidException("Unknown syntax mode file defininition with version " + version);
}
break;
case "Mode":
syntaxModes.Add(new SyntaxMode(reader.GetAttribute("file"),
reader.GetAttribute("name"),
reader.GetAttribute("extensions")));
break;
default:
throw new HighlightingDefinitionInvalidException("Unknown node in syntax mode file :" + reader.Name);
}
break;
}
}
reader.Close();
return syntaxModes;
}
public override string ToString()
{
return string.Format("[SyntaxMode: FileName={0}, Name={1}, Extensions=({2})]", fileName, name, string.Join(",", extensions));
}
}
}

View File

@@ -0,0 +1,239 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Diagnostics;
using System.Drawing;
namespace ICSharpCode.TextEditor.Document
{
public enum TextWordType {
Word,
Space,
Tab
}
/// <summary>
/// This class represents single words with color information, two special versions of a word are
/// spaces and tabs.
/// </summary>
public class TextWord
{
HighlightColor color;
LineSegment line;
IDocument document;
int offset;
int length;
public sealed class SpaceTextWord : TextWord
{
public SpaceTextWord()
{
length = 1;
}
public SpaceTextWord(HighlightColor color)
{
length = 1;
base.SyntaxColor = color;
}
public override Font GetFont(FontContainer fontContainer)
{
return null;
}
public override TextWordType Type {
get {
return TextWordType.Space;
}
}
public override bool IsWhiteSpace {
get {
return true;
}
}
}
public sealed class TabTextWord : TextWord
{
public TabTextWord()
{
length = 1;
}
public TabTextWord(HighlightColor color)
{
length = 1;
base.SyntaxColor = color;
}
public override Font GetFont(FontContainer fontContainer)
{
return null;
}
public override TextWordType Type {
get {
return TextWordType.Tab;
}
}
public override bool IsWhiteSpace {
get {
return true;
}
}
}
static TextWord spaceWord = new SpaceTextWord();
static TextWord tabWord = new TabTextWord();
bool hasDefaultColor;
public static TextWord Space {
get {
return spaceWord;
}
}
public static TextWord Tab {
get {
return tabWord;
}
}
public int Offset {
get {
return offset;
}
}
public int Length {
get {
return length;
}
}
/// <summary>
/// Splits the <paramref name="word"/> into two parts: the part before <paramref name="pos"/> is assigned to
/// the reference parameter <paramref name="word"/>, the part after <paramref name="pos"/> is returned.
/// </summary>
public static TextWord Split(ref TextWord word, int pos)
{
#if DEBUG
if (word.Type != TextWordType.Word)
throw new ArgumentException("word.Type must be Word");
if (pos <= 0)
throw new ArgumentOutOfRangeException("pos", pos, "pos must be > 0");
if (pos >= word.Length)
throw new ArgumentOutOfRangeException("pos", pos, "pos must be < word.Length");
#endif
TextWord after = new TextWord(word.document, word.line, word.offset + pos, word.length - pos, word.color, word.hasDefaultColor);
word = new TextWord(word.document, word.line, word.offset, pos, word.color, word.hasDefaultColor);
return after;
}
public bool HasDefaultColor {
get {
return hasDefaultColor;
}
}
public virtual TextWordType Type {
get {
return TextWordType.Word;
}
}
public string Word {
get {
if (document == null) {
return string.Empty;
}
return document.GetText(line.Offset + offset, length);
}
}
public virtual Font GetFont(FontContainer fontContainer)
{
return color.GetFont(fontContainer);
}
public Color Color {
get {
if (color == null)
return Color.Black;
else
return color.Color;
}
}
public bool Bold {
get {
if (color == null)
return false;
else
return color.Bold;
}
}
public bool Italic {
get {
if (color == null)
return false;
else
return color.Italic;
}
}
public HighlightColor SyntaxColor {
get {
return color;
}
set {
Debug.Assert(value != null);
color = value;
}
}
public virtual bool IsWhiteSpace {
get {
return false;
}
}
public virtual bool IsDelimiter { get; set; } = false;
protected TextWord()
{
}
// TAB
public TextWord(IDocument document, LineSegment line, int offset, int length, HighlightColor color, bool hasDefaultColor)
{
Debug.Assert(document != null);
Debug.Assert(line != null);
Debug.Assert(color != null);
this.document = document;
this.line = line;
this.offset = offset;
this.length = length;
this.color = color;
this.hasDefaultColor = hasDefaultColor;
}
/// <summary>
/// Converts a <see cref="TextWord"/> instance to string (for debug purposes)
/// </summary>
public override string ToString()
{
return "[TextWord: Word = " + Word + ", Color = " + Color + "]";
}
}
}