Kephra / lib / Kephra / Edit.pm

use strict;
use warnings;

use Kephra::Config;
use Kephra::CommandList;

#package Kephra::Edit;
package Kephra::App::Editor;

Kephra::CommandList::register_cmd_namespace('edit');
#Kephra::CommandList::add_cmd (
# id => [function  => '$doc->move_sel_or_word_left',]
#);

#$config_container = Kephra::Config:: {}


sub undo { $_[0]->Undo }
sub redo { $_[0]->Redo }

sub move_sel_or_word_left  { $_[0]->move_sel_or_word(-1) }
sub move_sel_or_word_right { $_[0]->move_sel_or_word(+1) }
sub move_sel_or_word {
	my ($self, $movement) = @_;
	my ($start, $end) = $self->GetSelection;
	return if $start == 0 and $movement < 0;
	return if $end == $self->GetLength and $movement > 0;
	my $move_wordwise;
	$self->BeginUndoAction;
	if ($start == $end) { # select the current word
		my $pos = $start;
		$start = $self->WordStartPosition($pos, 1);
		$end = $self->WordEndPosition($pos, 1);
		$self->SetSelection($start, $end);
		$move_wordwise = 1;
	} else {              # check if word is already is selected
		$move_wordwise = 1 if $start == $self->WordStartPosition($start, 1)
		                   and  $end == $self->WordEndPosition ($end, 1);
	}
	my $selection = $self->GetSelectedText;
	$self->ReplaceSelection('');
	if ($move_wordwise) {
		$self->InsertText( $start, $selection);
	} else {
		my $line = $self->LineFromPosition($start);
		my $pos;
		if ($start == $self->PositionFromLine($line) and $movement == -1){ 
			$pos = $self->GetLineEndPosition( $line-1 );
		}
		elsif ($start == $self->GetLineEndPosition($line) 
		and $self->GetLineCount-1 > $line and $movement == 1){
			$pos = $self->PositionFromLine( $line+1 );
		}
		else { $pos = $start + $movement }
		$self->InsertText( $pos, $selection);
		$self->SetSelection( $pos, $pos + length($selection) );
	}
	$self->EndUndoAction;
	#Kephra::API::log("$start, $end", 1);
}
sub move_sel_or_line_up      { $_[0]->move_sel_or_line(-1) }
sub move_sel_or_line_down    { $_[0]->move_sel_or_line(+1) }
sub move_sel_or_line {
	my ($self, $movement) = @_;
	my ($start, $end) = $self->GetSelection;
	my $line_sel = [ $self->LineFromPosition($start), $self->LineFromPosition($end) ];
	my $last_line = $self->LineFromPosition( $self->GetLength );
	return if $line_sel->[0] == 0 and $movement < 0;
	# move inside document borders
	$movement = $line_sel->[0]              
		if $movement < 0 and $line_sel->[0]+$movement < 0;
	$movement = $last_line - $line_sel->[1]
		if $movement > 0 and $line_sel->[1]+$movement > $last_line;

	$self->BeginUndoAction;
	if ($start != $end){     # move selection
		$self->SetSelection( 
			$self->PositionFromLine(  $line_sel->[0] ),
			$self->GetLineEndPosition($line_sel->[1] )
		);
		my $selection = $self->GetSelectedText;
		$self->ReplaceSelection('');
		$self->GotoPos(1) if $self->GetCurrentPos == 0;
		$self->DeleteBack() if $selection;
		my $destination_line = $line_sel->[0] + $movement;
		my $pos = $self->PositionFromLine( $destination_line );
		$self->GotoPos($pos);
		$self->NewLine;
		$pos++ if $self->LineFromPosition( $self->GetLength ) <= $destination_line;
		$self->GotoPos($pos);
		$self->InsertText( $pos, $selection);
		$self->select_whole_lines( $line_sel->[0]+$movement, $line_sel->[1]+$movement );
	} else {                  # move one line
		my $col = $self->GetColumn($self->GetCurrentPos());
		if ($movement < 0){   # up
			my $line = $line_sel->[0];
			$self->GotoLine($line--), $self->LineTranspose for 1..abs $movement;
		} else {              # down
			my $line = $line_sel->[0]+1;
			$self->GotoLine($line++), $self->LineTranspose for 1..    $movement;
		}
		my $pos = $self->PositionFromLine ($line_sel->[0] + $movement) + $col;
		$self->SetSelection( $pos, $pos );
	}
	$self->EndUndoAction;
}

sub select_whole_lines {
	my ($self, $start, $end) = @_;
	$self->SetSelection( 
		$self->PositionFromLine($start),
		$self->GetLineEndPosition($end)
	);
}

