Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrowEdit", "CrowEdit.csproj", "{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}"
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30711.63
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CrowEdit", "CrowEdit.csproj", "{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crow.Coding", "Crow.Coding\Crow.Coding.csproj", "{78842EE4-8A2F-4C75-AEC6-C95F15AD3994}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crow.Coding", "Crow.Coding\Crow.Coding.csproj", "{78842EE4-8A2F-4C75-AEC6-C95F15AD3994}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crow", "..\crow\Crow\Crow.csproj", "{0D18388D-8DDB-43DE-A608-0C65F0AEC4E0}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Global", "Global", "{3118E6C1-2180-4364-9A17-511D546E18CD}"
+ ProjectSection(SolutionItems) = preProject
+ Directory.Build.props = Directory.Build.props
+ README.md = README.md
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Release|Any CPU = Release|Any CPU
Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Release|Any CPU.Build.0 = Release|Any CPU
{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAA67D93-458E-4DD7-9CDA-4EC7F73D47FF}.Release|Any CPU.Build.0 = Release|Any CPU
- {0D18388D-8DDB-43DE-A608-0C65F0AEC4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0D18388D-8DDB-43DE-A608-0C65F0AEC4E0}.Release|Any CPU.Build.0 = Release|Any CPU
- {0D18388D-8DDB-43DE-A608-0C65F0AEC4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0D18388D-8DDB-43DE-A608-0C65F0AEC4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {78842EE4-8A2F-4C75-AEC6-C95F15AD3994}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {121E26CF-4A0F-4E74-BC0F-82BABEFDE8BF}
EndGlobalSection
EndGlobal
using Crow;
using System.IO;
using System.Collections.Generic;
+using Crow.Text;
namespace CrowEdit
{
CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions;
const string _defaultFileName = "unnamed.txt";
- string _text = "", _origText="";
- bool isDirty = false;
- public new bool IsDirty { get { return _text != _origText; } }
-
- List<string> undoStack = new List<string>();
- List<string> redoStack = new List<string>();
-
- public string Text {
- get { return _text; }
+ string source = "";
+ int dirtyUndoLevel;//
+ public new bool IsDirty { get { return undoStack.Count != dirtyUndoLevel; } }
+ public string Source {
+ get => source;
set {
- if (_text == value)
+ if (source == value)
return;
- undoStack.Add (_text);
+ source = value;
+ NotifyValueChanged (source);
+ }
+ }
+ public CommandGroup EditorCommands => new CommandGroup (CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDSave, CMDSaveAs);
+
+ Stack<TextChange> undoStack = new Stack<TextChange> ();
+ Stack<TextChange> redoStack = new Stack<TextChange> ();
+
+ void undo () {
+ if (undoStack.TryPop (out TextChange tch)) {
+ redoStack.Push (tch.Inverse (source));
+ CMDRedo.CanExecute = true;
+ apply (tch);
+ editor.SetCursorPosition (tch.End + tch.ChangedText.Length);
+ }
+ if (undoStack.Count == 0)
+ CMDUndo.CanExecute = false;
+ }
+ void redo () {
+ if (redoStack.TryPop (out TextChange tch)) {
+ undoStack.Push (tch.Inverse (source));
CMDUndo.CanExecute = true;
- redoStack.Clear ();
- CMDRedo.CanExecute = false;
- _text = value;
- NotifyValueChanged (_text);
- NotifyValueChanged ("IsDirty", IsDirty);
+ apply (tch);
+ editor.SetCursorPosition (tch.End + tch.ChangedText.Length);
}
+ if (redoStack.Count == 0)
+ CMDRedo.CanExecute = false;
+ }
+ bool disableTextChangedEvent = false;
+ void apply (TextChange change) {
+ Span<char> tmp = stackalloc char[source.Length + (change.ChangedText.Length - change.Length)];
+ ReadOnlySpan<char> src = source.AsSpan ();
+ src.Slice (0, change.Start).CopyTo (tmp);
+ if (!string.IsNullOrEmpty(change.ChangedText))
+ change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
+ src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
+ disableTextChangedEvent = true;
+ Source = tmp.ToString ();
+ disableTextChangedEvent = false;
+ NotifyValueChanged ("IsDirty", IsDirty);
}
public string CurrentDir {
- get { return Configuration.Global.Get<string>("CurrentDir"); }
+ get => Configuration.Global.Get<string>("CurrentDir");
set {
if (CurrentDir == value)
return;
}
}
public string CurrentFilePath {
- get { return Configuration.Global.Get<string> ("CurrentFilePath"); }
+ get => Configuration.Global.Get<string> ("CurrentFilePath");
set {
if (CurrentFilePath == value)
return;
Configuration.Global.Set ("CurrentFilePath", value);
NotifyValueChanged (CurrentFilePath);
-
}
}
public string CurFileName {
public string CurFileDir {
get => string.IsNullOrEmpty (CurrentFilePath) ? CurrentDir : Path.GetDirectoryName (CurrentFilePath);
}
-
public bool ShowLeftPane {
- get { return Configuration.Global.Get<bool> ("ShowLeftPane"); }
+ get => Configuration.Global.Get<bool> ("ShowLeftPane");
set {
if (ShowLeftPane == value)
return;
NotifyValueChanged (ShowLeftPane);
}
}
+ public bool ReopenLastFile {
+ get => Configuration.Global.Get<bool> ("ReopenLastFile");
+ set {
+ if (ReopenLastFile == value)
+ return;
+ Configuration.Global.Set ("ReopenLastFile", value);
+ NotifyValueChanged (ReopenLastFile);
+ }
+ }
- void initCommands(){
+ void initCommands (){
CMDNew = new Command(new Action(() => onNewFile())) { Caption = "New", Icon = new SvgPicture("#CrowEdit.ui.icons.blank-file.svg")};
CMDOpen = new Command(new Action(() => openFileDialog())) { Caption = "Open...", Icon = new SvgPicture("#CrowEdit.ui.icons.outbox.svg")};
CMDSave = new Command(new Action(() => saveFileDialog())) { Caption = "Save", Icon = new SvgPicture("#CrowEdit.ui.icons.inbox.svg"), CanExecute = false};
mb.Yes += (sender, e) => newFile();
} else
newFile ();
- }
- void undo(){
- string step = undoStack [undoStack.Count -1];
- redoStack.Add (_text);
- CMDRedo.CanExecute = true;
- undoStack.RemoveAt(undoStack.Count -1);
-
- _text = step;
-
- NotifyValueChanged ("Text", (object)_text);
- NotifyValueChanged ("IsDirty", IsDirty);
-
- if (undoStack.Count == 0)
- CMDUndo.CanExecute = false;
- }
- void redo(){
- string step = redoStack [redoStack.Count -1];
- undoStack.Add (_text);
- CMDUndo.CanExecute = true;
- redoStack.RemoveAt(redoStack.Count -1);
- _text = step;
- NotifyValueChanged ("Text", (object)_text);
- NotifyValueChanged ("IsDirty", IsDirty);
-
- if (redoStack.Count == 0)
- CMDRedo.CanExecute = false;
- }
- void openOptionsDialog(){
- Widget ed = this.FindByName("editor");
- Load ("#CrowEdit.ui.EditorOptions.crow").DataSource = ed;
- }
- void openFileDialog(){
- Load ("#CrowEdit.ui.openFile.crow").DataSource = this;
- }
- void saveFileDialog(){
- Load ("#CrowEdit.ui.saveFile.crow").DataSource = this;
- }
+ }
+ void openOptionsDialog() => Load ("#CrowEdit.ui.EditorOptions.crow").DataSource = this;
+ void openFileDialog() => Load ("#CrowEdit.ui.openFile.crow").DataSource = this;
+ void saveFileDialog() => Load ("#CrowEdit.ui.saveFile.crow").DataSource = this;
void openFileDialog_OkClicked (object sender, EventArgs e)
{
FileDialog fd = sender as FileDialog;
void saveFileDialog_OkClicked (object sender, EventArgs e)
{
FileDialog fd = sender as FileDialog;
-
if (string.IsNullOrEmpty (fd.SelectedFile))
- return;
- CurrentFilePath = Path.Combine (fd.SelectedDirectory, fd.SelectedFile);
-
-// using (StreamWriter sr = new StreamWriter (fd.SelectedFile)) {
-// sr.Write(_text);
-// }
- _origText = _text;
-
- NotifyValueChanged ("IsDirty", false);
- }
+ return;
+ save (fd.SelectedFile, fd.SelectedDirectory);
+ }
void onTextChanged (object sender, TextChangeEventArgs e)
{
- //System.Diagnostics.Debug.WriteLine ("text changed");
- NotifyValueChanged ("IsDirty", IsDirty);
+ if (disableTextChangedEvent)
+ return;
+ undoStack.Push (e.Change.Inverse(source));
+ redoStack.Clear ();
+ CMDUndo.CanExecute = true;
+ CMDRedo.CanExecute = false;
+ apply (e.Change);
}
void goUpDirClick (object sender, MouseButtonEventArgs e) {
}
void newFile () {
CurrentFilePath = Path.Combine (CurFileDir, _defaultFileName);
- _origText = _text = "";
- NotifyValueChanged ("Text", (object)_text);
- NotifyValueChanged ("IsDirty", false);
- redoStack.Clear ();
- undoStack.Clear ();
- CMDRedo.CanExecute = false;
- CMDUndo.CanExecute = false;
+ disableTextChangedEvent = true;
+ Source = "";
+ disableTextChangedEvent = false;
+ resetUndoRedo ();
}
void openFile (string filePath, string directory) {
CurrentFilePath = Path.Combine(directory, filePath);
- //reloadFromFile ();
-
- redoStack.Clear ();
- undoStack.Clear ();
- CMDRedo.CanExecute = false;
- CMDUndo.CanExecute = false;
+ reloadFromFile ();
+ resetUndoRedo ();
}
- /***temp***/
- string source;
- public string Source {
- get => source;
- set {
- if (source == value)
- return;
- source = value;
- NotifyValueChanged (source);
+ void save (string filePath, string directory) {
+ CurrentFilePath = Path.Combine (directory, filePath);
+ using (StreamWriter sr = new StreamWriter (CurrentFilePath)) {
+ sr.Write (source);
}
+ dirtyUndoLevel = undoStack.Count;
+
+ NotifyValueChanged ("IsDirty", IsDirty);
}
+
void reloadFromFile () {
+ disableTextChangedEvent = true;
if (File.Exists (CurrentFilePath)) {
using (Stream s = new FileStream (CurrentFilePath, FileMode.Open)) {
using (StreamReader sr = new StreamReader (s))
Source = sr.ReadToEnd ();
}
}
+ disableTextChangedEvent = false;
+ resetUndoRedo ();
}
- /********************************/
- [STAThread]
+ void resetUndoRedo () {
+ undoStack.Clear ();
+ redoStack.Clear ();
+ CMDUndo.CanExecute = false;
+ CMDRedo.CanExecute = false;
+ dirtyUndoLevel = 0;
+ }
static void Main ()
{
using (CrowEdit win = new CrowEdit ())
win.Run ();
}
- public CrowEdit ()
- : base(800, 600)
- {}
+ public CrowEdit () : base(800, 600) {}
protected override void OnInitialized () {
base.OnInitialized ();
if (CurrentDir == null)
CurrentDir = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
-
- this.ValueChanged += CrowEdit_ValueChanged;
+
initCommands ();
Load ("#CrowEdit.ui.main.crow").DataSource = this;
- }
+ editor = FindByName ("tb") as TextBox;
- /*void textView_KeyDown (object sender, Crow.KeyEventArgs e)
- {
- if (e.Control) {
- if (e.Key == Key.W) {
- if (e.Shift)
- CMDRedo.Execute ();
- else
- CMDUndo.Execute ();
- }
- }
- }*/
+ if (ReopenLastFile)
+ reloadFromFile ();
+ }
+ TextBox editor;
+ void textView_KeyDown (object sender, Crow.KeyEventArgs e) {
+ if (Ctrl && e.Key == Glfw.Key.W) {
+ if (Shift)
+ CMDRedo.Execute ();
+ else
+ CMDUndo.Execute ();
- void CrowEdit_ValueChanged (object sender, ValueChangeEventArgs e)
- {
- if (e.MemberName == "IsDirty" && isDirty != (bool)e.NewValue) {
- isDirty = (bool)e.NewValue;
- if (isDirty) {
- CMDSave.CanExecute = true;
- CMDSaveAs.CanExecute = true;
- }else{
- CMDSave.CanExecute = false;
- CMDSaveAs.CanExecute = false;
- }
}
}
-
}
}
</VerticalStack>
<Splitter Width="6" Visible="{ShowLeftPane}"/>
<VerticalStack>
- <HorizontalStack Height="Stretched" >
- <!--<TextBox VerticalAlignment="Top" Height="Stretched" Width="Stretched"
- Text="{Source}" Multiline="true" TextAlignment="TopLeft"
- Font="mono 10"/>-->
+ <!--<HorizontalStack Height="Stretched" >
<SourceEditor Focusable="true" Name="editor" Font="consolas, 12" VerticalAlignment="Top" FilePath="{CurrentFilePath}"
Foreground="Jet" Background="White" Width="Stretched" Height="Stretched" KeyDown="textView_KeyDown"/>
<ScrollBar Name="scrollbarY" Value="{²../editor.ScrollY}"
<ScrollBar Style="HScrollBar" Name="scrollbarX" Value="{²../editor.ScrollX}"
Maximum="{../editor.MaxScrollX}" Height="14"
LargeIncrement="{../editor.VisibleColumns}"
- CursorSize="{../editor.ChildWidthRatio}"/>
+ CursorSize="{../editor.ChildWidthRatio}"/>-->
+ <HorizontalStack>
+ <TextBox Name="tb" Text="{Source}" Multiline="true" Font="consolas, 12" Focusable="true" Height="Stretched" Width="Stretched"
+ ContextCommands="{EditorCommands}"
+ TextChanged="onTextChanged" KeyDown="textView_KeyDown"/>
+ <ScrollBar Value="{²../tb.ScrollY}"
+ LargeIncrement="{../tb.PageHeight}" SmallIncrement="1"
+ CursorRatio="{../tb.ChildHeightRatio}" Maximum="{../tb.MaxScrollY}" />
+ </HorizontalStack>
+ <ScrollBar Style="HScrollBar" Value="{²../tb.ScrollX}"
+ LargeIncrement="{../tb.PageWidth}" SmallIncrement="1"
+ CursorRatio="{../tb.ChildWidthRatio}" Maximum="{../tb.MaxScrollX}" />
<HorizontalStack Height="Fit">
- <Label Text="{../../editor.HoverError}" Width="Stretched"/>
- <Widget Background="Red" Width="5" Height="5" Visible="{../../editor.IsDirty}"/>
- <Label Text="Hover Line:" Foreground="Black"/>
- <Label Text="{../../editor.HoverLine}"/>
- <Widget Height="5" Width="10"/>
- <Label Text="Line:" Foreground="Black"/>
- <Label Text="{../../editor.CurrentLine}"/>
- <Widget Height="5" Width="10"/>
- <Label Text="column:" Foreground="Black"/>
- <Label Text="{../../editor.CurrentColumn}"/>
+ <Widget Width="Stretched"/>
<Widget Height="5" Width="10"/>
- <Label Text="ScrollX:" Foreground="Black"/>
- <Label Text="{../../editor.ScrollX}"/>
+ <Label Text="Line:" Foreground="Grey"/>
+ <Label Text="{../../tb.CurrentLine}" Margin="3"/>
+ <Label Text="col:" Foreground="Grey"/>
+ <Label Text="{../../tb.CurrentColumn}" Margin="3"/>
</HorizontalStack>
</VerticalStack>
</HorizontalStack>