namespace Crow.Coding
{
+ /// <summary>
+ /// Code buffer, lines are arranged in a List<string>, new line chars are removed during string.split on '\n...',
+ /// </summary>
public class CodeBuffer
{
+ //those events are handled in SourceEditor to help keeping sync between textbuffer and parser.
+ //modified lines are marked for reparse
#region Events
public event EventHandler<CodeBufferEventArgs> LineUpadateEvent;
public event EventHandler<CodeBufferEventArgs> LineRemoveEvent;
/// <summary>
/// convert buffer postition to visual position
/// </summary>
- Point getVisualPos (Point buffPos) {
+ Point getTabulatedPos (Point buffPos) {
int vCol = this[buffPos.Y].Substring(0, buffPos.X).Replace("\t", new String(' ', Interface.TabSize)).Length;
return new Point (vCol, buffPos.Y);
}
/// <summary>
/// Gets visual position computed from actual buffer position
/// </summary>
- public Point VisualPosition {
- get { return getVisualPos (new Point (_currentCol, _currentLine)); }
+ public Point TabulatedPosition {
+ get { return getTabulatedPos (new Point (_currentCol, _currentLine)); }
}
/// <summary>
/// set buffer current position from visual position
/// </summary>
- public void SetBufferPos(Point visualPosition) {
- CurrentPosition = getBuffPos(visualPosition);
+ public void SetBufferPos(Point tabulatedPosition) {
+ CurrentPosition = getBuffPos(tabulatedPosition);
}
#region Editing and moving cursor
Point selectionStart = -1;
Point selectionEnd = -1;
- public void SetSelection (Point visualStart, Point visualEnd) {
- selectionStart = getBuffPos (visualStart);
- selectionEnd = getBuffPos (visualEnd);
+ /// <summary>
+ /// Set selection in buffer coords from tabulated coords
+ /// </summary>
+ public void SetSelection (Point tabulatedStart, Point tabulatedEnd) {
+ selectionStart = getBuffPos (tabulatedStart);
+ selectionEnd = getBuffPos (tabulatedEnd);
}
+ /// <summary>
+ /// Set selection in buffer to -1, empty selection
+ /// </summary>
public void ResetSelection () {
selectionStart = selectionEnd = -1;
}
bool selectionIsEmpty {
get { return selectionStart == selectionEnd; }
}
+ /// <summary>
+ /// Current column in buffer coordinate, tabulation = 1 char
+ /// </summary>
public int CurrentColumn{
get { return _currentCol; }
set {
_currentCol = value;
}
}
+ /// <summary>
+ /// Current row in buffer coordinate, tabulation = 1 char
+ /// </summary>
public int CurrentLine{
get { return _currentLine; }
set {
CurrentColumn = cc;
}
}
+ /// <summary>
+ /// Current position in buffer coordinate, tabulation = 1 char
+ /// </summary>
public Point CurrentPosition {
get { return new Point(CurrentColumn, CurrentLine); }
set {
_currentLine = value.Y;
}
}
+ /// <summary>
+ /// get char at current position in buffer
+ /// </summary>
protected Char CurrentChar { get { return lines [CurrentLine] [CurrentColumn]; } }
/// <summary>
- /// Moves cursor one char to the left.
+ /// Moves cursor one char to the left, move up if cursor reaches start of line
/// </summary>
/// <returns><c>true</c> if move succeed</returns>
public bool MoveLeft(){
return true;
}
/// <summary>
- /// Moves cursor one char to the right.
+ /// Moves cursor one char to the right, move down if cursor reaches end of line
/// </summary>
/// <returns><c>true</c> if move succeed</returns>
public bool MoveRight(){
CurFilePath = fd.SelectedFile;
CurrentDir = fd.SelectedDirectory;
- using (StreamReader sr = new StreamReader (CurFileFullPath)) {
- _origText = sr.ReadToEnd ();
- }
- _text = _origText;
-
- NotifyValueChanged ("Text", _text);
- NotifyValueChanged ("IsDirty", false);
- redoStack.Clear ();
- undoStack.Clear ();
- CMDRedo.CanExecute = false;
- CMDUndo.CanExecute = false;
-
+// redoStack.Clear ();
+// undoStack.Clear ();
+// CMDRedo.CanExecute = false;
+// CMDUndo.CanExecute = false;
+//
NotifyValueChanged ("CurFileFullPath", CurFileFullPath);
}
void saveFileDialog_OkClicked (object sender, EventArgs e)
namespace Crow.Coding
{
+ /// <summary>
+ /// base class for tokenizing sources
+ /// </summary>
public abstract class Parser
{
+ /// <summary>
+ /// Default tokens, this enum may be overriden in derived parser with the new keyword,
+ /// see XMLParser for example.
+ /// </summary>
public enum TokenType {
Unknown,
WhiteSpace,
}
#region low level parsing
+ /// <summary>
+ /// Read one char from current position in buffer and store it into the current token
+ /// </summary>
+ /// <param name="startOfTok">if true, set the Start position of the current token to the current position</param>
protected void readToCurrTok(bool startOfTok = false){
if (startOfTok)
currentTok.Start = CurrentPosition;
currentTok += Read();
}
+ /// <summary>
+ /// read n char from the buffer and store it into the current token
+ /// </summary>
protected void readToCurrTok(int length) {
for (int i = 0; i < length; i++)
currentTok += Read ();
}
+ /// <summary>
+ /// Save current token into current TokensLine and raz current token
+ /// </summary>
+ protected void saveAndResetCurrentTok() {
+ currentTok.End = CurrentPosition;
+ TokensLine.Add (currentTok);
+ currentTok = default(Token);
+ }
+ /// <summary>
+ /// read one char and add current token to current TokensLine, current token is reset
+ /// </summary>
+ /// <param name="type">Type of the token</param>
+ /// <param name="startToc">set start of token to current position</param>
protected void readAndResetCurrentTok(System.Enum type, bool startToc = false) {
readToCurrTok ();
saveAndResetCurrentTok (type);
}
- protected void saveAndResetCurrentTok() { this.saveAndResetCurrentTok (currentTok.Type); }
+ /// <summary>
+ /// Save current tok
+ /// </summary>
+ /// <param name="type">set the type of the tok</param>
protected void saveAndResetCurrentTok(System.Enum type) {
currentTok.Type = (TokenType)type;
- currentTok.End = CurrentPosition;
- TokensLine.Add (currentTok);
- currentTok = default(Token);
+ saveAndResetCurrentTok ();
}
+ /// <summary>
+ /// Peek next char, emit '\n' if current column > buffer's line length
+ /// Throw error if eof is true
+ /// </summary>
protected virtual char Peek() {
if (eof)
throw new ParsingException (this, "Unexpected End of File");
return currentColumn < buffer [currentLine].Length ?
buffer [currentLine] [currentColumn] : '\n';
}
+ /// <summary>
+ /// Peek n char from buffer or less if remaining char in buffer's line is less than requested
+ /// if end of line is reached, no '\n' will be emitted, instead, empty string is returned. '\n' should be checked only
+ /// with single char Peek().
+ /// Throw error is eof is true
+ /// </summary>
+ /// <param name="length">Length.</param>
protected virtual string Peek(int length) {
if (eof)
throw new ParsingException (this, "Unexpected End of File");
return "";
return buffer [currentLine].Substring (currentColumn, lg);
}
+ /// <summary>
+ /// read one char from buffer at current position, if '\n' is read, current line is incremented
+ /// and column is reset to 0
+ /// </summary>
protected virtual char Read() {
char c = Peek ();
-
+ //TODO: the parsing is done line by line, we should be able to remove the next line handling from read
if (c == '\n') {
currentLine++;
if (currentLine >= buffer.Length)
currentColumn++;
return c;
}
+ /// <summary>
+ /// read until end of line is reached
+ /// </summary>
+ /// <returns>string read</returns>
protected virtual string ReadLine () {
string tmp = "";
while (!eof) {
}
return tmp;
}
+ /// <summary>
+ /// read until end expression is reached or end of line.
+ /// </summary>
+ /// <returns>string read minus the ending expression that has to be read after</returns>
+ /// <param name="endExp">Expression to search for</param>
protected virtual string ReadLineUntil (string endExp){
string tmp = "";
}
return tmp;
}
+ /// <summary>
+ /// skip white spaces, but not line break. Save spaces in a WhiteSpace token.
+ /// </summary>
protected void SkipWhiteSpaces () {
if (currentTok.Type != TokenType.Unknown)
throw new ParsingException (this, "current token should be reset to unknown (0) before skiping white spaces");
using System.Linq;
using System.Diagnostics;
using CrowEdit;
+using System.IO;
namespace Crow.Coding
{
}
#region private and protected fields
+ string filePath = "unamed.txt";
+ int leftMargin = 0; //margin used to display line numbers, folding errors,etc...
int visibleLines = 1;
int visibleColumns = 1;
CodeBuffer buffer;
}
RegisterForGraphicUpdate ();
}
+
#region Buffer events handlers
void Buffer_BufferCleared (object sender, EventArgs e)
{
#endregion
#region Public Crow Properties
- [XmlAttributeAttribute][DefaultValue("label")]
- public string Text
+ [XmlAttributeAttribute]
+ public string FilePath
{
get {
return buffer == null ? "" : buffer.FullText;
}
set
{
- if (string.Equals (value, buffer?.FullText, StringComparison.Ordinal))
+ if (filePath == value)
+ return;
+
+ filePath = value;
+ NotifyValueChanged ("FilePath", filePath);
+
+ if (!File.Exists (filePath))
return;
- buffer.Load (value);
+ using (StreamReader sr = new StreamReader (filePath)) {
+ string txt = sr.ReadToEnd ();
+ buffer.Load (txt);
+ }
MaxScrollY = Math.Max (0, buffer.Length - visibleLines);
MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns);
- OnTextChanged (this, null);
RegisterForGraphicUpdate ();
}
}
/// <returns><c>true</c> if move succeed</returns>
public bool MoveLeft(){
bool res = buffer.MoveLeft();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
return res;
}
/// <summary>
/// <returns><c>true</c> if move succeed</returns>
public bool MoveRight(){
bool res = buffer.MoveRight();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
return res;
}
public void GotoWordStart(){
buffer.GotoWordStart();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
}
public void GotoWordEnd(){
buffer.GotoWordEnd();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
}
public void DeleteChar()
{
if (!selectionIsEmpty)
buffer.SetSelection (selectionStart, selectionEnd);
buffer.DeleteChar ();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
SelBegin = -1;
SelRelease = -1;
OnTextChanged (this, null);
DeleteChar ();
buffer.Insert (str);
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
OnTextChanged (this, null);
RegisterForGraphicUpdate();
protected void InsertLineBreak()
{
buffer.InsertLineBreak ();
- CurrentPosition = buffer.VisualPosition;
+ CurrentPosition = buffer.TabulatedPosition;
OnTextChanged (this, null);
}
#endregion
else
CurrentLine = ScrollY + (int)Math.Floor (mouseLocalPos.Y / fe.Height);
- CurrentPosition = buffer.VisualPosition; //for rounding if in middle of tabs
+ CurrentPosition = buffer.TabulatedPosition; //for rounding if in middle of tabs
}
public override void onMouseEnter (object sender, MouseMoveEventArgs e)
{
this.InsertLineBreak ();
break;
case Key.Escape:
- Text = "";
- CurrentColumn = 0;
SelRelease = -1;
break;
case Key.Home:
{
get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); }
}
-// public bool NameIsValid(string name)
-// {
-// if (!rxNameStartChar.IsMatch(char.ConvertFromUtf32(((string)name)[0])))
-// return false;
-//
-// return rxNameChar.IsMatch(name);
-// }
-// private bool NextCharIsValidPubidChar
-// {
-// get { return rxPubidChar.IsMatch(char.ConvertFromUtf32(Peek())); }
-// }
-// private bool AttributeValueIsValid(string name)
-// {
-// return string.IsNullOrEmpty(name) ? true : rxAttributeValue.IsMatch(name);
-// }
-// private bool NextCharIsValidEntityValue
-// {
-// get { return rxEntityValue.IsMatch(char.ConvertFromUtf32(Peek())); }
-// }
#endregion
public override void SetLineInError (ParsingException ex)
<HorizontalStack Height="Stretched" >
<SourceEditor Focusable="true" Name="editor" Font="couriernew, 14" VerticalAlignment="Top" Margin="10"
Foreground="Jet" Background="Ivory" Width="Stretched" Height="Stretched"
- Text="{Text}" KeyDown="textView_KeyDown"/>
+ FilePath="{CurFileFullPath}" KeyDown="textView_KeyDown"/>
<ScrollBar Name="scrollbarY" Value="{²../editor.ScrollY}"
Maximum="{../editor.MaxScrollY}" Orientation="Vertical"
Width="14" />