From: Jean-Philippe Bruyère Date: Sat, 10 Mar 2018 05:03:25 +0000 (+0100) Subject: getStremFromPath made instanced for overriding in designiface, crowide wip X-Git-Tag: 0.7.3~4^2~14 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=407690e9b8a2693a7bd831e954c079cb26c569b7;p=jp%2Fcrow.git getStremFromPath made instanced for overriding in designiface, crowide wip --- diff --git a/CrowIDE/CrowIDE.csproj b/CrowIDE/CrowIDE.csproj index 4f48ad0e..399e0d99 100644 --- a/CrowIDE/CrowIDE.csproj +++ b/CrowIDE/CrowIDE.csproj @@ -70,7 +70,6 @@ - @@ -94,36 +93,40 @@ src\InterfaceControler.cs - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + + + + @@ -141,10 +144,6 @@ Crow.TreeExpandable.template - - Crow.Coding.EditPane.template - - @@ -164,8 +163,6 @@ Crow.MenuItem.template - - @@ -255,7 +252,27 @@ - + + Crow.ContextMenu.template + + + Crow.Coding.EditPane.template + + + Crow.Coding.ui.EditPaneItems.template + + + Crow.Coding.ui.IMLEdit.itemp + + + Crow.Coding.ui.SourceEditor.crow + + + Crow.Coding.ui.SrcEdit.itemp + + + Crow.Coding.ui.SvgEdit.itemp + diff --git a/CrowIDE/icons/compile.svg b/CrowIDE/icons/compile.svg index 3f6ed2be..c1a14e77 100644 --- a/CrowIDE/icons/compile.svg +++ b/CrowIDE/icons/compile.svg @@ -2,8 +2,8 @@ - - - - + + + + diff --git a/CrowIDE/src/CrowIDE.cs b/CrowIDE/src/CrowIDE.cs index a5e8c249..588700b8 100644 --- a/CrowIDE/src/CrowIDE.cs +++ b/CrowIDE/src/CrowIDE.cs @@ -38,7 +38,7 @@ namespace Crow.Coding { class CrowIDE : CrowWindow { - public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, CMDQuit, + public Command CMDNew, CMDOpen, CMDSave, CMDSaveAs, cmdCloseSolution, CMDQuit, CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions, CMDViewGTExp, CMDViewProps, CMDViewProj, CMDViewProjProps, CMDViewErrors, CMDViewSolution, CMDViewEditor, CMDViewProperties, @@ -59,6 +59,8 @@ namespace Crow.Coding CMDHelp = new Command(new Action(() => System.Diagnostics.Debug.WriteLine("help"))) { Caption = "Help", Icon = new SvgPicture("#Crow.Coding.ui.icons.question.svg")}; CMDOptions = new Command(new Action(() => openOptionsDialog())) { Caption = "Editor Options", Icon = new SvgPicture("#Crow.Coding.ui.icons.tools.svg")}; + cmdCloseSolution = new Command(new Action(() => closeSolution())) { Caption = "Close Solution", Icon = new SvgPicture("#Crow.Coding.ui.icons.paste-on-document.svg"), CanExecute = true}; + CMDViewErrors = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winErrors.crow"))) { Caption = "Errors pane"}; CMDViewSolution = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winSolution.crow"))) @@ -70,7 +72,7 @@ namespace Crow.Coding CMDViewToolbox = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winToolbox.crow"))) { Caption = "Toolbox"}; - CMDViewGTExp = new Command(new Action(() => loadWindow ("#Crow.Coding.ui.GTreeExplorer.crow"))) { Caption = "Graphic Tree Explorer"}; + CMDViewGTExp = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.GTreeExplorer.crow"))) { Caption = "Graphic Tree Explorer"}; CMDViewProps = new Command(new Action(() => loadWindow ("#Crow.Coding.ui.MemberView.crow"))) { Caption = "Properties View"}; CMDCompile = new Command(new Action(() => compileSolution())) { Caption = "Compile"}; CMDViewProj = new Command(new Action(() => loadWindow ("#Crow.Coding.ui.CSProjExplorer.crow"))) { Caption = "Project Explorer"}; @@ -85,7 +87,11 @@ namespace Crow.Coding void saveFileDialog() {} void undo() {} void redo() {} - + void closeSolution (){ + if (currentSolution != null) + currentSolution.CloseSolution (); + CurrentSolution = null; + } [STAThread] static void Main () @@ -166,7 +172,9 @@ namespace Crow.Coding if (currentSolution == value) return; currentSolution = value; - NotifyValueChanged ("CurrentSolution", currentSolution); + lock (MainIFace) { + NotifyValueChanged ("CurrentSolution", currentSolution); + } } } diff --git a/CrowIDE/src/DesignInterface.cs b/CrowIDE/src/DesignInterface.cs index 3c1abf01..4178e398 100644 --- a/CrowIDE/src/DesignInterface.cs +++ b/CrowIDE/src/DesignInterface.cs @@ -29,6 +29,7 @@ using System.Globalization; using System.Threading; using System.Collections.Generic; using System.Diagnostics; +using System.IO; namespace Crow.Coding { @@ -80,6 +81,16 @@ namespace Crow.Coding System.Diagnostics.Debugger.Break (); return null; } + public override System.IO.Stream GetStreamFromPath (string path) + { + ProjectFile pi; + if (ProjFile.Project.solution.GetProjectFileFromPath (path, out pi)) { + return new FileStream (pi.AbsolutePath, FileMode.Open); + } + + Console.WriteLine ("File not found: {0}", path); + return null; + } public override bool ProcessMouseMove (int x, int y) { int deltaX = x - Mouse.X; @@ -171,7 +182,7 @@ namespace Crow.Coding LayoutingQueueItem lqi; while (LayoutingQueue.Count > 0) { lqi = LayoutingQueue.Dequeue (); - Console.WriteLine (lqi.ToString ()); + //Console.WriteLine (lqi.ToString ()); #if DEBUG_LAYOUTING currentLQI = lqi; curLQIsTries.Add(currentLQI); diff --git a/CrowIDE/src/EditPane.cs b/CrowIDE/src/EditPane.cs deleted file mode 100644 index a75522f0..00000000 --- a/CrowIDE/src/EditPane.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// EditPane.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 Crow; -using System.Linq; - -namespace Crow.Coding -{ - public class EditPane : TemplatedGroup - { - public EditPane () {} - - object selectedItemElement = null; - - public override int SelectedIndex { - get { - return base.SelectedIndex; - } - set { - base.SelectedIndex = value; - } - } - public object SelectedItemElement { - get { return selectedItemElement; } - set { - if (selectedItemElement == value) - return; - selectedItemElement = value; - NotifyValueChanged ("SelectedItemElement", selectedItemElement); - } - } - } -} - diff --git a/CrowIDE/src/Editor.cs b/CrowIDE/src/Editor.cs deleted file mode 100644 index 41aa6069..00000000 --- a/CrowIDE/src/Editor.cs +++ /dev/null @@ -1,104 +0,0 @@ -// -// Editor.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.Threading; -using System.Xml.Serialization; - -namespace Crow.Coding -{ - public abstract class Editor : ScrollingObject - { - #region CTOR - protected Editor ():base(){ - Thread t = new Thread (backgroundThreadFunc); - t.IsBackground = true; - t.Start (); - } - #endregion - - protected ReaderWriterLockSlim editorMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - protected ProjectFile projFile = null; - Exception error = null; - - public virtual ProjectFile ProjectNode - { - get { return projFile; } - set - { - if (projFile == value) - return; - - if (projFile != null) - projFile.UnregisterEditor (this); - - projFile = value; - - if (projFile != null) - projFile.RegisterEditor (this); - - NotifyValueChanged ("ProjectNode", projFile); - } - } - [XmlIgnore]public Exception Error { - get { return error; } - set { - if (error == value) - return; - error = value; - NotifyValueChanged ("Error", error); - NotifyValueChanged ("HasError", HasError); - } - } - [XmlIgnore]public bool HasError { - get { return error != null; } - } - - protected abstract void updateEditorFromProjFile (); - protected abstract void updateProjFileFromEditor (); - protected abstract bool EditorIsDirty { get; set; } - protected virtual bool IsReady { get { return true; }} - protected virtual void updateCheckPostProcess () {} - - protected void backgroundThreadFunc () { - while (true) { - if (IsReady) { - if (projFile != null) { - if (!projFile.RegisteredEditors [this]) { - projFile.RegisteredEditors [this] = true; - updateEditorFromProjFile (); - } else if (EditorIsDirty) { - EditorIsDirty = false; - updateProjFileFromEditor (); - } - updateCheckPostProcess (); - } - } - Thread.Sleep (50); - } - } - } -} - diff --git a/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs b/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs new file mode 100644 index 00000000..13c422a6 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs @@ -0,0 +1,528 @@ +// +// 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; +using System.Diagnostics; +using System.Threading; + +namespace Crow.Coding +{ + /// + /// Code buffer, lines are arranged in a List, new line chars are removed during string.split on '\n...', + /// + public class CodeBuffer + { + public ReaderWriterLockSlim editMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + + //those events are handled in SourceEditor to help keeping sync between textbuffer,parser and editor. + //modified lines are marked for reparse + #region Events + public event EventHandler LineUpadateEvent; + public event EventHandler LineRemoveEvent; + public event EventHandler LineAdditionEvent; + public event EventHandler FoldingEvent; + public event EventHandler BufferCleared; + public event EventHandler SelectionChanged; + public event EventHandler PositionChanged; + #endregion + + string lineBreak = Interface.LineBreak; + List lines = new List(); + public int longestLineIdx = 0; + public int longestLineCharCount = 0; + /// + /// real position in char arrays, tab = 1 char + /// + int _currentLine = 0; + int _currentCol = 0; + + public int LineCount { get { return lines.Count;}} + public int IndexOf (CodeLine cl) { + return lines.IndexOf (cl); + } + + public CodeLine this[int i] + { + get { return lines[i]; } + set { + if (lines [i] == value) + return; + editMutex.EnterWriteLock (); + lines [i] = value; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + } + + public void RemoveAt(int i){ + editMutex.EnterWriteLock (); + lines.RemoveAt (i); + editMutex.ExitWriteLock (); + LineRemoveEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void Insert(int i, string item){ + editMutex.EnterWriteLock (); + lines.Insert (i, item); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void Add(CodeLine item){ + editMutex.EnterWriteLock (); + lines.Add (item); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (lines.Count - 1)); + } + public void AddRange (string[] items){ + int start = lines.Count; + editMutex.EnterWriteLock (); + for (int i = 0; i < items.Length; i++) + lines.Add (items [i]); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + } + public void AddRange (CodeLine[] items){ + int start = lines.Count; + editMutex.EnterWriteLock (); + lines.AddRange (items); + editMutex.ExitWriteLock (); + LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + } + public void Clear () { + editMutex.EnterWriteLock (); + longestLineCharCount = 0; + lines.Clear (); + editMutex.ExitWriteLock (); + BufferCleared.Raise (this, null); + } + public void UpdateLine(int i, string newContent){ + editMutex.EnterWriteLock (); + this [i].Content = newContent; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void AppenedLine(int i, string newContent){ + editMutex.EnterWriteLock (); + this [i].Content += newContent; + editMutex.ExitWriteLock (); + LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + public void RemoveLeadingTab (int l) { + if (this [l] [0] == '\t') { + UpdateLine (l, this [l].Content.Substring (1)); + return; + } + int i = 0; + while (i < Interface.TabSize) { + if (this [l] [i] != ' ') + break; + i++; + } + if (i > 0) + UpdateLine (l, this [l].Content.Substring (i)); + } + public void ToogleFolding (int line) { + if (!this [line].IsFoldable) + return; + editMutex.EnterWriteLock (); + this [line].IsFolded = !this [line].IsFolded; + editMutex.ExitWriteLock (); + FoldingEvent.Raise (this, new CodeBufferEventArgs (line)); + } + public void Load(string rawSource, string lineBrkRegex = @"\r\n|\r|\n|\\\n") { + this.Clear(); + + if (string.IsNullOrEmpty (rawSource)) + return; + + AddRange (Regex.Split (rawSource, lineBrkRegex)); + + lineBreak = detectLineBreakKind (rawSource); + } + + /// + /// Finds the longest visual line as printed on screen with tabulation replaced with n spaces + /// + public void FindLongestVisualLine(){ + longestLineCharCount = 0; + editMutex.EnterReadLock (); + for (int i = 0; i < this.LineCount; i++) { + if (lines[i].PrintableLength > longestLineCharCount) { + longestLineCharCount = lines[i].PrintableLength; + longestLineIdx = i; + } + } + editMutex.ExitReadLock (); + //Debug.WriteLine ("Longest line: {0}->{1}", longestLineIdx, longestLineCharCount); + } + /// line break could be '\r' or '\n' or '\r\n' + static string detectLineBreakKind(string buffer){ + string strLB = ""; + + if (string.IsNullOrEmpty(buffer)) + return Interface.LineBreak; + int i = 0; + while ( i < buffer.Length) { + if (buffer [i] == '\r') { + strLB += '\r'; + i++; + } + if (i < buffer.Length) { + if (buffer [i] == '\r') + return "\r"; + if (buffer[i] == '\n') + strLB += '\n'; + } + if (!string.IsNullOrEmpty (strLB)) + return strLB; + i++; + } + return Interface.LineBreak; + } + /// + /// return all lines with linebreaks + /// + public string FullText{ + get { + if (lines.Count == 0) + return ""; + string tmp = ""; + editMutex.EnterReadLock (); + for (int i = 0; i < lines.Count -1; i++) + tmp += lines [i].Content + this.lineBreak; + tmp += lines [lines.Count - 1].Content; + editMutex.ExitReadLock (); + return tmp; + } + } + + /// + /// unfolded and not in folds line count + /// + public int UnfoldedLines { + get { + int i = 0, vl = 0; + editMutex.EnterReadLock (); + while (i < LineCount) { + if (this [i].IsFolded) { + i = GetEndNodeIndex (i); + if (i < 0) { + Console.WriteLine ("error folding"); + break; + } + } + i++; + vl++; + } + editMutex.ExitReadLock (); + //Debug.WriteLine ("unfolded lines: " + vl); + return vl; + } + } + + /// + /// convert visual position to buffer position + /// + Point getBuffPos (Point visualPos) { + int i = 0; + int buffCol = 0; + while (i < visualPos.X) { + if (this [visualPos.Y] [buffCol] == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + return new Point (buffCol, visualPos.Y); + } + + public int GetEndNodeIndex (int line) { + return IndexOf (this [line].SyntacticNode.EndLine); + } + + int ConverteTabulatedPosOfCurLine (int column) { + int tmp = 0; + int i = 0; + while (i < lines [_currentLine].Content.Length){ + if (lines [_currentLine].Content [i] == '\t') + tmp += 4; + else + tmp++; + if (tmp > column) + break; + i++; + } + return i; + } + + public int CurrentTabulatedColumn { + get { + return lines [_currentLine].Content.Substring (0, _currentCol). + Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + } + /// + /// Gets visual position computed from actual buffer position + /// +// public Point TabulatedPosition { +// get { return new Point (TabulatedColumn, _currentLine); } +// } + /// + /// set buffer current position from visual position + /// +// public void SetBufferPos(Point tabulatedPosition) { +// CurrentPosition = getBuffPos(tabulatedPosition); +// } + + #region Editing and moving cursor + Point selStartPos = -1; //selection start (row,column) + Point selEndPos = -1; //selection end (row,column) + + public bool SelectionInProgress { get { return selStartPos >= 0; }} + public void SetSelStartPos () { + selStartPos = selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + public void SetSelEndPos () { + selEndPos = CurrentPosition; + SelectionChanged.Raise (this, null); + } + public void SetSelectionOnFullLines () { + if (!SelectionInProgress) + return; + Point s = new Point (0, SelectionStart.Y); + Point e = new Point (this [SelectionEnd.Y].Length, SelectionEnd.Y); + selStartPos = s; + selEndPos = e; + SelectionChanged.Raise (this, null); + } + /// + /// Set selection in buffer to -1, empty selection + /// + public void ResetSelection () { + selStartPos = selEndPos = -1; + SelectionChanged.Raise (this, null); + } + + public string SelectedText { + get { + if (SelectionIsEmpty) + return ""; + Point selStart = SelectionStart; + Point selEnd = SelectionEnd; + if (selStart.Y == selEnd.Y) + return this [selStart.Y].Content.Substring (selStart.X, selEnd.X - selStart.X); + string tmp = ""; + tmp = this [selStart.Y].Content.Substring (selStart.X); + for (int l = selStart.Y + 1; l < selEnd.Y; l++) { + tmp += Interface.LineBreak + this [l].Content; + } + tmp += Interface.LineBreak + this [selEnd.Y].Content.Substring (0, selEnd.X); + return tmp; + } + } + /// + /// ordered selection start and end positions in char units + /// + public Point SelectionStart { + get { return selEndPos < 0 || selStartPos.Y < selEndPos.Y ? selStartPos : + selStartPos.Y > selEndPos.Y ? selEndPos : + selStartPos.X < selEndPos.X ? selStartPos : selEndPos; } + } + public Point SelectionEnd { + get { return selEndPos < 0 || selStartPos.Y > selEndPos.Y ? selStartPos : + selStartPos.Y < selEndPos.Y ? selEndPos : + selStartPos.X > selEndPos.X ? selStartPos : selEndPos; } + } + public bool SelectionIsEmpty + { get { return selEndPos == selStartPos; } } + int requestedColumn = -1; + /// + /// Current column in buffer coordinate, tabulation = 1 char + /// + public int CurrentColumn{ + get { return _currentCol; } + set { + if (value == _currentCol) + return; + + editMutex.EnterReadLock (); + + if (value < 0) + _currentCol = 0; + else if (value > lines [_currentLine].Length) + _currentCol = lines [_currentLine].Length; + else + _currentCol = value; + + requestedColumn = CurrentTabulatedColumn; + + editMutex.ExitReadLock (); + + PositionChanged.Raise (this, null); + } + } + /// + /// Current row in buffer coordinate, tabulation = 1 char + /// + public int CurrentLine{ + get { return _currentLine; } + set { + if (value == _currentLine) + return; + + editMutex.EnterReadLock (); + + if (value >= lines.Count) + _currentLine = lines.Count-1; + else if (value < 0) + _currentLine = 0; + else + _currentLine = value; +// if (_currentCol < 0) +// requestedColumn = tabu _currentCol; + int tabulatedRequestedCol = ConverteTabulatedPosOfCurLine(requestedColumn); + if (requestedColumn > lines [_currentLine].PrintableLength) + _currentCol = lines [_currentLine].Length; + else + //_currentCol = requestedColumn; + _currentCol = tabulatedRequestedCol; + //Debug.WriteLine ("buff cur line: " + _currentLine); + + editMutex.ExitReadLock(); + + PositionChanged.Raise (this, null); + } + } + public CodeLine CurrentCodeLine { + get { return this [_currentLine]; } + } + /// + /// Current position in buffer coordinate, tabulation = 1 char + /// + public Point CurrentPosition { + get { return new Point(CurrentColumn, CurrentLine); } +// set { +// _currentCol = value.X; +// _currentLine = value.Y; +// } + } + /// + /// get char at current position in buffer + /// + protected Char CurrentChar { get { return lines [CurrentLine] [CurrentColumn]; } } + + public void GotoWordStart(){ + if (this[CurrentLine].Length == 0) + return; + CurrentColumn--; + //skip white spaces + while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) + CurrentColumn--; + while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) + CurrentColumn--; + if (!char.IsLetterOrDigit (this.CurrentChar)) + CurrentColumn++; + } + public void GotoWordEnd(){ + //skip white spaces + if (CurrentColumn >= this [CurrentLine].Length - 1) + return; + while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) + CurrentColumn++; + while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) + CurrentColumn++; + if (char.IsLetterOrDigit (this.CurrentChar)) + CurrentColumn++; + } + public void DeleteChar() + { + editMutex.EnterWriteLock (); + if (SelectionIsEmpty) { + if (CurrentColumn == 0) { + if (CurrentLine == 0) { + editMutex.ExitWriteLock (); + return; + } + CurrentLine--; + CurrentColumn = this [CurrentLine].Length; + AppenedLine (CurrentLine, this [CurrentLine + 1].Content); + RemoveAt (CurrentLine + 1); + editMutex.ExitWriteLock (); + return; + } + CurrentColumn--; + UpdateLine (CurrentLine, this [CurrentLine].Content.Remove (CurrentColumn, 1)); + } else { + int linesToRemove = SelectionEnd.Y - SelectionStart.Y + 1; + int l = SelectionStart.Y; + + if (linesToRemove > 0) { + UpdateLine (l, this [l].Content.Remove (SelectionStart.X, this [l].Length - SelectionStart.X) + + this [SelectionEnd.Y].Content.Substring (SelectionEnd.X, this [SelectionEnd.Y].Length - SelectionEnd.X)); + l++; + for (int c = 0; c < linesToRemove - 1; c++) + RemoveAt (l); + CurrentLine = SelectionStart.Y; + CurrentColumn = SelectionStart.X; + } else + UpdateLine (l, this [l].Content.Remove (SelectionStart.X, SelectionEnd.X - SelectionStart.X)); + CurrentColumn = SelectionStart.X; + ResetSelection (); + } + editMutex.ExitWriteLock (); + } + /// + /// Insert new string at caret position, should be sure no line break is inside. + /// + /// String. + public void Insert(string str) + { + if (!SelectionIsEmpty) + this.DeleteChar (); + string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray(); + UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[0])); + CurrentColumn += strLines[0].Length; + for (int i = 1; i < strLines.Length; i++) { + InsertLineBreak (); + UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[i])); + CurrentColumn += strLines[i].Length; + } + } + /// + /// Insert a line break. + /// + public void InsertLineBreak() + { + if (CurrentColumn > 0) { + Insert (CurrentLine + 1, this [CurrentLine].Content.Substring (CurrentColumn)); + UpdateLine (CurrentLine, this [CurrentLine].Content.Substring (0, CurrentColumn)); + } else + Insert(CurrentLine, ""); + + CurrentColumn = 0; + CurrentLine++; + } + #endregion + } +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs b/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs new file mode 100644 index 00000000..07dd25b6 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/CodeBufferEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Crow.Coding +{ + public class CodeBufferEventArgs : EventArgs { + public int LineStart; + public int LineCount; + + public CodeBufferEventArgs(int lineNumber) { + LineStart = lineNumber; + LineCount = 1; + } + public CodeBufferEventArgs(int lineStart, int lineCount) { + LineStart = lineStart; + LineCount = lineCount; + } + } + +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs b/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs new file mode 100644 index 00000000..23f43fba --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/CodeLine.cs @@ -0,0 +1,82 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +namespace Crow.Coding +{ + public class CodeLine + { + public string Content; + public List Tokens; + public int EndingState = 0; + public Node SyntacticNode; + public ParserException exception; + + public CodeLine (string _content){ + Content = _content; + Tokens = null; + exception = null; + } + + public char this[int i] + { + get { return Content[i]; } + set { + if (Content [i] == value) + return; + StringBuilder sb = new StringBuilder(Content); + sb[i] = value; + Content = sb.ToString(); + Tokens = null; + //LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + } + } + public bool IsFoldable { get { return SyntacticNode == null ? false : + SyntacticNode.EndLine != SyntacticNode.StartLine && SyntacticNode.EndLine != null; } } + public int FoldingLevel { get { return IsFoldable ? SyntacticNode.Level : 0; } } + public bool IsFolded = false; + public bool IsParsed { + get { return Tokens != null; } + } + public string PrintableContent { + get { + return string.IsNullOrEmpty (Content) ? "" : Content.Replace ("\t", new String (' ', Interface.TabSize)); + } + } + public int PrintableLength { + get { + return PrintableContent.Length; + } + } + public int Length { + get { + return string.IsNullOrEmpty (Content) ? 0 : Content.Length; + } + } + public int FirstNonBlankTokIndex { + get { return Tokens == null ? -1 : Tokens.FindIndex (tk=>tk.Type != BufferParser.TokenType.WhiteSpace); } + } + + public void SetLineInError (ParserException ex) { + Tokens = null; + exception = ex; + } + +// public static implicit operator string(CodeLine sl) { +// return sl == null ? "" : sl.Content; +// } + public static implicit operator CodeLine(string s) { + return new CodeLine(s); + } + public static bool operator ==(string s1, CodeLine s2) + { + return string.Equals (s1, s2.Content); + } + public static bool operator !=(string s1, CodeLine s2) + { + return !string.Equals (s1, s2.Content); + } + } +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/Node.cs b/CrowIDE/src/Editors/CodeBuffer/Node.cs new file mode 100644 index 00000000..9db55428 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/Node.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace Crow.Coding +{ + public class Node + { + public Node Parent; + public string Name; + public string Type; + public CodeLine StartLine; + public CodeLine EndLine; + public Dictionary Attributes = new Dictionary (); + + public List Children = new List(); + + public Node () + { + } + + public void AddChild (Node child) { + child.Parent = this; + Children.Add (child); + } + + public int Level { + get { return Parent == null ? 1 : Parent.Level + 1; } + } + + public override string ToString () + { + return string.Format ("Name:{0}, Type:{1}\n\tparent:{2}", Name, Type, Parent); + } + } +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs b/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs new file mode 100644 index 00000000..e605dd55 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs @@ -0,0 +1,1205 @@ +// +// ScrollingTextBox.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; +using System.Text; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Linq; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace Crow.Coding +{ + /// + /// Scrolling text box optimized for monospace fonts, for coding + /// + public class SourceEditor : Editor + { + #region CTOR + public SourceEditor (): base() + { + formatting.Add ((int)XMLParser.TokenType.AttributeName, new TextFormatting (Color.Teal, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementName, new TextFormatting (Color.DarkBlue, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementStart, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementEnd, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementClosing, new TextFormatting (Color.Black, Color.Transparent)); + + formatting.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormatting (Color.Carmine, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormatting (Color.Carmine, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormatting (Color.TractorRed, Color.Transparent, false, true)); + formatting.Add ((int)XMLParser.TokenType.XMLDecl, new TextFormatting (Color.AoEnglish, Color.Transparent)); + + formatting.Add ((int)BufferParser.TokenType.BlockComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.LineComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.OperatorOrPunctuation, new TextFormatting (Color.Black, Color.Transparent)); + //formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.DarkCyan, Color.Transparent)); + + parsing.Add (".crow", "Crow.Coding.XMLParser"); + parsing.Add (".svg", "Crow.Coding.XMLParser"); + parsing.Add (".template", "Crow.Coding.XMLParser"); + parsing.Add (".cs", "Crow.Coding.CSharpParser"); + parsing.Add (".style", "Crow.Coding.StyleParser"); + + buffer = new CodeBuffer (); + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + buffer.SelectionChanged += Buffer_SelectionChanged; + buffer.PositionChanged += Buffer_PositionChanged; + buffer.FoldingEvent += Buffer_FoldingEvent; + buffer.Add (new CodeLine("")); + } + #endregion + + string oldSource = ""; + //save requested position on error, and try it on next move + int requestedLine = 0, requestedCol = 0; + volatile bool isDirty = false; + + const int leftMarginGap = 3;//gap between items in margin and text + const int foldSize = 9;//folding rectangles size + const int foldHSpace = 4;//folding level tabulation x + int foldMargin { get { return parser == null ? 0 : parser.SyntacticTreeMaxDepth * foldHSpace; }}//folding margin size + + #region private and protected fields + bool foldingEnabled = true; + int leftMargin = 0; //margin used to display line numbers, folding errors,etc... + int visibleLines = 1; + int visibleColumns = 1; + int firstPrintedLine = -1; + int printedCurrentLine = 0;//Index of the currentline in the PrintedLines array + + CodeBuffer buffer; + BufferParser parser; + List PrintedLines;//list of lines visible in the Editor depending on scrolling and folding + + Dictionary formatting = new Dictionary(); + Dictionary parsing = new Dictionary(); + + Color selBackground; + Color selForeground; + int selStartCol; + int selEndCol; + + protected Rectangle rText; + protected FontExtents fe; + protected TextExtents te; + + Point mouseLocalPos; + bool doubleClicked = false; + #endregion + + void measureLeftMargin () { + leftMargin = 0; + if (PrintLineNumbers) + leftMargin += (int)Math.Ceiling((double)buffer.LineCount.ToString().Length * fe.MaxXAdvance) +6; + if (foldingEnabled) + leftMargin += foldMargin; + if (leftMargin > 0) + leftMargin += leftMarginGap; + updateVisibleColumns (); + } + void findLongestLineAndUpdateMaxScrollX() { + buffer.FindLongestVisualLine (); + updateMaxScrollX (); +// Debug.WriteLine ("SourceEditor: Find Longest line and update maxscrollx: {0} visible cols:{1}", MaxScrollX, visibleColumns); + } + /// + /// Updates visible line in widget, adapt max scroll y and updatePrintedLines + /// + void updateVisibleLines(){ + visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); + NotifyValueChanged ("VisibleLines", visibleLines); + updateMaxScrollY (); + updatePrintedLines (); + RegisterForGraphicUpdate (); +// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); + } + void updateVisibleColumns(){ + visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance); + NotifyValueChanged ("VisibleColumns", visibleColumns); + updateMaxScrollX (); +// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); + } + void updateMaxScrollX () { + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + if (buffer.longestLineCharCount > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount); + } + void updateMaxScrollY () { + if (parser == null || !foldingEnabled) { + MaxScrollY = Math.Max (0, buffer.LineCount - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } else { + MaxScrollY = Math.Max (0, buffer.UnfoldedLines - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } + } + void updatePrintedLines () { + buffer.editMutex.EnterReadLock (); + editorMutex.EnterWriteLock (); + + PrintedLines = new List (); + int curL = 0; + int i = 0; + + while (curL < buffer.LineCount && i < ScrollY) { + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + curL++; + i++; + } + + firstPrintedLine = curL; + i = 0; + while (i < visibleLines && curL < buffer.LineCount) { + PrintedLines.Add (buffer [curL]); + + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + + curL++; + i++; + } + + buffer.editMutex.ExitReadLock (); + editorMutex.ExitWriteLock (); + } + void updateOnScreenCurLineFromBuffCurLine(){ + printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); + } + void toogleFolding (int line) { + if (parser == null || !foldingEnabled) + return; + buffer.ToogleFolding (line); + } + + #region Editor overrides + protected override void updateEditorFromProjFile () + { + buffer.editMutex.EnterWriteLock (); + loadSource (); + buffer.editMutex.ExitWriteLock (); + + isDirty = false; + oldSource = projFile.Source; + CurrentLine = requestedLine; + CurrentColumn = requestedCol; + projFile.RegisteredEditors [this] = true; + } + protected override void updateProjFileFromEditor () + { + buffer.editMutex.EnterWriteLock (); + string newsrc = buffer.FullText; + buffer.editMutex.ExitWriteLock (); + projFile.UpdateSource (this, newsrc); + } + protected override bool EditorIsDirty { + get { return isDirty; } + set { isDirty = value; } + } + protected override bool IsReady { + get { return buffer != null; } + } + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + editorMutex.EnterWriteLock (); + + buffer.longestLineCharCount = 0; + buffer.longestLineIdx = 0; + measureLeftMargin (); + MaxScrollX = MaxScrollY = 0; + PrintedLines = null; + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + + editorMutex.ExitWriteLock (); + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + int charCount = buffer[lptr].PrintableLength; + if (charCount > buffer.longestLineCharCount) { + buffer.longestLineIdx = lptr; + buffer.longestLineCharCount = charCount; + }else if (lptr <= buffer.longestLineIdx) + buffer.longestLineIdx++; + if (parser == null) + continue; + parser.TryParseBufferLine (e.LineStart + i); + } + + if (parser != null) + parser.reparseSource (); + + measureLeftMargin (); + + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + if (lptr <= buffer.longestLineIdx) + trigFindLongestLine = true; + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + measureLeftMargin (); + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + + int lptr = e.LineStart + i; + if (lptr == buffer.longestLineIdx) + trigFindLongestLine = true; + else if (buffer[lptr].PrintableLength > buffer.longestLineCharCount) { + buffer.longestLineCharCount = buffer[lptr].PrintableLength; + buffer.longestLineIdx = lptr; + } + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_PositionChanged (object sender, EventArgs e) + { + Console.WriteLine ("Position changes: ({0},{1})", buffer.CurrentLine, buffer.CurrentColumn); + int cc = buffer.CurrentTabulatedColumn; + + if (cc > visibleColumns + ScrollX) { + ScrollX = cc - visibleColumns; + } else if (cc < ScrollX) + ScrollX = cc; + + RegisterForGraphicUpdate (); + updateOnScreenCurLineFromBuffCurLine (); + notifyPositionChanged (); + } + + void Buffer_SelectionChanged (object sender, EventArgs e) + { + RegisterForGraphicUpdate (); + } + void Buffer_FoldingEvent (object sender, CodeBufferEventArgs e) + { + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + } + #endregion + + void notifyPositionChanged (){ + try { + NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); + NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); + NotifyValueChanged ("CurrentLineHasError", CurrentLineHasError); + NotifyValueChanged ("CurrentLineError", CurrentLineError); + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + } + + #region Public Crow Properties + public int CurrentLine{ + get { return buffer == null ? 0 : buffer.CurrentLine+1; } + set { + try { + int l = value - 1; + if (l == buffer.CurrentLine) + return; + buffer.CurrentLine = l; + if (buffer [l].IsFolded) + buffer.ToogleFolding (l); + } catch (Exception ex) { + requestedLine = value - 1; + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } + } + } + public int CurrentColumn{ + get { return buffer == null ? 0 : buffer.CurrentColumn+1; } + set { + try { + if (value - 1 == buffer.CurrentColumn) + return; + buffer.CurrentColumn = value - 1; + } catch (Exception ex) { + requestedCol = value - 1; + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } + } + } + public bool PrintLineNumbers + { + get { return Configuration.Global.Get ("PrintLineNumbers"); } + set { + if (PrintLineNumbers == value) + return; + Configuration.Global.Set ("PrintLineNumbers", value); + NotifyValueChanged ("PrintLineNumbers", PrintLineNumbers); + measureLeftMargin (); + RegisterForGraphicUpdate (); + } + } + [DefaultValue("BlueGray")] + public virtual Color SelectionBackground { + get { return selBackground; } + set { + if (value == selBackground) + return; + selBackground = value; + NotifyValueChanged ("SelectionBackground", selBackground); + RegisterForRedraw (); + } + } + [DefaultValue("White")] + public virtual Color SelectionForeground { + get { return selForeground; } + set { + if (value == selForeground) + return; + selForeground = value; + NotifyValueChanged ("SelectionForeground", selForeground); + RegisterForRedraw (); + } + } + public override int ScrollY { + get { + return base.ScrollY; + } + set { + if (value == base.ScrollY) + return; + base.ScrollY = value; + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + RegisterForGraphicUpdate (); + } + } + public ParserException CurrentLineError { + get { return buffer?.CurrentCodeLine?.exception; } + } + public bool CurrentLineHasError { + get { return buffer == null ? false : buffer.CurrentCodeLine == null ? false : + buffer.CurrentCodeLine.exception != null; } + } + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; + } + set { + base.ProjectNode = value; + if (projFile != null) + parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); + } + } + #endregion + + BufferParser getParserFromExt (string extension) { + if (string.IsNullOrEmpty(extension)) + return null; + if (!parsing.ContainsKey(extension)) + return null; + Type parserType = Type.GetType (parsing [extension]); + if (parserType == null) + return null; + return (BufferParser)Activator.CreateInstance (parserType, buffer ); + } + void loadSource () { + + try { + + if (parser == null) + buffer.Load (projFile.Source); + else//parser may have special linebrk rules + buffer.Load (projFile.Source, parser.LineBrkRegex); + + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + } + + projFile.RegisteredEditors [this] = true; + + updateMaxScrollY (); + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + updatePrintedLines (); + + RegisterForGraphicUpdate (); + } + + /// + /// Current editor line, when set, update buffer.CurrentLine + /// + int PrintedCurrentLine { + get { return printedCurrentLine;} + set { + if (value < 0) { + ScrollY += value; + printedCurrentLine = 0; + } else if (PrintedLines.Count < visibleLines && value >= PrintedLines.Count) { + printedCurrentLine = PrintedLines.Count - 1; + }else if (value >= visibleLines) { + ScrollY += value - visibleLines + 1; + printedCurrentLine = visibleLines - 1; + }else + printedCurrentLine = value; + //Debug.WriteLine ("printed current line:" + printedCurrentLine.ToString ()); + //update position in buffer + buffer.CurrentLine = buffer.IndexOf (PrintedLines[printedCurrentLine]); + } + } + int getTabulatedColumn (int col, int line) { + return buffer [line].Content.Substring (0, col).Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + int getTabulatedColumn (Point pos) { + return getTabulatedColumn (pos.X,pos.Y); + } + /// + /// Moves cursor one char to the left, move up if cursor reaches start of line + /// + /// true if move succeed + public bool MoveLeft(){ + if (buffer.CurrentColumn == 0) { + if (printedCurrentLine == 0) + return false; + PrintedCurrentLine--; + buffer.CurrentColumn = int.MaxValue; + } else + buffer.CurrentColumn--; + return true; + } + /// + /// Moves cursor one char to the right, move down if cursor reaches end of line + /// + /// true if move succeed + public bool MoveRight(){ + if (buffer.CurrentColumn >= buffer.CurrentCodeLine.Length) { + if (PrintedCurrentLine == buffer.UnfoldedLines - 1) + return false; + buffer.CurrentColumn = 0; + PrintedCurrentLine++; + } else + buffer.CurrentColumn++; + return true; + } + + #region Drawing + void drawLine(Context gr, Rectangle cb, int i) { + CodeLine cl = PrintedLines[i]; + int lineIndex = buffer.IndexOf(cl); + + double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; + + //Draw line numbering + Color mgFg = Color.Gray; + Color mgBg = Color.White; + if (PrintLineNumbers){ + Rectangle mgR = new Rectangle ((int)x, (int)y, leftMargin - leftMarginGap, (int)Math.Ceiling((fe.Ascent+fe.Descent))); + if (cl.exception != null) { + mgBg = Color.Red; + if (buffer.CurrentLine == lineIndex) + mgFg = Color.White; + else + mgFg = Color.LightGray; + }else if (buffer.CurrentLine == lineIndex) { + mgFg = Color.Black; + mgBg = Color.DarkGray; + } + string strLN = (lineIndex+1).ToString (); + gr.SetSourceColor (mgBg); + gr.Rectangle (mgR); + gr.Fill(); + gr.SetSourceColor (mgFg); + + gr.MoveTo (cb.X + (int)(gr.TextExtents (buffer.LineCount.ToString()).Width - gr.TextExtents (strLN).Width), y + fe.Ascent); + gr.ShowText (strLN); + gr.Fill (); + } + + + + //draw folding + if (foldingEnabled){ + + Rectangle rFld = new Rectangle (cb.X + leftMargin - leftMarginGap - foldMargin, + (int)(y + (fe.Ascent + fe.Descent) / 2.0 - foldSize / 2.0), foldSize, foldSize); + + gr.SetSourceColor (Color.Black); + gr.LineWidth = 1.0; + + int level = 0; + bool closingNode = false; + + if (currentNode != null) { + if (cl == currentNode.EndLine) { + currentNode = currentNode.Parent; + closingNode = true; + } + if (currentNode != null) + level = currentNode.Level - 1; + } + + for (int l = 0; l < level; l++) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent + fe.Descent); + rFld.Left += foldHSpace; + } + if (closingNode) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent / 2 + 0.5); + gr.LineTo (rFld.Center.X + 0.5 + foldSize / 2, y + fe.Ascent / 2 + 0.5); + closingNode = false; + } + gr.SetDash (new double[]{ 1.5 },0.0); + gr.SetSourceColor (Color.Gray); + gr.Stroke (); + gr.SetDash (new double[]{}, 0.0); + + if (cl.IsFoldable) { + gr.Rectangle (rFld); + gr.SetSourceColor (Color.White); + gr.Fill(); + gr.SetSourceColor (Color.Black); + gr.Rectangle (rFld, 1.0); + if (cl.IsFolded) { + gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2); + gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2); + }else + currentNode = cl.SyntacticNode; + + gr.MoveTo (rFld.Left + 2, rFld.Center.Y + 0.5); + gr.LineTo (rFld.Right - 2, rFld.Center.Y + 0.5); + gr.Stroke (); + } + } + + gr.SetSourceColor (Foreground); + x += leftMargin; + + if (cl.Tokens == null) + drawRawCodeLine (gr, x, y, i, lineIndex); + else + drawParsedCodeLine (gr, x, y, i, lineIndex); + } + Node currentNode = null; +// void drawParsed(Context gr){ +// if (PrintedLines == null) +// return; +// +// gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); +// gr.SetFontSize (Font.Size); +// gr.FontOptions = Interface.FontRenderingOptions; +// gr.Antialias = Interface.Antialias; +// +// Rectangle cb = ClientRectangle; +// gr.Save (); +// CairoHelpers.CairoRectangle (gr, cb, CornerRadius); +// gr.Clip (); +// +// bool selectionInProgress = false; +// +// Foreground.SetAsSource (gr); +// +// #region draw text cursor +// if (SelBegin != SelRelease) +// selectionInProgress = true; +// else if (HasFocus){ +// gr.LineWidth = 1.0; +// double cursorX = + leftMargin + cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; +// gr.MoveTo (0.5 + cursorX, cb.Y + printedCurrentLine * (fe.Ascent+fe.Descent)); +// gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); +// gr.Stroke(); +// } +// #endregion +// +// for (int i = 0; i < PrintedLines.Count; i++) +// drawTokenLine (gr, i, selectionInProgress, cb); +// +// gr.Restore (); +// } + void drawRawCodeLine(Context gr, double x, double y, int i, int lineIndex) { + string lstr = buffer[lineIndex].PrintableContent; + if (ScrollX < lstr.Length) + lstr = lstr.Substring (ScrollX); + else + lstr = ""; + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + + //System.Diagnostics.Debug.WriteLine ("sel start: " + buffer.SelectionStart + " sel end: " + buffer.SelectionEnd); + if (lineIndex == buffer.SelectionStart.Y) { + rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; + rLineW -= selStartCol * fe.MaxXAdvance; + } + if (lineIndex == buffer.SelectionEnd.Y) + rLineW -= (lstr.Length - selEndCol) * fe.MaxXAdvance; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (SelectionBackground); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (SelectionForeground); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + } + void drawParsedCodeLine (Context gr, double x, double y, int i, int lineIndex) { + int lPtr = 0; + CodeLine cl = PrintedLines[i]; + + for (int t = 0; t < cl.Tokens.Count; t++) { + string lstr = cl.Tokens [t].PrintableContent; + if (lPtr < ScrollX) { + if (lPtr - ScrollX + lstr.Length <= 0) { + lPtr += lstr.Length; + continue; + } + lstr = lstr.Substring (ScrollX - lPtr); + lPtr += ScrollX - lPtr; + } + Color bg = this.Background; + Color fg = this.Foreground; + Color selbg = this.SelectionBackground; + Color selfg = this.SelectionForeground; + FontSlant fts = FontSlant.Normal; + FontWeight ftw = FontWeight.Normal; + + if (formatting.ContainsKey ((int)cl.Tokens [t].Type)) { + TextFormatting tf = formatting [(int)cl.Tokens [t].Type]; + bg = tf.Background; + fg = tf.Foreground; + if (tf.Bold) + ftw = FontWeight.Bold; + if (tf.Italic) + fts = FontSlant.Italic; + } + + gr.SelectFontFace (Font.Name, fts, ftw); + gr.SetSourceColor (fg); + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (buffer.SelectionInProgress && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y && + !(lineIndex == buffer.SelectionStart.Y && lPtr + lstr.Length <= selStartCol) && + !(lineIndex == buffer.SelectionEnd.Y && selEndCol <= lPtr)) { + + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + double startAdjust = 0.0; + + if ((lineIndex == buffer.SelectionStart.Y) && (selStartCol < lPtr + lstr.Length) && (selStartCol > lPtr)) + startAdjust = (selStartCol - lPtr) * fe.MaxXAdvance; + rLineX += startAdjust; + if ((lineIndex == buffer.SelectionEnd.Y) && (selEndCol < lPtr + lstr.Length)) + rLineW = (selEndCol - lPtr) * fe.MaxXAdvance; + rLineW -= startAdjust; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (selbg); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (selfg); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + x += (int)lstr.Length * fe.MaxXAdvance; + lPtr += lstr.Length; + } + } + + #endregion + + #region GraphicObject overrides + public override Font Font { + get { return base.Font; } + set { + base.Font = value; + + using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) { + using (Context gr = new Context (img)) { + gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); + gr.SetFontSize (Font.Size); + + fe = gr.FontExtents; + } + } + MaxScrollY = 0; + RegisterForGraphicUpdate (); + } + } + protected override int measureRawSize(LayoutingType lt) + { + if (lt == LayoutingType.Height) + return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; + + return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2 + leftMargin; + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + + if (layoutType == LayoutingType.Height) + updateVisibleLines (); + else if (layoutType == LayoutingType.Width) + updateVisibleColumns (); + } + + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); + gr.SetFontSize (Font.Size); + gr.FontOptions = Interface.FontRenderingOptions; + gr.Antialias = Interface.Antialias; + + Rectangle cb = ClientRectangle; + + Foreground.SetAsSource (gr); + + buffer.editMutex.EnterReadLock (); + editorMutex.EnterReadLock (); + + #region draw text cursor + if (buffer.SelectionInProgress){ + selStartCol = getTabulatedColumn (buffer.SelectionStart); + selEndCol = getTabulatedColumn (buffer.SelectionEnd); + }else if (HasFocus && printedCurrentLine >= 0){ + gr.LineWidth = 1.0; + double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance + leftMargin; + gr.MoveTo (0.5 + cursorX, cb.Y + (printedCurrentLine) * (fe.Ascent+fe.Descent)); + gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); + gr.Stroke(); + } + #endregion + + if (PrintedLines?.Count > 0) { + int unfoldedLines = buffer.UnfoldedLines; + currentNode = null; + CodeLine cl = PrintedLines[0]; + int idx0 = buffer.IndexOf(cl); + int li = idx0-1; + while (li >= 0) { + if (buffer [li].IsFoldable && !buffer [li].IsFolded) { + if (buffer.IndexOf(buffer [li].SyntacticNode.EndLine) > idx0){ + currentNode = buffer [li].SyntacticNode; + break; + } + } + li--; + } + + for (int i = 0; i < visibleLines; i++) { + if (i + ScrollY >= unfoldedLines)//TODO:need optimize + break; + drawLine (gr, cb, i); + } + } + + editorMutex.ExitReadLock (); + + buffer.editMutex.ExitReadLock (); + + } + #endregion + + #region Mouse handling + + int hoverLine = -1; + public int HoverLine { + get { return hoverLine; } + set { + if (hoverLine == value) + return; + hoverLine = value; + NotifyValueChanged ("HoverLine", hoverLine); + } + } + void updateHoverLine () { + int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + hvl = Math.Min (PrintedLines.Count, hvl); + HoverLine = buffer.IndexOf (PrintedLines[hvl]); + } + void updateCurrentPosFromMouseLocalPos(){ + PrintedCurrentLine = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X - leftMargin) / fe.MaxXAdvance); + + int i = 0; + int buffCol = 0; + while (i < curVisualCol && buffCol < buffer.CurrentCodeLine.Length) { + if (buffer.CurrentCodeLine[buffCol] == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + buffer.CurrentColumn = buffCol; + } + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { + base.onMouseEnter (sender, e); + if (e.X - ScreenCoordinates(Slot).X < leftMargin + ClientRectangle.X) + IFace.MouseCursor = XCursor.Default; + else + IFace.MouseCursor = XCursor.Text; + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); + IFace.MouseCursor = XCursor.Default; + } + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; + + updateHoverLine (); + + if (!e.Mouse.IsButtonDown (MouseButton.Left)) { + if (mouseLocalPos.X < leftMargin) + IFace.MouseCursor = XCursor.Default; + else + IFace.MouseCursor = XCursor.Text; + return; + } + + if (!HasFocus || !buffer.SelectionInProgress) + return; + + //mouse is down + updateCurrentPosFromMouseLocalPos(); + buffer.SetSelEndPos (); + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + if (!this.Focusable) + return; + + if (mouseLocalPos.X >= leftMargin) + base.onMouseDown (sender, e); + + if (doubleClicked) { + doubleClicked = false; + return; + } + + if (mouseLocalPos.X < leftMargin) { + toogleFolding (buffer.IndexOf (PrintedLines [(int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent)))])); + return; + } + + updateCurrentPosFromMouseLocalPos (); + buffer.SetSelStartPos (); + } + public override void onMouseUp (object sender, MouseButtonEventArgs e) + { + base.onMouseUp (sender, e); + + if (buffer.SelectionIsEmpty) + buffer.ResetSelection (); + } + + public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) + { + doubleClicked = true; + base.onMouseDoubleClick (sender, e); + + buffer.GotoWordStart (); + buffer.SetSelStartPos (); + buffer.GotoWordEnd (); + buffer.SetSelEndPos (); + } + + public override void onMouseWheel (object sender, MouseWheelEventArgs e) + { + base.onMouseWheel (sender, e); + } + #endregion + + #region Keyboard handling + public override void onKeyDown (object sender, KeyboardKeyEventArgs e) + { + //base.onKeyDown (sender, e); + + Key key = e.Key; + + if (e.Control) { + switch (key) { + case Key.S: + projFile.Save (); + break; + case Key.W: + editorMutex.EnterWriteLock (); + if (e.Shift) + projFile.Redo (null); + else + projFile.Undo (null); + editorMutex.ExitWriteLock (); + break; + default: + Console.WriteLine (""); + break; + } + } + + switch (key) + { + case Key.Back: + buffer.DeleteChar (); + break; + case Key.Clear: + break; + case Key.Delete: + if (buffer.SelectionIsEmpty) + MoveRight (); + else if (e.Shift) + IFace.Clipboard = buffer.SelectedText; + buffer.DeleteChar (); + break; + case Key.Enter: + case Key.KeypadEnter: + if (!buffer.SelectionIsEmpty) + buffer.DeleteChar (); + buffer.InsertLineBreak (); + break; + case Key.Escape: + buffer.ResetSelection (); + break; + case Key.Home: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + break; + case Key.End: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + break; + case Key.Insert: + if (e.Shift) + buffer.Insert (IFace.Clipboard); + else if (e.Control && !buffer.SelectionIsEmpty) + IFace.Clipboard = buffer.SelectedText; + break; + case Key.Left: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.GotoWordStart (); + else + MoveLeft (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.GotoWordStart (); + else + MoveLeft(); + break; + case Key.Right: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.GotoWordEnd (); + else + MoveRight (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.GotoWordEnd (); + else + MoveRight (); + break; + case Key.Up: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine--; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine--; + break; + case Key.Down: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine++; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine++; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine += visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine += visibleLines; + break; + case Key.PageUp: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine -= visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine -= visibleLines; + break; + case Key.RWin: + break; + case Key.Tab: + if (e.Shift) { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + //TODO + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) + buffer.RemoveLeadingTab (i); + buffer.SetSelectionOnFullLines (); + } else { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + buffer.Insert ("\t"); + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) { + buffer.UpdateLine (i, "\t" + buffer [i].Content); + } + } + + break; + case Key.F8: + toogleFolding (buffer.CurrentLine); + break; + default: + break; + } + RegisterForGraphicUpdate(); + } + public override void onKeyPress (object sender, KeyPressEventArgs e) + { + base.onKeyPress (sender, e); + + buffer.Insert (e.KeyChar.ToString()); + buffer.ResetSelection (); + } + #endregion + } +} \ No newline at end of file diff --git a/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs b/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs new file mode 100644 index 00000000..f7b2e518 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/TextFormatting.cs @@ -0,0 +1,19 @@ +using System; + +namespace Crow.Coding +{ + public struct TextFormatting { + public Color Foreground; + public Color Background; + public bool Bold; + public bool Italic; + + public TextFormatting(Color fg, Color bg, bool bold = false, bool italic = false){ + Foreground = fg; + Background = bg; + Bold = bold; + Italic = italic; + } + } +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/Token.cs b/CrowIDE/src/Editors/CodeBuffer/Token.cs new file mode 100644 index 00000000..8b4df5e5 --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/Token.cs @@ -0,0 +1,71 @@ +// +// Token.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; + +namespace Crow.Coding +{ + public struct Token + { + public BufferParser.TokenType Type; + public string Content; + public Point Start; + public Point End; + + public string PrintableContent { + get { return string.IsNullOrEmpty(Content) ? "" : Content.Replace("\t", new String(' ', Interface.TabSize)); } + } + +// public Token (TokenType tokType, string content = ""){ +// Type = tokType; +// Content = content; +// } + + public bool IsNull { get { return IsEmpty && Type == BufferParser.TokenType.Unknown; }} + public bool IsEmpty { get { return string.IsNullOrEmpty(Content); }} + + public static bool operator == (Token t, System.Enum tt){ + return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); + } + public static bool operator != (Token t, System.Enum tt){ + return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); + } + public static bool operator == (System.Enum tt, Token t){ + return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); + } + public static bool operator != (System.Enum tt, Token t){ + return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); + } + + public static Token operator +(Token t, char c){ + t.Content += c; + return t; + } + public static Token operator +(Token t, string s){ + t.Content += s; + return t; + } + public override string ToString () + { + return string.Format ("[Tok{2}->{3}:{0}: {1}]", Type,Content,Start,End); + } + } +} + diff --git a/CrowIDE/src/Editors/EditPane.cs b/CrowIDE/src/Editors/EditPane.cs new file mode 100644 index 00000000..a75522f0 --- /dev/null +++ b/CrowIDE/src/Editors/EditPane.cs @@ -0,0 +1,57 @@ +// +// EditPane.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 Crow; +using System.Linq; + +namespace Crow.Coding +{ + public class EditPane : TemplatedGroup + { + public EditPane () {} + + object selectedItemElement = null; + + public override int SelectedIndex { + get { + return base.SelectedIndex; + } + set { + base.SelectedIndex = value; + } + } + public object SelectedItemElement { + get { return selectedItemElement; } + set { + if (selectedItemElement == value) + return; + selectedItemElement = value; + NotifyValueChanged ("SelectedItemElement", selectedItemElement); + } + } + } +} + diff --git a/CrowIDE/src/Editors/Editor.cs b/CrowIDE/src/Editors/Editor.cs new file mode 100644 index 00000000..88cab8e9 --- /dev/null +++ b/CrowIDE/src/Editors/Editor.cs @@ -0,0 +1,104 @@ +// +// Editor.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.Threading; +using System.Xml.Serialization; + +namespace Crow.Coding +{ + public abstract class Editor : ScrollingObject + { + #region CTOR + protected Editor ():base(){ + Thread t = new Thread (backgroundThreadFunc); + t.IsBackground = true; + t.Start (); + } + #endregion + + protected ReaderWriterLockSlim editorMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + protected ProjectFile projFile = null; + Exception error = null; + + public virtual ProjectFile ProjectNode + { + get { return projFile; } + set + { + if (projFile == value) + return; + + if (projFile != null) + projFile.UnregisterEditor (this); + + projFile = value; + + if (projFile != null) + projFile.RegisterEditor (this); + + NotifyValueChanged ("ProjectNode", projFile); + } + } + [XmlIgnore]public Exception Error { + get { return error; } + set { + if (error == value) + return; + error = value; + NotifyValueChanged ("Error", error); + NotifyValueChanged ("HasError", HasError); + } + } + [XmlIgnore]public bool HasError { + get { return error != null; } + } + + protected abstract void updateEditorFromProjFile (); + protected abstract void updateProjFileFromEditor (); + protected abstract bool EditorIsDirty { get; set; } + protected virtual bool IsReady { get { return true; }} + protected virtual void updateCheckPostProcess () {} + + protected void backgroundThreadFunc () { + while (true) { + if (IsReady) { + if (projFile != null) { + if (!projFile.RegisteredEditors [this]) { + projFile.RegisteredEditors [this] = true; + updateEditorFromProjFile (); + } else if (EditorIsDirty) { + EditorIsDirty = false; + updateProjFileFromEditor (); + } + updateCheckPostProcess (); + } + } + Thread.Sleep (10); + } + } + } +} + diff --git a/CrowIDE/src/Editors/ImlVisualEditor.cs b/CrowIDE/src/Editors/ImlVisualEditor.cs new file mode 100644 index 00000000..1ba6c559 --- /dev/null +++ b/CrowIDE/src/Editors/ImlVisualEditor.cs @@ -0,0 +1,520 @@ +// +// ImlVisualEditor.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2016 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 Crow; +using System.Threading; +using System.Xml.Serialization; +using System.ComponentModel; +using System.IO; +using System.Collections.Generic; +using Crow.IML; +using System.Text; +using System.Xml; + +namespace Crow.Coding +{ + public class ImlVisualEditor : Editor + { + #region CTOR + public ImlVisualEditor () : base() + { + imlVE = new DesignInterface (); + } + #endregion + + DesignInterface imlVE; + GraphicObject selectedItem; + ImlProjectItem imlProjFile; + Exception imlError = null; + + bool drawGrid, snapToGrid; + int gridSpacing; + + [DefaultValue(true)] + public bool DrawGrid { + get { return drawGrid; } + set { + if (drawGrid == value) + return; + drawGrid = value; + NotifyValueChanged ("DrawGrid", drawGrid); + RegisterForRedraw (); + } + } + [DefaultValue(true)] + public bool SnapToGrid { + get { return snapToGrid; } + set { + if (snapToGrid == value) + return; + snapToGrid = value; + NotifyValueChanged ("SnapToGrid", snapToGrid); + } + } + [DefaultValue(10)] + public int GridSpacing { + get { return gridSpacing; } + set { + if (gridSpacing == value) + return; + gridSpacing = value; + NotifyValueChanged ("GridSpacing", gridSpacing); + RegisterForRedraw (); + } + } + [XmlAttributeAttribute]public GraphicObject SelectedItem { + get { return selectedItem; } + set { + if (selectedItem == value) + return; + selectedItem = value; + NotifyValueChanged ("SelectedItem", selectedItem); + RegisterForRedraw (); + } + } + /// PoinprojFilever the widget + public virtual GraphicObject HoverWidget + { + get { return imlVE.HoverWidget; } + set { + if (HoverWidget == value) + return; + + imlVE.HoverWidget = value; + + NotifyValueChanged ("HoverWidget", HoverWidget); + } + } + [XmlIgnore]public List LQIs { + get { return imlVE.LQIs; } + } + + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; + } + set { + base.ProjectNode = value; + imlProjFile = projFile as ImlProjectItem; + imlVE.ProjFile = imlProjFile; + } + } + + public List GraphicTree { + get { return imlVE.GraphicTree; } + } + protected override void updateProjFileFromEditor () + { + try { + projFile.UpdateSource(this, imlProjFile.Instance.GetIML()); + } catch (Exception ex) { + Error = ex.InnerException; + if (Monitor.IsEntered(imlVE.UpdateMutex)) + Monitor.Exit (imlVE.UpdateMutex); + } + } + protected override void updateEditorFromProjFile () { + try { + string selItemDesignID = null; + if (SelectedItem!=null) + selItemDesignID = SelectedItem.design_id; + imlVE.ClearInterface(); + Instantiator.NextInstantiatorID = 0; + imlVE.Styling = projFile.Project.solution.Styling; + imlVE.DefaultValuesLoader.Clear(); + imlVE.DefaultTemplates = projFile.Project.solution.DefaultTemplates; + imlVE.Instantiators = new Dictionary(); + + //prevent error on empty file + bool emptyFile = true; + string src = projFile.Source; + using (Stream s = new MemoryStream (Encoding.UTF8.GetBytes (src))) { + using (XmlReader itr = XmlReader.Create (s)) { + while(itr.Read()){ + if (itr.NodeType == XmlNodeType.Element){ + emptyFile = false; + break; + } + } + } + } + GraphicObject go = null; + Error = null; + + if (emptyFile){ + imlProjFile.Instance = null; + }else{ + imlVE.LoadIMLFragment(src); + imlProjFile.Instance = imlVE.GraphicTree[0]; + if (selItemDesignID!=null) + imlProjFile.Instance.FindByDesignID(selItemDesignID,out go); + + } + SelectedItem = go; + } catch (Exception ex) { + Error = ex.InnerException; + if (Monitor.IsEntered(imlVE.UpdateMutex)) + Monitor.Exit (imlVE.UpdateMutex); + } + } + + protected override bool EditorIsDirty { + get { return imlProjFile == null ? false : + imlProjFile.Instance == null ? false : imlProjFile.Instance.design_HasChanged; } + set { + if (GraphicTree [0] != null) + GraphicTree [0].design_HasChanged = value; + } + } + protected override bool IsReady { + get { return updateEnabled && imlVE != null && imlProjFile != null; } + } + bool updateEnabled; + /// + /// use to disable update if tab is not the visible one + /// + public bool UpdateEnabled { + get { return updateEnabled; } + set { + if (value == updateEnabled) + return; + updateEnabled = value; + NotifyValueChanged ("UpdateEnabled", updateEnabled); + } + } + protected override void updateCheckPostProcess () + { + imlVE.Update (); + bool isDirty = false; + + lock (imlVE.RenderMutex) + isDirty = imlVE.IsDirty; + + if (isDirty) { + lock (IFace.UpdateMutex) + RegisterForRedraw (); + } + } + + #region GraphicObject overrides + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + switch (layoutType) { + case LayoutingType.Width: + case LayoutingType.Height: + imlVE.ProcessResize (this.ClientRectangle.Size); + break; + } + } + + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + GraphicObject oldHW = HoverWidget; + Rectangle scr = this.ScreenCoordinates (this.getSlot ()); + ProcessMouseMove (e.X - scr.X, e.Y - scr.Y); + + if (oldHW == HoverWidget) + return; + + if (draggedObj != null) { + if (isPossibleContainer (HoverWidget) && draggedObjContainer != HoverWidget) { + removeDraggedObjFrom (); + tryAddDraggedObjTo (HoverWidget); + } + } + + RegisterForRedraw (); + + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + //base.onMouseDown (sender, e); + SelectedItem = HoverWidget; + + if (SelectedItem != null && projFile != null) { + projFile.CurrentLine = SelectedItem.design_line; + projFile.CurrentColumn = SelectedItem.design_column; + } + + } + + protected override void onDraw (Cairo.Context gr) + { + base.onDraw (gr); + if (!drawGrid) + return; + + + Rectangle cb = ClientRectangle; + const double gridLineWidth = 0.1; + double glhw = gridLineWidth / 2.0; + int nbLines = cb.Width / gridSpacing ; + double d = cb.Left + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (d-glhw, cb.Y); + gr.LineTo (d-glhw, cb.Bottom); + d += gridSpacing; + } + nbLines = cb.Height / gridSpacing; + d = cb.Top + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (cb.X, d - glhw); + gr.LineTo (cb.Right, d -glhw); + d += gridSpacing; + } + gr.LineWidth = gridLineWidth; + Foreground.SetAsSource (gr, cb); + gr.Stroke (); + + lock (imlVE.RenderMutex) { + using (Cairo.Surface surf = new Cairo.ImageSurface (imlVE.bmp, Cairo.Format.Argb32, + imlVE.ClientRectangle.Width, imlVE.ClientRectangle.Height, imlVE.ClientRectangle.Width * 4)) { + gr.SetSourceSurface (surf, cb.Left, cb.Top); + gr.Paint (); + } + imlVE.IsDirty = false; + } + + Rectangle hr; + if (HoverWidget != null) { + hr = HoverWidget.ScreenCoordinates (HoverWidget.getSlot ()); +// gr.SetSourceColor (Color.LightGray); +// gr.DrawCote (new Cairo.PointD (hr.X, hr.Center.Y), new Cairo.PointD (hr.Right, hr.Center.Y)); +// gr.DrawCote (new Cairo.PointD (hr.Center.X, hr.Y), new Cairo.PointD (hr.Center.X, hr.Bottom)); + //hr.Inflate (2); + gr.SetSourceColor (Color.LightGray); + gr.SetDash (new double[]{ 3.0, 3.0 }, 0.0); + gr.Rectangle (hr, 1.0); + } + + if (SelectedItem?.Parent == null) + return; + hr = SelectedItem.ScreenCoordinates(SelectedItem.getSlot ()); + hr.Inflate (1); + gr.LineWidth = 2; + gr.SetSourceColor (Color.Yellow); + gr.SetDash (new double[]{ 5.0, 3.0 },0.0); + gr.Rectangle (hr, 1.0); + } + + protected override void onDragEnter (object sender, DragDropEventArgs e) + { + base.onDragEnter (sender, e); + GraphicObjectDesignContainer godc = e.DragSource.DataSource as GraphicObjectDesignContainer; + if (godc == null) + return; + createDraggedObj (godc.CrowType); + } + protected override void onDragLeave (object sender, DragDropEventArgs e) + { + base.onDragLeave (sender, e); + + ClearDraggedObj (); + } + #endregion + + #region draggedObj handling + public GraphicObject draggedObj = null; + public GraphicObject draggedObjContainer = null; + + bool tryAddDraggedObjTo(GraphicObject g){ + lock (imlVE.UpdateMutex) { + if (g.GetType ().IsSubclassOf (typeof(Container))) { + Container c = g as Container; + c.SetChild (draggedObj); + EditorIsDirty = true; + } else if (g.GetType ().IsSubclassOf (typeof(Group))) { + Group c = g as Group; + c.AddChild (draggedObj); + } else + return false; + EditorIsDirty = true; + draggedObjContainer = g; + } + return true; + } + bool isPossibleContainer (GraphicObject g){ + if (g.GetType().IsSubclassOf(typeof(Container))){ + Container c = g as Container; + return c.Child == null; + } + return g.GetType ().IsSubclassOf (typeof(Group)); + } + void removeDraggedObjFrom(){ + if (draggedObjContainer == null) + return; + lock (imlVE.UpdateMutex) { + if (draggedObjContainer.GetType().IsSubclassOf(typeof(Container))){ + Container c = draggedObjContainer as Container; + c.SetChild (null); + EditorIsDirty = true; + //Console.WriteLine ("remove {0} from {1}", draggedObj, c); + }else if (draggedObjContainer.GetType().IsSubclassOf(typeof(Group))){ + Group c = draggedObjContainer as Group; + c.RemoveChild (draggedObj); + EditorIsDirty = true; + //Console.WriteLine ("remove {0} from {1}", draggedObj, c); + }//else + // Console.WriteLine ("Error removing dragged obj"); + } + draggedObjContainer = null; + } + void createDraggedObj (Type crowType) { + lock (imlVE.UpdateMutex) { + draggedObj = imlVE.CreateITorFromIMLFragment ("<" + crowType.Name + "/>").CreateInstance (); + } + } + public void ClearDraggedObj (bool removeFromTree = true) { + //Console.WriteLine ("Clear dragged obj {0}, remove from tree = {1}", draggedObj, removeFromTree); + if (removeFromTree) + removeDraggedObjFrom (); + draggedObjContainer = null; + if (draggedObj == null) + return; + if (removeFromTree) + draggedObj.Dispose (); + draggedObj = null; + } + #endregion + + + void WidgetCheckOver (GraphicObject go, MouseMoveEventArgs e){ + Type tGo = go.GetType(); + if (typeof(TemplatedGroup).IsAssignableFrom (tGo)) { + + } else if (typeof(TemplatedContainer).IsAssignableFrom (tGo)) { + TemplatedContainer c = go as TemplatedContainer; + if (c.Content?.MouseIsIn (e.Position) == true) { + WidgetCheckOver (c.Content, e); + return; + } + } else if (typeof(TemplatedControl).IsAssignableFrom (tGo)) { + } else if (typeof(Group).IsAssignableFrom (tGo)) { + Group c = go as Group; + for (int i = c.Children.Count -1; i >= 0; i--) { + if (c.Children[i].MouseIsIn (e.Position)) { + WidgetCheckOver (c.Children[i], e); + return; + } + } + } else if (typeof(Crow.Container).IsAssignableFrom (tGo)) { + Crow.Container c = go as Crow.Container; + if (c.Child?.MouseIsIn (e.Position)==true) { + WidgetCheckOver (c.Child, e); + return; + } + } + HoverWidget = go; + WidgetMouseEnter (go, e); + } + void WidgetMouseLeave (GraphicObject go, MouseMoveEventArgs e){ + + } + void WidgetMouseEnter (GraphicObject go, MouseMoveEventArgs e){ + + } + void WidgetMouseMove (GraphicObject go, MouseMoveEventArgs e){} + public bool ProcessMouseMove(int x, int y) + { + int deltaX = x - imlVE.Mouse.X; + int deltaY = y - imlVE.Mouse.Y; + imlVE.Mouse.X = x; + imlVE.Mouse.Y = y; + MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY); + e.Mouse = imlVE.Mouse; + + if (imlVE.ActiveWidget != null) { + //TODO, ensure object is still in the graphic tree + //send move evt even if mouse move outside bounds + WidgetMouseMove (imlVE.ActiveWidget, e); + return true; + } + + if (HoverWidget != null) { + //TODO, ensure object is still in the graphic tree + //check topmost graphicobject first + GraphicObject tmp = HoverWidget; + GraphicObject topc = null; + while (tmp is GraphicObject) { + topc = tmp; + tmp = tmp.LogicalParent as GraphicObject; + } + int idxhw = imlVE.GraphicTree.IndexOf (topc); + if (idxhw != 0) { + int i = 0; + while (i < idxhw) { + if (imlVE.GraphicTree [i].LogicalParent == imlVE.GraphicTree [i].Parent) { + if (imlVE.GraphicTree [i].MouseIsIn (e.Position)) { + while (imlVE.HoverWidget != null) { + WidgetMouseLeave (imlVE.HoverWidget, e); + imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; + } + + WidgetCheckOver (GraphicTree [i], e); + return true; + } + } + i++; + } + } + + + if (imlVE.HoverWidget.MouseIsIn (e.Position)) { + WidgetCheckOver (imlVE.HoverWidget, (e)); + return true; + } else { + WidgetMouseLeave (imlVE.HoverWidget, e); + //seek upward from last focused graph obj's + while (imlVE.HoverWidget.LogicalParent as GraphicObject != null) { + imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; + if (imlVE.HoverWidget.MouseIsIn (e.Position)) { + WidgetCheckOver (imlVE.HoverWidget, e); + return true; + } else + WidgetMouseLeave (imlVE.HoverWidget, e); + } + } + } + + //top level graphic obj's parsing + lock (imlVE.GraphicTree) { + for (int i = 0; i < imlVE.GraphicTree.Count; i++) { + GraphicObject g = imlVE.GraphicTree [i]; + if (g.MouseIsIn (e.Position)) { + WidgetCheckOver (g, e); + return true; + } + } + } + imlVE.HoverWidget = null; + return false; + + } + + void GTView_SelectedItemChanged (object sender, SelectionChangeEventArgs e) + { + SelectedItem = e.NewValue as GraphicObject; + } + } +} diff --git a/CrowIDE/src/Editors/Parsers/BufferParser.cs b/CrowIDE/src/Editors/Parsers/BufferParser.cs new file mode 100644 index 00000000..dfec17a3 --- /dev/null +++ b/CrowIDE/src/Editors/Parsers/BufferParser.cs @@ -0,0 +1,380 @@ +using System; +using System.IO; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Crow.Coding +{ + /// + /// base class for tokenizing sources + /// + public abstract class BufferParser + { + /// + /// Default tokens, this enum may be overriden in derived parser with the new keyword, + /// see XMLParser for example. + /// + public enum TokenType { + Unknown = 0, + WhiteSpace = 1, + NewLine = 2, + LineComment = 3, + BlockCommentStart = 4, + BlockComment = 5, + BlockCommentEnd = 6, + Preprocessor = 7, + Identifier = 8, + Keyword = 9, + OpenBlock = 10, + CloseBlock = 11, + StatementEnding = 12, + OperatorOrPunctuation = 13, + IntegerLitteral = 14, + RealLitteral = 15, + StringLitteralOpening = 16, + StringLitteralClosing = 17, + StringLitteral = 18, + CharLitteralOpening = 19, + CharLitteralClosing = 20, + CharLitteral = 21, + BoolLitteral = 22, + NullLitteral = 23, + Type = 24, + } + + #region CTOR + public BufferParser (CodeBuffer _buffer) + { + buffer = _buffer; + + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + //buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + } + + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + + } + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + reparseSource (); + } + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) + TryParseBufferLine (e.LineStart + i); + reparseSource (); + } + #endregion + + internal int currentLine = 0; + internal int currentColumn = 0; + + int syntTreeDepth = 0; + public int SyntacticTreeDepth { + get { return syntTreeDepth;} + set { + syntTreeDepth = value; + if (syntTreeDepth > SyntacticTreeMaxDepth) + SyntacticTreeMaxDepth = syntTreeDepth; + } + } + public int SyntacticTreeMaxDepth = 0; + + protected CodeBuffer buffer; + protected Token currentTok; + protected bool eol = true; + protected Point CurrentPosition { + get { return new Point (currentLine, currentColumn); } + set { + currentLine = value.Y; + currentColumn = value.X; + } + } + + public Node RootNode; + + public abstract void ParseCurrentLine(); + public abstract void SyntaxAnalysis (); + public void reparseSource () { + for (int i = 0; i < buffer.LineCount; i++) { + if (!buffer[i].IsParsed) + TryParseBufferLine (i); + } + try { + SyntaxAnalysis (); + } catch (Exception ex) { + Debug.WriteLine ("Syntax Error: " + ex.ToString ()); + if (ex is ParserException) + SetLineInError (ex as ParserException); + } + } + public void TryParseBufferLine(int lPtr) { + buffer [lPtr].exception = null; + currentLine = lPtr; + currentColumn = 0; + eol = false; + + try { + ParseCurrentLine (); + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + if (ex is ParserException) + SetLineInError (ex as ParserException); + } + + } + + public virtual void SetLineInError(ParserException ex) { + currentTok = default(Token); + if (ex.Line >= buffer.LineCount) + ex.Line = buffer.LineCount - 1; + if (buffer [ex.Line].IsFolded) + buffer.ToogleFolding (ex.Line); + buffer [ex.Line].SetLineInError (ex); + } + public virtual string LineBrkRegex { + get { return @"\r\n|\r|\n|\\\\n"; } + } + void updateFolding () { + // Stack foldings = new Stack(); + // bool inStartTag = false; + // + // for (int i = 0; i < parser.Tokens.Count; i++) { + // TokenList tl = parser.Tokens [i]; + // tl.foldingTo = null; + // int fstTK = tl.FirstNonBlankTokenIndex; + // if (fstTK > 0 && fstTK < tl.Count - 1) { + // if (tl [fstTK + 1] != XMLParser.TokenType.ElementName) + // continue; + // if (tl [fstTK] == XMLParser.TokenType.ElementStart) { + // //search closing tag + // int tkPtr = fstTK+2; + // while (tkPtr < tl.Count) { + // if (tl [tkPtr] == XMLParser.TokenType.ElementClosing) + // + // tkPtr++; + // } + // if (tl.EndingState == (int)XMLParser.States.Content) + // foldings.Push (tl); + // else if (tl.EndingState == (int)XMLParser.States.StartTag) + // inStartTag = true; + // continue; + // } + // if (tl [fstTK] == XMLParser.TokenType.ElementEnd) { + // TokenList tls = foldings.Pop (); + // int fstTKs = tls.FirstNonBlankTokenIndex; + // if (tls [fstTK + 1].Content == tl [fstTK + 1].Content) { + // tl.foldingTo = tls; + // continue; + // } + // parser.CurrentPosition = tls [fstTK + 1].Start; + // parser.SetLineInError(new ParserException(parser, "closing tag not corresponding")); + // } + // + // } + // } + } + + #region low level parsing + protected void addCharToCurTok(char c, Point position){ + currentTok.Start = position; + currentTok += c; + } + /// + /// Read one char from current position in buffer and store it into the current token + /// + /// if true, set the Start position of the current token to the current position + protected void readToCurrTok(bool startOfTok = false){ + if (startOfTok) + currentTok.Start = CurrentPosition; + currentTok += Read(); + } + /// + /// read n char from the buffer and store it into the current token + /// + protected void readToCurrTok(int length) { + for (int i = 0; i < length; i++) + currentTok += Read (); + } + /// + /// Save current token into current TokensLine and raz current token + /// + protected void saveAndResetCurrentTok() { + currentTok.End = CurrentPosition; + buffer[currentLine].Tokens.Add (currentTok); + currentTok = default(Token); + } + /// + /// read one char and add current token to current TokensLine, current token is reset + /// + /// Type of the token + /// set start of token to current position + protected void readAndResetCurrentTok(System.Enum type, bool startToc = false) { + readToCurrTok (); + saveAndResetCurrentTok (type); + } + /// + /// Save current tok + /// + /// set the type of the tok + protected void saveAndResetCurrentTok(System.Enum type) { + currentTok.Type = (TokenType)type; + saveAndResetCurrentTok (); + } + protected void setPreviousTokOfTypeTo (TokenType inType, TokenType newType) { + for (int i = currentLine; i >= 0; i--) { + int j = buffer [i].Tokens.Count - 1; + while (j >= 0) { + if (buffer [i].Tokens [j].Type == inType) { + Token t = buffer [i].Tokens [j]; + t.Type = newType; + buffer [i].Tokens [j] = t; + return; + } + j--; + } + } + } + /// + /// Peek next char, emit '\n' if current column > buffer's line length + /// Throw error if eof is true + /// + protected virtual char Peek() { + if (eol) + throw new ParserException (currentLine, currentColumn, "Unexpected End of line"); + return currentColumn < buffer [currentLine].Length ? + buffer [currentLine] [currentColumn] : '\n'; + } + /// + /// 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 + /// + /// Length. + protected virtual string Peek(int length) { + if (eol) + throw new ParserException (currentLine, currentColumn, "Unexpected End of Line"); + int lg = Math.Min(length, Math.Max (buffer [currentLine].Length - currentColumn, buffer [currentLine].Length - currentColumn - length)); + if (lg == 0) + return ""; + return buffer [currentLine].Content.Substring (currentColumn, lg); + } + /// + /// read one char from buffer at current position, if '\n' is read, current line is incremented + /// and column is reset to 0 + /// + protected virtual char Read() { + char c = Peek (); + if (c == '\n') + eol = true; + currentColumn++; + return c; + } + protected virtual string Read(int charCount){ + string tmp = ""; + for (int i = 0; i < charCount; i++) { + if (eol) + break; + tmp += Read (); + } + return tmp; + } + /// + /// read until end of line is reached + /// + /// string read + protected virtual string ReadLine () { + StringBuilder tmp = new StringBuilder(); + char c = Read (); + while (!eol) { + tmp.Append (c); + c = Read (); + } + return tmp.ToString(); + } + /// + /// read until end expression is reached or end of line. + /// + /// string read minus the ending expression that has to be read after + /// Expression to search for + protected virtual string ReadLineUntil (string endExp){ + string tmp = ""; + + while (!eol) { + if (buffer [currentLine].Length - currentColumn - endExp.Length < 0) { + tmp += ReadLine(); + break; + } + if (string.Equals (Peek (endExp.Length), endExp)) + return tmp; + tmp += Read(); + } + return tmp; + } + /// + /// skip white spaces, but not line break. Save spaces in a WhiteSpace token. + /// + protected void SkipWhiteSpaces () { + if (currentTok.Type != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "current token should be reset to unknown (0) before skiping white spaces"); + while (!eol) { + if (!char.IsWhiteSpace (Peek ())||Peek()=='\n') + break; + readToCurrTok (currentTok.Type == TokenType.Unknown); + currentTok.Type = TokenType.WhiteSpace; + } + if (currentTok.Type != TokenType.Unknown) + saveAndResetCurrentTok (); + } + #endregion + + protected Node addChildNode (Node curNode, CodeLine cl, int tokPtr, string type = "") { + Node n = new Node () { Name = cl.Tokens [tokPtr].Content, StartLine = cl, Type = type }; + curNode.AddChild (n); + if (cl.SyntacticNode == null) + cl.SyntacticNode = n; + SyntacticTreeDepth++; + return n; + } + protected void closeNodeAndGoUp (ref Node n, CodeLine cl, string type = ""){ + while (n != null) { + if (n.Type == type) { + n.EndLine = cl; + n = n.Parent; + SyntacticTreeDepth--; + break; + } + n = n.Parent; + SyntacticTreeDepth--; + } + } + protected void closeNodeAndGoUp (ref Node n, CodeLine cl){ + SyntacticTreeDepth--; + n.EndLine = cl; + n = n.Parent; + } + + protected void initSyntaxAnalysis () { + RootNode = new Node () { Name = "RootNode", Type="Root" }; + SyntacticTreeDepth = SyntacticTreeMaxDepth = 0; + } + + + protected void throwParserException(string msg){ + throw new ParserException (currentLine, currentColumn, msg); + } + } +} \ No newline at end of file diff --git a/CrowIDE/src/Editors/Parsers/CSharpParser.cs b/CrowIDE/src/Editors/Parsers/CSharpParser.cs new file mode 100644 index 00000000..62090bc1 --- /dev/null +++ b/CrowIDE/src/Editors/Parsers/CSharpParser.cs @@ -0,0 +1,384 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Linq; + +namespace Crow.Coding +{ + public class CSharpParser : BufferParser + { + #region keywords + string[] keywords = new string[] { + "abstract", + "as", + "ascending", + "async", + "await", + "base", + "bool", + "break", + "byte", + "case", + "catch", + "char", + "checked", + "class", + "const", + "continue", + "decimal", + "default", + "delegate", + "descending", + "do", + "double", + "dynamic", + "else", + "enum", + "equals", + "event", + "explicit", + "extern", + "false", + "finally", + "fixed", + "float", + "for", + "foreach", + "from", + "get", + "goto", + "group", + "if", + "implicit", + "in", + "int", + "interface", + "internal", + "is", + "join", + "let", + "lock", + "long", + "nameof", + "namespace", + "new", + "null", + "object", + "operator", + "orderby", + "out", + "override", + "params", + "partial", + "private", + "protected", + "public", + "readonly", + "ref", + "return", + "sbyte", + "sealed", + "select", + "set", + "short", + "sizeof", + "stackalloc", + "static", + "string", + "struct", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "uint", + "ulong", + "unchecked", + "unsafe", + "ushort", + "using", + "value", + "var", + "virtual", + "void", + "volatile", + "when", + "where", + "while", + "yield " + }; + #endregion + + public enum States + { + init, + BlockComment, + InNameSpace, + InClass, + InMember, + Unknown, + } + + public CSharpParser (CodeBuffer _buffer) : base(_buffer) + { + } + + #region Regular Expression for validity checks + static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}"); + static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNewLineChar = new Regex(@"\u000D|\u000A|\u0085|\u2028|\u2029"); + static Regex rxWhiteSpaceChar = new Regex(@"\p{Zs}|\u0009|\u000B|\u000C"); + static Regex rxDecimal = new Regex(@"[0-9]+"); + static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + + public static bool CharIsValidCharStartName (char c) { + return rxNameStartChar.IsMatch(new string(new char[]{c})); + } + public static bool CharIsValidCharName (char c) { + return rxNameChar.IsMatch(new string(new char[]{c})); + } + + public bool nextCharIsValidCharStartName + { + get { return CharIsValidCharStartName(Peek()); } + } + public bool nextCharIsValidCharName + { + get { return CharIsValidCharName(Peek()); } + } + #endregion + + States curState = States.init; + States savedState = States.init; + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + while (! eol) { + if (currentTok.IsNull) + SkipWhiteSpaces (); + + if (curState == States.BlockComment) { + currentTok.Start = CurrentPosition; + currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; + currentTok += ReadLineUntil ("*/"); + if (Peek (2) == "*/") { + readToCurrTok (2); + curState = savedState; + } + saveAndResetCurrentTok (); + continue; + } + + switch (Peek()) { + case '\n': + eol = true; + if (!currentTok.IsNull) + saveAndResetCurrentTok (); + break; + case '#': + readToCurrTok (true); + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Preprocessor); + break; + case '/': + readToCurrTok (true); + switch (Peek ()) { + case '*': + readToCurrTok (); + currentTok += ReadLine (); + //currentTok.Type = (Parser.TokenType)TokenType.BlockComment; + savedState = curState; + curState = States.BlockComment; + saveAndResetCurrentTok (TokenType.BlockComment); + break; + case '/': + //readToCurrTok (); + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.LineComment); + //currentTok.Type = (Parser.TokenType)TokenType.LineComment; + break; + default: + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Unknown); + break; + } + break; + case '{': + if (currentTok.IsNull) + readAndResetCurrentTok (TokenType.OpenBlock, true); + else + readToCurrTok (); + break; + case '}': + if (currentTok.IsNull) + readAndResetCurrentTok (TokenType.CloseBlock, true); + else + readToCurrTok (); + break; + case '\\'://unicode escape sequence + if (!(currentTok.Type == TokenType.Identifier || + currentTok.IsEmpty || currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral)) { + saveAndResetCurrentTok (); + } + Point pos = CurrentPosition; + Read (); + char escChar = Read (); + + if (escChar == 'u') { + char c = char.ConvertFromUtf32 (int.Parse (Read (4), System.Globalization.NumberStyles.HexNumber))[0]; + if (currentTok.IsEmpty) { + if (!CharIsValidCharStartName (c)) + throwParserException ("expecting identifier start"); + currentTok.Start = pos; + currentTok.Type = TokenType.Identifier; + } else if (currentTok.Type == TokenType.Identifier) { + if (!CharIsValidCharName (c)) + throwParserException ("expecting identifier valid char"); + } + currentTok += c; + break; + } + currentTok += new String (new char[] { '\\', escChar }); + break; + case '\'': + if (currentTok.IsNull) { + readAndResetCurrentTok (TokenType.CharLitteralOpening, true); + currentTok.Type = TokenType.CharLitteral; + } else if (currentTok.Type == TokenType.CharLitteral) { + saveAndResetCurrentTok (); + readAndResetCurrentTok (TokenType.CharLitteralClosing, true); + } else if (currentTok.Type == TokenType.StringLitteral){ + readToCurrTok (); + } else + throwParserException ("unexpected character: (\')"); + break; + case '"': + if (currentTok.IsNull) { + readAndResetCurrentTok (TokenType.StringLitteralOpening, true); + currentTok.Type = TokenType.StringLitteral; + } else if (currentTok.Type == TokenType.StringLitteral) { + saveAndResetCurrentTok (); + readAndResetCurrentTok (TokenType.StringLitteralClosing, true); + } else + throwParserException ("unexpected character: (\")"); + break; + default: + if (currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral) { + readToCurrTok (currentTok.IsEmpty); + } else if (currentTok.IsNull) { + if (nextCharIsValidCharStartName) { + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + + if (keywords.Contains (currentTok.Content)) + saveAndResetCurrentTok (TokenType.Keyword); + else + saveAndResetCurrentTok (TokenType.Identifier); + continue; + } else + readAndResetCurrentTok(TokenType.Unknown, true); + } else + readAndResetCurrentTok(TokenType.Unknown, true); + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + int ptrLine = 0; + while (ptrLine < buffer.LineCount) { + CodeLine cl = buffer [ptrLine]; + if (cl.Tokens == null){ + ptrLine++; + continue; + } + cl.SyntacticNode = null; + + int tokPtr = 0; + bool onlyWhiteSpace = true; + while (tokPtr < cl.Tokens.Count) { + if (cl.Tokens [tokPtr].Type == TokenType.WhiteSpace) { + tokPtr++; + continue; + } + + if (cl.Tokens [tokPtr].Type == TokenType.LineComment && onlyWhiteSpace) { + int startLine = ptrLine; + ptrLine++; + while (ptrLine < buffer.LineCount) { + int idx = buffer [ptrLine].FirstNonBlankTokIndex; + if (idx < 0) + break; + if (buffer [ptrLine].Tokens [idx].Type != TokenType.LineComment) + break; + ptrLine++; + } + ptrLine--; + if (ptrLine - startLine > 0) { + currentNode = addChildNode (currentNode, cl, tokPtr, "comment"); + closeNodeAndGoUp (ref currentNode, buffer [ptrLine], "comment"); + } + break; + } + + switch (cl.Tokens [tokPtr].Type) { + case TokenType.OpenBlock: + currentNode = addChildNode (currentNode, cl, tokPtr); + break; + case TokenType.CloseBlock: + closeNodeAndGoUp (ref currentNode, cl); + break; + case TokenType.Preprocessor: + if (cl.Tokens [tokPtr].Content.StartsWith ("#region")) { + currentNode = addChildNode (currentNode, cl, tokPtr, "region"); + } else if (cl.Tokens [tokPtr].Content.StartsWith ("#endregion")) { + + closeNodeAndGoUp (ref currentNode, cl,"region"); + } + break; + } + onlyWhiteSpace = false; + tokPtr++; + } + ptrLine++; + } + ptrLine = 0; + while (ptrLine < buffer.LineCount) { + CodeLine cl = buffer [ptrLine]; + if (cl.IsFoldable) { + if (cl.SyntacticNode.Type == "comment" || cl.SyntacticNode.Type == "region") + cl.IsFolded = true; + } + ptrLine++; + } + } + } +} + diff --git a/CrowIDE/src/Editors/Parsers/StyleParser.cs b/CrowIDE/src/Editors/Parsers/StyleParser.cs new file mode 100644 index 00000000..9a1e74cd --- /dev/null +++ b/CrowIDE/src/Editors/Parsers/StyleParser.cs @@ -0,0 +1,179 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Linq; + +namespace Crow.Coding +{ + public class StyleParser : BufferParser + { + enum States { init, classNames, members, value, endOfStatement } + + public StyleParser (CodeBuffer _buffer) : base(_buffer) + { + } + + #region Character ValidityCheck + static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}"); + static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxDecimal = new Regex(@"[0-9]+"); + static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + + public bool nextCharIsValidCharStartName + { + get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } + } + public bool nextCharIsValidCharName + { + get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } + } + #endregion + + States curState = States.classNames; + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + while (! eol) { + SkipWhiteSpaces (); + + if (eol) + break; + + if (Peek () == '\n') { + if (currentTok != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + Read (); + eol = true; + continue; + } + + switch (Peek()) { + case '/': + readToCurrTok (true); + switch (Peek ()) { + case '/': + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.LineComment); + break; + default: + currentTok += ReadLine (); + saveAndResetCurrentTok (TokenType.Unknown); + break; + } + break; + case ',': + if (curState != States.init && curState != States.classNames ) + throw new ParserException (currentLine, currentColumn, "Unexpected char ','"); + readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); + curState = States.classNames; + break; + case '{': + if (!(curState == States.init || curState == States.classNames)) + throw new ParserException (currentLine, currentColumn, "Unexpected char '{'"); + readAndResetCurrentTok (TokenType.OpenBlock, true); + curState = States.members; + break; + case '}': + if (curState != States.members) + throw new ParserException (currentLine, currentColumn, "Unexpected char '}'"); + readAndResetCurrentTok (TokenType.CloseBlock, true); + curState = States.classNames; + break; + case '=': + if (curState == States.classNames) + throw new ParserException (currentLine, currentColumn, "Unexpected char '='"); + setPreviousTokOfTypeTo (TokenType.Type, TokenType.Identifier); + readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); + curState = States.value; + break; + case '"': + if (curState != States.value) + throw new ParserException (currentLine, currentColumn, "Unexpected char '\"'"); + readAndResetCurrentTok (TokenType.StringLitteralOpening, true); + + while (!eol) { + currentTok += ReadLineUntil ("\""); + if (currentTok.Content [currentTok.Content.Length - 1] == '\\') + readToCurrTok (); + else + break; + } + if (eol) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + saveAndResetCurrentTok (TokenType.StringLitteral); + + readAndResetCurrentTok (TokenType.StringLitteralClosing, true); + curState = States.endOfStatement; + break; + case ';': + if (curState != States.endOfStatement) + throw new ParserException (currentLine, currentColumn, "Unexpected end of statement"); + readAndResetCurrentTok (TokenType.StatementEnding, true); + curState = States.members; + break; + default: + if (currentTok.Type != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "error curtok not null"); + if (curState == States.value) + throw new ParserException (currentLine, currentColumn, "expecting value enclosed in '\"'"); + if (curState == States.endOfStatement) + throw new ParserException (currentLine, currentColumn, "expecting end of statement"); + + if (nextCharIsValidCharStartName) { + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + } + saveAndResetCurrentTok (TokenType.Type); + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + for (int i = 0; i < buffer.LineCount; i++) { + CodeLine cl = buffer[i]; + if (cl.Tokens == null) + continue; + cl.SyntacticNode = null; + + int tokPtr = 0; + while (tokPtr < cl.Tokens.Count) { + switch (cl.Tokens [tokPtr].Type) { + case TokenType.OpenBlock: + currentNode = addChildNode (currentNode, cl, tokPtr, "style"); + break; + case TokenType.CloseBlock: + closeNodeAndGoUp (ref currentNode, cl, "style"); + break; + } + tokPtr++; + } + } + } + } +} + diff --git a/CrowIDE/src/Editors/Parsers/XMLParser.cs b/CrowIDE/src/Editors/Parsers/XMLParser.cs new file mode 100644 index 00000000..d31e1023 --- /dev/null +++ b/CrowIDE/src/Editors/Parsers/XMLParser.cs @@ -0,0 +1,298 @@ +using System; +using Crow; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Linq; + +namespace Crow.Coding +{ + public class XMLParser : BufferParser + { + public new enum TokenType { + Unknown = BufferParser.TokenType.Unknown, + WhiteSpace = BufferParser.TokenType.WhiteSpace, + NewLine = BufferParser.TokenType.NewLine, + LineComment = BufferParser.TokenType.LineComment, + BlockCommentStart = BufferParser.TokenType.BlockCommentStart, + BlockComment = BufferParser.TokenType.BlockComment, + BlockCommentEnd = BufferParser.TokenType.BlockCommentEnd, + ElementName = BufferParser.TokenType.Identifier, + AttributeName = BufferParser.TokenType.Keyword, + ElementClosing = BufferParser.TokenType.StatementEnding, + Affectation = BufferParser.TokenType.OperatorOrPunctuation, + AttributeValueOpening = BufferParser.TokenType.StringLitteralOpening, + AttributeValueClosing = BufferParser.TokenType.StringLitteralClosing, + AttributeValue = BufferParser.TokenType.StringLitteral, + XMLDecl = BufferParser.TokenType.Preprocessor, + ElementStart = 50, + ElementEnd = 51, + } + + public enum States + { + init, //first statement of prolog, xmldecl should only apear in this state + prolog, //misc before doctypedecl + InternalSubset, //doctype declaration subset + ExternalSubsetInit, + ExternalSubset, + BlockComment, + DTDEnd,//doctype finished + XML,//normal xml + StartTag,//inside start tag + Content,//after start tag with no closing slash + EndTag + } + + #region CTOR + public XMLParser (CodeBuffer _buffer) : base(_buffer) {} + #endregion + + enum Keywords + { + DOCTYPE, + ELEMENT, + ATTLIST, + ENTITY, + NOTATION + } + + States curState = States.init; + + #region Regular Expression for validity checks + //private static Regex rxValidChar = new Regex("[\u0020-\uD7FF]"); + private static Regex rxValidChar = new Regex(@"\u0009|\u000A|\u000D|[\u0020-\uD7FF]|[\uE000-\uFFFD]"); //| [\u10000-\u10FFFF] unable to set those plans + private static Regex rxNameStartChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]"); // | [\u10000-\uEFFFF] + private static Regex rxNameChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|-|\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]");//[\u10000-\uEFFFF]| + private static Regex rxDecimal = new Regex(@"[0-9]+"); + private static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + private static Regex rxAttributeValue = new Regex(@"[^<]"); + private static Regex rxEntityValue = new Regex(@"[^<]"); + private static Regex rxPubidChar = new Regex(@"\u0020|\u000D|\u000A|[a-zA-Z0-9]|[-\(\)\+\,\./:=\?;!\*#@\$_%]"); + #endregion + + #region Character ValidityCheck + public bool nextCharIsValidCharStartName + { + get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } + } + public bool nextCharIsValidCharName + { + get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } + } + #endregion + + public override void SetLineInError (ParserException ex) + { + base.SetLineInError (ex); + //buffer[ex.Line].Tokens.EndingState = (int)States.init; + } + + public override void ParseCurrentLine () + { + //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); + CodeLine cl = buffer [currentLine]; + cl.Tokens = new List (); + + //retrieve current parser state from previous line + if (currentLine > 0) + curState = (States)buffer[currentLine - 1].EndingState; + else + curState = States.init; + + States previousEndingState = (States)cl.EndingState; + + + while (! eol) { + SkipWhiteSpaces (); + + if (eol) + break; + + if (Peek () == '\n') { + if (currentTok != TokenType.Unknown) + throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); + Read (); + eol = true; + continue; + } + + if (curState == States.BlockComment) { + if (currentTok != TokenType.Unknown) + Debugger.Break (); + + currentTok.Start = CurrentPosition; + currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; + currentTok += ReadLineUntil ("-->"); + if (Peek (3) == "-->") { + readToCurrTok (3); + curState = States.XML; + } + saveAndResetCurrentTok (); + continue; + } + + switch (Peek()) { + case '<': + readToCurrTok (true); + switch (Peek()) { + case '?': + if (curState != States.init) + throw new ParserException (currentLine, currentColumn, "xml decl may appear only on first line"); + readToCurrTok (); + currentTok += ReadLineUntil ("?>"); + if (Peek (2) != "?>") + throw new ParserException (currentLine, currentColumn, "expecting '?>'"); + readToCurrTok (2); + saveAndResetCurrentTok (TokenType.XMLDecl); + curState = States.prolog; + break; + case '!': + readToCurrTok (); + switch (Peek()) { + case '-': + readToCurrTok (); + if (Peek () != '-') + throw new ParserException (currentLine, currentColumn, "Expecting comment start tag"); + readToCurrTok (); + currentTok += ReadLineUntil ("--"); + if (Peek (3) == "-->") { + readToCurrTok (3); + }else + curState = States.BlockComment; + saveAndResetCurrentTok (TokenType.BlockComment); + break; + default: + throw new ParserException (currentLine, currentColumn, "error"); + } + break; + default: + if (!(curState == States.Content || curState == States.XML || curState == States.init || curState == States.prolog)) + throw new ParserException (currentLine, currentColumn, "Unexpected char: '<'"); + if (Peek () == '/') { + curState = States.EndTag; + readToCurrTok (); + saveAndResetCurrentTok (TokenType.ElementEnd); + } else { + curState = States.StartTag; + saveAndResetCurrentTok (TokenType.ElementStart); + } + + if (!nextCharIsValidCharStartName) + throw new ParserException (currentLine, currentColumn, "Expected element name"); + + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + + saveAndResetCurrentTok (TokenType.ElementName); + break; + } + break; + case '/': + if (curState != States.StartTag) + throw new ParserException (currentLine, currentColumn, "Unexpected char: '/'"); + readToCurrTok (true); + if (Peek () != '>') + throw new ParserException (currentLine, currentColumn, "Expecting '>'"); + readAndResetCurrentTok (TokenType.ElementEnd); + + curState = States.XML; + break; + case '>': + readAndResetCurrentTok (TokenType.ElementClosing, true); + switch (curState) { + case States.EndTag: + curState = States.XML; + break; + case States.StartTag: + curState = States.Content; + break; + default: + throw new ParserException (currentLine, currentColumn, "Unexpected char: '>'"); + } + break; + default: + switch (curState) { + case States.StartTag: + if (!nextCharIsValidCharStartName) + throw new ParserException (currentLine, currentColumn, "Expected attribute name"); + readToCurrTok (true); + while (nextCharIsValidCharName) + readToCurrTok (); + saveAndResetCurrentTok (TokenType.AttributeName); + + SkipWhiteSpaces (); + + if (Peek () != '=') + throw new ParserException (currentLine, currentColumn, "Expecting: '='"); + readAndResetCurrentTok (TokenType.Affectation, true); + + SkipWhiteSpaces (); + + char openAttVal = Peek (); + if (openAttVal != '"' && openAttVal != '\'') + throw new ParserException (currentLine, currentColumn, "Expecting attribute value enclosed either in '\"' or in \"'\""); + readAndResetCurrentTok (TokenType.AttributeValueOpening, true); + + currentTok.Start = CurrentPosition; + currentTok.Content = ReadLineUntil (new string (new char[]{ openAttVal })); + saveAndResetCurrentTok (TokenType.AttributeValue); + + if (Peek () != openAttVal) + throw new ParserException (currentLine, currentColumn, string.Format ("Expecting {0}", openAttVal)); + readAndResetCurrentTok (TokenType.AttributeValueClosing, true); + break; + default: + throw new ParserException (currentLine, currentColumn, "unexpected char: " + Peek ()); + } + break; + } + } + + if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) + buffer [currentLine + 1].Tokens = null; + + cl.EndingState = (int)curState; + } + + public override void SyntaxAnalysis () + { + initSyntaxAnalysis (); + Node currentNode = RootNode; + + for (int i = 0; i < buffer.LineCount; i++) { + CodeLine cl = buffer[i]; + if (cl.Tokens == null) + continue; + cl.SyntacticNode = null; + + int tokPtr = 0; + while (tokPtr < cl.Tokens.Count) { + switch ((XMLParser.TokenType)cl.Tokens [tokPtr].Type) { + case TokenType.ElementStart: + tokPtr++; + currentNode = addChildNode (currentNode, cl, tokPtr, "Element"); + break; + case TokenType.ElementEnd: + tokPtr++; + if (tokPtr < cl.Tokens.Count) { + if ((XMLParser.TokenType)cl.Tokens [tokPtr].Type == TokenType.ElementName && + cl.Tokens [tokPtr].Content != currentNode.Name) + throw new ParserException (currentLine, currentColumn, "Closing tag mismatch"); + } + closeNodeAndGoUp (ref currentNode, cl, "Element"); + break; + case TokenType.ElementClosing: + //currentNode = currentNode.Parent; + break; + default: + break; + } + tokPtr++; + } + } + } + } +} + diff --git a/CrowIDE/src/Editors/SvgEditor.cs b/CrowIDE/src/Editors/SvgEditor.cs new file mode 100644 index 00000000..219eea67 --- /dev/null +++ b/CrowIDE/src/Editors/SvgEditor.cs @@ -0,0 +1,137 @@ +// +// SvgEditor.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.ComponentModel; +using Cairo; + +namespace Crow.Coding +{ + public class SvgEditor : Editor + { + SvgPicture _pic = new SvgPicture(); + + int zoom; + + [DefaultValue(100)] + public int Zoom { + get { return zoom; } + set { + if (zoom == value) + return; + zoom = value; + NotifyValueChanged ("Zoom", zoom); + updateMaxScrolls (); + RegisterForGraphicUpdate (); + } + } + + void updateMaxScrolls() { + MaxScrollX = Math.Max(0, _pic.Dimensions.Width * zoom / 100 - Slot.Width); + MaxScrollY = Math.Max(0, _pic.Dimensions.Height * zoom / 100 - Slot.Height); + + if (Slot.Width + MaxScrollX > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / (Slot.Width + MaxScrollX)); + else + NotifyValueChanged ("ChildWidthRatio", 0); + + if (Slot.Height + MaxScrollY > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / (Slot.Height + MaxScrollY)); + else + NotifyValueChanged ("ChildHeightRatio", 0); + } + #region editor overrides + protected override void updateEditorFromProjFile () + { + Error = null; + try { + editorMutex.EnterWriteLock(); + _pic.LoadSvgFragment (projFile.Source); + _pic.Scaled = true; + _pic.KeepProportions = true; + } catch (Exception ex) { + Error = ex; + } + editorMutex.ExitWriteLock (); + updateMaxScrolls (); + RegisterForGraphicUpdate (); + } + protected override void updateProjFileFromEditor () + { + throw new NotImplementedException (); + } + protected override bool EditorIsDirty { + get { return false; } + set { + throw new NotImplementedException (); + } + } + #endregion + + #region GraphicObject overrides + protected override int measureRawSize (LayoutingType lt) + { + if (_pic == null) + return 2 * Margin; + //_pic = "#Crow.Images.Icons.IconAlerte.svg"; + //TODO:take scalling in account + if (lt == LayoutingType.Width) + return _pic.Dimensions.Width + 2 * Margin; + else + return _pic.Dimensions.Height + 2 * Margin; + } + protected override void onDraw (Context gr) + { + base.onDraw (gr); + + Rectangle r = ClientRectangle; + Foreground.SetAsSource (gr, r); + gr.Rectangle (r, 0.1); + gr.Stroke (); + + r.Width = _pic.Dimensions.Width * zoom / 100; + r.Height = _pic.Dimensions.Height * zoom / 100; + + gr.Save (); + + editorMutex.EnterReadLock (); + + gr.Translate (-ScrollX, -ScrollY); + if (_pic != null) + _pic.Paint (gr, r); + editorMutex.ExitReadLock (); + + gr.Restore (); + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + if ((layoutType | LayoutingType.Sizing) > 0) + updateMaxScrolls (); + } + #endregion + } +} + diff --git a/CrowIDE/src/Extensions.cs b/CrowIDE/src/Extensions.cs index 0d12fec8..05ef71e4 100644 --- a/CrowIDE/src/Extensions.cs +++ b/CrowIDE/src/Extensions.cs @@ -25,6 +25,9 @@ namespace Crow { public static partial class Extensions { + public static string GetIcon(this GraphicObject go){ + return "#Crow.Coding.icons.toolbox." + go.GetType().FullName + ".svg"; + } public static List GetChildren(this GraphicObject go){ Type goType = go.GetType(); if (typeof (Group).IsAssignableFrom (goType)) diff --git a/CrowIDE/src/GraphicObjectDesignContainer.cs b/CrowIDE/src/GraphicObjectDesignContainer.cs index c8e1a70f..e7776d26 100644 --- a/CrowIDE/src/GraphicObjectDesignContainer.cs +++ b/CrowIDE/src/GraphicObjectDesignContainer.cs @@ -52,7 +52,7 @@ namespace Crow.Coding go.IFace.DragImageHeight = dis; go.IFace.DragImageWidth = dis; SvgPicture pic = new SvgPicture (); - pic.Load (IconPath); + pic.Load (go.IFace, IconPath); ImageSurface img = new ImageSurface (Format.Argb32, dis, dis); using (Context ctx = new Context (img)) { Rectangle r = new Rectangle (0, 0, dis, dis); diff --git a/CrowIDE/src/ImlVisualEditor.cs b/CrowIDE/src/ImlVisualEditor.cs deleted file mode 100644 index d084904e..00000000 --- a/CrowIDE/src/ImlVisualEditor.cs +++ /dev/null @@ -1,506 +0,0 @@ -// -// ImlVisualEditor.cs -// -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2016 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 Crow; -using System.Threading; -using System.Xml.Serialization; -using System.ComponentModel; -using System.IO; -using System.Collections.Generic; -using Crow.IML; -using System.Text; -using System.Xml; - -namespace Crow.Coding -{ - public class ImlVisualEditor : Editor - { - #region CTOR - public ImlVisualEditor () : base() - { - imlVE = new DesignInterface (); - } - #endregion - - DesignInterface imlVE; - GraphicObject selectedItem; - ImlProjectItem imlProjFile; - Exception imlError = null; - - bool drawGrid, snapToGrid; - int gridSpacing; - - [DefaultValue(true)] - public bool DrawGrid { - get { return drawGrid; } - set { - if (drawGrid == value) - return; - drawGrid = value; - NotifyValueChanged ("DrawGrid", drawGrid); - RegisterForRedraw (); - } - } - [DefaultValue(true)] - public bool SnapToGrid { - get { return snapToGrid; } - set { - if (snapToGrid == value) - return; - snapToGrid = value; - NotifyValueChanged ("SnapToGrid", snapToGrid); - } - } - [DefaultValue(10)] - public int GridSpacing { - get { return gridSpacing; } - set { - if (gridSpacing == value) - return; - gridSpacing = value; - NotifyValueChanged ("GridSpacing", gridSpacing); - RegisterForRedraw (); - } - } - [XmlAttributeAttribute]public GraphicObject SelectedItem { - get { return selectedItem; } - set { - if (selectedItem == value) - return; - selectedItem = value; - NotifyValueChanged ("SelectedItem", selectedItem); - RegisterForRedraw (); - } - } - /// PoinprojFilever the widget - public virtual GraphicObject HoverWidget - { - get { return imlVE.HoverWidget; } - set { - if (HoverWidget == value) - return; - - imlVE.HoverWidget = value; - - NotifyValueChanged ("HoverWidget", HoverWidget); - } - } - [XmlIgnore]public List LQIs { - get { return imlVE.LQIs; } - } - - public override ProjectFile ProjectNode { - get { - return base.ProjectNode; - } - set { - base.ProjectNode = value; - imlProjFile = projFile as ImlProjectItem; - imlVE.ProjFile = imlProjFile; - } - } - - public List GraphicTree { - get { return imlVE.GraphicTree; } - } - protected override void updateProjFileFromEditor () - { - try { - projFile.UpdateSource(this, imlProjFile.Instance.GetIML()); - } catch (Exception ex) { - Error = ex.InnerException; - if (Monitor.IsEntered(imlVE.UpdateMutex)) - Monitor.Exit (imlVE.UpdateMutex); - } - } - protected override void updateEditorFromProjFile () { - try { - string selItemDesignID = null; - if (SelectedItem!=null) - selItemDesignID = SelectedItem.design_id; - imlVE.ClearInterface(); - Instantiator.NextInstantiatorID = 0; - imlVE.Styling = projFile.Project.solution.Styling; - imlVE.DefaultValuesLoader.Clear(); - imlVE.DefaultTemplates = projFile.Project.solution.DefaultTemplates; - imlVE.Instantiators = new Dictionary(); - - //prevent error on empty file - bool emptyFile = true; - string src = projFile.Source; - using (Stream s = new MemoryStream (Encoding.UTF8.GetBytes (src))) { - using (XmlReader itr = XmlReader.Create (s)) { - while(itr.Read()){ - if (itr.NodeType == XmlNodeType.Element){ - emptyFile = false; - break; - } - } - } - } - GraphicObject go = null; - Error = null; - - if (emptyFile){ - imlProjFile.Instance = null; - }else{ - imlVE.LoadIMLFragment(src); - imlProjFile.Instance = imlVE.GraphicTree[0]; - if (selItemDesignID!=null) - imlProjFile.Instance.FindByDesignID(selItemDesignID,out go); - - } - SelectedItem = go; - } catch (Exception ex) { - Error = ex.InnerException; - if (Monitor.IsEntered(imlVE.UpdateMutex)) - Monitor.Exit (imlVE.UpdateMutex); - } - } - - protected override bool EditorIsDirty { - get { return (bool)imlProjFile.Instance?.design_HasChanged; } - set { - if (GraphicTree [0] != null) - GraphicTree [0].design_HasChanged = value; - } - } - protected override bool IsReady { - get { return imlVE != null && imlProjFile != null; } - } - protected override void updateCheckPostProcess () - { - imlVE.Update (); - bool isDirty = false; - - lock (imlVE.RenderMutex) - isDirty = imlVE.IsDirty; - - if (isDirty) { - lock (IFace.UpdateMutex) - RegisterForRedraw (); - } - } - - #region GraphicObject overrides - public override void OnLayoutChanges (LayoutingType layoutType) - { - base.OnLayoutChanges (layoutType); - switch (layoutType) { - case LayoutingType.Width: - case LayoutingType.Height: - imlVE.ProcessResize (this.ClientRectangle.Size); - break; - } - } - - public override void onMouseMove (object sender, MouseMoveEventArgs e) - { - base.onMouseMove (sender, e); - - GraphicObject oldHW = HoverWidget; - Rectangle scr = this.ScreenCoordinates (this.getSlot ()); - ProcessMouseMove (e.X - scr.X, e.Y - scr.Y); - - if (oldHW == HoverWidget) - return; - - if (draggedObj != null) { - if (isPossibleContainer (HoverWidget) && draggedObjContainer != HoverWidget) { - removeDraggedObjFrom (); - tryAddDraggedObjTo (HoverWidget); - } - } - - RegisterForRedraw (); - - } - public override void onMouseDown (object sender, MouseButtonEventArgs e) - { - //base.onMouseDown (sender, e); - SelectedItem = HoverWidget; - - if (SelectedItem != null && projFile != null) { - projFile.CurrentLine = SelectedItem.design_line; - projFile.CurrentColumn = SelectedItem.design_column; - } - - } - - protected override void onDraw (Cairo.Context gr) - { - base.onDraw (gr); - if (!drawGrid) - return; - - - Rectangle cb = ClientRectangle; - const double gridLineWidth = 0.1; - double glhw = gridLineWidth / 2.0; - int nbLines = cb.Width / gridSpacing ; - double d = cb.Left + gridSpacing; - for (int i = 0; i < nbLines; i++) { - gr.MoveTo (d-glhw, cb.Y); - gr.LineTo (d-glhw, cb.Bottom); - d += gridSpacing; - } - nbLines = cb.Height / gridSpacing; - d = cb.Top + gridSpacing; - for (int i = 0; i < nbLines; i++) { - gr.MoveTo (cb.X, d - glhw); - gr.LineTo (cb.Right, d -glhw); - d += gridSpacing; - } - gr.LineWidth = gridLineWidth; - Foreground.SetAsSource (gr, cb); - gr.Stroke (); - - lock (imlVE.RenderMutex) { - using (Cairo.Surface surf = new Cairo.ImageSurface (imlVE.bmp, Cairo.Format.Argb32, - imlVE.ClientRectangle.Width, imlVE.ClientRectangle.Height, imlVE.ClientRectangle.Width * 4)) { - gr.SetSourceSurface (surf, cb.Left, cb.Top); - gr.Paint (); - } - imlVE.IsDirty = false; - } - - Rectangle hr; - if (HoverWidget != null) { - hr = HoverWidget.ScreenCoordinates (HoverWidget.getSlot ()); -// gr.SetSourceColor (Color.LightGray); -// gr.DrawCote (new Cairo.PointD (hr.X, hr.Center.Y), new Cairo.PointD (hr.Right, hr.Center.Y)); -// gr.DrawCote (new Cairo.PointD (hr.Center.X, hr.Y), new Cairo.PointD (hr.Center.X, hr.Bottom)); - //hr.Inflate (2); - gr.SetSourceColor (Color.LightGray); - gr.SetDash (new double[]{ 3.0, 3.0 }, 0.0); - gr.Rectangle (hr, 1.0); - } - - if (SelectedItem?.Parent == null) - return; - hr = SelectedItem.ScreenCoordinates(SelectedItem.getSlot ()); - hr.Inflate (1); - gr.LineWidth = 2; - gr.SetSourceColor (Color.Yellow); - gr.SetDash (new double[]{ 5.0, 3.0 },0.0); - gr.Rectangle (hr, 1.0); - } - - protected override void onDragEnter (object sender, DragDropEventArgs e) - { - base.onDragEnter (sender, e); - GraphicObjectDesignContainer godc = e.DragSource.DataSource as GraphicObjectDesignContainer; - if (godc == null) - return; - createDraggedObj (godc.CrowType); - } - protected override void onDragLeave (object sender, DragDropEventArgs e) - { - base.onDragLeave (sender, e); - - ClearDraggedObj (); - } - #endregion - - #region draggedObj handling - public GraphicObject draggedObj = null; - public GraphicObject draggedObjContainer = null; - - bool tryAddDraggedObjTo(GraphicObject g){ - lock (imlVE.UpdateMutex) { - if (g.GetType ().IsSubclassOf (typeof(Container))) { - Container c = g as Container; - c.SetChild (draggedObj); - EditorIsDirty = true; - } else if (g.GetType ().IsSubclassOf (typeof(Group))) { - Group c = g as Group; - c.AddChild (draggedObj); - } else - return false; - EditorIsDirty = true; - draggedObjContainer = g; - } - return true; - } - bool isPossibleContainer (GraphicObject g){ - if (g.GetType().IsSubclassOf(typeof(Container))){ - Container c = g as Container; - return c.Child == null; - } - return g.GetType ().IsSubclassOf (typeof(Group)); - } - void removeDraggedObjFrom(){ - if (draggedObjContainer == null) - return; - lock (imlVE.UpdateMutex) { - if (draggedObjContainer.GetType().IsSubclassOf(typeof(Container))){ - Container c = draggedObjContainer as Container; - c.SetChild (null); - EditorIsDirty = true; - //Console.WriteLine ("remove {0} from {1}", draggedObj, c); - }else if (draggedObjContainer.GetType().IsSubclassOf(typeof(Group))){ - Group c = draggedObjContainer as Group; - c.RemoveChild (draggedObj); - EditorIsDirty = true; - //Console.WriteLine ("remove {0} from {1}", draggedObj, c); - }//else - // Console.WriteLine ("Error removing dragged obj"); - } - draggedObjContainer = null; - } - void createDraggedObj (Type crowType) { - lock (imlVE.UpdateMutex) { - draggedObj = imlVE.CreateITorFromIMLFragment ("<" + crowType.Name + "/>").CreateInstance (); - } - } - public void ClearDraggedObj (bool removeFromTree = true) { - //Console.WriteLine ("Clear dragged obj {0}, remove from tree = {1}", draggedObj, removeFromTree); - if (removeFromTree) - removeDraggedObjFrom (); - draggedObjContainer = null; - if (draggedObj == null) - return; - if (removeFromTree) - draggedObj.Dispose (); - draggedObj = null; - } - #endregion - - - void WidgetCheckOver (GraphicObject go, MouseMoveEventArgs e){ - Type tGo = go.GetType(); - if (typeof(TemplatedGroup).IsAssignableFrom (tGo)) { - - } else if (typeof(TemplatedContainer).IsAssignableFrom (tGo)) { - TemplatedContainer c = go as TemplatedContainer; - if (c.Content?.MouseIsIn (e.Position) == true) { - WidgetCheckOver (c.Content, e); - return; - } - } else if (typeof(TemplatedControl).IsAssignableFrom (tGo)) { - } else if (typeof(Group).IsAssignableFrom (tGo)) { - Group c = go as Group; - for (int i = c.Children.Count -1; i >= 0; i--) { - if (c.Children[i].MouseIsIn (e.Position)) { - WidgetCheckOver (c.Children[i], e); - return; - } - } - } else if (typeof(Crow.Container).IsAssignableFrom (tGo)) { - Crow.Container c = go as Crow.Container; - if (c.Child?.MouseIsIn (e.Position)==true) { - WidgetCheckOver (c.Child, e); - return; - } - } - HoverWidget = go; - WidgetMouseEnter (go, e); - } - void WidgetMouseLeave (GraphicObject go, MouseMoveEventArgs e){ - - } - void WidgetMouseEnter (GraphicObject go, MouseMoveEventArgs e){ - - } - void WidgetMouseMove (GraphicObject go, MouseMoveEventArgs e){} - public bool ProcessMouseMove(int x, int y) - { - int deltaX = x - imlVE.Mouse.X; - int deltaY = y - imlVE.Mouse.Y; - imlVE.Mouse.X = x; - imlVE.Mouse.Y = y; - MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY); - e.Mouse = imlVE.Mouse; - - if (imlVE.ActiveWidget != null) { - //TODO, ensure object is still in the graphic tree - //send move evt even if mouse move outside bounds - WidgetMouseMove (imlVE.ActiveWidget, e); - return true; - } - - if (HoverWidget != null) { - //TODO, ensure object is still in the graphic tree - //check topmost graphicobject first - GraphicObject tmp = HoverWidget; - GraphicObject topc = null; - while (tmp is GraphicObject) { - topc = tmp; - tmp = tmp.LogicalParent as GraphicObject; - } - int idxhw = imlVE.GraphicTree.IndexOf (topc); - if (idxhw != 0) { - int i = 0; - while (i < idxhw) { - if (imlVE.GraphicTree [i].LogicalParent == imlVE.GraphicTree [i].Parent) { - if (imlVE.GraphicTree [i].MouseIsIn (e.Position)) { - while (imlVE.HoverWidget != null) { - WidgetMouseLeave (imlVE.HoverWidget, e); - imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; - } - - WidgetCheckOver (GraphicTree [i], e); - return true; - } - } - i++; - } - } - - - if (imlVE.HoverWidget.MouseIsIn (e.Position)) { - WidgetCheckOver (imlVE.HoverWidget, (e)); - return true; - } else { - WidgetMouseLeave (imlVE.HoverWidget, e); - //seek upward from last focused graph obj's - while (imlVE.HoverWidget.LogicalParent as GraphicObject != null) { - imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; - if (imlVE.HoverWidget.MouseIsIn (e.Position)) { - WidgetCheckOver (imlVE.HoverWidget, e); - return true; - } else - WidgetMouseLeave (imlVE.HoverWidget, e); - } - } - } - - //top level graphic obj's parsing - lock (imlVE.GraphicTree) { - for (int i = 0; i < imlVE.GraphicTree.Count; i++) { - GraphicObject g = imlVE.GraphicTree [i]; - if (g.MouseIsIn (e.Position)) { - WidgetCheckOver (g, e); - return true; - } - } - } - imlVE.HoverWidget = null; - return false; - - } - - void GTView_SelectedItemChanged (object sender, SelectionChangeEventArgs e) - { - SelectedItem = e.NewValue as GraphicObject; - } - } -} diff --git a/CrowIDE/src/ProjectNodes.cs b/CrowIDE/src/ProjectNodes.cs index f96ec5cd..1c4c8b26 100644 --- a/CrowIDE/src/ProjectNodes.cs +++ b/CrowIDE/src/ProjectNodes.cs @@ -200,15 +200,15 @@ namespace Crow.Coding : base (pi.Project, pi.node) { cmdSave = new Crow.Command (new Action (() => Save ())) - { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; - cmdSave = new Crow.Command (new Action (() => SaveAs ())) - { Caption = "Save As ..", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; + { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; + cmdSaveAs = new Crow.Command (new Action (() => SaveAs ())) + { Caption = "Save As ..", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false }; cmdOpen = new Crow.Command (new Action (() => Open ())) { Caption = "Open", Icon = new SvgPicture ("#Crow.Coding.ui.icons.outbox.svg"), CanExecute = false }; cmdUndo = new Crow.Command (new Action (() => Undo (null))) - { Caption = "Undo", Icon = new SvgPicture ("#Crow.Coding.icons.undo.svg"), CanExecute = false }; + { Caption = "Undo", Icon = new SvgPicture ("#Crow.Coding.icons.undo.svg"), CanExecute = false }; cmdRedo = new Crow.Command (new Action (() => Redo (null))) - { Caption = "Redo", Icon = new SvgPicture ("#Crow.Coding.icons.redo.svg"), CanExecute = false }; + { Caption = "Redo", Icon = new SvgPicture ("#Crow.Coding.icons.redo.svg"), CanExecute = false }; Commands.Insert (0, cmdOpen); Commands.Insert (1, cmdSave); @@ -453,6 +453,14 @@ namespace Crow.Coding NotifyValueChanged ("Instance", instance); } } + + public List GraphicTree { + get { return new List (new GraphicObject[] {instance}); } + } + + void GTView_SelectedItemChanged (object sender, SelectionChangeEventArgs e){ + SelectedItem = e.NewValue; + } } } diff --git a/CrowIDE/src/Solution.cs b/CrowIDE/src/Solution.cs index fb4bcbfa..1b89dc09 100644 --- a/CrowIDE/src/Solution.cs +++ b/CrowIDE/src/Solution.cs @@ -214,6 +214,15 @@ namespace Crow.Coding{ saveOpenedItemsInUserConfig (); } + public void CloseSolution () { + while (openedItems.Count > 0) { + openedItems.RemoveElement (openedItems [0]); + } + while (toolboxItems.Count > 0) { + toolboxItems.RemoveElement (toolboxItems [0]); + } + NotifyValueChanged ("Projects", null); + } /// /// Solution name /// diff --git a/CrowIDE/src/SourceEditor/BufferParser.cs b/CrowIDE/src/SourceEditor/BufferParser.cs deleted file mode 100644 index dfec17a3..00000000 --- a/CrowIDE/src/SourceEditor/BufferParser.cs +++ /dev/null @@ -1,380 +0,0 @@ -using System; -using System.IO; -using Crow; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace Crow.Coding -{ - /// - /// base class for tokenizing sources - /// - public abstract class BufferParser - { - /// - /// Default tokens, this enum may be overriden in derived parser with the new keyword, - /// see XMLParser for example. - /// - public enum TokenType { - Unknown = 0, - WhiteSpace = 1, - NewLine = 2, - LineComment = 3, - BlockCommentStart = 4, - BlockComment = 5, - BlockCommentEnd = 6, - Preprocessor = 7, - Identifier = 8, - Keyword = 9, - OpenBlock = 10, - CloseBlock = 11, - StatementEnding = 12, - OperatorOrPunctuation = 13, - IntegerLitteral = 14, - RealLitteral = 15, - StringLitteralOpening = 16, - StringLitteralClosing = 17, - StringLitteral = 18, - CharLitteralOpening = 19, - CharLitteralClosing = 20, - CharLitteral = 21, - BoolLitteral = 22, - NullLitteral = 23, - Type = 24, - } - - #region CTOR - public BufferParser (CodeBuffer _buffer) - { - buffer = _buffer; - - buffer.LineUpadateEvent += Buffer_LineUpadateEvent; - //buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; - buffer.LineRemoveEvent += Buffer_LineRemoveEvent; - buffer.BufferCleared += Buffer_BufferCleared; - } - - #endregion - - #region Buffer events handlers - void Buffer_BufferCleared (object sender, EventArgs e) - { - - } - void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) - { - - } - void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) - { - reparseSource (); - } - void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) - { - for (int i = 0; i < e.LineCount; i++) - TryParseBufferLine (e.LineStart + i); - reparseSource (); - } - #endregion - - internal int currentLine = 0; - internal int currentColumn = 0; - - int syntTreeDepth = 0; - public int SyntacticTreeDepth { - get { return syntTreeDepth;} - set { - syntTreeDepth = value; - if (syntTreeDepth > SyntacticTreeMaxDepth) - SyntacticTreeMaxDepth = syntTreeDepth; - } - } - public int SyntacticTreeMaxDepth = 0; - - protected CodeBuffer buffer; - protected Token currentTok; - protected bool eol = true; - protected Point CurrentPosition { - get { return new Point (currentLine, currentColumn); } - set { - currentLine = value.Y; - currentColumn = value.X; - } - } - - public Node RootNode; - - public abstract void ParseCurrentLine(); - public abstract void SyntaxAnalysis (); - public void reparseSource () { - for (int i = 0; i < buffer.LineCount; i++) { - if (!buffer[i].IsParsed) - TryParseBufferLine (i); - } - try { - SyntaxAnalysis (); - } catch (Exception ex) { - Debug.WriteLine ("Syntax Error: " + ex.ToString ()); - if (ex is ParserException) - SetLineInError (ex as ParserException); - } - } - public void TryParseBufferLine(int lPtr) { - buffer [lPtr].exception = null; - currentLine = lPtr; - currentColumn = 0; - eol = false; - - try { - ParseCurrentLine (); - } catch (Exception ex) { - Debug.WriteLine (ex.ToString ()); - if (ex is ParserException) - SetLineInError (ex as ParserException); - } - - } - - public virtual void SetLineInError(ParserException ex) { - currentTok = default(Token); - if (ex.Line >= buffer.LineCount) - ex.Line = buffer.LineCount - 1; - if (buffer [ex.Line].IsFolded) - buffer.ToogleFolding (ex.Line); - buffer [ex.Line].SetLineInError (ex); - } - public virtual string LineBrkRegex { - get { return @"\r\n|\r|\n|\\\\n"; } - } - void updateFolding () { - // Stack foldings = new Stack(); - // bool inStartTag = false; - // - // for (int i = 0; i < parser.Tokens.Count; i++) { - // TokenList tl = parser.Tokens [i]; - // tl.foldingTo = null; - // int fstTK = tl.FirstNonBlankTokenIndex; - // if (fstTK > 0 && fstTK < tl.Count - 1) { - // if (tl [fstTK + 1] != XMLParser.TokenType.ElementName) - // continue; - // if (tl [fstTK] == XMLParser.TokenType.ElementStart) { - // //search closing tag - // int tkPtr = fstTK+2; - // while (tkPtr < tl.Count) { - // if (tl [tkPtr] == XMLParser.TokenType.ElementClosing) - // - // tkPtr++; - // } - // if (tl.EndingState == (int)XMLParser.States.Content) - // foldings.Push (tl); - // else if (tl.EndingState == (int)XMLParser.States.StartTag) - // inStartTag = true; - // continue; - // } - // if (tl [fstTK] == XMLParser.TokenType.ElementEnd) { - // TokenList tls = foldings.Pop (); - // int fstTKs = tls.FirstNonBlankTokenIndex; - // if (tls [fstTK + 1].Content == tl [fstTK + 1].Content) { - // tl.foldingTo = tls; - // continue; - // } - // parser.CurrentPosition = tls [fstTK + 1].Start; - // parser.SetLineInError(new ParserException(parser, "closing tag not corresponding")); - // } - // - // } - // } - } - - #region low level parsing - protected void addCharToCurTok(char c, Point position){ - currentTok.Start = position; - currentTok += c; - } - /// - /// Read one char from current position in buffer and store it into the current token - /// - /// if true, set the Start position of the current token to the current position - protected void readToCurrTok(bool startOfTok = false){ - if (startOfTok) - currentTok.Start = CurrentPosition; - currentTok += Read(); - } - /// - /// read n char from the buffer and store it into the current token - /// - protected void readToCurrTok(int length) { - for (int i = 0; i < length; i++) - currentTok += Read (); - } - /// - /// Save current token into current TokensLine and raz current token - /// - protected void saveAndResetCurrentTok() { - currentTok.End = CurrentPosition; - buffer[currentLine].Tokens.Add (currentTok); - currentTok = default(Token); - } - /// - /// read one char and add current token to current TokensLine, current token is reset - /// - /// Type of the token - /// set start of token to current position - protected void readAndResetCurrentTok(System.Enum type, bool startToc = false) { - readToCurrTok (); - saveAndResetCurrentTok (type); - } - /// - /// Save current tok - /// - /// set the type of the tok - protected void saveAndResetCurrentTok(System.Enum type) { - currentTok.Type = (TokenType)type; - saveAndResetCurrentTok (); - } - protected void setPreviousTokOfTypeTo (TokenType inType, TokenType newType) { - for (int i = currentLine; i >= 0; i--) { - int j = buffer [i].Tokens.Count - 1; - while (j >= 0) { - if (buffer [i].Tokens [j].Type == inType) { - Token t = buffer [i].Tokens [j]; - t.Type = newType; - buffer [i].Tokens [j] = t; - return; - } - j--; - } - } - } - /// - /// Peek next char, emit '\n' if current column > buffer's line length - /// Throw error if eof is true - /// - protected virtual char Peek() { - if (eol) - throw new ParserException (currentLine, currentColumn, "Unexpected End of line"); - return currentColumn < buffer [currentLine].Length ? - buffer [currentLine] [currentColumn] : '\n'; - } - /// - /// 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 - /// - /// Length. - protected virtual string Peek(int length) { - if (eol) - throw new ParserException (currentLine, currentColumn, "Unexpected End of Line"); - int lg = Math.Min(length, Math.Max (buffer [currentLine].Length - currentColumn, buffer [currentLine].Length - currentColumn - length)); - if (lg == 0) - return ""; - return buffer [currentLine].Content.Substring (currentColumn, lg); - } - /// - /// read one char from buffer at current position, if '\n' is read, current line is incremented - /// and column is reset to 0 - /// - protected virtual char Read() { - char c = Peek (); - if (c == '\n') - eol = true; - currentColumn++; - return c; - } - protected virtual string Read(int charCount){ - string tmp = ""; - for (int i = 0; i < charCount; i++) { - if (eol) - break; - tmp += Read (); - } - return tmp; - } - /// - /// read until end of line is reached - /// - /// string read - protected virtual string ReadLine () { - StringBuilder tmp = new StringBuilder(); - char c = Read (); - while (!eol) { - tmp.Append (c); - c = Read (); - } - return tmp.ToString(); - } - /// - /// read until end expression is reached or end of line. - /// - /// string read minus the ending expression that has to be read after - /// Expression to search for - protected virtual string ReadLineUntil (string endExp){ - string tmp = ""; - - while (!eol) { - if (buffer [currentLine].Length - currentColumn - endExp.Length < 0) { - tmp += ReadLine(); - break; - } - if (string.Equals (Peek (endExp.Length), endExp)) - return tmp; - tmp += Read(); - } - return tmp; - } - /// - /// skip white spaces, but not line break. Save spaces in a WhiteSpace token. - /// - protected void SkipWhiteSpaces () { - if (currentTok.Type != TokenType.Unknown) - throw new ParserException (currentLine, currentColumn, "current token should be reset to unknown (0) before skiping white spaces"); - while (!eol) { - if (!char.IsWhiteSpace (Peek ())||Peek()=='\n') - break; - readToCurrTok (currentTok.Type == TokenType.Unknown); - currentTok.Type = TokenType.WhiteSpace; - } - if (currentTok.Type != TokenType.Unknown) - saveAndResetCurrentTok (); - } - #endregion - - protected Node addChildNode (Node curNode, CodeLine cl, int tokPtr, string type = "") { - Node n = new Node () { Name = cl.Tokens [tokPtr].Content, StartLine = cl, Type = type }; - curNode.AddChild (n); - if (cl.SyntacticNode == null) - cl.SyntacticNode = n; - SyntacticTreeDepth++; - return n; - } - protected void closeNodeAndGoUp (ref Node n, CodeLine cl, string type = ""){ - while (n != null) { - if (n.Type == type) { - n.EndLine = cl; - n = n.Parent; - SyntacticTreeDepth--; - break; - } - n = n.Parent; - SyntacticTreeDepth--; - } - } - protected void closeNodeAndGoUp (ref Node n, CodeLine cl){ - SyntacticTreeDepth--; - n.EndLine = cl; - n = n.Parent; - } - - protected void initSyntaxAnalysis () { - RootNode = new Node () { Name = "RootNode", Type="Root" }; - SyntacticTreeDepth = SyntacticTreeMaxDepth = 0; - } - - - protected void throwParserException(string msg){ - throw new ParserException (currentLine, currentColumn, msg); - } - } -} \ No newline at end of file diff --git a/CrowIDE/src/SourceEditor/CSharpParser.cs b/CrowIDE/src/SourceEditor/CSharpParser.cs deleted file mode 100644 index 62090bc1..00000000 --- a/CrowIDE/src/SourceEditor/CSharpParser.cs +++ /dev/null @@ -1,384 +0,0 @@ -using System; -using Crow; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text.RegularExpressions; -using System.Linq; - -namespace Crow.Coding -{ - public class CSharpParser : BufferParser - { - #region keywords - string[] keywords = new string[] { - "abstract", - "as", - "ascending", - "async", - "await", - "base", - "bool", - "break", - "byte", - "case", - "catch", - "char", - "checked", - "class", - "const", - "continue", - "decimal", - "default", - "delegate", - "descending", - "do", - "double", - "dynamic", - "else", - "enum", - "equals", - "event", - "explicit", - "extern", - "false", - "finally", - "fixed", - "float", - "for", - "foreach", - "from", - "get", - "goto", - "group", - "if", - "implicit", - "in", - "int", - "interface", - "internal", - "is", - "join", - "let", - "lock", - "long", - "nameof", - "namespace", - "new", - "null", - "object", - "operator", - "orderby", - "out", - "override", - "params", - "partial", - "private", - "protected", - "public", - "readonly", - "ref", - "return", - "sbyte", - "sealed", - "select", - "set", - "short", - "sizeof", - "stackalloc", - "static", - "string", - "struct", - "switch", - "this", - "throw", - "true", - "try", - "typeof", - "uint", - "ulong", - "unchecked", - "unsafe", - "ushort", - "using", - "value", - "var", - "virtual", - "void", - "volatile", - "when", - "where", - "while", - "yield " - }; - #endregion - - public enum States - { - init, - BlockComment, - InNameSpace, - InClass, - InMember, - Unknown, - } - - public CSharpParser (CodeBuffer _buffer) : base(_buffer) - { - } - - #region Regular Expression for validity checks - static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); - static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}"); - static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); - static Regex rxNewLineChar = new Regex(@"\u000D|\u000A|\u0085|\u2028|\u2029"); - static Regex rxWhiteSpaceChar = new Regex(@"\p{Zs}|\u0009|\u000B|\u000C"); - static Regex rxDecimal = new Regex(@"[0-9]+"); - static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); - - public static bool CharIsValidCharStartName (char c) { - return rxNameStartChar.IsMatch(new string(new char[]{c})); - } - public static bool CharIsValidCharName (char c) { - return rxNameChar.IsMatch(new string(new char[]{c})); - } - - public bool nextCharIsValidCharStartName - { - get { return CharIsValidCharStartName(Peek()); } - } - public bool nextCharIsValidCharName - { - get { return CharIsValidCharName(Peek()); } - } - #endregion - - States curState = States.init; - States savedState = States.init; - - public override void ParseCurrentLine () - { - //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); - CodeLine cl = buffer [currentLine]; - cl.Tokens = new List (); - - - //retrieve current parser state from previous line - if (currentLine > 0) - curState = (States)buffer[currentLine - 1].EndingState; - else - curState = States.init; - - States previousEndingState = (States)cl.EndingState; - - while (! eol) { - if (currentTok.IsNull) - SkipWhiteSpaces (); - - if (curState == States.BlockComment) { - currentTok.Start = CurrentPosition; - currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; - currentTok += ReadLineUntil ("*/"); - if (Peek (2) == "*/") { - readToCurrTok (2); - curState = savedState; - } - saveAndResetCurrentTok (); - continue; - } - - switch (Peek()) { - case '\n': - eol = true; - if (!currentTok.IsNull) - saveAndResetCurrentTok (); - break; - case '#': - readToCurrTok (true); - currentTok += ReadLine (); - saveAndResetCurrentTok (TokenType.Preprocessor); - break; - case '/': - readToCurrTok (true); - switch (Peek ()) { - case '*': - readToCurrTok (); - currentTok += ReadLine (); - //currentTok.Type = (Parser.TokenType)TokenType.BlockComment; - savedState = curState; - curState = States.BlockComment; - saveAndResetCurrentTok (TokenType.BlockComment); - break; - case '/': - //readToCurrTok (); - currentTok += ReadLine (); - saveAndResetCurrentTok (TokenType.LineComment); - //currentTok.Type = (Parser.TokenType)TokenType.LineComment; - break; - default: - currentTok += ReadLine (); - saveAndResetCurrentTok (TokenType.Unknown); - break; - } - break; - case '{': - if (currentTok.IsNull) - readAndResetCurrentTok (TokenType.OpenBlock, true); - else - readToCurrTok (); - break; - case '}': - if (currentTok.IsNull) - readAndResetCurrentTok (TokenType.CloseBlock, true); - else - readToCurrTok (); - break; - case '\\'://unicode escape sequence - if (!(currentTok.Type == TokenType.Identifier || - currentTok.IsEmpty || currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral)) { - saveAndResetCurrentTok (); - } - Point pos = CurrentPosition; - Read (); - char escChar = Read (); - - if (escChar == 'u') { - char c = char.ConvertFromUtf32 (int.Parse (Read (4), System.Globalization.NumberStyles.HexNumber))[0]; - if (currentTok.IsEmpty) { - if (!CharIsValidCharStartName (c)) - throwParserException ("expecting identifier start"); - currentTok.Start = pos; - currentTok.Type = TokenType.Identifier; - } else if (currentTok.Type == TokenType.Identifier) { - if (!CharIsValidCharName (c)) - throwParserException ("expecting identifier valid char"); - } - currentTok += c; - break; - } - currentTok += new String (new char[] { '\\', escChar }); - break; - case '\'': - if (currentTok.IsNull) { - readAndResetCurrentTok (TokenType.CharLitteralOpening, true); - currentTok.Type = TokenType.CharLitteral; - } else if (currentTok.Type == TokenType.CharLitteral) { - saveAndResetCurrentTok (); - readAndResetCurrentTok (TokenType.CharLitteralClosing, true); - } else if (currentTok.Type == TokenType.StringLitteral){ - readToCurrTok (); - } else - throwParserException ("unexpected character: (\')"); - break; - case '"': - if (currentTok.IsNull) { - readAndResetCurrentTok (TokenType.StringLitteralOpening, true); - currentTok.Type = TokenType.StringLitteral; - } else if (currentTok.Type == TokenType.StringLitteral) { - saveAndResetCurrentTok (); - readAndResetCurrentTok (TokenType.StringLitteralClosing, true); - } else - throwParserException ("unexpected character: (\")"); - break; - default: - if (currentTok.Type == TokenType.StringLitteral || currentTok.Type == TokenType.CharLitteral) { - readToCurrTok (currentTok.IsEmpty); - } else if (currentTok.IsNull) { - if (nextCharIsValidCharStartName) { - readToCurrTok (true); - while (nextCharIsValidCharName) - readToCurrTok (); - - if (keywords.Contains (currentTok.Content)) - saveAndResetCurrentTok (TokenType.Keyword); - else - saveAndResetCurrentTok (TokenType.Identifier); - continue; - } else - readAndResetCurrentTok(TokenType.Unknown, true); - } else - readAndResetCurrentTok(TokenType.Unknown, true); - break; - } - } - - if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) - buffer [currentLine + 1].Tokens = null; - - cl.EndingState = (int)curState; - } - - public override void SyntaxAnalysis () - { - initSyntaxAnalysis (); - Node currentNode = RootNode; - - int ptrLine = 0; - while (ptrLine < buffer.LineCount) { - CodeLine cl = buffer [ptrLine]; - if (cl.Tokens == null){ - ptrLine++; - continue; - } - cl.SyntacticNode = null; - - int tokPtr = 0; - bool onlyWhiteSpace = true; - while (tokPtr < cl.Tokens.Count) { - if (cl.Tokens [tokPtr].Type == TokenType.WhiteSpace) { - tokPtr++; - continue; - } - - if (cl.Tokens [tokPtr].Type == TokenType.LineComment && onlyWhiteSpace) { - int startLine = ptrLine; - ptrLine++; - while (ptrLine < buffer.LineCount) { - int idx = buffer [ptrLine].FirstNonBlankTokIndex; - if (idx < 0) - break; - if (buffer [ptrLine].Tokens [idx].Type != TokenType.LineComment) - break; - ptrLine++; - } - ptrLine--; - if (ptrLine - startLine > 0) { - currentNode = addChildNode (currentNode, cl, tokPtr, "comment"); - closeNodeAndGoUp (ref currentNode, buffer [ptrLine], "comment"); - } - break; - } - - switch (cl.Tokens [tokPtr].Type) { - case TokenType.OpenBlock: - currentNode = addChildNode (currentNode, cl, tokPtr); - break; - case TokenType.CloseBlock: - closeNodeAndGoUp (ref currentNode, cl); - break; - case TokenType.Preprocessor: - if (cl.Tokens [tokPtr].Content.StartsWith ("#region")) { - currentNode = addChildNode (currentNode, cl, tokPtr, "region"); - } else if (cl.Tokens [tokPtr].Content.StartsWith ("#endregion")) { - - closeNodeAndGoUp (ref currentNode, cl,"region"); - } - break; - } - onlyWhiteSpace = false; - tokPtr++; - } - ptrLine++; - } - ptrLine = 0; - while (ptrLine < buffer.LineCount) { - CodeLine cl = buffer [ptrLine]; - if (cl.IsFoldable) { - if (cl.SyntacticNode.Type == "comment" || cl.SyntacticNode.Type == "region") - cl.IsFolded = true; - } - ptrLine++; - } - } - } -} - diff --git a/CrowIDE/src/SourceEditor/CodeBuffer.cs b/CrowIDE/src/SourceEditor/CodeBuffer.cs deleted file mode 100644 index 13c422a6..00000000 --- a/CrowIDE/src/SourceEditor/CodeBuffer.cs +++ /dev/null @@ -1,528 +0,0 @@ -// -// 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; -using System.Diagnostics; -using System.Threading; - -namespace Crow.Coding -{ - /// - /// Code buffer, lines are arranged in a List, new line chars are removed during string.split on '\n...', - /// - public class CodeBuffer - { - public ReaderWriterLockSlim editMutex = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - - //those events are handled in SourceEditor to help keeping sync between textbuffer,parser and editor. - //modified lines are marked for reparse - #region Events - public event EventHandler LineUpadateEvent; - public event EventHandler LineRemoveEvent; - public event EventHandler LineAdditionEvent; - public event EventHandler FoldingEvent; - public event EventHandler BufferCleared; - public event EventHandler SelectionChanged; - public event EventHandler PositionChanged; - #endregion - - string lineBreak = Interface.LineBreak; - List lines = new List(); - public int longestLineIdx = 0; - public int longestLineCharCount = 0; - /// - /// real position in char arrays, tab = 1 char - /// - int _currentLine = 0; - int _currentCol = 0; - - public int LineCount { get { return lines.Count;}} - public int IndexOf (CodeLine cl) { - return lines.IndexOf (cl); - } - - public CodeLine this[int i] - { - get { return lines[i]; } - set { - if (lines [i] == value) - return; - editMutex.EnterWriteLock (); - lines [i] = value; - editMutex.ExitWriteLock (); - LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); - } - } - - public void RemoveAt(int i){ - editMutex.EnterWriteLock (); - lines.RemoveAt (i); - editMutex.ExitWriteLock (); - LineRemoveEvent.Raise (this, new CodeBufferEventArgs (i)); - } - public void Insert(int i, string item){ - editMutex.EnterWriteLock (); - lines.Insert (i, item); - editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (i)); - } - public void Add(CodeLine item){ - editMutex.EnterWriteLock (); - lines.Add (item); - editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (lines.Count - 1)); - } - public void AddRange (string[] items){ - int start = lines.Count; - editMutex.EnterWriteLock (); - for (int i = 0; i < items.Length; i++) - lines.Add (items [i]); - editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); - } - public void AddRange (CodeLine[] items){ - int start = lines.Count; - editMutex.EnterWriteLock (); - lines.AddRange (items); - editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); - } - public void Clear () { - editMutex.EnterWriteLock (); - longestLineCharCount = 0; - lines.Clear (); - editMutex.ExitWriteLock (); - BufferCleared.Raise (this, null); - } - public void UpdateLine(int i, string newContent){ - editMutex.EnterWriteLock (); - this [i].Content = newContent; - editMutex.ExitWriteLock (); - LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); - } - public void AppenedLine(int i, string newContent){ - editMutex.EnterWriteLock (); - this [i].Content += newContent; - editMutex.ExitWriteLock (); - LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); - } - public void RemoveLeadingTab (int l) { - if (this [l] [0] == '\t') { - UpdateLine (l, this [l].Content.Substring (1)); - return; - } - int i = 0; - while (i < Interface.TabSize) { - if (this [l] [i] != ' ') - break; - i++; - } - if (i > 0) - UpdateLine (l, this [l].Content.Substring (i)); - } - public void ToogleFolding (int line) { - if (!this [line].IsFoldable) - return; - editMutex.EnterWriteLock (); - this [line].IsFolded = !this [line].IsFolded; - editMutex.ExitWriteLock (); - FoldingEvent.Raise (this, new CodeBufferEventArgs (line)); - } - public void Load(string rawSource, string lineBrkRegex = @"\r\n|\r|\n|\\\n") { - this.Clear(); - - if (string.IsNullOrEmpty (rawSource)) - return; - - AddRange (Regex.Split (rawSource, lineBrkRegex)); - - lineBreak = detectLineBreakKind (rawSource); - } - - /// - /// Finds the longest visual line as printed on screen with tabulation replaced with n spaces - /// - public void FindLongestVisualLine(){ - longestLineCharCount = 0; - editMutex.EnterReadLock (); - for (int i = 0; i < this.LineCount; i++) { - if (lines[i].PrintableLength > longestLineCharCount) { - longestLineCharCount = lines[i].PrintableLength; - longestLineIdx = i; - } - } - editMutex.ExitReadLock (); - //Debug.WriteLine ("Longest line: {0}->{1}", longestLineIdx, longestLineCharCount); - } - /// line break could be '\r' or '\n' or '\r\n' - static string detectLineBreakKind(string buffer){ - string strLB = ""; - - if (string.IsNullOrEmpty(buffer)) - return Interface.LineBreak; - int i = 0; - while ( i < buffer.Length) { - if (buffer [i] == '\r') { - strLB += '\r'; - i++; - } - if (i < buffer.Length) { - if (buffer [i] == '\r') - return "\r"; - if (buffer[i] == '\n') - strLB += '\n'; - } - if (!string.IsNullOrEmpty (strLB)) - return strLB; - i++; - } - return Interface.LineBreak; - } - /// - /// return all lines with linebreaks - /// - public string FullText{ - get { - if (lines.Count == 0) - return ""; - string tmp = ""; - editMutex.EnterReadLock (); - for (int i = 0; i < lines.Count -1; i++) - tmp += lines [i].Content + this.lineBreak; - tmp += lines [lines.Count - 1].Content; - editMutex.ExitReadLock (); - return tmp; - } - } - - /// - /// unfolded and not in folds line count - /// - public int UnfoldedLines { - get { - int i = 0, vl = 0; - editMutex.EnterReadLock (); - while (i < LineCount) { - if (this [i].IsFolded) { - i = GetEndNodeIndex (i); - if (i < 0) { - Console.WriteLine ("error folding"); - break; - } - } - i++; - vl++; - } - editMutex.ExitReadLock (); - //Debug.WriteLine ("unfolded lines: " + vl); - return vl; - } - } - - /// - /// convert visual position to buffer position - /// - Point getBuffPos (Point visualPos) { - int i = 0; - int buffCol = 0; - while (i < visualPos.X) { - if (this [visualPos.Y] [buffCol] == '\t') - i += Interface.TabSize; - else - i++; - buffCol++; - } - return new Point (buffCol, visualPos.Y); - } - - public int GetEndNodeIndex (int line) { - return IndexOf (this [line].SyntacticNode.EndLine); - } - - int ConverteTabulatedPosOfCurLine (int column) { - int tmp = 0; - int i = 0; - while (i < lines [_currentLine].Content.Length){ - if (lines [_currentLine].Content [i] == '\t') - tmp += 4; - else - tmp++; - if (tmp > column) - break; - i++; - } - return i; - } - - public int CurrentTabulatedColumn { - get { - return lines [_currentLine].Content.Substring (0, _currentCol). - Replace ("\t", new String (' ', Interface.TabSize)).Length; - } - } - /// - /// Gets visual position computed from actual buffer position - /// -// public Point TabulatedPosition { -// get { return new Point (TabulatedColumn, _currentLine); } -// } - /// - /// set buffer current position from visual position - /// -// public void SetBufferPos(Point tabulatedPosition) { -// CurrentPosition = getBuffPos(tabulatedPosition); -// } - - #region Editing and moving cursor - Point selStartPos = -1; //selection start (row,column) - Point selEndPos = -1; //selection end (row,column) - - public bool SelectionInProgress { get { return selStartPos >= 0; }} - public void SetSelStartPos () { - selStartPos = selEndPos = CurrentPosition; - SelectionChanged.Raise (this, null); - } - public void SetSelEndPos () { - selEndPos = CurrentPosition; - SelectionChanged.Raise (this, null); - } - public void SetSelectionOnFullLines () { - if (!SelectionInProgress) - return; - Point s = new Point (0, SelectionStart.Y); - Point e = new Point (this [SelectionEnd.Y].Length, SelectionEnd.Y); - selStartPos = s; - selEndPos = e; - SelectionChanged.Raise (this, null); - } - /// - /// Set selection in buffer to -1, empty selection - /// - public void ResetSelection () { - selStartPos = selEndPos = -1; - SelectionChanged.Raise (this, null); - } - - public string SelectedText { - get { - if (SelectionIsEmpty) - return ""; - Point selStart = SelectionStart; - Point selEnd = SelectionEnd; - if (selStart.Y == selEnd.Y) - return this [selStart.Y].Content.Substring (selStart.X, selEnd.X - selStart.X); - string tmp = ""; - tmp = this [selStart.Y].Content.Substring (selStart.X); - for (int l = selStart.Y + 1; l < selEnd.Y; l++) { - tmp += Interface.LineBreak + this [l].Content; - } - tmp += Interface.LineBreak + this [selEnd.Y].Content.Substring (0, selEnd.X); - return tmp; - } - } - /// - /// ordered selection start and end positions in char units - /// - public Point SelectionStart { - get { return selEndPos < 0 || selStartPos.Y < selEndPos.Y ? selStartPos : - selStartPos.Y > selEndPos.Y ? selEndPos : - selStartPos.X < selEndPos.X ? selStartPos : selEndPos; } - } - public Point SelectionEnd { - get { return selEndPos < 0 || selStartPos.Y > selEndPos.Y ? selStartPos : - selStartPos.Y < selEndPos.Y ? selEndPos : - selStartPos.X > selEndPos.X ? selStartPos : selEndPos; } - } - public bool SelectionIsEmpty - { get { return selEndPos == selStartPos; } } - int requestedColumn = -1; - /// - /// Current column in buffer coordinate, tabulation = 1 char - /// - public int CurrentColumn{ - get { return _currentCol; } - set { - if (value == _currentCol) - return; - - editMutex.EnterReadLock (); - - if (value < 0) - _currentCol = 0; - else if (value > lines [_currentLine].Length) - _currentCol = lines [_currentLine].Length; - else - _currentCol = value; - - requestedColumn = CurrentTabulatedColumn; - - editMutex.ExitReadLock (); - - PositionChanged.Raise (this, null); - } - } - /// - /// Current row in buffer coordinate, tabulation = 1 char - /// - public int CurrentLine{ - get { return _currentLine; } - set { - if (value == _currentLine) - return; - - editMutex.EnterReadLock (); - - if (value >= lines.Count) - _currentLine = lines.Count-1; - else if (value < 0) - _currentLine = 0; - else - _currentLine = value; -// if (_currentCol < 0) -// requestedColumn = tabu _currentCol; - int tabulatedRequestedCol = ConverteTabulatedPosOfCurLine(requestedColumn); - if (requestedColumn > lines [_currentLine].PrintableLength) - _currentCol = lines [_currentLine].Length; - else - //_currentCol = requestedColumn; - _currentCol = tabulatedRequestedCol; - //Debug.WriteLine ("buff cur line: " + _currentLine); - - editMutex.ExitReadLock(); - - PositionChanged.Raise (this, null); - } - } - public CodeLine CurrentCodeLine { - get { return this [_currentLine]; } - } - /// - /// Current position in buffer coordinate, tabulation = 1 char - /// - public Point CurrentPosition { - get { return new Point(CurrentColumn, CurrentLine); } -// set { -// _currentCol = value.X; -// _currentLine = value.Y; -// } - } - /// - /// get char at current position in buffer - /// - protected Char CurrentChar { get { return lines [CurrentLine] [CurrentColumn]; } } - - public void GotoWordStart(){ - if (this[CurrentLine].Length == 0) - return; - CurrentColumn--; - //skip white spaces - while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) - CurrentColumn--; - while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0) - CurrentColumn--; - if (!char.IsLetterOrDigit (this.CurrentChar)) - CurrentColumn++; - } - public void GotoWordEnd(){ - //skip white spaces - if (CurrentColumn >= this [CurrentLine].Length - 1) - return; - while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) - CurrentColumn++; - while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < this [CurrentLine].Length-1) - CurrentColumn++; - if (char.IsLetterOrDigit (this.CurrentChar)) - CurrentColumn++; - } - public void DeleteChar() - { - editMutex.EnterWriteLock (); - if (SelectionIsEmpty) { - if (CurrentColumn == 0) { - if (CurrentLine == 0) { - editMutex.ExitWriteLock (); - return; - } - CurrentLine--; - CurrentColumn = this [CurrentLine].Length; - AppenedLine (CurrentLine, this [CurrentLine + 1].Content); - RemoveAt (CurrentLine + 1); - editMutex.ExitWriteLock (); - return; - } - CurrentColumn--; - UpdateLine (CurrentLine, this [CurrentLine].Content.Remove (CurrentColumn, 1)); - } else { - int linesToRemove = SelectionEnd.Y - SelectionStart.Y + 1; - int l = SelectionStart.Y; - - if (linesToRemove > 0) { - UpdateLine (l, this [l].Content.Remove (SelectionStart.X, this [l].Length - SelectionStart.X) + - this [SelectionEnd.Y].Content.Substring (SelectionEnd.X, this [SelectionEnd.Y].Length - SelectionEnd.X)); - l++; - for (int c = 0; c < linesToRemove - 1; c++) - RemoveAt (l); - CurrentLine = SelectionStart.Y; - CurrentColumn = SelectionStart.X; - } else - UpdateLine (l, this [l].Content.Remove (SelectionStart.X, SelectionEnd.X - SelectionStart.X)); - CurrentColumn = SelectionStart.X; - ResetSelection (); - } - editMutex.ExitWriteLock (); - } - /// - /// Insert new string at caret position, should be sure no line break is inside. - /// - /// String. - public void Insert(string str) - { - if (!SelectionIsEmpty) - this.DeleteChar (); - string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray(); - UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[0])); - CurrentColumn += strLines[0].Length; - for (int i = 1; i < strLines.Length; i++) { - InsertLineBreak (); - UpdateLine (CurrentLine, this [CurrentLine].Content.Insert (CurrentColumn, strLines[i])); - CurrentColumn += strLines[i].Length; - } - } - /// - /// Insert a line break. - /// - public void InsertLineBreak() - { - if (CurrentColumn > 0) { - Insert (CurrentLine + 1, this [CurrentLine].Content.Substring (CurrentColumn)); - UpdateLine (CurrentLine, this [CurrentLine].Content.Substring (0, CurrentColumn)); - } else - Insert(CurrentLine, ""); - - CurrentColumn = 0; - CurrentLine++; - } - #endregion - } -} - diff --git a/CrowIDE/src/SourceEditor/CodeBufferEventArgs.cs b/CrowIDE/src/SourceEditor/CodeBufferEventArgs.cs deleted file mode 100644 index 07dd25b6..00000000 --- a/CrowIDE/src/SourceEditor/CodeBufferEventArgs.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace Crow.Coding -{ - public class CodeBufferEventArgs : EventArgs { - public int LineStart; - public int LineCount; - - public CodeBufferEventArgs(int lineNumber) { - LineStart = lineNumber; - LineCount = 1; - } - public CodeBufferEventArgs(int lineStart, int lineCount) { - LineStart = lineStart; - LineCount = lineCount; - } - } - -} - diff --git a/CrowIDE/src/SourceEditor/CodeLine.cs b/CrowIDE/src/SourceEditor/CodeLine.cs deleted file mode 100644 index 23f43fba..00000000 --- a/CrowIDE/src/SourceEditor/CodeLine.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Linq; - -namespace Crow.Coding -{ - public class CodeLine - { - public string Content; - public List Tokens; - public int EndingState = 0; - public Node SyntacticNode; - public ParserException exception; - - public CodeLine (string _content){ - Content = _content; - Tokens = null; - exception = null; - } - - public char this[int i] - { - get { return Content[i]; } - set { - if (Content [i] == value) - return; - StringBuilder sb = new StringBuilder(Content); - sb[i] = value; - Content = sb.ToString(); - Tokens = null; - //LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); - } - } - public bool IsFoldable { get { return SyntacticNode == null ? false : - SyntacticNode.EndLine != SyntacticNode.StartLine && SyntacticNode.EndLine != null; } } - public int FoldingLevel { get { return IsFoldable ? SyntacticNode.Level : 0; } } - public bool IsFolded = false; - public bool IsParsed { - get { return Tokens != null; } - } - public string PrintableContent { - get { - return string.IsNullOrEmpty (Content) ? "" : Content.Replace ("\t", new String (' ', Interface.TabSize)); - } - } - public int PrintableLength { - get { - return PrintableContent.Length; - } - } - public int Length { - get { - return string.IsNullOrEmpty (Content) ? 0 : Content.Length; - } - } - public int FirstNonBlankTokIndex { - get { return Tokens == null ? -1 : Tokens.FindIndex (tk=>tk.Type != BufferParser.TokenType.WhiteSpace); } - } - - public void SetLineInError (ParserException ex) { - Tokens = null; - exception = ex; - } - -// public static implicit operator string(CodeLine sl) { -// return sl == null ? "" : sl.Content; -// } - public static implicit operator CodeLine(string s) { - return new CodeLine(s); - } - public static bool operator ==(string s1, CodeLine s2) - { - return string.Equals (s1, s2.Content); - } - public static bool operator !=(string s1, CodeLine s2) - { - return !string.Equals (s1, s2.Content); - } - } -} - diff --git a/CrowIDE/src/SourceEditor/Node.cs b/CrowIDE/src/SourceEditor/Node.cs deleted file mode 100644 index 9db55428..00000000 --- a/CrowIDE/src/SourceEditor/Node.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Crow.Coding -{ - public class Node - { - public Node Parent; - public string Name; - public string Type; - public CodeLine StartLine; - public CodeLine EndLine; - public Dictionary Attributes = new Dictionary (); - - public List Children = new List(); - - public Node () - { - } - - public void AddChild (Node child) { - child.Parent = this; - Children.Add (child); - } - - public int Level { - get { return Parent == null ? 1 : Parent.Level + 1; } - } - - public override string ToString () - { - return string.Format ("Name:{0}, Type:{1}\n\tparent:{2}", Name, Type, Parent); - } - } -} - diff --git a/CrowIDE/src/SourceEditor/SourceEditor.cs b/CrowIDE/src/SourceEditor/SourceEditor.cs deleted file mode 100644 index 14538135..00000000 --- a/CrowIDE/src/SourceEditor/SourceEditor.cs +++ /dev/null @@ -1,1205 +0,0 @@ -// -// ScrollingTextBox.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; -using System.Text; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Linq; -using System.Diagnostics; -using System.IO; -using System.Threading; - -namespace Crow.Coding -{ - /// - /// Scrolling text box optimized for monospace fonts, for coding - /// - public class SourceEditor : Editor - { - #region CTOR - public SourceEditor (): base() - { - formatting.Add ((int)XMLParser.TokenType.AttributeName, new TextFormatting (Color.Teal, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementName, new TextFormatting (Color.DarkBlue, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementStart, new TextFormatting (Color.Black, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementEnd, new TextFormatting (Color.Black, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementClosing, new TextFormatting (Color.Black, Color.Transparent)); - - formatting.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormatting (Color.Carmine, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormatting (Color.Carmine, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormatting (Color.TractorRed, Color.Transparent, false, true)); - formatting.Add ((int)XMLParser.TokenType.XMLDecl, new TextFormatting (Color.AoEnglish, Color.Transparent)); - - formatting.Add ((int)BufferParser.TokenType.BlockComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); - formatting.Add ((int)BufferParser.TokenType.LineComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); - formatting.Add ((int)BufferParser.TokenType.OperatorOrPunctuation, new TextFormatting (Color.Black, Color.Transparent)); - //formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.DarkCyan, Color.Transparent)); - - parsing.Add (".crow", "Crow.Coding.XMLParser"); - parsing.Add (".svg", "Crow.Coding.XMLParser"); - parsing.Add (".template", "Crow.Coding.XMLParser"); - parsing.Add (".cs", "Crow.Coding.CSharpParser"); - parsing.Add (".style", "Crow.Coding.StyleParser"); - - buffer = new CodeBuffer (); - buffer.LineUpadateEvent += Buffer_LineUpadateEvent; - buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; - buffer.LineRemoveEvent += Buffer_LineRemoveEvent; - buffer.BufferCleared += Buffer_BufferCleared; - buffer.SelectionChanged += Buffer_SelectionChanged; - buffer.PositionChanged += Buffer_PositionChanged; - buffer.FoldingEvent += Buffer_FoldingEvent; - buffer.Add (new CodeLine("")); - } - #endregion - - string oldSource = ""; - //save requested position on error, and try it on next move - int requestedLine = 0, requestedCol = 0; - volatile bool isDirty = false; - - const int leftMarginGap = 3;//gap between items in margin and text - const int foldSize = 9;//folding rectangles size - const int foldHSpace = 4;//folding level tabulation x - int foldMargin { get { return parser == null ? 0 : parser.SyntacticTreeMaxDepth * foldHSpace; }}//folding margin size - - #region private and protected fields - bool foldingEnabled = true; - int leftMargin = 0; //margin used to display line numbers, folding errors,etc... - int visibleLines = 1; - int visibleColumns = 1; - int firstPrintedLine = -1; - int printedCurrentLine = 0;//Index of the currentline in the PrintedLines array - - CodeBuffer buffer; - BufferParser parser; - List PrintedLines;//list of lines visible in the Editor depending on scrolling and folding - - Dictionary formatting = new Dictionary(); - Dictionary parsing = new Dictionary(); - - Color selBackground; - Color selForeground; - int selStartCol; - int selEndCol; - - protected Rectangle rText; - protected FontExtents fe; - protected TextExtents te; - - Point mouseLocalPos; - bool doubleClicked = false; - #endregion - - void measureLeftMargin () { - leftMargin = 0; - if (PrintLineNumbers) - leftMargin += (int)Math.Ceiling((double)buffer.LineCount.ToString().Length * fe.MaxXAdvance) +6; - if (foldingEnabled) - leftMargin += foldMargin; - if (leftMargin > 0) - leftMargin += leftMarginGap; - updateVisibleColumns (); - } - void findLongestLineAndUpdateMaxScrollX() { - buffer.FindLongestVisualLine (); - updateMaxScrollX (); -// Debug.WriteLine ("SourceEditor: Find Longest line and update maxscrollx: {0} visible cols:{1}", MaxScrollX, visibleColumns); - } - /// - /// Updates visible line in widget, adapt max scroll y and updatePrintedLines - /// - void updateVisibleLines(){ - visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); - NotifyValueChanged ("VisibleLines", visibleLines); - updateMaxScrollY (); - updatePrintedLines (); - RegisterForGraphicUpdate (); -// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); -// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); - } - void updateVisibleColumns(){ - visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance); - NotifyValueChanged ("VisibleColumns", visibleColumns); - updateMaxScrollX (); -// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); -// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); - } - void updateMaxScrollX () { - MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); - if (buffer.longestLineCharCount > 0) - NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount); - } - void updateMaxScrollY () { - if (parser == null || !foldingEnabled) { - MaxScrollY = Math.Max (0, buffer.LineCount - visibleLines); - if (buffer.UnfoldedLines > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); - } else { - MaxScrollY = Math.Max (0, buffer.UnfoldedLines - visibleLines); - if (buffer.UnfoldedLines > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); - } - } - void updatePrintedLines () { - buffer.editMutex.EnterReadLock (); - editorMutex.EnterWriteLock (); - - PrintedLines = new List (); - int curL = 0; - int i = 0; - - while (curL < buffer.LineCount && i < ScrollY) { - if (buffer [curL].IsFolded) - curL = buffer.GetEndNodeIndex (curL); - curL++; - i++; - } - - firstPrintedLine = curL; - i = 0; - while (i < visibleLines && curL < buffer.LineCount) { - PrintedLines.Add (buffer [curL]); - - if (buffer [curL].IsFolded) - curL = buffer.GetEndNodeIndex (curL); - - curL++; - i++; - } - - buffer.editMutex.ExitReadLock (); - editorMutex.ExitWriteLock (); - } - void updateOnScreenCurLineFromBuffCurLine(){ - printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); - } - void toogleFolding (int line) { - if (parser == null || !foldingEnabled) - return; - buffer.ToogleFolding (line); - } - - #region Editor overrides - protected override void updateEditorFromProjFile () - { - buffer.editMutex.EnterWriteLock (); - loadSource (); - buffer.editMutex.ExitWriteLock (); - - isDirty = false; - oldSource = projFile.Source; - CurrentLine = requestedLine; - CurrentColumn = requestedCol; - projFile.RegisteredEditors [this] = true; - } - protected override void updateProjFileFromEditor () - { - buffer.editMutex.EnterWriteLock (); - string newsrc = buffer.FullText; - buffer.editMutex.ExitWriteLock (); - projFile.UpdateSource (this, newsrc); - } - protected override bool EditorIsDirty { - get { return isDirty; } - set { isDirty = value; } - } - protected override bool IsReady { - get { return buffer != null; } - } - #endregion - - #region Buffer events handlers - void Buffer_BufferCleared (object sender, EventArgs e) - { - editorMutex.EnterWriteLock (); - - buffer.longestLineCharCount = 0; - buffer.longestLineIdx = 0; - measureLeftMargin (); - MaxScrollX = MaxScrollY = 0; - PrintedLines = null; - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - - editorMutex.ExitWriteLock (); - } - void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) - { - for (int i = 0; i < e.LineCount; i++) { - int lptr = e.LineStart + i; - int charCount = buffer[lptr].PrintableLength; - if (charCount > buffer.longestLineCharCount) { - buffer.longestLineIdx = lptr; - buffer.longestLineCharCount = charCount; - }else if (lptr <= buffer.longestLineIdx) - buffer.longestLineIdx++; - if (parser == null) - continue; - parser.TryParseBufferLine (e.LineStart + i); - } - - if (parser != null) - parser.reparseSource (); - - measureLeftMargin (); - - updatePrintedLines (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) - { - bool trigFindLongestLine = false; - for (int i = 0; i < e.LineCount; i++) { - int lptr = e.LineStart + i; - if (lptr <= buffer.longestLineIdx) - trigFindLongestLine = true; - } - if (trigFindLongestLine) - findLongestLineAndUpdateMaxScrollX (); - - measureLeftMargin (); - updatePrintedLines (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) - { - bool trigFindLongestLine = false; - for (int i = 0; i < e.LineCount; i++) { - - int lptr = e.LineStart + i; - if (lptr == buffer.longestLineIdx) - trigFindLongestLine = true; - else if (buffer[lptr].PrintableLength > buffer.longestLineCharCount) { - buffer.longestLineCharCount = buffer[lptr].PrintableLength; - buffer.longestLineIdx = lptr; - } - } - if (trigFindLongestLine) - findLongestLineAndUpdateMaxScrollX (); - - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_PositionChanged (object sender, EventArgs e) - { - Console.WriteLine ("Position changes: ({0},{1})", buffer.CurrentLine, buffer.CurrentColumn); - int cc = buffer.CurrentTabulatedColumn; - - if (cc > visibleColumns + ScrollX) { - ScrollX = cc - visibleColumns; - } else if (cc < ScrollX) - ScrollX = cc; - - RegisterForGraphicUpdate (); - updateOnScreenCurLineFromBuffCurLine (); - notifyPositionChanged (); - } - - void Buffer_SelectionChanged (object sender, EventArgs e) - { - RegisterForGraphicUpdate (); - } - void Buffer_FoldingEvent (object sender, CodeBufferEventArgs e) - { - updatePrintedLines (); - updateOnScreenCurLineFromBuffCurLine (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - } - #endregion - - void notifyPositionChanged (){ - try { - NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); - NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); - NotifyValueChanged ("CurrentLineHasError", CurrentLineHasError); - NotifyValueChanged ("CurrentLineError", CurrentLineError); - } catch (Exception ex) { - Console.WriteLine (ex.ToString ()); - } - } - - #region Public Crow Properties - public int CurrentLine{ - get { return buffer == null ? 0 : buffer.CurrentLine+1; } - set { - try { - int l = value - 1; - if (l == buffer.CurrentLine) - return; - buffer.CurrentLine = l; - if (buffer [l].IsFolded) - buffer.ToogleFolding (l); - } catch (Exception ex) { - requestedLine = value - 1; - Console.WriteLine ("Error cur column: " + ex.ToString ()); - } - } - } - public int CurrentColumn{ - get { return buffer == null ? 0 : buffer.CurrentColumn+1; } - set { - try { - if (value - 1 == buffer.CurrentColumn) - return; - buffer.CurrentColumn = value - 1; - } catch (Exception ex) { - requestedCol = value - 1; - Console.WriteLine ("Error cur column: " + ex.ToString ()); - } - } - } - public bool PrintLineNumbers - { - get { return Configuration.Global.Get ("PrintLineNumbers"); } - set { - if (PrintLineNumbers == value) - return; - Configuration.Global.Set ("PrintLineNumbers", value); - NotifyValueChanged ("PrintLineNumbers", PrintLineNumbers); - measureLeftMargin (); - RegisterForGraphicUpdate (); - } - } - [DefaultValue("BlueGray")] - public virtual Color SelectionBackground { - get { return selBackground; } - set { - if (value == selBackground) - return; - selBackground = value; - NotifyValueChanged ("SelectionBackground", selBackground); - RegisterForRedraw (); - } - } - [DefaultValue("White")] - public virtual Color SelectionForeground { - get { return selForeground; } - set { - if (value == selForeground) - return; - selForeground = value; - NotifyValueChanged ("SelectionForeground", selForeground); - RegisterForRedraw (); - } - } - public override int ScrollY { - get { - return base.ScrollY; - } - set { - if (value == base.ScrollY) - return; - base.ScrollY = value; - updatePrintedLines (); - updateOnScreenCurLineFromBuffCurLine (); - RegisterForGraphicUpdate (); - } - } - public ParserException CurrentLineError { - get { return buffer?.CurrentCodeLine?.exception; } - } - public bool CurrentLineHasError { - get { return buffer == null ? false : buffer.CurrentCodeLine == null ? false : - buffer.CurrentCodeLine.exception != null; } - } - public override ProjectFile ProjectNode { - get { - return base.ProjectNode; - } - set { - base.ProjectNode = value; - if (projFile != null) - parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); - } - } - #endregion - - BufferParser getParserFromExt (string extension) { - if (string.IsNullOrEmpty(extension)) - return null; - if (!parsing.ContainsKey(extension)) - return null; - Type parserType = Type.GetType (parsing [extension]); - if (parserType == null) - return null; - return (BufferParser)Activator.CreateInstance (parserType, buffer ); - } - void loadSource () { - - try { - - if (parser == null) - buffer.Load (projFile.Source); - else//parser may have special linebrk rules - buffer.Load (projFile.Source, parser.LineBrkRegex); - - } catch (Exception ex) { - Debug.WriteLine (ex.ToString ()); - } - - projFile.RegisteredEditors [this] = true; - - updateMaxScrollY (); - MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); - updatePrintedLines (); - - RegisterForGraphicUpdate (); - } - - /// - /// Current editor line, when set, update buffer.CurrentLine - /// - int PrintedCurrentLine { - get { return printedCurrentLine;} - set { - if (value < 0) { - ScrollY += value; - printedCurrentLine = 0; - } else if (PrintedLines.Count < visibleLines && value >= PrintedLines.Count) { - printedCurrentLine = PrintedLines.Count - 1; - }else if (value >= visibleLines) { - ScrollY += value - visibleLines + 1; - printedCurrentLine = visibleLines - 1; - }else - printedCurrentLine = value; - //Debug.WriteLine ("printed current line:" + printedCurrentLine.ToString ()); - //update position in buffer - buffer.CurrentLine = buffer.IndexOf (PrintedLines[printedCurrentLine]); - } - } - int getTabulatedColumn (int col, int line) { - return buffer [line].Content.Substring (0, col).Replace ("\t", new String (' ', Interface.TabSize)).Length; - } - int getTabulatedColumn (Point pos) { - return getTabulatedColumn (pos.X,pos.Y); - } - /// - /// Moves cursor one char to the left, move up if cursor reaches start of line - /// - /// true if move succeed - public bool MoveLeft(){ - if (buffer.CurrentColumn == 0) { - if (printedCurrentLine == 0) - return false; - PrintedCurrentLine--; - buffer.CurrentColumn = int.MaxValue; - } else - buffer.CurrentColumn--; - return true; - } - /// - /// Moves cursor one char to the right, move down if cursor reaches end of line - /// - /// true if move succeed - public bool MoveRight(){ - if (buffer.CurrentColumn >= buffer.CurrentCodeLine.Length) { - if (PrintedCurrentLine == buffer.UnfoldedLines - 1) - return false; - buffer.CurrentColumn = 0; - PrintedCurrentLine++; - } else - buffer.CurrentColumn++; - return true; - } - - #region Drawing - void drawLine(Context gr, Rectangle cb, int i) { - CodeLine cl = PrintedLines[i]; - int lineIndex = buffer.IndexOf(cl); - - double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; - - //Draw line numbering - Color mgFg = Color.Gray; - Color mgBg = Color.White; - if (PrintLineNumbers){ - Rectangle mgR = new Rectangle ((int)x, (int)y, leftMargin - leftMarginGap, (int)Math.Ceiling((fe.Ascent+fe.Descent))); - if (cl.exception != null) { - mgBg = Color.Red; - if (buffer.CurrentLine == lineIndex) - mgFg = Color.White; - else - mgFg = Color.LightGray; - }else if (buffer.CurrentLine == lineIndex) { - mgFg = Color.Black; - mgBg = Color.DarkGray; - } - string strLN = (lineIndex+1).ToString (); - gr.SetSourceColor (mgBg); - gr.Rectangle (mgR); - gr.Fill(); - gr.SetSourceColor (mgFg); - - gr.MoveTo (cb.X + (int)(gr.TextExtents (buffer.LineCount.ToString()).Width - gr.TextExtents (strLN).Width), y + fe.Ascent); - gr.ShowText (strLN); - gr.Fill (); - } - - - - //draw folding - if (foldingEnabled){ - - Rectangle rFld = new Rectangle (cb.X + leftMargin - leftMarginGap - foldMargin, - (int)(y + (fe.Ascent + fe.Descent) / 2.0 - foldSize / 2.0), foldSize, foldSize); - - gr.SetSourceColor (Color.Black); - gr.LineWidth = 1.0; - - int level = 0; - bool closingNode = false; - - if (currentNode != null) { - if (cl == currentNode.EndLine) { - currentNode = currentNode.Parent; - closingNode = true; - } - if (currentNode != null) - level = currentNode.Level - 1; - } - - for (int l = 0; l < level; l++) { - gr.MoveTo (rFld.Center.X + 0.5, y); - gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent + fe.Descent); - rFld.Left += foldHSpace; - } - if (closingNode) { - gr.MoveTo (rFld.Center.X + 0.5, y); - gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent / 2 + 0.5); - gr.LineTo (rFld.Center.X + 0.5 + foldSize / 2, y + fe.Ascent / 2 + 0.5); - closingNode = false; - } - gr.SetDash (new double[]{ 1.5 },0.0); - gr.SetSourceColor (Color.Gray); - gr.Stroke (); - gr.SetDash (new double[]{}, 0.0); - - if (cl.IsFoldable) { - gr.Rectangle (rFld); - gr.SetSourceColor (Color.White); - gr.Fill(); - gr.SetSourceColor (Color.Black); - gr.Rectangle (rFld, 1.0); - if (cl.IsFolded) { - gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2); - gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2); - }else - currentNode = cl.SyntacticNode; - - gr.MoveTo (rFld.Left + 2, rFld.Center.Y + 0.5); - gr.LineTo (rFld.Right - 2, rFld.Center.Y + 0.5); - gr.Stroke (); - } - } - - gr.SetSourceColor (Foreground); - x += leftMargin; - - if (cl.Tokens == null) - drawRawCodeLine (gr, x, y, i, lineIndex); - else - drawParsedCodeLine (gr, x, y, i, lineIndex); - } - Node currentNode = null; -// void drawParsed(Context gr){ -// if (PrintedLines == null) -// return; -// -// gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); -// gr.SetFontSize (Font.Size); -// gr.FontOptions = Interface.FontRenderingOptions; -// gr.Antialias = Interface.Antialias; -// -// Rectangle cb = ClientRectangle; -// gr.Save (); -// CairoHelpers.CairoRectangle (gr, cb, CornerRadius); -// gr.Clip (); -// -// bool selectionInProgress = false; -// -// Foreground.SetAsSource (gr); -// -// #region draw text cursor -// if (SelBegin != SelRelease) -// selectionInProgress = true; -// else if (HasFocus){ -// gr.LineWidth = 1.0; -// double cursorX = + leftMargin + cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; -// gr.MoveTo (0.5 + cursorX, cb.Y + printedCurrentLine * (fe.Ascent+fe.Descent)); -// gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); -// gr.Stroke(); -// } -// #endregion -// -// for (int i = 0; i < PrintedLines.Count; i++) -// drawTokenLine (gr, i, selectionInProgress, cb); -// -// gr.Restore (); -// } - void drawRawCodeLine(Context gr, double x, double y, int i, int lineIndex) { - string lstr = buffer[lineIndex].PrintableContent; - if (ScrollX < lstr.Length) - lstr = lstr.Substring (ScrollX); - else - lstr = ""; - - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - - if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { - double rLineX = x, - rLineY = y, - rLineW = lstr.Length * fe.MaxXAdvance; - - //System.Diagnostics.Debug.WriteLine ("sel start: " + buffer.SelectionStart + " sel end: " + buffer.SelectionEnd); - if (lineIndex == buffer.SelectionStart.Y) { - rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; - rLineW -= selStartCol * fe.MaxXAdvance; - } - if (lineIndex == buffer.SelectionEnd.Y) - rLineW -= (lstr.Length - selEndCol) * fe.MaxXAdvance; - - gr.Save (); - gr.Operator = Operator.Source; - gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); - gr.SetSourceColor (SelectionBackground); - gr.FillPreserve (); - gr.Clip (); - gr.Operator = Operator.Over; - gr.SetSourceColor (SelectionForeground); - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - gr.Restore (); - } - } - void drawParsedCodeLine (Context gr, double x, double y, int i, int lineIndex) { - int lPtr = 0; - CodeLine cl = PrintedLines[i]; - - for (int t = 0; t < cl.Tokens.Count; t++) { - string lstr = cl.Tokens [t].PrintableContent; - if (lPtr < ScrollX) { - if (lPtr - ScrollX + lstr.Length <= 0) { - lPtr += lstr.Length; - continue; - } - lstr = lstr.Substring (ScrollX - lPtr); - lPtr += ScrollX - lPtr; - } - Color bg = this.Background; - Color fg = this.Foreground; - Color selbg = this.SelectionBackground; - Color selfg = this.SelectionForeground; - FontSlant fts = FontSlant.Normal; - FontWeight ftw = FontWeight.Normal; - - if (formatting.ContainsKey ((int)cl.Tokens [t].Type)) { - TextFormatting tf = formatting [(int)cl.Tokens [t].Type]; - bg = tf.Background; - fg = tf.Foreground; - if (tf.Bold) - ftw = FontWeight.Bold; - if (tf.Italic) - fts = FontSlant.Italic; - } - - gr.SelectFontFace (Font.Name, fts, ftw); - gr.SetSourceColor (fg); - - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - - if (buffer.SelectionInProgress && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y && - !(lineIndex == buffer.SelectionStart.Y && lPtr + lstr.Length <= selStartCol) && - !(lineIndex == buffer.SelectionEnd.Y && selEndCol <= lPtr)) { - - double rLineX = x, - rLineY = y, - rLineW = lstr.Length * fe.MaxXAdvance; - double startAdjust = 0.0; - - if ((lineIndex == buffer.SelectionStart.Y) && (selStartCol < lPtr + lstr.Length) && (selStartCol > lPtr)) - startAdjust = (selStartCol - lPtr) * fe.MaxXAdvance; - rLineX += startAdjust; - if ((lineIndex == buffer.SelectionEnd.Y) && (selEndCol < lPtr + lstr.Length)) - rLineW = (selEndCol - lPtr) * fe.MaxXAdvance; - rLineW -= startAdjust; - - gr.Save (); - gr.Operator = Operator.Source; - gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); - gr.SetSourceColor (selbg); - gr.FillPreserve (); - gr.Clip (); - gr.Operator = Operator.Over; - gr.SetSourceColor (selfg); - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - gr.Restore (); - } - x += (int)lstr.Length * fe.MaxXAdvance; - lPtr += lstr.Length; - } - } - - #endregion - - #region GraphicObject overrides - public override Font Font { - get { return base.Font; } - set { - base.Font = value; - - using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) { - using (Context gr = new Context (img)) { - gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); - gr.SetFontSize (Font.Size); - - fe = gr.FontExtents; - } - } - MaxScrollY = 0; - RegisterForGraphicUpdate (); - } - } - protected override int measureRawSize(LayoutingType lt) - { - if (lt == LayoutingType.Height) - return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; - - return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2 + leftMargin; - } - public override void OnLayoutChanges (LayoutingType layoutType) - { - base.OnLayoutChanges (layoutType); - - if (layoutType == LayoutingType.Height) - updateVisibleLines (); - else if (layoutType == LayoutingType.Width) - updateVisibleColumns (); - } - - protected override void onDraw (Context gr) - { - base.onDraw (gr); - - gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); - gr.SetFontSize (Font.Size); - gr.FontOptions = Interface.FontRenderingOptions; - gr.Antialias = Interface.Antialias; - - Rectangle cb = ClientRectangle; - - Foreground.SetAsSource (gr); - - buffer.editMutex.EnterReadLock (); - editorMutex.EnterReadLock (); - - #region draw text cursor - if (buffer.SelectionInProgress){ - selStartCol = getTabulatedColumn (buffer.SelectionStart); - selEndCol = getTabulatedColumn (buffer.SelectionEnd); - }else if (HasFocus && printedCurrentLine >= 0){ - gr.LineWidth = 1.0; - double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance + leftMargin; - gr.MoveTo (0.5 + cursorX, cb.Y + (printedCurrentLine) * (fe.Ascent+fe.Descent)); - gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); - gr.Stroke(); - } - #endregion - - if (PrintedLines != null) { - int unfoldedLines = buffer.UnfoldedLines; - currentNode = null; - CodeLine cl = PrintedLines[0]; - int idx0 = buffer.IndexOf(cl); - int li = idx0-1; - while (li >= 0) { - if (buffer [li].IsFoldable && !buffer [li].IsFolded) { - if (buffer.IndexOf(buffer [li].SyntacticNode.EndLine) > idx0){ - currentNode = buffer [li].SyntacticNode; - break; - } - } - li--; - } - - for (int i = 0; i < visibleLines; i++) { - if (i + ScrollY >= unfoldedLines)//TODO:need optimize - break; - drawLine (gr, cb, i); - } - } - - editorMutex.ExitReadLock (); - - buffer.editMutex.ExitReadLock (); - - } - #endregion - - #region Mouse handling - - int hoverLine = -1; - public int HoverLine { - get { return hoverLine; } - set { - if (hoverLine == value) - return; - hoverLine = value; - NotifyValueChanged ("HoverLine", hoverLine); - } - } - void updateHoverLine () { - int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); - hvl = Math.Min (PrintedLines.Count, hvl); - HoverLine = buffer.IndexOf (PrintedLines[hvl]); - } - void updateCurrentPosFromMouseLocalPos(){ - PrintedCurrentLine = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); - int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X - leftMargin) / fe.MaxXAdvance); - - int i = 0; - int buffCol = 0; - while (i < curVisualCol && buffCol < buffer.CurrentCodeLine.Length) { - if (buffer.CurrentCodeLine[buffCol] == '\t') - i += Interface.TabSize; - else - i++; - buffCol++; - } - buffer.CurrentColumn = buffCol; - } - public override void onMouseEnter (object sender, MouseMoveEventArgs e) - { - base.onMouseEnter (sender, e); - if (e.X - ScreenCoordinates(Slot).X < leftMargin + ClientRectangle.X) - IFace.MouseCursor = XCursor.Default; - else - IFace.MouseCursor = XCursor.Text; - } - public override void onMouseLeave (object sender, MouseMoveEventArgs e) - { - base.onMouseLeave (sender, e); - IFace.MouseCursor = XCursor.Default; - } - public override void onMouseMove (object sender, MouseMoveEventArgs e) - { - base.onMouseMove (sender, e); - - mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; - - updateHoverLine (); - - if (!e.Mouse.IsButtonDown (MouseButton.Left)) { - if (mouseLocalPos.X < leftMargin) - IFace.MouseCursor = XCursor.Default; - else - IFace.MouseCursor = XCursor.Text; - return; - } - - if (!HasFocus || !buffer.SelectionInProgress) - return; - - //mouse is down - updateCurrentPosFromMouseLocalPos(); - buffer.SetSelEndPos (); - } - public override void onMouseDown (object sender, MouseButtonEventArgs e) - { - if (!this.Focusable) - return; - - if (mouseLocalPos.X >= leftMargin) - base.onMouseDown (sender, e); - - if (doubleClicked) { - doubleClicked = false; - return; - } - - if (mouseLocalPos.X < leftMargin) { - toogleFolding (buffer.IndexOf (PrintedLines [(int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent)))])); - return; - } - - updateCurrentPosFromMouseLocalPos (); - buffer.SetSelStartPos (); - } - public override void onMouseUp (object sender, MouseButtonEventArgs e) - { - base.onMouseUp (sender, e); - - if (buffer.SelectionIsEmpty) - buffer.ResetSelection (); - } - - public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) - { - doubleClicked = true; - base.onMouseDoubleClick (sender, e); - - buffer.GotoWordStart (); - buffer.SetSelStartPos (); - buffer.GotoWordEnd (); - buffer.SetSelEndPos (); - } - - public override void onMouseWheel (object sender, MouseWheelEventArgs e) - { - base.onMouseWheel (sender, e); - } - #endregion - - #region Keyboard handling - public override void onKeyDown (object sender, KeyboardKeyEventArgs e) - { - //base.onKeyDown (sender, e); - - Key key = e.Key; - - if (e.Control) { - switch (key) { - case Key.S: - projFile.Save (); - break; - case Key.W: - editorMutex.EnterWriteLock (); - if (e.Shift) - projFile.Redo (null); - else - projFile.Undo (null); - editorMutex.ExitWriteLock (); - break; - default: - Console.WriteLine (""); - break; - } - } - - switch (key) - { - case Key.Back: - buffer.DeleteChar (); - break; - case Key.Clear: - break; - case Key.Delete: - if (buffer.SelectionIsEmpty) - MoveRight (); - else if (e.Shift) - IFace.Clipboard = buffer.SelectedText; - buffer.DeleteChar (); - break; - case Key.Enter: - case Key.KeypadEnter: - if (!buffer.SelectionIsEmpty) - buffer.DeleteChar (); - buffer.InsertLineBreak (); - break; - case Key.Escape: - buffer.ResetSelection (); - break; - case Key.Home: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.CurrentLine = 0; - buffer.CurrentColumn = 0; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.CurrentLine = 0; - buffer.CurrentColumn = 0; - break; - case Key.End: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.CurrentLine = int.MaxValue; - buffer.CurrentColumn = int.MaxValue; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.CurrentLine = int.MaxValue; - buffer.CurrentColumn = int.MaxValue; - break; - case Key.Insert: - if (e.Shift) - buffer.Insert (IFace.Clipboard); - else if (e.Control && !buffer.SelectionIsEmpty) - IFace.Clipboard = buffer.SelectedText; - break; - case Key.Left: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.GotoWordStart (); - else - MoveLeft (); - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.GotoWordStart (); - else - MoveLeft(); - break; - case Key.Right: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.GotoWordEnd (); - else - MoveRight (); - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.GotoWordEnd (); - else - MoveRight (); - break; - case Key.Up: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine--; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine--; - break; - case Key.Down: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine++; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine++; - break; - case Key.Menu: - break; - case Key.NumLock: - break; - case Key.PageDown: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine += visibleLines; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine += visibleLines; - break; - case Key.PageUp: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine -= visibleLines; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine -= visibleLines; - break; - case Key.RWin: - break; - case Key.Tab: - if (e.Shift) { - if (buffer.SelectionIsEmpty || - (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { - //TODO - break; - } - for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) - buffer.RemoveLeadingTab (i); - buffer.SetSelectionOnFullLines (); - } else { - if (buffer.SelectionIsEmpty || - (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { - buffer.Insert ("\t"); - break; - } - for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) { - buffer.UpdateLine (i, "\t" + buffer [i].Content); - } - } - - break; - case Key.F8: - toogleFolding (buffer.CurrentLine); - break; - default: - break; - } - RegisterForGraphicUpdate(); - } - public override void onKeyPress (object sender, KeyPressEventArgs e) - { - base.onKeyPress (sender, e); - - buffer.Insert (e.KeyChar.ToString()); - buffer.ResetSelection (); - } - #endregion - } -} \ No newline at end of file diff --git a/CrowIDE/src/SourceEditor/StyleParser.cs b/CrowIDE/src/SourceEditor/StyleParser.cs deleted file mode 100644 index 9a1e74cd..00000000 --- a/CrowIDE/src/SourceEditor/StyleParser.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using Crow; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text.RegularExpressions; -using System.Linq; - -namespace Crow.Coding -{ - public class StyleParser : BufferParser - { - enum States { init, classNames, members, value, endOfStatement } - - public StyleParser (CodeBuffer _buffer) : base(_buffer) - { - } - - #region Character ValidityCheck - static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); - static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}"); - static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); - static Regex rxDecimal = new Regex(@"[0-9]+"); - static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); - - public bool nextCharIsValidCharStartName - { - get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } - } - public bool nextCharIsValidCharName - { - get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } - } - #endregion - - States curState = States.classNames; - - public override void ParseCurrentLine () - { - //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); - CodeLine cl = buffer [currentLine]; - cl.Tokens = new List (); - - //retrieve current parser state from previous line - if (currentLine > 0) - curState = (States)buffer[currentLine - 1].EndingState; - else - curState = States.init; - - States previousEndingState = (States)cl.EndingState; - - while (! eol) { - SkipWhiteSpaces (); - - if (eol) - break; - - if (Peek () == '\n') { - if (currentTok != TokenType.Unknown) - throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); - Read (); - eol = true; - continue; - } - - switch (Peek()) { - case '/': - readToCurrTok (true); - switch (Peek ()) { - case '/': - currentTok += ReadLine (); - saveAndResetCurrentTok (TokenType.LineComment); - break; - default: - currentTok += ReadLine (); - saveAndResetCurrentTok (TokenType.Unknown); - break; - } - break; - case ',': - if (curState != States.init && curState != States.classNames ) - throw new ParserException (currentLine, currentColumn, "Unexpected char ','"); - readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); - curState = States.classNames; - break; - case '{': - if (!(curState == States.init || curState == States.classNames)) - throw new ParserException (currentLine, currentColumn, "Unexpected char '{'"); - readAndResetCurrentTok (TokenType.OpenBlock, true); - curState = States.members; - break; - case '}': - if (curState != States.members) - throw new ParserException (currentLine, currentColumn, "Unexpected char '}'"); - readAndResetCurrentTok (TokenType.CloseBlock, true); - curState = States.classNames; - break; - case '=': - if (curState == States.classNames) - throw new ParserException (currentLine, currentColumn, "Unexpected char '='"); - setPreviousTokOfTypeTo (TokenType.Type, TokenType.Identifier); - readAndResetCurrentTok (TokenType.OperatorOrPunctuation, true); - curState = States.value; - break; - case '"': - if (curState != States.value) - throw new ParserException (currentLine, currentColumn, "Unexpected char '\"'"); - readAndResetCurrentTok (TokenType.StringLitteralOpening, true); - - while (!eol) { - currentTok += ReadLineUntil ("\""); - if (currentTok.Content [currentTok.Content.Length - 1] == '\\') - readToCurrTok (); - else - break; - } - if (eol) - throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); - saveAndResetCurrentTok (TokenType.StringLitteral); - - readAndResetCurrentTok (TokenType.StringLitteralClosing, true); - curState = States.endOfStatement; - break; - case ';': - if (curState != States.endOfStatement) - throw new ParserException (currentLine, currentColumn, "Unexpected end of statement"); - readAndResetCurrentTok (TokenType.StatementEnding, true); - curState = States.members; - break; - default: - if (currentTok.Type != TokenType.Unknown) - throw new ParserException (currentLine, currentColumn, "error curtok not null"); - if (curState == States.value) - throw new ParserException (currentLine, currentColumn, "expecting value enclosed in '\"'"); - if (curState == States.endOfStatement) - throw new ParserException (currentLine, currentColumn, "expecting end of statement"); - - if (nextCharIsValidCharStartName) { - readToCurrTok (true); - while (nextCharIsValidCharName) - readToCurrTok (); - } - saveAndResetCurrentTok (TokenType.Type); - break; - } - } - - if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) - buffer [currentLine + 1].Tokens = null; - - cl.EndingState = (int)curState; - } - public override void SyntaxAnalysis () - { - initSyntaxAnalysis (); - Node currentNode = RootNode; - - for (int i = 0; i < buffer.LineCount; i++) { - CodeLine cl = buffer[i]; - if (cl.Tokens == null) - continue; - cl.SyntacticNode = null; - - int tokPtr = 0; - while (tokPtr < cl.Tokens.Count) { - switch (cl.Tokens [tokPtr].Type) { - case TokenType.OpenBlock: - currentNode = addChildNode (currentNode, cl, tokPtr, "style"); - break; - case TokenType.CloseBlock: - closeNodeAndGoUp (ref currentNode, cl, "style"); - break; - } - tokPtr++; - } - } - } - } -} - diff --git a/CrowIDE/src/SourceEditor/TextFormatting.cs b/CrowIDE/src/SourceEditor/TextFormatting.cs deleted file mode 100644 index f7b2e518..00000000 --- a/CrowIDE/src/SourceEditor/TextFormatting.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Crow.Coding -{ - public struct TextFormatting { - public Color Foreground; - public Color Background; - public bool Bold; - public bool Italic; - - public TextFormatting(Color fg, Color bg, bool bold = false, bool italic = false){ - Foreground = fg; - Background = bg; - Bold = bold; - Italic = italic; - } - } -} - diff --git a/CrowIDE/src/SourceEditor/Token.cs b/CrowIDE/src/SourceEditor/Token.cs deleted file mode 100644 index 8b4df5e5..00000000 --- a/CrowIDE/src/SourceEditor/Token.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Token.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; - -namespace Crow.Coding -{ - public struct Token - { - public BufferParser.TokenType Type; - public string Content; - public Point Start; - public Point End; - - public string PrintableContent { - get { return string.IsNullOrEmpty(Content) ? "" : Content.Replace("\t", new String(' ', Interface.TabSize)); } - } - -// public Token (TokenType tokType, string content = ""){ -// Type = tokType; -// Content = content; -// } - - public bool IsNull { get { return IsEmpty && Type == BufferParser.TokenType.Unknown; }} - public bool IsEmpty { get { return string.IsNullOrEmpty(Content); }} - - public static bool operator == (Token t, System.Enum tt){ - return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); - } - public static bool operator != (Token t, System.Enum tt){ - return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); - } - public static bool operator == (System.Enum tt, Token t){ - return Convert.ToInt32(t.Type) == Convert.ToInt32(tt); - } - public static bool operator != (System.Enum tt, Token t){ - return Convert.ToInt32(t.Type) != Convert.ToInt32(tt); - } - - public static Token operator +(Token t, char c){ - t.Content += c; - return t; - } - public static Token operator +(Token t, string s){ - t.Content += s; - return t; - } - public override string ToString () - { - return string.Format ("[Tok{2}->{3}:{0}: {1}]", Type,Content,Start,End); - } - } -} - diff --git a/CrowIDE/src/SourceEditor/XMLParser.cs b/CrowIDE/src/SourceEditor/XMLParser.cs deleted file mode 100644 index d31e1023..00000000 --- a/CrowIDE/src/SourceEditor/XMLParser.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using Crow; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Diagnostics; -using System.Linq; - -namespace Crow.Coding -{ - public class XMLParser : BufferParser - { - public new enum TokenType { - Unknown = BufferParser.TokenType.Unknown, - WhiteSpace = BufferParser.TokenType.WhiteSpace, - NewLine = BufferParser.TokenType.NewLine, - LineComment = BufferParser.TokenType.LineComment, - BlockCommentStart = BufferParser.TokenType.BlockCommentStart, - BlockComment = BufferParser.TokenType.BlockComment, - BlockCommentEnd = BufferParser.TokenType.BlockCommentEnd, - ElementName = BufferParser.TokenType.Identifier, - AttributeName = BufferParser.TokenType.Keyword, - ElementClosing = BufferParser.TokenType.StatementEnding, - Affectation = BufferParser.TokenType.OperatorOrPunctuation, - AttributeValueOpening = BufferParser.TokenType.StringLitteralOpening, - AttributeValueClosing = BufferParser.TokenType.StringLitteralClosing, - AttributeValue = BufferParser.TokenType.StringLitteral, - XMLDecl = BufferParser.TokenType.Preprocessor, - ElementStart = 50, - ElementEnd = 51, - } - - public enum States - { - init, //first statement of prolog, xmldecl should only apear in this state - prolog, //misc before doctypedecl - InternalSubset, //doctype declaration subset - ExternalSubsetInit, - ExternalSubset, - BlockComment, - DTDEnd,//doctype finished - XML,//normal xml - StartTag,//inside start tag - Content,//after start tag with no closing slash - EndTag - } - - #region CTOR - public XMLParser (CodeBuffer _buffer) : base(_buffer) {} - #endregion - - enum Keywords - { - DOCTYPE, - ELEMENT, - ATTLIST, - ENTITY, - NOTATION - } - - States curState = States.init; - - #region Regular Expression for validity checks - //private static Regex rxValidChar = new Regex("[\u0020-\uD7FF]"); - private static Regex rxValidChar = new Regex(@"\u0009|\u000A|\u000D|[\u0020-\uD7FF]|[\uE000-\uFFFD]"); //| [\u10000-\u10FFFF] unable to set those plans - private static Regex rxNameStartChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]"); // | [\u10000-\uEFFFF] - private static Regex rxNameChar = new Regex(@":|[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]|-|\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]");//[\u10000-\uEFFFF]| - private static Regex rxDecimal = new Regex(@"[0-9]+"); - private static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); - private static Regex rxAttributeValue = new Regex(@"[^<]"); - private static Regex rxEntityValue = new Regex(@"[^<]"); - private static Regex rxPubidChar = new Regex(@"\u0020|\u000D|\u000A|[a-zA-Z0-9]|[-\(\)\+\,\./:=\?;!\*#@\$_%]"); - #endregion - - #region Character ValidityCheck - public bool nextCharIsValidCharStartName - { - get { return rxNameStartChar.IsMatch(new string(new char[]{Peek()})); } - } - public bool nextCharIsValidCharName - { - get { return rxNameChar.IsMatch(new string(new char[]{Peek()})); } - } - #endregion - - public override void SetLineInError (ParserException ex) - { - base.SetLineInError (ex); - //buffer[ex.Line].Tokens.EndingState = (int)States.init; - } - - public override void ParseCurrentLine () - { - //Debug.WriteLine (string.Format("parsing line:{0}", currentLine)); - CodeLine cl = buffer [currentLine]; - cl.Tokens = new List (); - - //retrieve current parser state from previous line - if (currentLine > 0) - curState = (States)buffer[currentLine - 1].EndingState; - else - curState = States.init; - - States previousEndingState = (States)cl.EndingState; - - - while (! eol) { - SkipWhiteSpaces (); - - if (eol) - break; - - if (Peek () == '\n') { - if (currentTok != TokenType.Unknown) - throw new ParserException (currentLine, currentColumn, "Unexpected end of line"); - Read (); - eol = true; - continue; - } - - if (curState == States.BlockComment) { - if (currentTok != TokenType.Unknown) - Debugger.Break (); - - currentTok.Start = CurrentPosition; - currentTok.Type = (BufferParser.TokenType)TokenType.BlockComment; - currentTok += ReadLineUntil ("-->"); - if (Peek (3) == "-->") { - readToCurrTok (3); - curState = States.XML; - } - saveAndResetCurrentTok (); - continue; - } - - switch (Peek()) { - case '<': - readToCurrTok (true); - switch (Peek()) { - case '?': - if (curState != States.init) - throw new ParserException (currentLine, currentColumn, "xml decl may appear only on first line"); - readToCurrTok (); - currentTok += ReadLineUntil ("?>"); - if (Peek (2) != "?>") - throw new ParserException (currentLine, currentColumn, "expecting '?>'"); - readToCurrTok (2); - saveAndResetCurrentTok (TokenType.XMLDecl); - curState = States.prolog; - break; - case '!': - readToCurrTok (); - switch (Peek()) { - case '-': - readToCurrTok (); - if (Peek () != '-') - throw new ParserException (currentLine, currentColumn, "Expecting comment start tag"); - readToCurrTok (); - currentTok += ReadLineUntil ("--"); - if (Peek (3) == "-->") { - readToCurrTok (3); - }else - curState = States.BlockComment; - saveAndResetCurrentTok (TokenType.BlockComment); - break; - default: - throw new ParserException (currentLine, currentColumn, "error"); - } - break; - default: - if (!(curState == States.Content || curState == States.XML || curState == States.init || curState == States.prolog)) - throw new ParserException (currentLine, currentColumn, "Unexpected char: '<'"); - if (Peek () == '/') { - curState = States.EndTag; - readToCurrTok (); - saveAndResetCurrentTok (TokenType.ElementEnd); - } else { - curState = States.StartTag; - saveAndResetCurrentTok (TokenType.ElementStart); - } - - if (!nextCharIsValidCharStartName) - throw new ParserException (currentLine, currentColumn, "Expected element name"); - - readToCurrTok (true); - while (nextCharIsValidCharName) - readToCurrTok (); - - saveAndResetCurrentTok (TokenType.ElementName); - break; - } - break; - case '/': - if (curState != States.StartTag) - throw new ParserException (currentLine, currentColumn, "Unexpected char: '/'"); - readToCurrTok (true); - if (Peek () != '>') - throw new ParserException (currentLine, currentColumn, "Expecting '>'"); - readAndResetCurrentTok (TokenType.ElementEnd); - - curState = States.XML; - break; - case '>': - readAndResetCurrentTok (TokenType.ElementClosing, true); - switch (curState) { - case States.EndTag: - curState = States.XML; - break; - case States.StartTag: - curState = States.Content; - break; - default: - throw new ParserException (currentLine, currentColumn, "Unexpected char: '>'"); - } - break; - default: - switch (curState) { - case States.StartTag: - if (!nextCharIsValidCharStartName) - throw new ParserException (currentLine, currentColumn, "Expected attribute name"); - readToCurrTok (true); - while (nextCharIsValidCharName) - readToCurrTok (); - saveAndResetCurrentTok (TokenType.AttributeName); - - SkipWhiteSpaces (); - - if (Peek () != '=') - throw new ParserException (currentLine, currentColumn, "Expecting: '='"); - readAndResetCurrentTok (TokenType.Affectation, true); - - SkipWhiteSpaces (); - - char openAttVal = Peek (); - if (openAttVal != '"' && openAttVal != '\'') - throw new ParserException (currentLine, currentColumn, "Expecting attribute value enclosed either in '\"' or in \"'\""); - readAndResetCurrentTok (TokenType.AttributeValueOpening, true); - - currentTok.Start = CurrentPosition; - currentTok.Content = ReadLineUntil (new string (new char[]{ openAttVal })); - saveAndResetCurrentTok (TokenType.AttributeValue); - - if (Peek () != openAttVal) - throw new ParserException (currentLine, currentColumn, string.Format ("Expecting {0}", openAttVal)); - readAndResetCurrentTok (TokenType.AttributeValueClosing, true); - break; - default: - throw new ParserException (currentLine, currentColumn, "unexpected char: " + Peek ()); - } - break; - } - } - - if (cl.EndingState != (int)curState && currentLine < buffer.LineCount - 1) - buffer [currentLine + 1].Tokens = null; - - cl.EndingState = (int)curState; - } - - public override void SyntaxAnalysis () - { - initSyntaxAnalysis (); - Node currentNode = RootNode; - - for (int i = 0; i < buffer.LineCount; i++) { - CodeLine cl = buffer[i]; - if (cl.Tokens == null) - continue; - cl.SyntacticNode = null; - - int tokPtr = 0; - while (tokPtr < cl.Tokens.Count) { - switch ((XMLParser.TokenType)cl.Tokens [tokPtr].Type) { - case TokenType.ElementStart: - tokPtr++; - currentNode = addChildNode (currentNode, cl, tokPtr, "Element"); - break; - case TokenType.ElementEnd: - tokPtr++; - if (tokPtr < cl.Tokens.Count) { - if ((XMLParser.TokenType)cl.Tokens [tokPtr].Type == TokenType.ElementName && - cl.Tokens [tokPtr].Content != currentNode.Name) - throw new ParserException (currentLine, currentColumn, "Closing tag mismatch"); - } - closeNodeAndGoUp (ref currentNode, cl, "Element"); - break; - case TokenType.ElementClosing: - //currentNode = currentNode.Parent; - break; - default: - break; - } - tokPtr++; - } - } - } - } -} - diff --git a/CrowIDE/src/SvgEditor.cs b/CrowIDE/src/SvgEditor.cs deleted file mode 100644 index 219eea67..00000000 --- a/CrowIDE/src/SvgEditor.cs +++ /dev/null @@ -1,137 +0,0 @@ -// -// SvgEditor.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.ComponentModel; -using Cairo; - -namespace Crow.Coding -{ - public class SvgEditor : Editor - { - SvgPicture _pic = new SvgPicture(); - - int zoom; - - [DefaultValue(100)] - public int Zoom { - get { return zoom; } - set { - if (zoom == value) - return; - zoom = value; - NotifyValueChanged ("Zoom", zoom); - updateMaxScrolls (); - RegisterForGraphicUpdate (); - } - } - - void updateMaxScrolls() { - MaxScrollX = Math.Max(0, _pic.Dimensions.Width * zoom / 100 - Slot.Width); - MaxScrollY = Math.Max(0, _pic.Dimensions.Height * zoom / 100 - Slot.Height); - - if (Slot.Width + MaxScrollX > 0) - NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / (Slot.Width + MaxScrollX)); - else - NotifyValueChanged ("ChildWidthRatio", 0); - - if (Slot.Height + MaxScrollY > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / (Slot.Height + MaxScrollY)); - else - NotifyValueChanged ("ChildHeightRatio", 0); - } - #region editor overrides - protected override void updateEditorFromProjFile () - { - Error = null; - try { - editorMutex.EnterWriteLock(); - _pic.LoadSvgFragment (projFile.Source); - _pic.Scaled = true; - _pic.KeepProportions = true; - } catch (Exception ex) { - Error = ex; - } - editorMutex.ExitWriteLock (); - updateMaxScrolls (); - RegisterForGraphicUpdate (); - } - protected override void updateProjFileFromEditor () - { - throw new NotImplementedException (); - } - protected override bool EditorIsDirty { - get { return false; } - set { - throw new NotImplementedException (); - } - } - #endregion - - #region GraphicObject overrides - protected override int measureRawSize (LayoutingType lt) - { - if (_pic == null) - return 2 * Margin; - //_pic = "#Crow.Images.Icons.IconAlerte.svg"; - //TODO:take scalling in account - if (lt == LayoutingType.Width) - return _pic.Dimensions.Width + 2 * Margin; - else - return _pic.Dimensions.Height + 2 * Margin; - } - protected override void onDraw (Context gr) - { - base.onDraw (gr); - - Rectangle r = ClientRectangle; - Foreground.SetAsSource (gr, r); - gr.Rectangle (r, 0.1); - gr.Stroke (); - - r.Width = _pic.Dimensions.Width * zoom / 100; - r.Height = _pic.Dimensions.Height * zoom / 100; - - gr.Save (); - - editorMutex.EnterReadLock (); - - gr.Translate (-ScrollX, -ScrollY); - if (_pic != null) - _pic.Paint (gr, r); - editorMutex.ExitReadLock (); - - gr.Restore (); - } - public override void OnLayoutChanges (LayoutingType layoutType) - { - base.OnLayoutChanges (layoutType); - if ((layoutType | LayoutingType.Sizing) > 0) - updateMaxScrolls (); - } - #endregion - } -} - diff --git a/CrowIDE/ui/ContextMenu.template b/CrowIDE/ui/ContextMenu.template new file mode 100644 index 00000000..2b03d1f2 --- /dev/null +++ b/CrowIDE/ui/ContextMenu.template @@ -0,0 +1,42 @@ + + + + + + + + + + diff --git a/CrowIDE/ui/CrowIDE.crow b/CrowIDE/ui/CrowIDE.crow index 02aa6fd8..94a57e71 100644 --- a/CrowIDE/ui/CrowIDE.crow +++ b/CrowIDE/ui/CrowIDE.crow @@ -5,6 +5,7 @@ + diff --git a/CrowIDE/ui/DockWindows/winToolbox.crow b/CrowIDE/ui/DockWindows/winToolbox.crow index d6b1bd4c..9059c7a4 100644 --- a/CrowIDE/ui/DockWindows/winToolbox.crow +++ b/CrowIDE/ui/DockWindows/winToolbox.crow @@ -1,8 +1,8 @@  - + - + diff --git a/CrowIDE/ui/EditPane.template b/CrowIDE/ui/EditPane.template deleted file mode 100644 index 43be10d6..00000000 --- a/CrowIDE/ui/EditPane.template +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/CrowIDE/ui/EditPaneItems.template b/CrowIDE/ui/EditPaneItems.template deleted file mode 100644 index d0c0922f..00000000 --- a/CrowIDE/ui/EditPaneItems.template +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CrowIDE/ui/GTreeExpITemp.crow b/CrowIDE/ui/GTreeExpITemp.crow index 4be4f094..d3447366 100644 --- a/CrowIDE/ui/GTreeExpITemp.crow +++ b/CrowIDE/ui/GTreeExpITemp.crow @@ -1,28 +1,29 @@  - + - - + + diff --git a/CrowIDE/ui/GTreeExplorer.crow b/CrowIDE/ui/GTreeExplorer.crow index b62b02a1..a4d5f727 100644 --- a/CrowIDE/ui/GTreeExplorer.crow +++ b/CrowIDE/ui/GTreeExplorer.crow @@ -1,30 +1,18 @@  - - + +