Skip to content

Commit

Permalink
Merge pull request #120 from ahmetsait/change-history
Browse files Browse the repository at this point in the history
Fix #105: Implement change history
  • Loading branch information
desjarlais authored May 9, 2024
2 parents c810827 + 34dcd51 commit 14353a7
Show file tree
Hide file tree
Showing 13 changed files with 399 additions and 24 deletions.
7 changes: 7 additions & 0 deletions Scintilla.NET.TestApp/FormMain.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 54 additions & 4 deletions Scintilla.NET.TestApp/FormMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,38 @@ namespace ScintillaNET.TestApp;

public partial class FormMain : Form
{
string baseTitle;
string? currentFileName = null;

public string? CurrentFileName
{
get => this.currentFileName;
set
{
BaseTitle = Path.GetFileName(this.currentFileName = value);
}
}

public string BaseTitle
{
get => this.baseTitle;
set
{
this.Text = (this.baseTitle = value) + (scintilla.Modified ? " *" : "");
}
}

public FormMain()
{
InitializeComponent();

baseTitle = this.Text;

scintilla.LexerName = "cpp";

SetScintillaStyles(scintilla);
AdjustLineNumberMargin(scintilla);
AdjustMarkerMargin(scintilla);
AdjustFoldMargin(scintilla);

Version scintillaNetVersion = scintilla.GetType().Assembly.GetName().Version;
Expand Down Expand Up @@ -119,6 +143,16 @@ private static void AdjustLineNumberMargin(Scintilla scintilla)
maxLineNumberCharLengthMap[scintilla] = maxLineNumberCharLength;
}

private static void AdjustMarkerMargin(Scintilla scintilla)
{
scintilla.Margins[1].Width = 16;
scintilla.Margins[1].Sensitive = false;
//scintilla.Markers[Marker.HistoryRevertedToModified].SetForeColor(Color.Orange);
//scintilla.Markers[Marker.HistoryRevertedToModified].SetBackColor(scintilla.Margins[1].BackColor);
//scintilla.Markers[Marker.HistoryRevertedToOrigin].SetForeColor(Color.Orange);
//scintilla.Markers[Marker.HistoryRevertedToOrigin].SetBackColor(scintilla.Margins[1].BackColor);
}

private static void AdjustFoldMargin(Scintilla scintilla)
{
// Instruct the lexer to calculate folding
Expand Down Expand Up @@ -147,22 +181,28 @@ private static void AdjustFoldMargin(Scintilla scintilla)
scintilla.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner;

// Enable automatic folding
scintilla.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change);
scintilla.AutomaticFold = AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change;
}

private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
scintilla.Text = File.ReadAllText(openFileDialog.FileName, Encoding.UTF8);
CurrentFileName = openFileDialog.FileName;
scintilla.Text = File.ReadAllText(CurrentFileName, Encoding.UTF8);
scintilla.ClearChangeHistory();
scintilla.SetSavePoint();
}
}

private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
if (CurrentFileName is null && saveFileDialog.ShowDialog(this) == DialogResult.OK)
CurrentFileName = saveFileDialog.FileName;

if (CurrentFileName is not null)
{
File.WriteAllText(saveFileDialog.FileName, scintilla.Text, Encoding.UTF8);
File.WriteAllText(CurrentFileName, scintilla.Text, Encoding.UTF8);
scintilla.SetSavePoint();
}
}
Expand Down Expand Up @@ -195,4 +235,14 @@ private void scintilla_TextChanged(object sender, EventArgs e)
{
AdjustLineNumberMargin(scintilla);
}

private void scintilla_SavePointLeft(object sender, EventArgs e)
{
Text = BaseTitle + " *";
}

private void scintilla_SavePointReached(object sender, EventArgs e)
{
Text = BaseTitle;
}
}
1 change: 1 addition & 0 deletions Scintilla.NET.TestApp/Scintilla.NET.TestApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
<ApplicationManifest>app.manifest</ApplicationManifest>
<RootNamespace>ScintillaNET.TestApp</RootNamespace>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Update="FormMain.cs">
Expand Down
34 changes: 34 additions & 0 deletions Scintilla.NET/ChangeHistory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ScintillaNET;

/// <summary>
/// Bit-flags for whether Scintilla should keep track of document change history and in which ways it should display the difference.
/// </summary>
[Flags]
public enum ChangeHistory : int
{
/// <summary>
/// The default: change history turned off.
/// </summary>
Disabled = NativeMethods.SC_CHANGE_HISTORY_DISABLED,

/// <summary>
/// Track changes to the document.
/// </summary>
Enabled = NativeMethods.SC_CHANGE_HISTORY_ENABLED,

/// <summary>
/// Display changes in the margin using the SC_MARKNUM_HISTORY markers.
/// </summary>
Markers = NativeMethods.SC_CHANGE_HISTORY_MARKERS,

/// <summary>
/// Display changes in the text using the INDICATOR_HISTORY indicators.
/// </summary>
Indicators = NativeMethods.SC_CHANGE_HISTORY_INDICATORS,
}
161 changes: 161 additions & 0 deletions Scintilla.NET/FlagsEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace ScintillaNET;

internal class FlagsConverter<T> : TypeConverter where T : struct, Enum
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
}

