# Underline

## Name

Underline

## Category

Format

## Notation

- Markdown
- PukiWiki

## Shortcut

Ctrl+U

## Code

```pascal
var BB := Editor.BlockBegin;
var BE := Editor.BlockEnd;

procedure MarkdownUnderline;
const
  SymBegin = '<ins>';
  SymEnd = '</ins>';
begin
  // not select or select one line
  if BB.Y = BE.Y then
  begin
    var
      Selected = Editor.SelText <> '';
    Editor.SelText := SymBegin + Editor.SelText + SymEnd;
    if not Selected then
      Editor.CaretX := Editor.CaretX - Length(SymEnd);
    Exit;
  end;

  // select only line breaks
  if RegEx.IsMatch(Editor.SelText, '\A(\r\n)+\z', False, False) then
  begin
    Editor.MoveCaret(BB.Y, BB.X);
    Editor.Insert(SymBegin + SymEnd);
    Editor.CaretX := Editor.CaretX - Length(SymEnd);
    Exit;
  end;

  // select lines
  var
    BeginLine := BB.Y;
  var
    EndLine := BE.Y;

  if BB.X = (Length(Editor.GetLine(BB.Y)) + 1) then
    Inc(BeginLine);

  if (BE.X = 1) and (BeginLine < EndLine) then
    Dec(EndLine);

  // exclude empty line
  while (EndLine > BeginLine) and (Editor.GetLIne(BeginLine) = '') do
    Inc(BeginLine);

  // exclude empty line
  while (EndLine > BeginLine) and (Editor.GetLIne(EndLine) = '') do
    Dec(EndLine);

  if EndLine = BE.Y then
    Editor.MoveCaret(BE.Y, BE.X)
  else
    Editor.MoveCaret(EndLine, Length(Editor.GetLine(EndLine)) + 1);

  var
    EndLineLength := Length(Editor.GetLine(EndLine));
  Editor.Insert(SymEnd);

  if BeginLine = BB.Y then
    Editor.MoveCaret(BB.Y, BB.X)
  else
    Editor.MoveCaret(BeginLine, 1);

  Editor.Insert(SymBegin);

  var
    CurrentLine := BeginLine + 1;

  while CurrentLine < EndLine do
  begin
    if Editor.GetLine(CurrentLine) = '' then
    begin
      // paragraph end
      Editor.AppendTextAtLine(CurrentLine - 1, SymEnd);
      Inc(CurrentLine);
      while Editor.GetLine(CurrentLine) = '' do
        Inc(CurrentLine);
      // paragraph begin
      Editor.InsertTextAtLineStart(CurrentLine, SymBegin);
    end;
    Inc(CurrentLine);
  end;

  if BE.Y = EndLine then
    Editor.MoveCaret(BE.Y, BE.X + Length(Editor.GetLine(BE.Y)) - EndLineLength)
  else
    Editor.MoveCaret(BE.Y, BE.X);
end;


procedure PukiWikiUnderline;
const
  SymBegin = '%%%';
  SymEnd = '%%%';
begin
  // not select or select one line
  if BB.Y = BE.Y then
  begin
    var
      Selected = Editor.SelText <> '';
    Editor.SelText := SymBegin + Editor.SelText + SymEnd;
    if not Selected then
      Editor.CaretX := Editor.CaretX - Length(SymEnd);
    Exit;
  end;

  // select only line breaks
  if RegEx.IsMatch(Editor.SelText, '\A(\r\n)+\z', False, False) then
  begin
    Editor.MoveCaret(BB.Y, BB.X);
    Editor.Insert(SymBegin + SymEnd);
    Editor.CaretX := Editor.CaretX - Length(SymEnd);
    Exit;
  end;

  // select lines
  var
    BeginLine := BB.Y;
  var
    EndLine := BE.Y;

  if BB.X = (Length(Editor.GetLine(BB.Y)) + 1) then
    Inc(BeginLine);

  if (BE.X = 1) and (BeginLine < EndLine) then
    Dec(EndLine);

  // exclude empty line
  while (EndLine > BeginLine) and (Editor.GetLIne(BeginLine) = '') do
    Inc(BeginLine);

  // exclude empty line
  while (EndLine > BeginLine) and (Editor.GetLIne(EndLine) = '') do
    Dec(EndLine);

  if EndLine = BE.Y then
    Editor.MoveCaret(BE.Y, BE.X)
  else
    Editor.MoveCaret(EndLine, Length(Editor.GetLine(EndLine)) + 1);

  var
    EndLineLength := Length(Editor.GetLine(EndLine));
  Editor.Insert(SymEnd);

  if BeginLine = BB.Y then
    Editor.MoveCaret(BB.Y, BB.X)
  else
    Editor.MoveCaret(BeginLine, 1);

  Editor.Insert(SymBegin);

  for var I := BeginLine + 1 to EndLine do
  begin
    if Editor.GetLine(I) <> '' then
      Editor.InsertTextAtLineStart(I, SymBegin);
  end;

  for var I := BeginLine to EndLine - 1 do
  begin
    if Editor.GetLine(I) <> '' then
      Editor.AppendTextAtLine(I, SymEnd);
  end;

  if BE.Y = EndLine then
    Editor.MoveCaret(BE.Y, BE.X + Length(Editor.GetLine(BE.Y)) - EndLineLength)
  else
    Editor.MoveCaret(BE.Y, BE.X);
end;


Editor.BeginUndoBlock;
try
  case Editor.Notation of
    NotationMarkdown: 
      MarkdownUnderline;
    NotationPukiWiki: 
      PukiWikiUnderline;
  end;
finally
  Editor.EndUndoBlock;
end;
```
