Jump to content
Sign in to follow this  
Attila Kovacs

Moving Line or Block in the IDE editor

Recommended Posts

Yesterday I had the feeling I'm missing this feature from the IDE, today I can't remember why, maybe I'll recall it later 🙂

 

 

 

 

And my rough implementation of the feature:

 

Comments, patches, etc. are welcome.

( f.e. I'm completely ignoring the top and the bottom of the file, and other line endings as 0D 0A, also not sure about utf-8 in the code)

Blocks are moving on the basis of the starting and ending line. This is intended.

 

procedure TKeyboardBinding.BindKeyboard(const BindingServices: IOTAKeyBindingServices);
begin
  BindingServices.AddKeyBinding([ShortCut(VK_UP, [ssAlt])], MoveLineOrBlockUp, nil);
  BindingServices.AddKeyBinding([ShortCut(VK_DOWN, [ssAlt])], MoveLineOrBlockDown, nil);
end;

procedure TKeyboardBinding.MoveLineOrBlock(ADirection: Integer; const Context: IOTAKeyContext; var BindingResult: TKeyBindingResult);
var
  EditPosition: IOTAEditPosition;
  EditBlock: IOTAEditBlock;
  CurrentRow: Integer;
  CurrentRowEnd: Integer;
  BlockSize: Integer;
  IsAutoIndent: Boolean;
  CodeLine: string;
  sr, er: Integer;
begin
  EditPosition := Context.EditBuffer.EditPosition;
  EditBlock := Context.EditBuffer.EditBlock;
  // Store original cursor row
  CurrentRow := EditPosition.Row;
  // Length of the selected block (0 means no block)
  BlockSize := EditBlock.Size;
  // Store AutoIndent property
  IsAutoIndent := Context.EditBuffer.BufferOptions.AutoIndent;
  // Turn off AutoIndent, if necessary
  if IsAutoIndent then
    Context.EditBuffer.BufferOptions.AutoIndent := False;

  if (EditPosition.Row = 1) and (ADirection = -1) then
    Exit;

  if (BlockSize = 0) then
  begin
    // Only a single line to move

    EditPosition.Save;
    if ADirection = 1 then
      EditPosition.Move(EditPosition.Row + ADirection, EditPosition.Column);

    // Move to end of current line
    EditPosition.MoveEOL;
    // Get the column position
    CurrentRowEnd := EditPosition.Column;
    // Move to beginning of current line
    EditPosition.MoveBOL;
    // Get the text of the current line, less the EOL marker
    CodeLine := EditPosition.Read(CurrentRowEnd + 1);

    if Ord(CodeLine[Length(CodeLine)]) <> $0A then
      Exit;

    EditPosition.Move(EditPosition.Row - 1, EditPosition.Column);

    // Move to end of current line
    EditPosition.MoveEOL;
    // Get the column position
    CurrentRowEnd := EditPosition.Column;
    // Move to beginning of current line
    EditPosition.MoveBOL;
    // Get the text of the current line, less the EOL marker
    CodeLine := CodeLine + EditPosition.Read(CurrentRowEnd + 1);

    if Ord(CodeLine[Length(CodeLine)]) <> $0A then
      Exit;

    EditPosition.Delete(Length(CodeLine) - 2);
    EditPosition.InsertText(CodeLine);

    // Move cursor to original position EditPosition.Restore;
    EditPosition.Restore;
    EditPosition.Move(EditPosition.Row + ADirection, EditPosition.Column);
    BindingResult := krHandled;
  end
  else
  begin
    // More than one line selected. Get block text
    sr := EditBlock.StartingRow;
    er := EditBlock.EndingRow;
    if (EditBlock.StartingColumn <> 1) or (EditBlock.EndingColumn <> 1) then
    begin
      EditPosition.Move(sr, 1);
      EditBlock.BeginBlock;
      EditPosition.Move(er + 1, 1);
      EditBlock.EndBlock;
      sr := EditBlock.StartingRow;
      er := EditBlock.EndingRow;
    end;

    CodeLine := EditBlock.Text;
    EditBlock.Delete;
    EditPosition.Move(EditPosition.Row + ADirection, 1);
    // Insert block text
    EditPosition.InsertText(CodeLine);

    EditPosition.Move(sr + ADirection, 1);
    EditBlock.BeginBlock;
    EditPosition.Move(er + ADirection, 1);
    EditBlock.EndBlock;
    BindingResult := krHandled;
  end;
  // Restore AutoIndent, if necessary
  if IsAutoIndent then
    Context.EditBuffer.BufferOptions.AutoIndent := True;
  BindingResult := krHandled;
end;


procedure TKeyboardBinding.MoveLineOrBlockDown(const Context: IOTAKeyContext; KeyCode: TShortCut; var BindingResult: TKeyBindingResult);
begin
  MoveLineOrBlock(1, Context, BindingResult);
end;


procedure TKeyboardBinding.MoveLineOrBlockUp(const Context: IOTAKeyContext; KeyCode: TShortCut; var BindingResult: TKeyBindingResult);
begin
  MoveLineOrBlock(-1, Context, BindingResult);
end;

 

Edited by Attila Kovacs

Share this post


Link to post

MMX Code Explorer offers that with Shift-Alt-Up/Down (if no other key binding catches it first).

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×