package Kephra::Edit::Goto; our $VERSION = '0.11'; use strict; use warnings; # # internal calls # sub _ep_ref { Kephra::App::EditPanel::_ref() } sub _center_caret { Kephra::Edit::_center_caret() } sub _pos { my $ep = _ep_ref(); my $pos = shift; $pos += $ep->GetLength if $pos < 0; $ep->GotoPos($pos); $ep->EnsureCaretVisible(); } # # simple jump calls # sub pos { position(@_) } sub position { # jump caret to character based text position my $pos = shift; return unless $pos; my $ep = _ep_ref(); my $max = $ep->GetLength; my $fvl = $ep->GetFirstVisibleLine; my $visible = $ep->GetLineVisible( $ep->LineFromPosition($pos) ); $pos += $max if $pos < 0; $pos = 0 if $pos < 0; $pos = $max if $pos > $max; $ep->SetCurrentPos($pos); $ep->SetSelection ($pos, $pos); $ep->SearchAnchor; #$visible ? $ep->ScrollToLine($fvl) : _center_caret(); $ep->EnsureCaretVisible; $ep->EnsureVisible( $ep->LineFromPosition($pos) ); #_center_caret(); } sub next_visible_pos { my $ep = _ep_ref(); my $line = $ep->GetCurrentLine(); return if $ep->GetLineVisible($line); $line = $ep->GetFoldParent($line) until $ep->GetLineVisible($line); $ep->GotoLine($line); _center_caret(); } sub line { my $ep = _ep_ref(); my $l18n = Kephra::API::localisation()->{dialog}{edit}; my $line = Kephra::Dialog::get_number( $l18n->{goto_line_input}, $l18n->{goto_line_headline}, $ep->GetCurrentLine + 1 ); line_nr( $line - 1) unless $line == &Wx::wxCANCEL; } sub line_nr { position( _ep_ref()->PositionFromLine( shift ) ) } sub last_edit { my $pos = Kephra::Document::Data::get_attribute('edit_pos'); position( $pos ) if defined $pos; } # # block navigation # sub prev_block{ _ep_ref()->CmdKeyExecute(&Wx::wxSTC_CMD_PARAUP) } sub next_block{ _ep_ref()->CmdKeyExecute(&Wx::wxSTC_CMD_PARADOWN) } # # brace navigation # sub prev_brace { my $ep = _ep_ref(); my $oldpos = my $pos = $ep->GetCurrentPos; my $braceleft = 1; # is brace left to caret $braceleft--, $pos-- if $ep->BraceMatch($pos-1) > -1; $ep->GotoPos($pos - 1); $ep->SearchAnchor(); my $newpos = $ep->SearchPrev(&Wx::wxSTC_FIND_REGEXP, '[{}()\[\]]'); $newpos++ if $ep->BraceMatch($newpos) > $newpos; $newpos-- if not $braceleft and $newpos == $ep->BraceMatch($pos)+1; $newpos > -1 ? position($newpos) : position($oldpos); } sub next_brace { my $ep = _ep_ref( ); my $oldpos = my $pos = $ep->GetCurrentPos; my $braceleft = 0; # is brace left to caret $braceleft++, $pos-- if $ep->BraceMatch($pos-1) > -1 and $ep->BraceMatch($pos) == -1; $ep->GotoPos($oldpos + 1); $ep->SearchAnchor(); my $newpos = $ep->SearchNext(&Wx::wxSTC_FIND_REGEXP, '[{}()\[\]]'); $newpos++ if $ep->BraceMatch($newpos) > $newpos; $newpos++ if not $braceleft and $newpos == $ep->BraceMatch($pos); $newpos > -1 ? position($newpos) : position($oldpos); } sub prev_related_brace { my $ep = _ep_ref(); my $pos = $ep->GetCurrentPos; my $braceright = 1; # is brace right to caret my $matchpos = $ep->BraceMatch(--$pos); $braceright--, $matchpos = $ep->BraceMatch(++$pos) if $matchpos == -1; if ($matchpos == -1) { prev_brace() } else { if ($matchpos < $pos) { $braceright ? position($matchpos) : position($matchpos+1); } else { # when there is no matching brace my $open_char = chr $ep->GetCharAt($pos); my $close_char = chr $ep->GetCharAt($matchpos); $ep->GotoPos($pos); $ep->SearchAnchor(); my $next_open = $ep->SearchPrev(0, $open_char); $ep->GotoPos($pos); $ep->SearchAnchor(); my $next_close = $ep->SearchPrev(0, $close_char); if ($next_open ==-1 and $next_close == -1) { $ep->GotoPos($ep->GetLength); $ep->SearchAnchor(); position( $ep->SearchPrev(0, $close_char) ); } else { $next_open > $next_close ? position( $next_open + 1 ) : position( $next_close ); } } } } sub next_related_brace { my $ep = _ep_ref(); my $pos = $ep->GetCurrentPos; my $braceleft = 1; # is brace left to caret my $matchpos = $ep->BraceMatch($pos); $braceleft--, $matchpos = $ep->BraceMatch(--$pos) if $matchpos == -1; if ($matchpos == -1) { next_brace() } else { if ($matchpos > $pos) { $braceleft ? position($matchpos+1) : position($matchpos); } else { # when there is no matching brace my $open_char = chr $ep->GetCharAt($matchpos); my $close_char = chr $ep->GetCharAt($pos); $ep->GotoPos($pos + 1); $ep->SearchAnchor(); my $next_open = $ep->SearchNext(0, $open_char); $ep->GotoPos($pos + 1); $ep->SearchAnchor(); my $next_close = $ep->SearchNext(0, $close_char); if ($next_open ==-1 and $next_close == -1) { $ep->GotoPos(0); $ep->SearchAnchor(); position( $ep->SearchNext(0, $open_char) ); } else { $next_open < $next_close ? position( $next_open + 1 ) : position( $next_close ); } } } } 1; __END__ =head1 NAME Kephra::App::Goto - caret jump functions =head1 DESCRIPTION =cut