sub indent_level { $_[0]->dent_level(+1) }
sub dedent_level { $_[0]->dent_level(-1) }
sub   dent_level {
	my ($self, $change, $lines) = @_;
	my ($start, $end) = $self->GetSelection;
	if ($start != $end){
		my $line_sel = [
			$self->LineFromPosition($start),
			$self->LineFromPosition($end)
		];
		# none empty line numbers of selection
		my @lines = grep {$self->PositionFromLine($_) != $self->GetLineEndPosition($_)}
						$line_sel->[0] .. $line_sel->[1];
		$self->BeginUndoAction;
		$self->_change_indentionlevel_level($change, \@lines);
		$self->select_whole_lines( @$line_sel );
		$self->EndUndoAction;
	} else {
		my $pos = $self->GetCurrentPos();
		my $line = $self->GetCurrentLine();
		my $old_indention = $self->GetLineIndentPosition($line);
		$self->BeginUndoAction;
		$self->_change_indentionlevel_level($change, $line);
		$pos += $self->GetLineIndentPosition($line) - $old_indention;
		$pos = $self->PositionFromLine($line) if $line > $self->LineFromPosition($pos)
		                                      or $pos == -1;
		$self->SetSelection( $pos, $pos );
		$self->EndUndoAction;
	}
}
sub _change_indentionlevel_level {
	my ($self, $change, $lines) = @_;
	my $tab_size = $self->GetIndent();
	$lines = $self->GetCurrentLine() unless defined $lines;
	$lines = [$lines] unless ref $lines eq ref [];
	for my $line (@$lines) {
		my $indent_level = int($self->GetLineIndentation($line) / $tab_size);
		$self->SetLineIndentation( $line, ($indent_level + $change) * $tab_size );
	}
}

sub comment {
	my ($self) = @_;
	my ($start, $end) = $self->GetSelection;
	my $line_sel = [ $self->LineFromPosition($start), $self->LineFromPosition($end) ];

	$self->BeginUndoAction;
	for ($line_sel->[0] .. $line_sel->[1]) {
		my $ipos = $self->GetLineIndentPosition($_);
		next if $ipos == $self->GetLineEndPosition($_);
		$self->InsertText($ipos, '#') unless $self->GetCharAt( $ipos ) == ord '#';
	}
	$self->SetSelection( 
		$self->PositionFromLine(  $line_sel->[0] ),
		$self->GetLineEndPosition($line_sel->[1] )
	);
	$self->EndUndoAction;
}
sub decomment {
	my ($self) = @_;
	my ($start, $end) = $self->GetSelection;
	my $line_sel = [ $self->LineFromPosition($start), $self->LineFromPosition($end) ];

	$self->BeginUndoAction;
	for ($line_sel->[0] .. $line_sel->[1]) {
		my $ipos = $self->GetLineIndentPosition($_);
		if ($self->GetCharAt( $ipos ) eq ord '#') {
			$self->SetTargetStart($ipos);
			$self->SetTargetEnd($ipos+1);
			$self->ReplaceTarget('');
		}
	}
	$self->SetSelection( 
		$self->PositionFromLine(  $line_sel->[0] ),
		$self->GetLineEndPosition($line_sel->[1] )
	);
	$self->EndUndoAction;
}
sub toggle_comment {
	my ($self) = @_;
	$self->GetCharAt( $self->GetLineIndentPosition( 
		$self->LineFromPosition ($self->GetSelectionStart)) ) eq ord '#'
			? decomment(@_)
			:   comment(@_);
}
sub prev_comment{
	my ($self) = @_;
	my ($start, $end) = $self->GetSelection;
	$self->GotoPos( $start );
	$self->SearchAnchor();
	my $found = $self->SearchPrev(0, '#');
	if( $found == -1) {
		$self->GotoPos( $self->GetLength );
		$self->SearchAnchor();
		$found = $self->SearchPrev(0, '#') 
	}
	$self->GotoPos( $found != -1 ? $found : $start );
}
sub next_comment {
	my ($self) = @_;
	my ($start, $end) = $self->GetSelection;
	$self->GotoPos( $start + 1 );
	$self->SearchAnchor();
	my $found = $self->SearchNext(0, '#');
	if( $found == -1) {
		$self->GotoPos( 0 );
		$self->SearchAnchor();
		$found = $self->SearchNext(0, '#') 
	}
	$self->GotoPos( $found != -1 ? $found : $start );
}

sub goto_last_edit {
	my ($self) = @_;
	$self->GotoPos( $self->{'edit_pos'} ) if exists $self->{'edit_pos'};
}

sub search_for_selection {} 
sub replace_with_selection {} 
sub find_next {}
sub find_prev {} 
sub replace_next {}
sub replace_prev {}

sub select_form {}
sub select_content {}

1;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.