From 6b06e18698312259869f11c19a6b5bedcb3e1fae Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Mon, 28 Aug 2017 11:42:31 +0200 Subject: [PATCH] SourceEditor wip --- Crow.dll.config | 19 ++ CrowEdit.csproj | 22 +-- src/CrowWindow.cs => CrowWindow.cs | 13 +- ...rfaceControler.cs => InterfaceControler.cs | 2 +- packages.config | 2 +- src/CodeTextBuffer.cs | 88 +++++++++ src/CrowEdit.cs | 9 +- src/ScrollingObject.cs | 180 ------------------ src/{ScrollingTextBox.cs => SourceEditor.cs} | 175 ++++++++++------- src/SourceLine.cs | 156 +++++++++++++++ src/{TextBuffer.cs => Token.cs} | 34 +++- ui/main.crow | 8 +- 12 files changed, 434 insertions(+), 274 deletions(-) create mode 100644 Crow.dll.config rename src/CrowWindow.cs => CrowWindow.cs (98%) rename src/InterfaceControler.cs => InterfaceControler.cs (99%) create mode 100644 src/CodeTextBuffer.cs delete mode 100644 src/ScrollingObject.cs rename src/{ScrollingTextBox.cs => SourceEditor.cs} (77%) create mode 100644 src/SourceLine.cs rename src/{TextBuffer.cs => Token.cs} (61%) diff --git a/Crow.dll.config b/Crow.dll.config new file mode 100644 index 0000000..ef7562a --- /dev/null +++ b/Crow.dll.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/CrowEdit.csproj b/CrowEdit.csproj index b34a2c4..e3340b4 100644 --- a/CrowEdit.csproj +++ b/CrowEdit.csproj @@ -61,25 +61,23 @@ - - gtk-sharp-3.0 - - packages\Crow.OpenTK.0.5.1\lib\net45\Crow.dll + packages\Crow.OpenTK.0.5.4\lib\net45\Crow.dll + + + + + + + - - - - - - - + @@ -104,4 +102,4 @@ - \ No newline at end of file + diff --git a/src/CrowWindow.cs b/CrowWindow.cs similarity index 98% rename from src/CrowWindow.cs rename to CrowWindow.cs index b1308d1..e66fa7b 100644 --- a/src/CrowWindow.cs +++ b/CrowWindow.cs @@ -63,12 +63,13 @@ namespace Crow ValueChanged.Raise(this, new ValueChangeEventArgs ("fpsMin", fpsMin)); } #endif - if (frameCpt % 3 == 0) - ValueChanged.Raise(this, new ValueChangeEventArgs ("fps", _fps)); - #if MEASURE_TIME -// foreach (PerformanceMeasure m in PerfMeasures) -// m.NotifyChanges(); - #endif + if (frameCpt % 20 == 0) { + ValueChanged.Raise (this, new ValueChangeEventArgs ("fps", _fps)); + #if MEASURE_TIME + foreach (PerformanceMeasure m in ifaceControl[0].PerfMeasures) + m.NotifyChanges (); + #endif + } } } diff --git a/src/InterfaceControler.cs b/InterfaceControler.cs similarity index 99% rename from src/InterfaceControler.cs rename to InterfaceControler.cs index 4d988c1..4da65d1 100644 --- a/src/InterfaceControler.cs +++ b/InterfaceControler.cs @@ -162,7 +162,7 @@ namespace Crow while (true) { CrowInterface.Update (); - //Thread.Sleep (1); + Thread.Sleep (1); } } diff --git a/packages.config b/packages.config index 9875ed7..5740be9 100644 --- a/packages.config +++ b/packages.config @@ -1,5 +1,5 @@  - + diff --git a/src/CodeTextBuffer.cs b/src/CodeTextBuffer.cs new file mode 100644 index 0000000..988b9c3 --- /dev/null +++ b/src/CodeTextBuffer.cs @@ -0,0 +1,88 @@ +// +// CodeTextBuffer.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Crow +{ + public class CodeTextBuffer : List + { + public CodeTextBuffer () : base() + { + } + + public int longestLineIdx = 0; + public int longestLineCharCount = 0; + + public CodeTextBuffer (string rawSource) : this (){ + if (string.IsNullOrEmpty (rawSource)) + return; + string[] lines = Regex.Split (rawSource, "\r\n|\r|\n|\\\\n"); + for (int i = 0; i < lines.Length; i++) { + if (lines [i].Length > longestLineCharCount) { + longestLineCharCount = lines [i].Length; + longestLineIdx = i; + } + this.Add (new SourceLine ( lines [i] )); + } + } + + /// + /// return all lines with linebreaks + /// + public string FullText{ + get { + string tmp = ""; + foreach (SourceLine sl in this) + tmp += sl.RawText + Interface.LineBreak; + return tmp; + } + } + + public void Tokenize (int lineIndex) { + //handle multiline block comments + if (lineIndex > 0){ + if (this [lineIndex - 1].Tokens?.LastOrDefault ().Type == TokenType.BlockComment) + this [lineIndex].PresetCurrentToken (TokenType.BlockComment); + } + this [lineIndex].Tokenize (); + } + + public void InsertLine(int index, SourceLine line){ + base.Insert (index, line); + } + public void RemoveLine (int index) { + base.RemoveAt (index); + } + + //public void Tokenize (int lineIndex) { + // //handle multiline block comments + // if (lineIndex > 0){ + // if (this [lineIndex - 1].Tokens?.LastOrDefault ().Type == TokenType.BlockComment) + // this [lineIndex].PresetCurrentToken (TokenType.BlockComment); + // } + // this [lineIndex].Tokenize (); + //} + } +} + diff --git a/src/CrowEdit.cs b/src/CrowEdit.cs index 1e0323f..ea9ef6b 100644 --- a/src/CrowEdit.cs +++ b/src/CrowEdit.cs @@ -54,11 +54,11 @@ namespace CrowEdit public bool IsDirty { get { return _text != _origText; }} public string CurrentDir { - get { return _curDir; } + get { return Configuration.Get("CurrentDir"); } set { - if (_curDir == value) + if (CurrentDir == value) return; - _curDir = value; + Configuration.Set ("CurrentDir", value); NotifyValueChanged ("CurrentDir", _curDir); } } @@ -190,6 +190,9 @@ namespace CrowEdit { base.OnLoad (e); + if (CurrentDir == null) + CurrentDir = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); + this.ValueChanged += CrowEdit_ValueChanged; initCommands (); diff --git a/src/ScrollingObject.cs b/src/ScrollingObject.cs deleted file mode 100644 index f0463ae..0000000 --- a/src/ScrollingObject.cs +++ /dev/null @@ -1,180 +0,0 @@ -// -// ScrollingObject.cs -// -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2013-2017 Jean-Philippe Bruyère -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using System.Xml.Serialization; -using System.ComponentModel; -using System.Collections; -using Cairo; - - -namespace Crow -{ - public class ScrollingObject : GraphicObject - { - #region CTOR - public ScrollingObject ():base() - { - } - #endregion - - int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed; - - /// Horizontal Scrolling Position - [XmlAttributeAttribute][DefaultValue(0)] - public virtual int ScrollX { - get { return scrollX; } - set { - if (scrollX == value) - return; - - int newS = value; - if (newS < 0) - newS = 0; - else if (newS > maxScrollX) - newS = maxScrollX; - - if (newS == scrollX) - return; - - scrollX = value; - - NotifyValueChanged ("ScrollX", scrollX); - RegisterForGraphicUpdate (); - } - } - /// Vertical Scrolling Position - [XmlAttributeAttribute][DefaultValue(0)] - public virtual int ScrollY { - get { return scrollY; } - set { - if (scrollY == value) - return; - - int newS = value; - if (newS < 0) - newS = 0; - else if (newS > maxScrollY) - newS = maxScrollY; - - if (newS == scrollY) - return; - - scrollY = value; - - NotifyValueChanged ("ScrollY", scrollY); - RegisterForGraphicUpdate (); - } - } - /// Horizontal Scrolling maximum value - [XmlAttributeAttribute][DefaultValue(0)] - public virtual int MaxScrollX { - get { return maxScrollX; } - set { - if (maxScrollX == value) - return; - - maxScrollX = value; - - if (scrollX > maxScrollX) - ScrollX = maxScrollX; - - NotifyValueChanged ("MaxScrollX", maxScrollX); - RegisterForGraphicUpdate (); - } - } - /// Vertical Scrolling maximum value - [XmlAttributeAttribute][DefaultValue(0)] - public virtual int MaxScrollY { - get { return maxScrollY; } - set { - if (maxScrollY == value) - return; - - maxScrollY = value; - - if (scrollY > maxScrollY) - ScrollY = maxScrollY; - - NotifyValueChanged ("MaxScrollY", maxScrollY); - RegisterForGraphicUpdate (); - } - } - /// Mouse Wheel Scrolling multiplier - [XmlAttributeAttribute][DefaultValue(1)] - public virtual int MouseWheelSpeed { - get { return mouseWheelSpeed; } - set { - if (mouseWheelSpeed == value) - return; - - mouseWheelSpeed = value; - - NotifyValueChanged ("MouseWheelSpeed", mouseWheelSpeed); - } - } - - /// Process scrolling vertically, or if shift is down, vertically - public override void onMouseWheel (object sender, MouseWheelEventArgs e) - { - base.onMouseWheel (sender, e); - if (CurrentInterface.Keyboard.IsKeyDown (Key.ShiftLeft)) - ScrollX -= e.Delta * MouseWheelSpeed; - else - ScrollY -= e.Delta * MouseWheelSpeed; - - } - /// Process scrolling with arrow keys, home and end keys. - public override void onKeyDown (object sender, KeyboardKeyEventArgs e) - { - base.onKeyDown (sender, e); - - switch (e.Key) { - case Key.Up: - ScrollY--; - break; - case Key.Down: - ScrollY++; - break; - case Key.Left: - ScrollX--; - break; - case Key.Right: - ScrollX++; - break; - case Key.Home: - ScrollX = 0; - ScrollY = 0; - break; - case Key.End: - ScrollX = MaxScrollX; - ScrollY = MaxScrollY; - break; - } - } - } -} - diff --git a/src/ScrollingTextBox.cs b/src/SourceEditor.cs similarity index 77% rename from src/ScrollingTextBox.cs rename to src/SourceEditor.cs index a9b429a..8f1748e 100644 --- a/src/ScrollingTextBox.cs +++ b/src/SourceEditor.cs @@ -33,16 +33,17 @@ using System.Text; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Linq; +using System.Diagnostics; namespace Crow { /// /// Scrolling text box optimized for monospace fonts, for coding /// - public class ScrollingTextBox : ScrollingObject + public class SourceEditor : ScrollingObject { #region CTOR - public ScrollingTextBox ():base() + public SourceEditor ():base() { @@ -59,11 +60,11 @@ namespace Crow #region private and protected fields string lineBreak = Interface.LineBreak; int visibleLines = 1; - List lines; + int visibleColumns = 1; + CodeTextBuffer buffer; string _text = "label"; Color selBackground; Color selForeground; - Point mouseLocalPos = 0;//mouse coord in widget space int _currentCol; //0 based cursor position in string int _currentLine; Point _selBegin = -1; //selection start (row,column) @@ -78,8 +79,8 @@ namespace Crow public string Text { get { - return lines == null ? - _text : lines.Aggregate((i, j) => i + Interface.LineBreak + j); + return buffer == null ? + _text : buffer.FullText; } set { @@ -91,8 +92,9 @@ namespace Crow if (string.IsNullOrEmpty(_text)) _text = ""; - lines = getLines; - MaxScrollY = Math.Max (0, lines.Count - visibleLines); + buffer = new CodeTextBuffer (_text); + MaxScrollY = Math.Max (0, buffer.Count - visibleLines); + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); OnTextChanged (this, null); RegisterForGraphicUpdate (); @@ -130,10 +132,16 @@ namespace Crow return; if (value < 0) _currentCol = 0; - else if (value > lines [_currentLine].Length) - _currentCol = lines [_currentLine].Length; + else if (value > buffer [_currentLine].Length) + _currentCol = buffer [_currentLine].Length; else _currentCol = value; + + if (_currentCol < ScrollX) + ScrollX = _currentCol; + else if (_currentCol >= ScrollX + visibleColumns) + ScrollX = _currentCol - visibleColumns + 1; + NotifyValueChanged ("CurrentColumn", _currentCol); } } @@ -143,8 +151,8 @@ namespace Crow set { if (value == _currentLine) return; - if (value >= lines.Count) - _currentLine = lines.Count-1; + if (value >= buffer.Count) + _currentLine = buffer.Count-1; else if (value < 0) _currentLine = 0; else @@ -153,6 +161,11 @@ namespace Crow int cc = _currentCol; _currentCol = 0; CurrentColumn = cc; + //System.Diagnostics.Debug.WriteLine ("Scroll:{0} visibleLines:{1} CurLine:{2}", ScrollY, visibleLines, CurrentLine); + if (_currentLine < ScrollY) + ScrollY = _currentLine; + else if (_currentLine >= ScrollY + visibleLines) + ScrollY = _currentLine - visibleLines + 1; NotifyValueChanged ("CurrentLine", _currentLine); } } @@ -197,7 +210,7 @@ namespace Crow [XmlIgnore]protected Char CurrentChar { get { - return lines [CurrentLine] [CurrentColumn]; + return buffer [CurrentLine] [CurrentColumn]; } } /// @@ -226,13 +239,13 @@ namespace Crow if (SelRelease < 0 || SelBegin < 0) return ""; if (selectionStart.Y == selectionEnd.Y) - return lines [selectionStart.Y].Substring (selectionStart.X, selectionEnd.X - selectionStart.X); + return buffer [selectionStart.Y].RawText.Substring (selectionStart.X, selectionEnd.X - selectionStart.X); string tmp = ""; - tmp = lines [selectionStart.Y].Substring (selectionStart.X); + tmp = buffer [selectionStart.Y].RawText.Substring (selectionStart.X); for (int l = selectionStart.Y + 1; l < selectionEnd.Y; l++) { - tmp += Interface.LineBreak + lines [l]; + tmp += Interface.LineBreak + buffer [l]; } - tmp += Interface.LineBreak + lines [selectionEnd.Y].Substring (0, selectionEnd.X); + tmp += Interface.LineBreak + buffer [selectionEnd.Y].RawText.Substring (0, selectionEnd.X); return tmp; } } @@ -265,8 +278,8 @@ namespace Crow /// true if move succeed public bool MoveRight(){ int tmp = _currentCol + 1; - if (tmp > lines [_currentLine].Length){ - if (CurrentLine == lines.Count - 1) + if (tmp > buffer [_currentLine].Length){ + if (CurrentLine == buffer.Count - 1) return false; CurrentLine++; CurrentColumn = 0; @@ -275,24 +288,24 @@ namespace Crow return true; } public void GotoWordStart(){ - if (lines[CurrentLine].Length == 0) + if (buffer[CurrentLine].Length == 0) return; CurrentColumn--; //skip white spaces while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) CurrentColumn--; - while (char.IsLetterOrDigit (lines [CurrentLine] [CurrentColumn]) && CurrentColumn > 0) + while (char.IsLetterOrDigit (buffer [CurrentLine] [CurrentColumn]) && CurrentColumn > 0) CurrentColumn--; if (!char.IsLetterOrDigit (this.CurrentChar)) CurrentColumn++; } public void GotoWordEnd(){ //skip white spaces - if (CurrentColumn >= lines [CurrentLine].Length - 1) + if (CurrentColumn >= buffer [CurrentLine].Length - 1) return; - while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1) + while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < buffer [CurrentLine].Length-1) CurrentColumn++; - while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1) + while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < buffer [CurrentLine].Length-1) CurrentColumn++; if (char.IsLetterOrDigit (this.CurrentChar)) CurrentColumn++; @@ -301,31 +314,31 @@ namespace Crow { if (selectionIsEmpty) { if (CurrentColumn == 0) { - if (CurrentLine == 0 && lines.Count == 1) + if (CurrentLine == 0 && buffer.Count == 1) return; CurrentLine--; - CurrentColumn = lines [CurrentLine].Length; - lines [CurrentLine] += lines [CurrentLine + 1]; - lines.RemoveAt (CurrentLine + 1); + CurrentColumn = buffer [CurrentLine].Length; + buffer [CurrentLine].RawText += buffer [CurrentLine + 1].RawText; + buffer.RemoveLine (CurrentLine + 1); OnTextChanged (this, null); return; } CurrentColumn--; - lines [CurrentLine] = lines [CurrentLine].Remove (CurrentColumn, 1); + buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Remove (CurrentColumn, 1); } else { int linesToRemove = selectionEnd.Y - selectionStart.Y + 1; int l = selectionStart.Y; if (linesToRemove > 0) { - lines [l] = lines [l].Remove (selectionStart.X, lines [l].Length - selectionStart.X) + - lines [selectionEnd.Y].Substring (selectionEnd.X, lines [selectionEnd.Y].Length - selectionEnd.X); + buffer [l].RawText = buffer [l].RawText.Remove (selectionStart.X, buffer [l].Length - selectionStart.X) + + buffer [selectionEnd.Y].RawText.Substring (selectionEnd.X, buffer [selectionEnd.Y].Length - selectionEnd.X); l++; for (int c = 0; c < linesToRemove-1; c++) - lines.RemoveAt (l); + buffer.RemoveLine (l); CurrentLine = selectionStart.Y; CurrentColumn = selectionStart.X; } else - lines [l] = lines [l].Remove (selectionStart.X, selectionEnd.X - selectionStart.X); + buffer [l].RawText = buffer [l].RawText.Remove (selectionStart.X, selectionEnd.X - selectionStart.X); CurrentColumn = selectionStart.X; SelBegin = -1; SelRelease = -1; @@ -354,7 +367,7 @@ namespace Crow protected override int measureRawSize(LayoutingType lt) { if (lt == LayoutingType.Height) - return (int)Math.Ceiling(fe.Height * lines.Count) + Margin * 2; + return (int)Math.Ceiling(fe.Height * buffer.Count) + Margin * 2; string txt = _text.Replace("\t", new String (' ', Interface.TabSize)); @@ -372,6 +385,8 @@ namespace Crow if (layoutType == LayoutingType.Height) updateVisibleLines (); + else if (layoutType == LayoutingType.Width) + updateVisibleColumns (); } protected override void onDraw (Context gr) { @@ -388,12 +403,13 @@ namespace Crow bool selectionInProgress = false; + Foreground.SetAsSource (gr); + #region draw text cursor if (SelBegin != SelRelease) selectionInProgress = true; else if (HasFocus){ - gr.SetSourceColor(Color.Red); - gr.LineWidth = 2.0; + gr.LineWidth = 1.0; double cursorX = cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; gr.MoveTo (0.5 + cursorX, cb.Y + (CurrentLine - ScrollY) * fe.Height); gr.LineTo (0.5 + cursorX, cb.Y + (CurrentLine + 1 - ScrollY) * fe.Height); @@ -401,13 +417,15 @@ namespace Crow } #endregion - Foreground.SetAsSource (gr); - for (int i = 0; i < visibleLines; i++) { int curL = i + ScrollY; - if (curL >= lines.Count) + if (curL >= buffer.Count) break; - string lstr = lines[curL]; + string lstr = buffer[curL].RawText; + if (ScrollX < lstr.Length) + lstr = lstr.Substring (ScrollX); + else + lstr = ""; gr.MoveTo (cb.X, cb.Y + fe.Ascent + fe.Height * i); gr.ShowText (lstr); @@ -416,12 +434,12 @@ namespace Crow if (selectionInProgress && curL >= selectionStart.Y && curL <= selectionEnd.Y) { double rLineX = cb.X, - rLineY = cb.Y + i * fe.Height, - rLineW = lstr.Length * fe.MaxXAdvance; + rLineY = cb.Y + i * fe.Height, + rLineW = lstr.Length * fe.MaxXAdvance; System.Diagnostics.Debug.WriteLine ("sel start: " + selectionStart + " sel end: " + selectionEnd); if (curL == selectionStart.Y) { - rLineX += selectionStart.X * fe.MaxXAdvance; + rLineX += (selectionStart.X - ScrollX) * fe.MaxXAdvance; rLineW -= selectionStart.X * fe.MaxXAdvance; } if (curL == selectionEnd.Y) @@ -446,39 +464,41 @@ namespace Crow #region Mouse handling void updatemouseLocalPos(Point mpos){ - mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; + Point mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; if (mouseLocalPos.X < 0) - mouseLocalPos.X = 0; - if (mouseLocalPos.Y < 0) - mouseLocalPos.Y = 0; + CurrentColumn--; + else + CurrentColumn = ScrollX + (int)Math.Round (mouseLocalPos.X / fe.MaxXAdvance); - CurrentLine = ScrollY + (int)Math.Floor (mouseLocalPos.Y / fe.Height); - CurrentColumn = ScrollX + (int)Math.Round (mouseLocalPos.X / fe.MaxXAdvance); + if (mouseLocalPos.Y < 0) + CurrentLine--; + else + CurrentLine = ScrollY + (int)Math.Floor (mouseLocalPos.Y / fe.Height); } public override void onMouseEnter (object sender, MouseMoveEventArgs e) { base.onMouseEnter (sender, e); - CurrentInterface.MouseCursor = XCursor.Text; + currentInterface.MouseCursor = XCursor.Text; } public override void onMouseLeave (object sender, MouseMoveEventArgs e) { base.onMouseLeave (sender, e); - CurrentInterface.MouseCursor = XCursor.Default; + currentInterface.MouseCursor = XCursor.Default; } protected override void onFocused (object sender, EventArgs e) { base.onFocused (sender, e); -// SelBegin = new Point(0,0); -// SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1); + // SelBegin = new Point(0,0); + // SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1); RegisterForRedraw (); } protected override void onUnfocused (object sender, EventArgs e) { base.onUnfocused (sender, e); -// SelBegin = -1; -// SelRelease = -1; + // SelBegin = -1; + // SelRelease = -1; RegisterForRedraw (); } public override void onMouseMove (object sender, MouseMoveEventArgs e) @@ -531,7 +551,7 @@ namespace Crow #region Keyboard handling public override void onKeyDown (object sender, KeyboardKeyEventArgs e) { - base.onKeyDown (sender, e); + //base.onKeyDown (sender, e); Key key = e.Key; @@ -549,7 +569,7 @@ namespace Crow if (!MoveRight ()) return; }else if (e.Shift) - CurrentInterface.Clipboard = this.SelectedText; + currentInterface.Clipboard = this.SelectedText; this.DeleteChar (); break; case Key.Enter: @@ -595,9 +615,9 @@ namespace Crow break; case Key.Insert: if (e.Shift) - this.Insert (CurrentInterface.Clipboard); + this.Insert (currentInterface.Clipboard); else if (e.Control && !selectionIsEmpty) - CurrentInterface.Clipboard = this.SelectedText; + currentInterface.Clipboard = this.SelectedText; break; case Key.Left: if (e.Shift) { @@ -660,8 +680,25 @@ namespace Crow case Key.NumLock: break; case Key.PageDown: + if (e.Shift) { + if (selectionIsEmpty) + SelBegin = CurrentPosition; + CurrentLine += visibleLines; + SelRelease = CurrentPosition; + break; + } + SelRelease = -1; + CurrentLine += visibleLines; break; case Key.PageUp: + if (e.Shift) { + if (selectionIsEmpty) + SelBegin = CurrentPosition; + CurrentLine -= visibleLines; + SelRelease = CurrentPosition; + break; + } + CurrentLine -= visibleLines; break; case Key.RWin: break; @@ -691,7 +728,7 @@ namespace Crow double GetXFromTextPointer(Context gr, Point pos) { try { - string l = lines [pos.Y].Substring (0, pos.X). + string l = buffer [pos.Y].RawText.Substring (0, pos.X). Replace ("\t", new String (' ', Interface.TabSize)); return gr.TextExtents (l).XAdvance; } catch{ @@ -726,11 +763,19 @@ namespace Crow void updateVisibleLines(){ visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / fe.Height); - MaxScrollY = Math.Max (0, lines.Count - visibleLines); + MaxScrollY = Math.Max (0, buffer.Count - visibleLines); System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); } + void updateVisibleColumns(){ + visibleColumns = (int)Math.Floor ((double)ClientRectangle.Width / fe.MaxXAdvance); + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + + System.Diagnostics.Debug.WriteLine ("update visible columns: " + visibleColumns); + System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); + } + /// @@ -742,11 +787,11 @@ namespace Crow if (!selectionIsEmpty) this.DeleteChar (); string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray(); - lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[0]); + buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Insert (CurrentColumn, strLines[0]); CurrentColumn += strLines[0].Length; for (int i = 1; i < strLines.Length; i++) { InsertLineBreak (); - lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[i]); + buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Insert (CurrentColumn, strLines[i]); CurrentColumn += strLines[i].Length; } OnTextChanged (this, null); @@ -758,8 +803,8 @@ namespace Crow /// protected void InsertLineBreak() { - lines.Insert(CurrentLine + 1, lines[CurrentLine].Substring(CurrentColumn)); - lines [CurrentLine] = lines [CurrentLine].Substring (0, CurrentColumn); + buffer.InsertLine(CurrentLine + 1, new SourceLine (buffer[CurrentLine].RawText.Substring(CurrentColumn))); + buffer [CurrentLine].RawText = buffer [CurrentLine].RawText.Substring (0, CurrentColumn); CurrentLine++; CurrentColumn = 0; OnTextChanged (this, null); diff --git a/src/SourceLine.cs b/src/SourceLine.cs new file mode 100644 index 0000000..cb777c6 --- /dev/null +++ b/src/SourceLine.cs @@ -0,0 +1,156 @@ +// +// SourceLine.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2017 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; + +namespace Crow +{ + /// + /// basic structure for line of source code + /// + public class SourceLine + { + public string RawText; + public List Tokens = null; + + public int Length { + get { return string.IsNullOrEmpty (RawText)? 0 : RawText.Length; } + } + public char this[int index]{ + get { return RawText [index]; } + + } + int ptr; //character pointer in the source string + Token tok; //current token parsed before addition to the token list + + public SourceLine () + { + } + public SourceLine (string rawText){ + RawText = rawText; + } + + /// + /// Tokenize this instance. + /// This tokenization step is used for display mainly, so literals are not interpreted + /// + public bool Tokenize(){ + Tokens = new List(); + ptr = 0; + + while (!eol) { + Char c = readChar (); + + //block comments + if (tok?.Type == TokenType.BlockComment) { + tok.Content += c; + if (c == '*') { + if (peekChar () == '/') { + tok.Content += readChar (); + saveCurTok (); + } + } + continue; + } else if (tok?.Type == TokenType.StringLiteral) { + tok.Content += c; + if (c == '\\')//may escape " char, so next char is read; + tok.Content += readChar (); + else if (c == '"') + saveCurTok (); + continue; + } else if (tok?.Type == TokenType.CharacterLiteral) { + tok.Content += c; + if (c == '\\')//may escape ' char, so next char is read; + tok.Content += readChar (); + else if (c == '\'') + saveCurTok (); + continue; + } else if (tok?.Type == TokenType.WhiteSpace) { + if (char.IsWhiteSpace (c)) { + tok.Content += c; + continue; + } + saveCurTok (); + //if (char.IsLetter (c)) + + } + + //single char tokens + if (c == '{') + tok.Type = TokenType.OpenBlock; + else if (c == '}') + tok.Type = TokenType.CloseBlock; + else if (c == '(') + tok.Type = TokenType.OpenParenth; + else if (c == ')') + tok.Type = TokenType.CloseParenth; + + + if (tok == null) { + tok = new Token () { Content = new string (c, 1) }; + + if (char.IsWhiteSpace (c)) + tok.Type = TokenType.WhiteSpace; + else if (char.IsDigit (c)) + tok.Type = TokenType.DigitalLiteral; + else if (char.IsLetter (c)) + tok.Type = TokenType.Unknown; + else if (c == '"') + tok.Type = TokenType.StringLiteral; + else {//put here all single step parsing token, reseting tok directely + saveCurTok (); + } + } + + + + ptr++; + } + return true; + } + /// add tok to token list and reset it to null + void saveCurTok(){ + Tokens.Add (tok); + tok = null; + } + public void PresetCurrentToken (TokenType tokType, string content = null){ + tok = new Token (tokType,content); + } + + bool eol { get { return ptr < RawText.Length; }} + char readChar() { + char c = RawText [ptr]; + ptr++; + return c; + } + char peekChar() { + return RawText [ptr]; + } + +// public static implicit operator SourceLine(string rawText){ +// return new SourceLine() { RawText = rawText }; +// } +// public static implicit operator string(SourceLine sl){ +// return sl?.RawText; +// } + } +} + diff --git a/src/TextBuffer.cs b/src/Token.cs similarity index 61% rename from src/TextBuffer.cs rename to src/Token.cs index f4afe8e..7639ca2 100644 --- a/src/TextBuffer.cs +++ b/src/Token.cs @@ -1,5 +1,5 @@ // -// TextBuffer.cs +// Token.cs // // Author: // Jean-Philippe Bruyère @@ -22,11 +22,39 @@ using System; namespace Crow { - public class TextBuffer + public enum TokenType { + Unknown, + WhiteSpace, + OpenParenth, + CloseParenth, + OpenBlock, + CloseBlock, + StatementEnding, + UnaryOp, + BinaryOp, + Affectation, + StringLiteral, + CharacterLiteral, + DigitalLiteral, + Literal, + Identifier, + Indexer, + Type, + LineComment, + BlockComment, + } + public class Token { - public TextBuffer () + public TokenType Type; + public string Content; + + public Token () { } + public Token (TokenType tokType, string content = null){ + Type = tokType; + Content = content; + } } } diff --git a/ui/main.crow b/ui/main.crow index 84f1700..981b5ca 100755 --- a/ui/main.crow +++ b/ui/main.crow @@ -21,9 +21,9 @@ - - + \ No newline at end of file -- 2.47.3