using ScintillaNET; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using static ScintillaNET.Style; using VPKSoft.ScintillaLexers; using ScintillaNET_FindReplaceDialog.FindAllResults; using ScintillaNET_FindReplaceDialog; using System.Windows.Forms; using ryCommon; using static VPKSoft.ScintillaLexers.LexerEnumerations; using Newtonsoft.Json.Linq; using DiffPlex.Model; using IfacesEnumsStructsClasses; namespace ryControls { public partial class HighlightEditor : Control { public HighlightEditor() : base() { if(!this.DesignMode) { this.Controls.Add(Editor); Editor.Parent = this; Editor.Dock= DockStyle.Fill; } Editor.CaretLineBackColor = Color.FromArgb(255, 255, 192); Editor.AutoCAutoHide = true; Editor.TextChanged += Scintilla_TextChanged; Editor.ContextMenuStrip = contextMenuStripHighlightText21; Editor.CharAdded += HighlightEditor_CharAdded; Editor.UpdateUI += HighlightEditor_UpdateUI; Editor.EolMode = Eol.CrLf; //Editor.AdditionalCaretForeColor=Color.Red; //Editor //base.HandleCreated += HighlightEditor_HandleCreated; //base.InternalFocusFlag = true; MyFindReplace = new FindReplace { Scintilla = Editor }; AutoComplete.TargetControlWrapper = new ScintillaWrapper(Editor); Editor.DoubleClick += Editor_DoubleClick; var ind_17= Editor.Indicators[17]; ind_17.ForeColor = Color.FromArgb(232, 232, 255); ind_17.Alpha = 100; ind_17.Style = IndicatorStyle.RoundBox; ind_17.Under = true; _indicator = Editor.Indicators[16]; _indicator.ForeColor = Color.Red; //_indicator.ForeColor = Color.LawnGreen; //Smart highlight _indicator.Alpha = 100; _indicator.Style = IndicatorStyle.RoundBox; _indicator.Under = true; Editor.IndicatorCurrent = _indicator.Index; this.LostFocus += HighlightEditor_LostFocus; Editor.LostFocus += HighlightEditor_LostFocus; Editor.InternalFocusFlag = true; Editor.CaretLineBackColorAlpha = 60; Editor.CaretPeriod = 0; } private void HighlightEditor_LostFocus(object sender, EventArgs e) { //Editor.AdditionalCaretForeColor } #region 属性设置 /// <summary> /// 读取或设置只读模式 /// </summary> [Description("是否开启只读模式")] public bool ReadOnly { get { return Editor.ReadOnly; } set { Editor.ReadOnly = value; } } [DefaultValue(ScintillaNET.BorderStyle.Fixed3D)] [Category("Appearance")] [Description("编辑器边框.")] public ScintillaNET.BorderStyle BorderStyle { get { return Editor.BorderStyle; } set { Editor.BorderStyle = value; } } /// <summary> /// 是否开启行号 /// </summary> [Description("是否开启行号")] public bool LineNumberOn { get; set; } = true; /// <summary> /// 是否使用自定义搜索功能 /// </summary> [Description("是否使用自定义搜索功能")] public bool UseCustomShowFindReplace { get; set; } = false; /// <summary> /// 是否使用自定义定位行功能 /// </summary> [Description("是否使用自定义定位行功能")] public bool UseCustomGotoLine { get; set; } = false; /// <summary> /// 当前高亮语言 /// </summary> public LexerType CurHighliteLang { get; set; } = LexerType.Text; /// <summary> /// 获取或设置是否开启自动标记功能 /// </summary> [Description("开启自动标记功能")] public bool AutoMark { get; set; } = true; /// <summary> /// 获取或设置编辑器字体 /// </summary> [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [DefaultValue(typeof(Font), "Consolas, 14pt")] public override Font Font { get => base.Font; set { base.Font = value; Editor.Font = value; for (int i = 0; i < Editor.Styles.Count; i++) { if (i != CallTip) SetStyleFont(i, value); } } } /// <summary> /// Sets font style properties /// </summary> /// <param name="index"></param> /// <param name="font"></param> private void SetStyleFont(int index, Font font) { Editor.Styles[index].Font = font.Name; Editor.Styles[index].SizeF = font.SizeInPoints; Editor.Styles[index].Bold = font.Bold; Editor.Styles[index].Italic = font.Italic; Editor.Styles[index].Underline = font.Underline; } /// <summary> /// 获取或设置当前选中的文字 /// </summary> public string SelectedText { get { var text= Editor.SelectedText.TrimEnd('\0'); if (text == "\0") { text = ""; } return text; } set { Editor.ReplaceSelection(value); } } /// <summary> /// 设置或获取文本 /// </summary> public override string Text { get { return Editor.Text; } set { bool Readonly = Editor.ReadOnly; if (Readonly) { Editor.ReadOnly = false; } Editor.Text = value; if (Readonly) { Editor.ReadOnly = true; } } } #endregion #region 对外公开的事件 /// <summary> /// 在自带菜单弹出前激发 /// </summary> [Description("在自带菜单弹出前激发")] public event CancelEventHandler OnMenuOpening; /// <summary> /// 保存热键发生时 /// </summary> [Description("保存热键发生时")] public event EventHandler OnSaveKeyHappen; /// <summary> /// 打开自定义查找窗口时发生 /// </summary> [Description("打开自定义查找窗口时发生")] public event EventHandler OnCustomShowFind; /// <summary> /// 打开自定义替换窗口时发生 /// </summary> [Description("打开自定义替换窗口时发生")] public event EventHandler OnCustomShowReplace; /// <summary> /// 打开自定义定位行窗口时发生 /// </summary> [Description("打开自定义定位行窗口时发生")] public event EventHandler OnCustomShowGotoLine; /// <summary> /// 选定内容发生变化 /// </summary> [Description("选定内容发生变化")] public event EventHandler OnSelectedChanged; #endregion #region 内部事件方法 private void Editor_DoubleClick(object sender, DoubleClickEventArgs e) { base.OnDoubleClick(new EventArgs()); } private void ContextMenuStripRichText1_Opening(object sender, CancelEventArgs e) { OnMenuOpening?.Invoke(sender, e); } private string Indent(int len) { var str = ""; for (int i = 0; i < len; i++) { str += " "; } return str; } private string last_selected = ""; private void HighlightEditor_UpdateUI(object sender,UpdateUIEventArgs e) { if (e.Change != UpdateChange.Content) { var selected_text = SelectedText; var sel_start = Editor.SelectionStart; var sel_id= sel_start + "|" + selected_text.Length; if (sel_id != last_selected) { ClearAllMark(); last_selected = sel_id; if (AutoMark) { MarkText(selected_text); } OnSelectedChanged?.Invoke(this, EventArgs.Empty); } if (selected_text.Length == 0) { var a = Editor.BraceMatch(sel_start); if (a >= 0) { Editor.IndicatorCurrent = _indicator.Index; Editor.IndicatorFillRange(a, 1); Editor.IndicatorFillRange(sel_start, 1); } else { if (sel_start - 1 >= 0) { a = Editor.BraceMatch(sel_start - 1); if (a >= 0) { Editor.IndicatorCurrent = _indicator.Index; Editor.IndicatorFillRange(a, 1); Editor.IndicatorFillRange(sel_start - 1, 1); } } } } var pos = Editor.CurrentPosition; var line = Editor.LineFromPosition(pos); Editor.IndicatorCurrent = 17; Editor.IndicatorFillRange(Editor.Lines[line].Position, Editor.Lines[line].Length); } if (LastProcessedChar != 0) { var pos = Editor.CurrentPosition; var line = Editor.LineFromPosition(pos); if (line >= 1) { if (LastProcessedChar == 10) { //Editor.Lines[line].Indentation = Editor.Lines[line - 1].Indentation; var nPrevLineText = Editor.Lines[line - 1].Text.Trim();//获取上一行文本 if (nPrevLineText.Length >= 1) { if ("{(<[".IndexOfEx(nPrevLineText.Substring(nPrevLineText.Length - 1, 1)) >= 0) { if (Editor.Lines[line].Text.Trim().StartsWith("}")) { Editor.ReplaceSelection(Indent(Editor.Lines[line - 1].Indentation)); } else { Editor.ReplaceSelection(Indent(Editor.Lines[line - 1].Indentation + 4)); } } else { Editor.ReplaceSelection(Indent(Editor.Lines[line - 1].Indentation)); } } else { for (int i = line - 2; i >0; i--) { nPrevLineText = Editor.Lines[i].Text.Trim(); if (nPrevLineText.Length >= 1) { if ("{(<[".IndexOfEx(nPrevLineText.Substring(nPrevLineText.Length - 1, 1)) >= 0) { if (Editor.Lines[line].Text.Trim().StartsWith("}")) { Editor.ReplaceSelection(Indent(Editor.Lines[i].Indentation)); } else { Editor.ReplaceSelection(Indent(Editor.Lines[i].Indentation + 4)); } } else { Editor.ReplaceSelection(Indent(Editor.Lines[i].Indentation)); } break; } } } } } LastProcessedChar = 0; // if(LastProcessedChar=='}' && this.GetCharAt(pos-2)==' ' && LastProcessedChar!=0) //{ // var startpos = this.WordStartPosition(pos - 1, false); // var linepos = this.Lines[line].Indentation; // if(startpos== linepos) // { // var othpos = this.BraceMatch(pos - 1); // var othline = this.LineFromPosition(othpos); // int nIndent = this.Lines[othline].Indentation; // this.TargetStart = startpos; // this.TargetEnd = pos - 1; // this.ReplaceTarget("xxxxxxx"); // } //} } } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData == (Keys.Control | Keys.S)) { OnSaveKeyHappen?.Invoke(this, new EventArgs()); return true; } else if (keyData == (Keys.Control | Keys.F)) { ShowFind(); return true; } else if (keyData == (Keys.Control | Keys.B)) { return true; } else if (keyData == (Keys.Control | Keys.M)) { return true; } else if (keyData == (Keys.Control | Keys.N)) { return true; } else if (keyData == (Keys.Control | Keys.J)) { return true; } else if (keyData == (Keys.Control | Keys.Q)) { return true; } else if (keyData == (Keys.Control | Keys.U)) { return true; } else if (keyData == (Keys.Control | Keys.I)) { return true; } else if (keyData == (Keys.Control | Keys.P)) { return true; } else if (keyData == (Keys.Control | Keys.W)) { return true; } else if (keyData == (Keys.Control | Keys.E)) { return true; } return base.ProcessCmdKey(ref msg, keyData);//这里就是返回没有重写的键位,也就是这个函数原本的处理方式 //其余键位默认处理 } private void HighlightEditor_CharAdded(object sender, CharAddedEventArgs e) { LastProcessedChar = e.Char; } private void Scintilla_TextChanged(object sender, EventArgs e) { base.OnTextChanged(new EventArgs()); if (LineNumberOn) { Scintilla scintilla = (Scintilla)sender; int maxLineNumberCharLengthFromTag = mark; // Did the number of characters in the line number display change? // i.e. nnn VS nn, or nnnn VS nn, etc... var maxLineNumberCharLength = scintilla.Lines.Count.ToString().Length; if (maxLineNumberCharLength == maxLineNumberCharLengthFromTag) return; // Calculate the width required to display the last line number // and include some padding for good measure. const int padding = 2; scintilla.Margins[0].Width = scintilla.TextWidth(ScintillaNET.Style.LineNumber, new string('9', maxLineNumberCharLength + 1)) + padding; mark = maxLineNumberCharLength; } } /// <summary> /// 判断改行为函数开头行 /// </summary> /// <param name="line"></param> /// <returns></returns> private bool IsFunLine(string line) { if (line.StartsWith("public", StringComparison.OrdinalIgnoreCase) || line.StartsWith("private", StringComparison.OrdinalIgnoreCase) || line.StartsWith("protected", StringComparison.OrdinalIgnoreCase) || line.StartsWith("const", StringComparison.OrdinalIgnoreCase)) { return true; } else { if (line.IndexOfEx("(") > 0 && line.IndexOfEx(")") > 0 && line.IndexOfEx("function")>=0) { return true; } } return false; } #endregion #region 对方公开方法或函数 public void FindText(string FindText) { Editor.TargetStart = 0; Editor.TargetEnd = Editor.TextLength; var pos = Editor.SearchInTarget(FindText); if (pos >= 0) { Editor.FirstVisibleLine = Editor.LineFromPosition(pos); } } /// <summary> /// 获取最近的函数名称所在行内容 /// </summary> /// <param name="high_editor"></param> /// <param name="fun_line_num"></param> /// <returns></returns> public string GetNearestFunLineStr(HighlightEditor high_editor,out int fun_line_num) { var line_num = high_editor.Editor.LineFromPosition(high_editor.Editor.CurrentPosition == 0 ? high_editor.Editor.FirstVisibleLine : high_editor.Editor.CurrentPosition); var lines = high_editor.Editor.Lines; var pre_fun_line = ""; var pre_fun_line_num = -1; var next_fun_line = ""; var next_fun_line_num = -1; string fun_line; for (int i = line_num; i >= 0; i--) { var line = lines[i].Text.Trim(); if (IsFunLine(line)) { pre_fun_line = line; pre_fun_line_num = i; break; } } if (pre_fun_line_num == -1 || (line_num - pre_fun_line_num) > 3) { for (int i = line_num + 1; i < lines.Count; i++) { var line = lines[i].Text.Trim(); if (IsFunLine(line)) { next_fun_line = line; next_fun_line_num = i; break; } } } if (next_fun_line_num == -1) { fun_line = pre_fun_line; fun_line_num = pre_fun_line_num; } else if (pre_fun_line_num == -1) { fun_line = next_fun_line; fun_line_num = next_fun_line_num; } else if ((line_num - pre_fun_line_num) > (next_fun_line_num - line_num)) { fun_line = next_fun_line; fun_line_num = next_fun_line_num; } else { fun_line = pre_fun_line; fun_line_num = pre_fun_line_num; } return fun_line; } /// <summary> /// 到达与指定编辑器同样的位置 /// </summary> /// <param name="high_editor"></param> public int GotoSameLocation(HighlightEditor high_editor) { if (high_editor.Editor.CurrentPosition == 0 && high_editor.Editor.FirstVisibleLine==0) { return 0; } var result = 0; var line_num=high_editor.Editor.LineFromPosition(high_editor.Editor.CurrentPosition==0? high_editor.Editor.FirstVisibleLine: high_editor.Editor.CurrentPosition); var lines = high_editor.Editor.Lines; string fun_line= GetNearestFunLineStr(high_editor,out var fun_line_num); if (fun_line_num >= 0) { Editor.TargetStart = 0; Editor.TargetEnd = Editor.TextLength; var pos= Editor.SearchInTarget(fun_line); if(pos>=0) { Editor.FirstVisibleLine = Editor.LineFromPosition(pos); result = Editor.FirstVisibleLine; } else { var str = fun_line.GetStr("", "("); if(str.Length>0) { pos = Editor.SearchInTarget(str); if (pos >= 0) { Editor.FirstVisibleLine = Editor.LineFromPosition(pos); result = Editor.FirstVisibleLine; } } } } return result; //var kk = Editor.Lines.FirstOrDefault(f => f.Text == high_editor.Editor.Lines[line_num].Text); } /// <summary> /// 标记文本 /// </summary> /// <param name="search_text"></param> public void MarkText(string search_text) { if (search_text.Length == 0) { ClearAllMark(); return; } if (search_text.IndexOfEx("\n") >= 0 || !search_text.Replace("_","").IsEngOrNum()) { ClearAllMark(); if (search_text.Length == 1) { var a= Editor.BraceMatch(Editor.SelectionStart); if (a >= 0) { Editor.IndicatorCurrent = _indicator.Index; Editor.IndicatorFillRange(a, 1); Editor.IndicatorFillRange(Editor.SelectionStart, 1); } return; } return; } var find_count = 0; //Editor.IndicatorCurrent = _indicator.Index; var _text = Editor.Text; var search_len = search_text.Length; var total_len = _text.Length; var pos = _text.IndexOf(search_text); while (pos != -1) { if (pos > 0 && pos < total_len - 1) { var word = _text.Substring(pos - 1, 1)[0]; if ((word >= 'a' && word <= 'z') || (word >= 'A' && word <= 'Z') || (word >= '0' && word <= '9') || word=='_') { //是数字字母不处理 pos = _text.IndexOf(search_text, pos + search_len); continue; } if ((pos + search_len) <= total_len - 1) { word = _text.Substring(pos + search_len, 1)[0]; if ((word >= 'a' && word <= 'z') || (word >= 'A' && word <= 'Z') || (word >= '0' && word <= '9') || word == '_') { //是数字字母不处理 pos = _text.IndexOf(search_text, pos + search_len); continue; } } } find_count++; Editor.IndicatorCurrent = _indicator.Index; Editor.IndicatorFillRange(pos, search_len); pos = _text.IndexOf(search_text, pos + search_len); } if (find_count == 1) { ClearAllMark(); return; } } /// <summary> /// 清除所有标记 /// </summary> public void ClearAllMark() { int currentIndicator = Editor.IndicatorCurrent; Editor.IndicatorCurrent = 17; Editor.IndicatorClearRange(0, Editor.TextLength); Editor.IndicatorCurrent = _indicator.Index; Editor.IndicatorClearRange(0, Editor.TextLength); Editor.IndicatorCurrent = currentIndicator; } /// <summary> /// 设置高亮文本 /// </summary> /// <param name="format"></param> public void SetHightlightText(string format) { SetHightlightText(this.Text, format); } /// <summary> /// 设置高亮文本 /// </summary> /// <param name="text"></param> /// <param name="format"></param> public void SetHightlightText(string text, string format) { bool Readonly = Editor.ReadOnly; if (Readonly) { Editor.ReadOnly = false; } Editor.Text = text; var _formart = format; if (_formart == "c#") { _formart = "cs"; } try { var LexerType = VPKSoft.ScintillaLexers.HelperClasses.LexerFileExtensions.LexerTypeFromFileName(@"1." + _formart); CurHighliteLang = LexerType; ScintillaLexers.CreateLexer(Editor, LexerType); } catch { CurHighliteLang = LexerType.Unknown; } if (Readonly) { Editor.ReadOnly = true; } Editor.Font = this.Font; for (int i = 0; i < Editor.Styles.Count; i++) { if (i != CallTip) SetStyleFont(i, this.Font); } } /// <summary> /// 设置文本 /// </summary> /// <param name="text"></param> /// <param name="format"></param> public void SetText(string text) { bool Readonly = Editor.ReadOnly; if (Readonly) { Editor.ReadOnly = false; } Editor.Text = text; if (Readonly) { Editor.ReadOnly = true; } } /// <summary> /// 显示查找对话框 /// </summary> public void ShowFind() { if (UseCustomShowFindReplace) { OnCustomShowFind?.Invoke(this, new EventArgs()); } else { MyFindReplace.ShowFind(); } } /// <summary> /// 显示替换对话框 /// </summary> public void ShowReplace() { if (UseCustomShowFindReplace) { OnCustomShowReplace?.Invoke(this, new EventArgs()); } else { MyFindReplace.ShowFind(1); } } /// <summary> /// 显示行定位对话框 /// </summary> public void ShowGotoLine() { if (UseCustomGotoLine) { OnCustomShowGotoLine?.Invoke(this, new EventArgs()); } else { GoTo MyGoTo = new GoTo(Editor); MyGoTo.ShowGoToDialog(); } } /// <summary> /// 根据标签获得菜单项 /// </summary> /// <param name="tag"></param> /// <returns></returns> public ToolStripItem GetMenuItem(string tag) { for (int i = 0; i < contextMenuStripHighlightText21.Items.Count; i++) { var item = contextMenuStripHighlightText21.Items[i]; if (item.Tag == null) { continue; } if (tag == item.Tag.ToString()) { return item; } } return null; } /// <summary> /// 设置自动完成列表 /// </summary> /// <param name="list"></param> public void SetAutoCompleteList(List<string> list) { AutoComplete.SetAutocompleteItems(list); } /// <summary> /// 添加菜单分隔线 /// </summary> /// <returns></returns> public ToolStripSeparator AddSeparatorMenu() { return contextMenuStripHighlightText21.AddSeparatorMenu(); } /// <summary> /// 添加菜单 /// </summary> /// <param name="name"></param> /// <param name="tag"></param> /// <returns></returns> public ToolStripMenuItem AddMenu(string name, string tag) { return contextMenuStripHighlightText21.AddMenu(name, tag); } #endregion #region 声明变量 int mark = -1; private string lastSelectedText = ""; private int LastProcessedChar; private Indicator _indicator; public override ContextMenuStrip ContextMenuStrip { get => Editor.ContextMenuStrip; set => Editor.ContextMenuStrip = value; } private readonly FindReplace MyFindReplace; public ScintillaNET.Scintilla Editor { get; set; } = new Scintilla(); private readonly AutocompleteMenuNS.AutocompleteMenu AutoComplete = new AutocompleteMenuNS.AutocompleteMenu(); private readonly ryControls.ContextMenuStripHighlightText2 contextMenuStripHighlightText21 = new ContextMenuStripHighlightText2(); #endregion } }