211 lines
6.6 KiB
C#
211 lines
6.6 KiB
C#
#region Using Directives
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using ScintillaNET;
|
|
|
|
#endregion Using Directives
|
|
|
|
|
|
namespace SCide
|
|
{
|
|
// A helper class to use the Scintilla container as an INI lexer.
|
|
// We'll ignore the fact that SciLexer.DLL already has an INI capable lexer. ;)
|
|
internal sealed class IniLexer
|
|
{
|
|
#region Constants
|
|
|
|
private const int EOL = -1;
|
|
|
|
// SciLexer's weird choice for a default style _index
|
|
private const int DEFAULT_STYLE = 32;
|
|
|
|
// Our custom styles (indexes chosen not to conflict with anything else)
|
|
private const int KEY_STYLE = 11;
|
|
private const int VALUE_STYLE = 12;
|
|
private const int ASSIGNMENT_STYLE = 13;
|
|
private const int SECTION_STYLE = 14;
|
|
private const int COMMENT_STYLE = 15;
|
|
private const int QUOTED_STYLE = 16;
|
|
|
|
#endregion Constants
|
|
|
|
|
|
#region Fields
|
|
|
|
private Scintilla _scintilla;
|
|
private int _startPos;
|
|
|
|
private int _index;
|
|
private string _text;
|
|
|
|
#endregion Fields
|
|
|
|
|
|
#region Methods
|
|
|
|
public static void Init(Scintilla scintilla)
|
|
{
|
|
// Reset any current language and enable the StyleNeeded
|
|
// event by setting the lexer to container.
|
|
scintilla.Indentation.SmartIndentType = SmartIndent.None;
|
|
scintilla.ConfigurationManager.Language = String.Empty;
|
|
scintilla.Lexing.LexerName = "container";
|
|
scintilla.Lexing.Lexer = Lexer.Container;
|
|
|
|
// Add our custom styles to the collection
|
|
scintilla.Styles[QUOTED_STYLE].ForeColor = Color.FromArgb(153, 51, 51);
|
|
scintilla.Styles[KEY_STYLE].ForeColor = Color.FromArgb(0, 0, 153);
|
|
scintilla.Styles[ASSIGNMENT_STYLE].ForeColor = Color.OrangeRed;
|
|
scintilla.Styles[VALUE_STYLE].ForeColor = Color.FromArgb(102, 0, 102);
|
|
scintilla.Styles[COMMENT_STYLE].ForeColor = Color.FromArgb(102, 102, 102);
|
|
scintilla.Styles[SECTION_STYLE].ForeColor = Color.FromArgb(0, 0, 102);
|
|
scintilla.Styles[SECTION_STYLE].Bold = true;
|
|
}
|
|
|
|
|
|
private int Read()
|
|
{
|
|
if (_index < _text.Length)
|
|
return _text[_index];
|
|
|
|
return EOL;
|
|
}
|
|
|
|
|
|
private void SetStyle(int style, int length)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
// TODO Still using old API
|
|
// This will style the _length of chars and advance the style pointer.
|
|
((INativeScintilla)_scintilla).SetStyling(length, style);
|
|
}
|
|
}
|
|
|
|
|
|
public void Style()
|
|
{
|
|
// TODO Still using the old API
|
|
// Signals that we're going to begin styling from this point.
|
|
((INativeScintilla)_scintilla).StartStyling(_startPos, 0x1F);
|
|
|
|
// Run our humble lexer...
|
|
StyleWhitespace();
|
|
switch(Read())
|
|
{
|
|
case '[':
|
|
|
|
// Section, default, comment
|
|
StyleUntilMatch(SECTION_STYLE, new char[] { ']' });
|
|
StyleCh(SECTION_STYLE);
|
|
StyleUntilMatch(DEFAULT_STYLE, new char[] { ';' });
|
|
goto case ';';
|
|
|
|
case ';':
|
|
|
|
// Comment
|
|
SetStyle(COMMENT_STYLE, _text.Length - _index);
|
|
break;
|
|
|
|
default:
|
|
|
|
// Key, assignment, quote, value, comment
|
|
StyleUntilMatch(KEY_STYLE, new char[] { '=', ';' });
|
|
switch (Read())
|
|
{
|
|
case '=':
|
|
|
|
// Assignment, quote, value, comment
|
|
StyleCh(ASSIGNMENT_STYLE);
|
|
switch (Read())
|
|
{
|
|
case '"':
|
|
|
|
// Quote
|
|
StyleCh(QUOTED_STYLE); // '"'
|
|
StyleUntilMatch(QUOTED_STYLE, new char[] { '"' });
|
|
|
|
// Make sure it wasn't an escaped quote
|
|
if (_index > 0 && _index < _text.Length && _text[_index - 1] == '\\')
|
|
goto case '"';
|
|
|
|
StyleCh(QUOTED_STYLE); // '"'
|
|
goto default;
|
|
|
|
default:
|
|
|
|
// Value, comment
|
|
StyleUntilMatch(VALUE_STYLE, new char[] { ';' });
|
|
SetStyle(COMMENT_STYLE, _text.Length - _index);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default: // ';', EOL
|
|
|
|
// Comment
|
|
SetStyle(COMMENT_STYLE, _text.Length - _index);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
private void StyleCh(int style)
|
|
{
|
|
// Style just one char and advance
|
|
SetStyle(style, 1);
|
|
_index++;
|
|
}
|
|
|
|
|
|
public static void StyleNeeded(Scintilla scintilla, Range range)
|
|
{
|
|
// Create an instance of our lexer and bada-bing the line!
|
|
IniLexer lexer = new IniLexer(scintilla, range.Start, range.StartingLine.Length);
|
|
lexer.Style();
|
|
}
|
|
|
|
|
|
private void StyleUntilMatch(int style, char[] chars)
|
|
{
|
|
// Advance until we match a char in the array
|
|
int startIndex = _index;
|
|
while (_index < _text.Length && Array.IndexOf<char>(chars, _text[_index]) < 0)
|
|
_index++;
|
|
|
|
if (startIndex != _index)
|
|
SetStyle(style, _index - startIndex);
|
|
}
|
|
|
|
|
|
private void StyleWhitespace()
|
|
{
|
|
// Advance the _index until non-whitespace character
|
|
int startIndex = _index;
|
|
while (_index < _text.Length && Char.IsWhiteSpace(_text[_index]))
|
|
_index++;
|
|
|
|
SetStyle(DEFAULT_STYLE, _index - startIndex);
|
|
}
|
|
|
|
#endregion Methods
|
|
|
|
|
|
#region Constructors
|
|
|
|
private IniLexer(Scintilla scintilla, int startPos, int length)
|
|
{
|
|
this._scintilla = scintilla;
|
|
this._startPos = startPos;
|
|
|
|
// One line of _text
|
|
this._text = scintilla.GetRange(startPos, startPos + length).Text;
|
|
}
|
|
|
|
#endregion Constructors
|
|
}
|
|
}
|