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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Span>, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user