public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is Enum e && destinationType == typeof(string))
{
if (Convert.ToUInt64(e) == 0)
{
return Enum.ToObject(e.GetType(), 0).ToString();
}
StringBuilder sb = new StringBuilder();
foreach (Enum item in Enum.GetValues(e.GetType()))
{
if (Convert.ToUInt64(item) != 0 && e.HasFlag(item))
{
if (sb.Length > 0)
sb.Append(" | ");
sb.Append(item);
}
}
return sb.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
Type t = typeof(T);
ulong bits = 0;
var nameList = str.Split('|').Select(x => x.Trim());
foreach (var name in nameList)
{
if (Enum.TryParse(name, out T bit))
bits |= Convert.ToUInt64(bit);
else
throw new InvalidCastException($"Cannot convert \"{str.Replace("\"", "\\\"")}\" to {t}.");
}
return Enum.ToObject(t, bits);
}
return base.ConvertFrom(context, culture, value);
}
}

internal class FlagsEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) => UITypeEditorEditStyle.DropDown;

public override bool IsDropDownResizable => true;

private int inCheck = 0;

private static ulong CombineEnumList(IEnumerable checkedList)
{
ulong bits = 0;
foreach (var item in checkedList)
{
bits |= Convert.ToUInt64(item);
}
return bits;
}

public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (value is Enum e && context.PropertyDescriptor.Attributes.OfType<FlagsAttribute>().Any())
{
IWindowsFormsEditorService svc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
Type enumType = e.GetType();

CheckedListBox checkedListBox = new() {
Dock = DockStyle.Fill,
CheckOnClick = true,
};
checkedListBox.ItemCheck += (object sender, ItemCheckEventArgs e) => {
if (inCheck > 0)
return;
inCheck++;
try
{
ulong bits = CombineEnumList(checkedListBox.CheckedItems);
ulong change = Convert.ToUInt64(checkedListBox.Items[e.Index]);
if (e.NewValue == CheckState.Checked)
bits |= change;
else if (e.NewValue == CheckState.Unchecked)
bits &= ~change;
Enum enumFinal = (Enum)Enum.ToObject(enumType, bits);
for (int i = 0; i < checkedListBox.Items.Count; i++)
{
Enum itemValue = (Enum)checkedListBox.Items[i];
checkedListBox.SetItemChecked(i, enumFinal.HasFlag(itemValue));
}
}
finally
{
inCheck--;
}
};
inCheck++;
try
{
foreach (Enum item in Enum.GetValues(enumType))
{
if (Convert.ToUInt64(item) != 0)
checkedListBox.Items.Add(item, e.HasFlag(item));
}
}
finally
{
inCheck--;
}
Button okBtton = new() {
Dock = DockStyle.Bottom,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
UseVisualStyleBackColor = true,
};
UserControl userControl = new();
userControl.Controls.Add(checkedListBox);
userControl.Controls.Add(okBtton);
okBtton.Text = NativeMethods.GetMessageBoxString(0); // OK
okBtton.Click += (object sender, EventArgs e) => {
ulong bits = 0;
foreach (Enum item in checkedListBox.CheckedItems)
{
bits |= Convert.ToUInt64(item);
}
value = Enum.ToObject(enumType, bits);
svc.CloseDropDown();
};
svc.DropDownControl(userControl);
return value;
}
else
return base.EditValue(context, provider, value);
}
}
4 changes: 2 additions & 2 deletions Scintilla.NET/IndicatorCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public int Count
{
get
{
return (NativeMethods.INDIC_MAX + 1);
return NativeMethods.INDICATOR_MAX + 1;
}
}

Expand Down Expand Up @@ -71,4 +71,4 @@ public IndicatorCollection(Scintilla scintilla)
{
this.scintilla = scintilla;
}
}
}
30 changes: 20 additions & 10 deletions Scintilla.NET/IndicatorStyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public enum IndicatorStyle
/// </summary>
DotBox = NativeMethods.INDIC_DOTBOX,

/// <summary>
/// A version of Squiggle that draws using a pixmap instead of as a series of line segments for performance.
/// </summary>
SquigglePixmap = NativeMethods.INDIC_SQUIGGLEPIXMAP,

// PIXMAP

/// <summary>
Expand Down Expand Up @@ -104,15 +109,20 @@ public enum IndicatorStyle
/// <summary>
/// A triangle below the center of the first character of the indicator range.
/// </summary>
PointCharacter = NativeMethods.INDIC_POINTCHARACTER /*,
PointCharacter = NativeMethods.INDIC_POINTCHARACTER,

/// <summary>
/// A vertical gradient between a color and alpha at top to fully transparent at bottom.
/// </summary>
Gradient = NativeMethods.INDIC_GRADIENT,

/// <summary>
/// A vertical gradient between a color and alpha at top to fully transparent at bottom.
/// </summary>
Gradient = NativeMethods.INDIC_GRADIENT,
/// <summary>
/// A vertical gradient with color and alpha in the mid-line fading to fully transparent at top and bottom.
/// </summary>
GradientCenter = NativeMethods.INDIC_GRADIENTCENTRE,

/// <summary>
/// A vertical gradient with color and alpha in the mid-line fading to fully transparent at top and bottom.
/// </summary>
GradientCenter = NativeMethods.INDIC_GRADIENTCENTRE */
}
/// <summary>
/// A triangle above the start of the indicator range.
/// </summary>
PointTop = NativeMethods.INDIC_POINT_TOP,
}
Loading

0 comments on commit 14353a7

Please sign in to comment.