private void PopSpanStack() { currentSpanStack.RemoveAt(currentSpanStack.Count - 1); inSpan = (currentSpanStack != null && currentSpanStack.Count > 0); activeSpan = inSpan ? currentSpanStack[currentSpanStack.Count - 1] : null; activeRuleSet = new HighlightRuleSet(); }
public Ca65Highlighting(ProjectType projectType) { Extensions = new[] { "s", "h" }; opcodes = new HashSet <string>(nesOpcodes); if (projectType == ProjectType.Snes) { opcodes.UnionWith(snesOpcodes); } Properties = new Dictionary <string, string>(); Properties.Add("LineComment", ";"); Rule = new HighlightRuleSet(); NumberWord = new Ca65WordType { Type = AsmWord.AsmWordType.NumberWord, Match = NumberMatch }; StringWord = new Ca65WordType { Type = AsmWord.AsmWordType.String, Match = StringMatch }; AddressWord = new Ca65WordType { Type = AsmWord.AsmWordType.AddressReference, Match = AddressMatch }; CommandWord = new Ca65WordType { Type = AsmWord.AsmWordType.Command, Match = CommandMatch }; CommentSpan = new Ca65Span { Begin = new char[] { ';' }, End = new char[] { '\n' }, Type = AsmWord.AsmWordType.Comment }; UpdateColorsFromDefault(); Type = new List <Ca65WordType> { NumberWord, StringWord, CommandWord }; //, AddressWord }; Spans = new List <Ca65Span> { CommentSpan }; }
List <TextWord> ParseLine(IDocument document) { List <TextWord> words = new List <TextWord>(); HighlightColor markNext = null; currentOffset = 0; currentLength = 0; inSpan = (currentSpanStack != null && currentSpanStack.Count > 0); activeSpan = inSpan ? currentSpanStack[currentSpanStack.Count - 1] : null; activeRuleSet = Rule; int currentLineLength = currentLine.Length; int currentLineOffset = currentLine.Offset; var firstWord = true; var isWord = false; var opcodeParams = false; var absoluteValue = false; for (int i = 0; i < currentLineLength; ++i) { char ch = document.GetCharAt(currentLineOffset + i); switch (ch) { case '\n': case '\r': PushCurWord(document, ref markNext, words, firstWord); if (isWord) { firstWord = false; } ++currentOffset; break; case ' ': PushCurWord(document, ref markNext, words, firstWord); if (isWord) { firstWord = false; } 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, firstWord); if (isWord) { firstWord = false; } if (activeSpan != null && activeSpan.Color.HasBackground) { words.Add(new TextWord.TabTextWord(activeSpan.Color)); } else { words.Add(TextWord.Tab); } ++currentOffset; break; default: var lookAhead = document.GetText(currentLineOffset + i, (currentLineLength - i)); var match = Regex.Match(lookAhead, OperatorMatch); if (match.Success) // && !Type.Any(t => Regex.IsMatch(lookAhead, t.Match))) ; Condition only necessary if a match type conflicts with operators { PushCurWord(document, ref markNext, words, firstWord); if (isWord) { firstWord = false; } currentLength = match.Length; PushCurWord(document, ref markNext, words, firstWord); isWord = true; i += match.Length - 1; continue; } isWord = true; // handle escape characters var 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; } } if (!inSpan && currentLength == 0) { // Handle new words from the beginning if (ch == '#') { currentLength += 1; words.Add(new AsmWord(document, currentLine, currentOffset, currentLength, DigitColor, false, AsmWord.AsmWordType.None)); if (opcodeParams) { absoluteValue = true; } i += currentLength - 1; currentOffset += currentLength; currentLength = 0; continue; } foreach (var type in Type) { var typeMatch = Regex.Match(lookAhead, type.Match); if (typeMatch.Success) { currentLength = typeMatch.Length; words.Add(new AsmWord(document, currentLine, currentOffset, currentLength, type.Color, false, type.Type)); i += currentLength - 1; currentOffset += currentLength; currentLength = 0; goto @skip; } } // highlight opcodes if (i + 2 < currentLineLength && (i + 3 == currentLineLength || Char.IsWhiteSpace(document.GetCharAt(currentLineOffset + i + 3)))) { var potentialOpcode = new string(new [] { document.GetCharAt(currentLineOffset + i + 0), document.GetCharAt(currentLineOffset + i + 1), document.GetCharAt(currentLineOffset + i + 2) }); if (opcodes.Contains(potentialOpcode.ToUpperInvariant())) { currentLength += 3; // add 3 letter word i += 2; // skip the next two letters words.Add(new AsmWord(document, currentLine, currentOffset, currentLength, OpcodeColor, false, AsmWord.AsmWordType.Opcode)); opcodeParams = true; // Anything after this will be treated as parameters to the opcode currentOffset += currentLength; currentLength = 0; continue; // If opcode, we have already completed the word, so move on to next word } } } // 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 ?? activeSpan.Color, false)); currentOffset += currentLength; currentLength = 0; i += regex.Length - 1; PopSpanStack(); continue; } } } // check for SPAN BEGIN foreach (var span in Spans) { if ((!span.IsBeginSingleWord || currentLength == 0) && (!span.IsBeginStartOfLine.HasValue || span.IsBeginStartOfLine.Value == (currentLength == 0 && words.TrueForAll(textWord => textWord.Type != TextWordType.Word))) && MatchExpr(currentLine, span.Begin, i, document, activeRuleSet.IgnoreCase)) { PushCurWord(document, ref markNext, words, firstWord); 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 ?? span.Color, false)); currentOffset += currentLength; currentLength = 0; i += regex.Length - 1; if (currentSpanStack == null) { currentSpanStack = new List <Ca65Span>(); } currentSpanStack.Add(span); span.IgnoreCase = activeRuleSet.IgnoreCase; inSpan = currentSpanStack != null && currentSpanStack.Count > 0; activeSpan = inSpan ? currentSpanStack[currentSpanStack.Count - 1] : null; activeRuleSet = new HighlightRuleSet(); goto @skip; } } // check if the char is a delimiter if (activeRuleSet != null && (int)ch < 256 && activeRuleSet.Delimiters[(int)ch]) { PushCurWord(document, ref markNext, words); if (currentOffset + currentLength + 1 < currentLine.Length) { ++currentLength; PushCurWord(document, ref markNext, words); continue; } } ++currentLength; @skip : continue; } } PushCurWord(document, ref markNext, words, firstWord); while (activeSpan != null && activeSpan.End != null && activeSpan.End[0] == '\n') { PopSpanStack(); } //OnParsedLine(document, currentLine, words); return(words); }