first commit
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user