using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ICSharpCode.TextEditor.Document; using ICSharpCode.TextEditor; using System.Text.RegularExpressions; namespace VisualPascalABC { public partial class Form1 { string Spaces(int n) => new string(' ', n); string GetLine(int lineNum) { var ta = CurrentCodeFileDocument.TextEditor.ActiveTextAreaControl.TextArea; var doc = ta.Document; if (lineNum < doc.TotalNumberOfLines) return TextUtilities.GetLineAsString(doc, lineNum); else return null; } void GetCurNextLines(out string Current, out string Next, out string Prev) // Next - следующая непустая строка { var ta = CurrentCodeFileDocument.TextEditor.ActiveTextAreaControl.TextArea; Current = GetLine(ta.Caret.Line); var i = ta.Caret.Line + 1; do { Next = GetLine(i); i++; } while (Next != null && Next.Trim() == ""); Prev = null; if (ta.Caret.Line == 0) return; var j = ta.Caret.Line; do { j--; Prev = GetLine(j); } while (j > 0 && Prev.Trim() == ""); if (Prev.Trim() == "") Prev = null; } int Indent(string s) { return Array.FindIndex(s.ToCharArray(), c => c != ' '); } int CurrentOffset() { var editor = VisualPascalABCProgram.MainForm.CurrentCodeFileDocument.TextEditor; var ta = editor.ActiveTextAreaControl.TextArea; var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); return editor.ActiveTextAreaControl.TextArea.Document.PositionToOffset(tl_beg); } private bool TextArea_KeyEventHandler(char ch) { if (!tsAutoInsertCode.Checked) return false; try { var editor = VisualPascalABCProgram.MainForm.CurrentCodeFileDocument.TextEditor; var ta = editor.ActiveTextAreaControl.TextArea; var doc = ta.Document; /*if (ch == ' ') { var caret1 = editor.ActiveTextAreaControl.Caret; int start1 = TextUtilities.FindPrevWordStart(editor.Document, caret1.Offset); var Text1 = editor.Document.GetText(start1, caret1.Offset - start1).TrimEnd(); if (Text1.ToLower().StartsWith("for") || Text1.ToLower().StartsWith("foreach")) { var curline = TextUtilities.GetLineAsString(editor.Document, caret1.Line); var len = curline.TrimEnd().Length; if (ta.Caret.Column == len) { doc.Replace(CurrentOffset(), curline.Length - len, " var"); ta.Caret.Column = ta.Caret.Column + 4; } } return false; }*/ /*if (ch == '(') { var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); doc.Insert(offset, ")"); return false; }*/ if (ch != '\n') return false; var caret = editor.ActiveTextAreaControl.Caret; int start = TextUtilities.FindPrevWordStart(editor.Document, caret.Offset); // Нужно, чтобы в Text было последнее слово в строке !!! Исключение - когда в следующей надо сделать просто сдвиг var Text = editor.Document.GetText(start, caret.Offset - start).TrimEnd(); //var curStrEnd = TextUtilities.GetLineAsString(editor.Document, caret.Line).Substring(caret.Column); if (Text.ToLower() == "begin") { string cur, next, prev; GetCurNextLines(out cur, out next, out prev); // Ничего не надо делать если begin - не последнее слово в строке var curStrEnd = cur.Substring(caret.Column); if (!string.IsNullOrWhiteSpace(curStrEnd)) return false; // анализ предыдущей var icur = Indent(cur); if (cur.Trim().ToLower() == "begin" && (next == null || Indent(next) < icur || Indent(next) == icur && !next.TrimStart().ToLower().StartsWith("end"))) // значит, это единственное слово begin в строке { // Проанализируем предыдущий оператор по первому слову var pst = prev?.TrimStart().ToLower(); if (pst != null) if (pst.StartsWith("if") || pst.StartsWith("for") || pst.StartsWith("loop") || pst.StartsWith("with") || pst.StartsWith("on") || pst.StartsWith("while") || pst.StartsWith("else") || pst.StartsWith("foreach")) // потом улучшу - для нескольких выборов { // Надо удалить в текущей строке пробелы чтобы выровнять begin по if var iprev = Indent(prev); var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); var cls = doc.GetLineSegment(ta.Caret.Line); // надо удалить всю строчку с begin и сформировать новую doc.Replace(cls.Offset, cls.Length , Spaces(iprev)+"begin"); ta.Caret.Column = iprev + 5; icur = iprev; } } ta.InsertString("\n" + Spaces(icur + 2)); if (next == null || Indent(next) < icur || Indent(next) == icur && !next.TrimStart().ToLower().StartsWith("end")) { var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); var send = "\n" + Spaces(icur) + "end"; if (next == null && (prev == null || !(prev.TrimStart().ToLower().StartsWith("procedure") || prev.TrimStart().ToLower().StartsWith("function")))) send += "."; else send += ";"; doc.Insert(offset, send); } return true; } else if (Text.ToLower() == "repeat") // repeat .. until { string cur, next, prev; GetCurNextLines(out cur, out next, out prev); if (!string.IsNullOrWhiteSpace(cur.Substring(caret.Column))) return false; var icur = Indent(cur); ta.InsertString("\n" + Spaces(icur + 2)); if (next == null || Indent(next) < icur || Indent(next) == icur && !next.TrimStart().ToLower().StartsWith("until")) { var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); var send = "\n" + Spaces(icur) + "until ;"; doc.Insert(offset, send); } return true; } else if (Text.ToLower() == "class" || Text.ToLower() == "record") // class .. end, record .. end { string cur, next, prev; GetCurNextLines(out cur, out next, out prev); if (!string.IsNullOrWhiteSpace(cur.Substring(caret.Column))) return false; var icur = Indent(cur); ta.InsertString("\n" + Spaces(icur + 2)); if (next == null || Indent(next) < icur || Indent(next) == icur && !next.TrimStart().ToLower().StartsWith("until")) { var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); var send = "\n" + Spaces(icur) + "end;"; doc.Insert(offset, send); } return true; } else if (Text.ToLower() == "of") { string cur, next, prev; GetCurNextLines(out cur, out next, out prev); if (!string.IsNullOrWhiteSpace(cur.Substring(caret.Column))) return false; var icur = Indent(cur); ta.InsertString("\n" + Spaces(icur + 2)); if (cur.TrimStart().ToLower().StartsWith("case") && next == null || Indent(next) < icur || Indent(next) == icur && !next.TrimStart().ToLower().StartsWith("end")) { var tl_beg = new TextLocation(ta.Caret.Column, ta.Caret.Line); int offset = doc.PositionToOffset(tl_beg); var send = "\n" + Spaces(icur) + "end;"; doc.Insert(offset, send); } return true; } else if (Text.ToLower() == "then" || Text.ToLower() == "else" || Text.ToLower() == "do" || Text.ToLower() == "try" || Text.ToLower() == "except" || Text.ToLower() == "finally" || Text.ToLower() == "var") { var cur = GetLine(ta.Caret.Line); var icur = Indent(cur); ta.InsertString("\n" + Spaces(icur + 2)); return true; } else { string cur, next, prev; GetCurNextLines(out cur, out next, out prev); if (ta.Caret.Column >= cur.Length) { // если prev заканчивается на then, а cur не начинается с begin, то отступ назад if ((prev.TrimEnd().EndsWith("then",StringComparison.InvariantCultureIgnoreCase) || prev.TrimEnd().EndsWith("else", StringComparison.InvariantCultureIgnoreCase) || prev.TrimEnd().EndsWith("do", StringComparison.InvariantCultureIgnoreCase)) && !(cur.TrimStart().StartsWith("begin", StringComparison.InvariantCultureIgnoreCase))) { var iprev = Indent(prev); ta.InsertString("\n" + Spaces(iprev)); return true; } /* if (Regex.IsMatch(curline, @"^\s*\w+\s*:=", RegexOptions.IgnoreCase)) // пока тут добавление ; после присваивания. Плохо перед else! И плохо если выражение продолжается на следующей строке! Убираем. { if (curline.Length > 0) { var last = curline[curline.Length - 1]; if (!char.IsLetterOrDigit(last) && last != ']' && last != ')') return false; } var curlinenew = Regex.Replace(curline, @"(\s*)(\S+)(\s*):=(\s*)([^;]+)(\s*)(;?)$", @"$1$2 := $5;", RegexOptions.IgnoreCase); while (curlinenew.EndsWith(";;")) curlinenew = curlinenew.Remove(curlinenew.Length - 1); doc.Replace(seg.Offset, curline.Length, curlinenew); ta.Caret.Column = curlinenew.Length; return false; } */ } } return false; } catch (Exception e) { } return false; } } }