2013-04-12 14:28:13 +02:00
# include "normal.hh"
# include "buffer.hh"
# include "buffer_manager.hh"
# include "client_manager.hh"
# include "color_registry.hh"
# include "command_manager.hh"
# include "commands.hh"
# include "context.hh"
# include "file.hh"
# include "option_manager.hh"
# include "register_manager.hh"
# include "selectors.hh"
# include "shell_manager.hh"
# include "string.hh"
# include "window.hh"
2013-05-16 22:20:14 +02:00
# include "user_interface.hh"
2013-06-05 19:20:21 +02:00
# include "utf8_iterator.hh"
2013-04-12 14:28:13 +02:00
namespace Kakoune
{
using namespace std : : placeholders ;
template < InsertMode mode >
2013-10-10 22:22:20 +02:00
void insert ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-09-12 23:47:23 +02:00
context . client ( ) . insert ( mode ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void repeat_insert ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-09-12 23:47:23 +02:00
context . client ( ) . repeat_last_insert ( ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 23:51:16 +02:00
bool show_auto_info_ifn ( const String & title , const String & info ,
const Context & context )
2013-05-16 22:20:14 +02:00
{
if ( not context . options ( ) [ " autoinfo " ] . get < bool > ( ) or not context . has_ui ( ) )
return false ;
2013-08-29 14:50:24 +02:00
ColorPair col = get_color ( " Information " ) ;
2013-05-16 22:20:14 +02:00
DisplayCoord pos = context . window ( ) . dimensions ( ) ;
pos . column - = 1 ;
2013-10-10 23:51:16 +02:00
context . ui ( ) . info_show ( title , info , pos , col , MenuStyle : : Prompt ) ;
2013-05-16 22:20:14 +02:00
return true ;
}
2013-07-27 15:58:06 +02:00
template < typename Cmd >
2013-10-10 23:51:16 +02:00
void on_next_key_with_autoinfo ( const Context & context , Cmd cmd ,
const String & title , const String & info )
2013-07-27 15:58:06 +02:00
{
2013-10-10 23:51:16 +02:00
const bool hide = show_auto_info_ifn ( title , info , context ) ;
2013-09-12 23:47:23 +02:00
context . client ( ) . on_next_key ( [ hide , cmd ] ( Key key , Context & context ) mutable {
2013-07-27 15:58:06 +02:00
if ( hide )
context . ui ( ) . info_hide ( ) ;
cmd ( key , context ) ;
} ) ;
}
2013-04-12 14:28:13 +02:00
template < SelectMode mode >
2013-10-10 22:22:20 +02:00
void goto_commands ( Context & context , int line )
2013-04-12 14:28:13 +02:00
{
2013-10-10 22:22:20 +02:00
if ( line ! = 0 )
2013-04-12 14:28:13 +02:00
{
context . push_jump ( ) ;
2013-10-10 22:22:20 +02:00
context . editor ( ) . select ( BufferCoord { line - 1 , 0 } ) ;
2013-04-12 14:28:13 +02:00
if ( context . has_window ( ) )
context . window ( ) . center_selection ( ) ;
}
else
2013-05-16 22:20:14 +02:00
{
2013-07-27 15:58:06 +02:00
on_next_key_with_autoinfo ( context , [ ] ( Key key , Context & context ) {
2013-04-12 14:28:13 +02:00
if ( key . modifiers ! = Key : : Modifiers : : None )
return ;
Editor & editor = context . editor ( ) ;
switch ( tolower ( key . key ) )
{
case ' g ' :
case ' k ' :
context . push_jump ( ) ;
2013-06-04 13:41:30 +02:00
editor . select ( BufferCoord { 0 , 0 } , mode ) ;
2013-04-12 14:28:13 +02:00
break ;
case ' l ' :
editor . select ( select_to_eol , mode ) ;
break ;
case ' h ' :
editor . select ( select_to_eol_reverse , mode ) ;
break ;
case ' j ' :
{
context . push_jump ( ) ;
2013-06-18 21:43:44 +02:00
editor . select ( { editor . buffer ( ) . line_count ( ) - 1 , 0 } , mode ) ;
2013-04-12 14:28:13 +02:00
break ;
}
case ' e ' :
context . push_jump ( ) ;
2013-06-04 19:23:11 +02:00
editor . select ( editor . buffer ( ) . back_coord ( ) , mode ) ;
2013-04-12 14:28:13 +02:00
break ;
case ' t ' :
if ( context . has_window ( ) )
{
auto line = context . window ( ) . position ( ) . line ;
2013-06-18 21:43:44 +02:00
editor . select ( { line , 0 } , mode ) ;
2013-04-12 14:28:13 +02:00
}
break ;
case ' b ' :
if ( context . has_window ( ) )
{
auto & window = context . window ( ) ;
auto line = window . position ( ) . line + window . dimensions ( ) . line - 1 ;
2013-06-18 21:43:44 +02:00
editor . select ( { line , 0 } , mode ) ;
2013-04-12 14:28:13 +02:00
}
break ;
case ' c ' :
if ( context . has_window ( ) )
{
auto & window = context . window ( ) ;
auto line = window . position ( ) . line + window . dimensions ( ) . line / 2 ;
2013-06-18 21:43:44 +02:00
editor . select ( { line , 0 } , mode ) ;
2013-04-12 14:28:13 +02:00
}
break ;
case ' a ' :
{
auto & buffer_manager = BufferManager : : instance ( ) ;
auto it = buffer_manager . begin ( ) ;
if ( it - > get ( ) = = & context . buffer ( ) and + + it = = buffer_manager . end ( ) )
break ;
context . push_jump ( ) ;
auto & client_manager = ClientManager : : instance ( ) ;
context . change_editor ( client_manager . get_unused_window_for_buffer ( * * it ) ) ;
break ;
}
case ' f ' :
{
2013-05-27 14:22:21 +02:00
const Range & sel = context . editor ( ) . main_selection ( ) ;
2013-06-03 18:58:09 +02:00
const Buffer & buffer = context . buffer ( ) ;
String filename = content ( buffer , sel ) ;
2013-05-21 14:01:04 +02:00
static constexpr char forbidden [ ] = { ' \' ' , ' \\ ' , ' \0 ' } ;
2013-04-12 14:28:13 +02:00
for ( auto c : forbidden )
if ( contains ( filename , c ) )
return ;
auto paths = context . options ( ) [ " path " ] . get < std : : vector < String > > ( ) ;
2013-06-03 18:58:09 +02:00
const String & buffer_name = buffer . name ( ) ;
2013-04-12 14:28:13 +02:00
auto it = find ( reversed ( buffer_name ) , ' / ' ) ;
if ( it ! = buffer_name . rend ( ) )
paths . insert ( paths . begin ( ) , String { buffer_name . begin ( ) , it . base ( ) } ) ;
String path = find_file ( filename , paths ) ;
2013-05-21 14:01:04 +02:00
if ( path . empty ( ) )
throw runtime_error ( " unable to find file ' " + filename + " ' " ) ;
CommandManager : : instance ( ) . execute ( " edit ' " + path + " ' " , context ) ;
2013-04-12 14:28:13 +02:00
break ;
}
}
2013-10-10 23:51:16 +02:00
} , " goto " ,
" g,k: buffer top \n "
" l: line end \n "
" h: line begin \n "
" j: buffer bottom \n "
" e: buffer end \n "
" t: window top \n "
" b: window bottom \n "
" c: window center \n "
" a: last buffer \n "
" f: file \n " ) ;
2013-05-16 22:20:14 +02:00
}
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void view_commands ( Context & context , int param )
2013-04-12 14:28:13 +02:00
{
2013-10-10 22:22:20 +02:00
on_next_key_with_autoinfo ( context , [ param ] ( Key key , Context & context ) {
2013-04-12 14:28:13 +02:00
if ( key . modifiers ! = Key : : Modifiers : : None or not context . has_window ( ) )
return ;
Window & window = context . window ( ) ;
switch ( tolower ( key . key ) )
{
2013-04-16 13:54:04 +02:00
case ' v ' :
2013-04-12 14:28:13 +02:00
case ' c ' :
context . window ( ) . center_selection ( ) ;
break ;
case ' t ' :
context . window ( ) . display_selection_at ( 0 ) ;
break ;
case ' b ' :
context . window ( ) . display_selection_at ( window . dimensions ( ) . line - 1 ) ;
break ;
2013-07-26 19:52:05 +02:00
case ' h ' :
2013-10-10 22:22:20 +02:00
context . window ( ) . scroll ( - std : : max < CharCount > ( 1 , param ) ) ;
2013-07-26 19:52:05 +02:00
break ;
2013-04-12 14:28:13 +02:00
case ' j ' :
2013-10-10 22:22:20 +02:00
context . window ( ) . scroll ( std : : max < LineCount > ( 1 , param ) ) ;
2013-04-12 14:28:13 +02:00
break ;
case ' k ' :
2013-10-10 22:22:20 +02:00
context . window ( ) . scroll ( - std : : max < LineCount > ( 1 , param ) ) ;
2013-04-12 14:28:13 +02:00
break ;
2013-07-24 01:38:30 +02:00
case ' l ' :
2013-10-10 22:22:20 +02:00
context . window ( ) . scroll ( std : : max < CharCount > ( 1 , param ) ) ;
2013-07-24 01:38:30 +02:00
break ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 23:51:16 +02:00
} , " view " ,
" v,c: center cursor \n "
" t: cursor on top \n "
" b: cursor on bottom \n "
" h: scroll left \n "
" j: scroll down \n "
" k: scroll up \n "
" l: scroll right \n " ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void replace_with_char ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-07-27 15:58:06 +02:00
on_next_key_with_autoinfo ( context , [ ] ( Key key , Context & context ) {
2013-07-02 15:03:20 +02:00
if ( not isprint ( key . key ) )
return ;
2013-04-12 14:28:13 +02:00
Editor & editor = context . editor ( ) ;
SelectionList sels = editor . selections ( ) ;
auto restore_sels = on_scope_end ( [ & ] { editor . select ( std : : move ( sels ) ) ; } ) ;
2013-06-01 14:22:57 +02:00
editor . multi_select ( std : : bind ( select_all_matches , _1 , _2 , Regex { " . " } ) ) ;
2013-04-12 14:28:13 +02:00
editor . insert ( codepoint_to_str ( key . key ) , InsertMode : : Replace ) ;
2013-10-10 23:51:16 +02:00
} , " replace with char " , " enter char to replace with \n " ) ;
2013-04-12 14:28:13 +02:00
}
2013-07-12 14:55:30 +02:00
Codepoint to_lower ( Codepoint cp ) { return tolower ( cp ) ; }
Codepoint to_upper ( Codepoint cp ) { return toupper ( cp ) ; }
Codepoint swap_case ( Codepoint cp )
2013-04-12 14:28:13 +02:00
{
2013-04-17 19:31:31 +02:00
Codepoint res = std : : tolower ( cp ) ;
return res = = cp ? std : : toupper ( cp ) : res ;
2013-04-12 14:28:13 +02:00
}
2013-07-12 14:55:30 +02:00
template < Codepoint ( * func ) ( Codepoint ) >
2013-10-10 22:22:20 +02:00
void for_each_char ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
Editor & editor = context . editor ( ) ;
std : : vector < String > sels = editor . selections_content ( ) ;
for ( auto & sel : sels )
{
for ( auto & c : sel )
2013-07-12 14:55:30 +02:00
c = func ( c ) ;
2013-04-12 14:28:13 +02:00
}
editor . insert ( sels , InsertMode : : Replace ) ;
}
2013-10-10 22:22:20 +02:00
void command ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-09-12 23:47:23 +02:00
context . client ( ) . prompt (
2013-04-12 14:28:13 +02:00
" : " , get_color ( " Prompt " ) ,
std : : bind ( & CommandManager : : complete , & CommandManager : : instance ( ) , _1 , _2 , _3 ) ,
[ ] ( const String & cmdline , PromptEvent event , Context & context ) {
if ( event = = PromptEvent : : Validate )
CommandManager : : instance ( ) . execute ( cmdline , context ) ;
} ) ;
}
2013-10-10 22:22:20 +02:00
void pipe ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-09-12 23:47:23 +02:00
context . client ( ) . prompt ( " pipe: " , get_color ( " Prompt " ) , complete_nothing ,
2013-04-12 14:28:13 +02:00
[ ] ( const String & cmdline , PromptEvent event , Context & context )
{
if ( event ! = PromptEvent : : Validate )
return ;
Editor & editor = context . editor ( ) ;
std : : vector < String > strings ;
for ( auto & sel : context . editor ( ) . selections ( ) )
2013-07-24 14:38:26 +02:00
{
auto str = content ( context . buffer ( ) , sel ) ;
bool insert_eol = str . back ( ) ! = ' \n ' ;
if ( insert_eol )
str + = ' \n ' ;
str = ShellManager : : instance ( ) . pipe ( str , cmdline , context ,
{ } , EnvVarMap { } ) ;
if ( insert_eol and str . back ( ) = = ' \n ' )
str = str . substr ( 0 , str . length ( ) - 1 ) ;
strings . push_back ( str ) ;
}
2013-04-12 14:28:13 +02:00
editor . insert ( strings , InsertMode : : Replace ) ;
} ) ;
}
2013-07-02 14:55:34 +02:00
template < SelectMode mode , Direction direction >
2013-10-10 22:22:20 +02:00
void search ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-07-02 14:55:34 +02:00
const char * prompt = direction = = Forward ? " search: " : " reverse search: " ;
2013-04-22 18:49:52 +02:00
DynamicSelectionList selections { context . buffer ( ) , context . editor ( ) . selections ( ) } ;
2013-09-12 23:47:23 +02:00
context . client ( ) . prompt ( prompt , get_color ( " Prompt " ) , complete_nothing ,
2013-04-12 14:28:13 +02:00
[ selections ] ( const String & str , PromptEvent event , Context & context ) {
try
{
context . editor ( ) . select ( selections ) ;
if ( event = = PromptEvent : : Abort )
return ;
Regex ex { str } ;
2013-09-12 23:47:23 +02:00
context . client ( ) . set_prompt_colors ( get_color ( " Prompt " ) ) ;
2013-04-12 14:28:13 +02:00
if ( event = = PromptEvent : : Validate )
{
if ( str . empty ( ) )
ex = Regex { RegisterManager : : instance ( ) [ ' / ' ] . values ( context ) [ 0 ] } ;
else
RegisterManager : : instance ( ) [ ' / ' ] = str ;
context . push_jump ( ) ;
}
else if ( str . empty ( ) or not context . options ( ) [ " incsearch " ] . get < bool > ( ) )
return ;
2013-07-02 14:55:34 +02:00
context . editor ( ) . select ( std : : bind ( select_next_match < direction > , _1 , _2 , ex ) , mode ) ;
2013-04-12 14:28:13 +02:00
}
catch ( boost : : regex_error & err )
{
if ( event = = PromptEvent : : Validate )
throw runtime_error ( " regex error: " _str + err . what ( ) ) ;
else
2013-09-12 23:47:23 +02:00
context . client ( ) . set_prompt_colors ( get_color ( " Error " ) ) ;
2013-04-12 14:28:13 +02:00
}
catch ( runtime_error & )
{
context . editor ( ) . select ( selections ) ;
// only validation should propagate errors,
// incremental search should not.
if ( event = = PromptEvent : : Validate )
throw ;
}
} ) ;
}
2013-07-02 14:55:34 +02:00
template < SelectMode mode , Direction direction >
2013-10-10 22:22:20 +02:00
void search_next ( Context & context , int param )
2013-04-12 14:28:13 +02:00
{
const String & str = RegisterManager : : instance ( ) [ ' / ' ] . values ( context ) [ 0 ] ;
if ( not str . empty ( ) )
{
try
{
Regex ex { str } ;
do {
2013-07-02 14:55:34 +02:00
context . editor ( ) . select ( std : : bind ( select_next_match < direction > , _1 , _2 , ex ) , mode ) ;
2013-10-10 22:22:20 +02:00
} while ( - - param > 0 ) ;
2013-04-12 14:28:13 +02:00
}
catch ( boost : : regex_error & err )
{
throw runtime_error ( " regex error: " _str + err . what ( ) ) ;
}
}
else
throw runtime_error ( " no search pattern " ) ;
}
template < bool smart >
2013-10-10 22:22:20 +02:00
void use_selection_as_search_pattern ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
std : : vector < String > patterns ;
auto & sels = context . editor ( ) . selections ( ) ;
2013-06-03 18:58:09 +02:00
const auto & buffer = context . buffer ( ) ;
2013-04-12 14:28:13 +02:00
for ( auto & sel : sels )
{
2013-06-05 19:20:21 +02:00
auto begin = utf8 : : make_iterator ( buffer . iterator_at ( sel . min ( ) ) ) ;
auto end = utf8 : : make_iterator ( buffer . iterator_at ( sel . max ( ) ) ) + 1 ;
auto content = " \\ Q " + String { begin . base ( ) , end . base ( ) } + " \\ E " ;
2013-04-12 14:28:13 +02:00
if ( smart )
{
2013-07-15 14:49:04 +02:00
if ( begin = = buffer . begin ( ) or ( is_word ( * begin ) and not is_word ( * ( begin - 1 ) ) ) )
2013-04-12 14:28:13 +02:00
content = " \\ b " + content ;
2013-06-05 19:20:21 +02:00
if ( end = = buffer . end ( ) or ( is_word ( * ( end - 1 ) ) and not is_word ( * end ) ) )
2013-04-12 14:28:13 +02:00
content = content + " \\ b " ;
}
patterns . push_back ( std : : move ( content ) ) ;
}
RegisterManager : : instance ( ) [ ' / ' ] = patterns ;
}
2013-10-10 22:22:20 +02:00
void yank ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
RegisterManager : : instance ( ) [ ' " ' ] = context . editor ( ) . selections_content ( ) ;
2013-05-13 14:23:07 +02:00
context . print_status ( { " yanked " + to_string ( context . editor ( ) . selections ( ) . size ( ) ) +
" selections " , get_color ( " Information " ) } ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void cat_yank ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
auto sels = context . editor ( ) . selections_content ( ) ;
String str ;
for ( auto & sel : sels )
str + = sel ;
RegisterManager : : instance ( ) [ ' " ' ] = memoryview < String > ( str ) ;
context . print_status ( { " concatenated and yanked " +
2013-05-13 14:23:07 +02:00
to_string ( sels . size ( ) ) + " selections " , get_color ( " Information " ) } ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void erase_selections ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
RegisterManager : : instance ( ) [ ' " ' ] = context . editor ( ) . selections_content ( ) ;
context . editor ( ) . erase ( ) ;
}
2013-10-10 22:22:20 +02:00
void change ( Context & context , int param )
2013-04-12 14:28:13 +02:00
{
RegisterManager : : instance ( ) [ ' " ' ] = context . editor ( ) . selections_content ( ) ;
2013-10-10 22:22:20 +02:00
insert < InsertMode : : Replace > ( context , param ) ;
2013-04-12 14:28:13 +02:00
}
static InsertMode adapt_for_linewise ( InsertMode mode )
{
if ( mode = = InsertMode : : Append )
return InsertMode : : InsertAtNextLineBegin ;
if ( mode = = InsertMode : : Insert )
return InsertMode : : InsertAtLineBegin ;
if ( mode = = InsertMode : : Replace )
return InsertMode : : Replace ;
kak_assert ( false ) ;
return InsertMode : : Insert ;
}
template < InsertMode insert_mode >
2013-10-10 22:22:20 +02:00
void paste ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
Editor & editor = context . editor ( ) ;
auto strings = RegisterManager : : instance ( ) [ ' " ' ] . values ( context ) ;
InsertMode mode = insert_mode ;
for ( auto & str : strings )
{
if ( not str . empty ( ) and str . back ( ) = = ' \n ' )
{
mode = adapt_for_linewise ( mode ) ;
break ;
}
}
editor . insert ( strings , mode ) ;
}
template < typename T >
void regex_prompt ( Context & context , const String prompt , T on_validate )
{
2013-09-12 23:47:23 +02:00
context . client ( ) . prompt ( prompt , get_color ( " Prompt " ) , complete_nothing ,
2013-04-12 14:28:13 +02:00
[ = ] ( const String & str , PromptEvent event , Context & context ) {
if ( event = = PromptEvent : : Validate )
{
try
{
2013-05-13 14:28:03 +02:00
on_validate ( str . empty ( ) ? Regex { } : Regex { str } , context ) ;
2013-04-12 14:28:13 +02:00
}
catch ( boost : : regex_error & err )
{
throw runtime_error ( " regex error: " _str + err . what ( ) ) ;
}
}
else if ( event = = PromptEvent : : Change )
{
const bool ok = Regex { str , boost : : regex_constants : : no_except } . status ( ) = = 0 ;
2013-09-12 23:47:23 +02:00
context . client ( ) . set_prompt_colors ( get_color ( ok ? " Prompt " : " Error " ) ) ;
2013-04-12 14:28:13 +02:00
}
} ) ;
}
2013-10-10 22:22:20 +02:00
void select_regex ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
regex_prompt ( context , " select: " , [ ] ( Regex ex , Context & context ) {
if ( ex . empty ( ) )
ex = Regex { RegisterManager : : instance ( ) [ ' / ' ] . values ( context ) [ 0 ] } ;
else
RegisterManager : : instance ( ) [ ' / ' ] = String { ex . str ( ) } ;
2013-05-13 14:28:03 +02:00
if ( not ex . empty ( ) and not ex . str ( ) . empty ( ) )
2013-06-01 14:22:57 +02:00
context . editor ( ) . multi_select ( std : : bind ( select_all_matches , _1 , _2 , ex ) ) ;
2013-04-12 14:28:13 +02:00
} ) ;
}
2013-10-10 22:22:20 +02:00
void split_regex ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
regex_prompt ( context , " split: " , [ ] ( Regex ex , Context & context ) {
if ( ex . empty ( ) )
ex = Regex { RegisterManager : : instance ( ) [ ' / ' ] . values ( context ) [ 0 ] } ;
else
RegisterManager : : instance ( ) [ ' / ' ] = String { ex . str ( ) } ;
2013-05-13 14:28:03 +02:00
if ( not ex . empty ( ) and not ex . str ( ) . empty ( ) )
2013-06-01 14:22:57 +02:00
context . editor ( ) . multi_select ( std : : bind ( split_selection , _1 , _2 , ex ) ) ;
2013-04-12 14:28:13 +02:00
} ) ;
}
2013-10-10 22:22:20 +02:00
void split_lines ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-07-29 14:50:31 +02:00
context . editor ( ) . multi_select ( [ ] ( const Buffer & buffer , const Selection & sel ) {
if ( sel . first ( ) . line = = sel . last ( ) . line )
return SelectionList { sel } ;
SelectionList res ;
auto min = sel . min ( ) ;
auto max = sel . max ( ) ;
res . push_back ( { min , { min . line , buffer [ min . line ] . length ( ) - 1 } } ) ;
for ( auto line = min . line + 1 ; line < max . line ; + + line )
res . push_back ( { line , { line , buffer [ line ] . length ( ) - 1 } } ) ;
res . push_back ( { max . line , max } ) ;
return res ;
2013-09-02 14:30:46 +02:00
} ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void join_select_spaces ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
Editor & editor = context . editor ( ) ;
editor . select ( select_whole_lines ) ;
editor . select ( select_to_eol , SelectMode : : Extend ) ;
2013-06-01 14:22:57 +02:00
editor . multi_select ( [ ] ( const Buffer & buffer , const Selection & sel )
2013-04-12 14:28:13 +02:00
{
2013-06-01 14:22:57 +02:00
SelectionList res = select_all_matches ( buffer , sel , Regex { " ( \n \\ h*)+ " } ) ;
2013-04-12 14:28:13 +02:00
// remove last end of line if selected
kak_assert ( std : : is_sorted ( res . begin ( ) , res . end ( ) ,
2013-06-06 19:39:53 +02:00
[ ] ( const Selection & lhs , const Selection & rhs )
{ return lhs . min ( ) < rhs . min ( ) ; } ) ) ;
if ( not res . empty ( ) and res . back ( ) . max ( ) = = buffer . back_coord ( ) )
2013-04-12 14:28:13 +02:00
res . pop_back ( ) ;
return res ;
} ) ;
editor . insert ( " " , InsertMode : : Replace ) ;
}
2013-10-10 22:22:20 +02:00
void join ( Context & context , int param )
2013-04-23 18:54:31 +02:00
{
Editor & editor = context . editor ( ) ;
DynamicSelectionList sels { editor . buffer ( ) , editor . selections ( ) } ;
auto restore_sels = on_scope_end ( [ & ] { editor . select ( ( SelectionList ) std : : move ( sels ) ) ; } ) ;
2013-10-10 22:22:20 +02:00
join_select_spaces ( context , param ) ;
2013-04-23 18:54:31 +02:00
}
2013-04-12 14:28:13 +02:00
template < bool matching >
2013-10-10 22:22:20 +02:00
void keep ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
constexpr const char * prompt = matching ? " keep matching: " : " keep not matching: " ;
regex_prompt ( context , prompt , [ ] ( const Regex & ex , Context & context ) {
Editor & editor = context . editor ( ) ;
2013-06-03 18:58:09 +02:00
const Buffer & buffer = context . buffer ( ) ;
2013-04-12 14:28:13 +02:00
SelectionList keep ;
2013-07-29 14:51:07 +02:00
for ( auto & sel : editor . selections ( ) )
2013-04-12 14:28:13 +02:00
{
2013-06-03 18:58:09 +02:00
if ( boost : : regex_search ( buffer . iterator_at ( sel . min ( ) ) ,
utf8 : : next ( buffer . iterator_at ( sel . max ( ) ) ) , ex ) = = matching )
2013-04-12 14:28:13 +02:00
keep . push_back ( sel ) ;
}
if ( keep . empty ( ) )
throw runtime_error ( " no selections remaining " ) ;
editor . select ( std : : move ( keep ) ) ;
} ) ;
}
2013-10-10 22:22:20 +02:00
void indent ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
size_t width = context . options ( ) [ " indentwidth " ] . get < int > ( ) ;
String indent ( ' ' , width ) ;
Editor & editor = context . editor ( ) ;
DynamicSelectionList sels { editor . buffer ( ) , editor . selections ( ) } ;
auto restore_sels = on_scope_end ( [ & ] { editor . select ( ( SelectionList ) std : : move ( sels ) ) ; } ) ;
editor . select ( select_whole_lines ) ;
2013-06-01 14:22:57 +02:00
editor . multi_select ( std : : bind ( select_all_matches , _1 , _2 , Regex { " ^[^ \n ] " } ) ) ;
2013-04-12 14:28:13 +02:00
editor . insert ( indent , InsertMode : : Insert ) ;
}
2013-10-10 22:22:20 +02:00
void deindent ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
int width = context . options ( ) [ " indentwidth " ] . get < int > ( ) ;
Editor & editor = context . editor ( ) ;
DynamicSelectionList sels { editor . buffer ( ) , editor . selections ( ) } ;
auto restore_sels = on_scope_end ( [ & ] { editor . select ( ( SelectionList ) std : : move ( sels ) ) ; } ) ;
editor . select ( select_whole_lines ) ;
2013-06-01 14:22:57 +02:00
editor . multi_select ( std : : bind ( select_all_matches , _1 , _2 ,
2013-05-13 14:23:07 +02:00
Regex { " ^ \\ h{1, " + to_string ( width ) + " } " } ) ) ;
2013-04-12 14:28:13 +02:00
editor . erase ( ) ;
}
2013-05-15 14:24:09 +02:00
template < ObjectFlags flags >
2013-10-10 22:22:20 +02:00
void select_object ( Context & context , int param )
2013-04-12 14:28:13 +02:00
{
2013-10-10 22:22:20 +02:00
int level = param < = 0 ? 0 : param - 1 ;
2013-10-08 20:24:56 +02:00
on_next_key_with_autoinfo ( context , [ level ] ( Key key , Context & context ) {
if ( key . modifiers ! = Key : : Modifiers : : None )
return ;
const Codepoint c = key . key ;
static constexpr struct
2013-04-12 14:28:13 +02:00
{
2013-10-08 20:24:56 +02:00
Codepoint key ;
Selection ( * func ) ( const Buffer & , const Selection & , ObjectFlags ) ;
} selectors [ ] = {
{ ' w ' , select_whole_word < Word > } ,
{ ' W ' , select_whole_word < WORD > } ,
{ ' s ' , select_whole_sentence } ,
{ ' p ' , select_whole_paragraph } ,
{ ' i ' , select_whole_indent } ,
2013-04-12 14:28:13 +02:00
} ;
2013-10-08 20:24:56 +02:00
for ( auto & sel : selectors )
{
if ( c = = sel . key )
return context . editor ( ) . select ( std : : bind ( sel . func , _1 , _2 , flags ) ) ;
}
2013-04-12 14:28:13 +02:00
2013-10-08 20:24:56 +02:00
static constexpr struct
{
CodepointPair pair ;
Codepoint name ;
} surrounding_pairs [ ] = {
{ { ' ( ' , ' ) ' } , ' b ' } ,
{ { ' { ' , ' } ' } , ' B ' } ,
{ { ' [ ' , ' ] ' } , ' r ' } ,
{ { ' < ' , ' > ' } , ' \0 ' } ,
{ { ' " ' , ' " ' } , ' \0 ' } ,
{ { ' \' ' , ' \' ' } , ' \0 ' } ,
} ;
for ( auto & sur : surrounding_pairs )
{
if ( sur . pair . first = = c or sur . pair . second = = c or
( sur . name ! = 0 and sur . name = = c ) )
return context . editor ( ) . select ( std : : bind ( select_surrounding , _1 , _2 ,
sur . pair , level , flags ) ) ;
}
2013-10-10 23:51:16 +02:00
} , " select object " ,
" b,(,): parenthesis block \n "
" B,{,}: braces block \n "
" r,[,]: brackets block \n "
" <,>: angle block \n "
" \" : double quote string \n "
" ': single quote string \n "
" w: word \n "
" W: WORD \n "
" s: sentence \n "
" p: paragraph \n "
" i: indent \n " ) ;
2013-04-12 14:28:13 +02:00
}
template < Key : : NamedKey key >
2013-10-10 22:22:20 +02:00
void scroll ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
static_assert ( key = = Key : : PageUp or key = = Key : : PageDown ,
2013-04-16 14:08:15 +02:00
" scrool only implements PageUp and PageDown " ) ;
2013-04-12 14:28:13 +02:00
Window & window = context . window ( ) ;
Buffer & buffer = context . buffer ( ) ;
DisplayCoord position = window . position ( ) ;
LineCount cursor_line = 0 ;
if ( key = = Key : : PageUp )
{
position . line - = ( window . dimensions ( ) . line - 2 ) ;
cursor_line = position . line ;
}
else if ( key = = Key : : PageDown )
{
position . line + = ( window . dimensions ( ) . line - 2 ) ;
cursor_line = position . line + window . dimensions ( ) . line - 1 ;
}
2013-06-03 19:10:28 +02:00
auto cursor_pos = utf8 : : advance ( buffer . iterator_at ( position . line ) ,
buffer . iterator_at ( position . line + 1 ) ,
2013-04-12 14:28:13 +02:00
position . column ) ;
2013-06-04 19:23:11 +02:00
window . select ( cursor_pos . coord ( ) ) ;
2013-04-12 14:28:13 +02:00
window . set_position ( position ) ;
}
2013-10-10 22:22:20 +02:00
void rotate_selections ( Context & context , int count )
2013-04-12 14:28:13 +02:00
{
2013-10-10 22:22:20 +02:00
context . editor ( ) . rotate_selections ( count ! = 0 ? count : 1 ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void rotate_selections_content ( Context & context , int count )
2013-10-02 20:10:31 +02:00
{
if ( count = = 0 )
count = 1 ;
2013-10-08 20:28:57 +02:00
Editor & editor = context . editor ( ) ;
2013-10-02 20:10:31 +02:00
auto strings = editor . selections_content ( ) ;
count = count % strings . size ( ) ;
std : : rotate ( strings . begin ( ) , strings . end ( ) - count , strings . end ( ) ) ;
editor . insert ( strings , InsertMode : : Replace ) ;
editor . rotate_selections ( count ) ;
}
2013-04-12 14:28:13 +02:00
enum class SelectFlags
{
None = 0 ,
Reverse = 1 ,
Inclusive = 2 ,
Extend = 4
} ;
constexpr SelectFlags operator | ( SelectFlags lhs , SelectFlags rhs )
{
return ( SelectFlags ) ( ( int ) lhs | ( int ) rhs ) ;
}
constexpr bool operator & ( SelectFlags lhs , SelectFlags rhs )
{
return ( ( int ) lhs & ( int ) rhs ) ! = 0 ;
}
template < SelectFlags flags >
2013-10-10 22:22:20 +02:00
void select_to_next_char ( Context & context , int param )
2013-04-12 14:28:13 +02:00
{
2013-07-27 15:58:06 +02:00
on_next_key_with_autoinfo ( context , [ param ] ( Key key , Context & context ) {
2013-04-12 14:28:13 +02:00
context . editor ( ) . select (
std : : bind ( flags & SelectFlags : : Reverse ? select_to_reverse : select_to ,
2013-06-01 14:22:57 +02:00
_1 , _2 , key . key , param , flags & SelectFlags : : Inclusive ) ,
2013-04-12 14:28:13 +02:00
flags & SelectFlags : : Extend ? SelectMode : : Extend : SelectMode : : Replace ) ;
2013-10-10 23:51:16 +02:00
} , " select to next char " , " enter char to select to " ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void start_or_end_macro_recording ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-09-12 23:47:23 +02:00
if ( context . client ( ) . is_recording ( ) )
context . client ( ) . stop_recording ( ) ;
2013-04-12 14:28:13 +02:00
else
2013-07-27 15:58:06 +02:00
on_next_key_with_autoinfo ( context , [ ] ( Key key , Context & context ) {
2013-10-10 23:58:41 +02:00
if ( key . modifiers = = Key : : Modifiers : : None and
key . key > = ' a ' and key . key < = ' z ' )
2013-09-12 23:47:23 +02:00
context . client ( ) . start_recording ( key . key ) ;
2013-10-10 23:51:16 +02:00
} , " record macro " , " enter macro name " ) ;
2013-04-12 14:28:13 +02:00
}
2013-10-10 22:22:20 +02:00
void replay_macro ( Context & context , int count )
2013-04-12 14:28:13 +02:00
{
2013-07-27 15:58:06 +02:00
on_next_key_with_autoinfo ( context , [ count ] ( Key key , Context & context ) mutable {
2013-04-12 14:28:13 +02:00
if ( key . modifiers = = Key : : Modifiers : : None )
{
2013-05-17 14:22:48 +02:00
static std : : unordered_set < char > running_macros ;
if ( contains ( running_macros , key . key ) )
throw runtime_error ( " recursive macros call detected " ) ;
2013-04-12 14:28:13 +02:00
memoryview < String > reg_val = RegisterManager : : instance ( ) [ key . key ] . values ( context ) ;
if ( not reg_val . empty ( ) )
{
2013-05-17 14:22:48 +02:00
running_macros . insert ( key . key ) ;
auto stop = on_scope_end ( [ & ] { running_macros . erase ( key . key ) ; } ) ;
2013-04-12 14:28:13 +02:00
auto keys = parse_keys ( reg_val [ 0 ] ) ;
scoped_edition edition ( context . editor ( ) ) ;
do { exec_keys ( keys , context ) ; } while ( - - count > 0 ) ;
}
}
2013-10-10 23:51:16 +02:00
} , " replay macro " , " enter macro name " ) ;
2013-04-12 14:28:13 +02:00
}
2013-07-02 14:55:34 +02:00
template < Direction direction >
2013-10-10 22:22:20 +02:00
void jump ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
2013-07-02 14:55:34 +02:00
auto jump = ( direction = = Forward ) ?
2013-04-12 14:28:13 +02:00
context . jump_forward ( ) : context . jump_backward ( ) ;
2013-05-27 19:23:59 +02:00
Buffer & buffer = const_cast < Buffer & > ( jump . buffer ( ) ) ;
2013-04-12 14:28:13 +02:00
BufferManager : : instance ( ) . set_last_used_buffer ( buffer ) ;
if ( & buffer ! = & context . buffer ( ) )
{
auto & manager = ClientManager : : instance ( ) ;
context . change_editor ( manager . get_unused_window_for_buffer ( buffer ) ) ;
}
context . editor ( ) . select ( SelectionList { jump } ) ;
}
2013-10-10 22:22:20 +02:00
void save_selections ( Context & context , int )
2013-10-02 19:48:50 +02:00
{
2013-10-08 20:28:57 +02:00
context . push_jump ( ) ;
context . print_status ( { " saved " + to_string ( context . editor ( ) . selections ( ) . size ( ) ) +
2013-10-02 19:48:50 +02:00
" selections " , get_color ( " Information " ) } ) ;
}
2013-09-02 14:30:46 +02:00
template < bool insert_at_begin >
2013-10-10 22:22:20 +02:00
void align ( Context & context , int )
2013-05-15 18:47:50 +02:00
{
auto & selections = context . editor ( ) . selections ( ) ;
auto & buffer = context . buffer ( ) ;
2013-07-26 00:44:00 +02:00
auto get_column = [ & buffer ] ( BufferCoord coord )
2013-06-05 18:47:39 +02:00
{ return buffer [ coord . line ] . char_count_to ( coord . column ) ; } ;
2013-05-15 18:47:50 +02:00
2013-09-18 19:54:04 +02:00
std : : vector < std : : vector < const Selection * > > columns ;
LineCount last_line = - 1 ;
size_t column = 0 ;
2013-05-15 18:47:50 +02:00
for ( auto & sel : selections )
2013-09-02 14:30:46 +02:00
{
2013-09-18 19:54:04 +02:00
auto line = sel . last ( ) . line ;
if ( sel . first ( ) . line ! = line )
2013-09-02 14:30:46 +02:00
throw runtime_error ( " align cannot work with multi line selections " ) ;
2013-09-18 19:54:04 +02:00
column = ( line = = last_line ) ? column + 1 : 0 ;
if ( column > = columns . size ( ) )
columns . resize ( column + 1 ) ;
columns [ column ] . push_back ( & sel ) ;
last_line = line ;
2013-09-02 14:30:46 +02:00
}
2013-05-15 18:47:50 +02:00
2013-09-18 19:54:04 +02:00
for ( auto & col : columns )
2013-05-15 18:47:50 +02:00
{
2013-09-18 19:54:04 +02:00
CharCount max_col = 0 ;
for ( auto & sel : col )
max_col = std : : max ( get_column ( sel - > last ( ) ) , max_col ) ;
for ( auto & sel : col )
{
CharCount padding = max_col - get_column ( sel - > last ( ) ) ;
auto it = buffer . iterator_at ( insert_at_begin ? sel - > min ( ) : sel - > last ( ) ) ;
buffer . insert ( it , String { ' ' , padding } ) ;
}
2013-05-15 18:47:50 +02:00
}
}
2013-04-12 14:28:13 +02:00
template < typename T >
class Repeated
{
public :
constexpr Repeated ( T t ) : m_func ( t ) { }
2013-10-10 22:22:20 +02:00
void operator ( ) ( Context & context , int count )
2013-04-12 14:28:13 +02:00
{
scoped_edition edition ( context . editor ( ) ) ;
2013-10-10 22:22:20 +02:00
do { m_func ( context , 0 ) ; } while ( - - count > 0 ) ;
2013-04-12 14:28:13 +02:00
}
private :
T m_func ;
} ;
template < typename T >
constexpr Repeated < T > repeated ( T func ) { return Repeated < T > ( func ) ; }
template < SelectMode mode , typename T >
class Select
{
public :
constexpr Select ( T t ) : m_func ( t ) { }
2013-10-10 22:22:20 +02:00
void operator ( ) ( Context & context , int )
2013-04-12 14:28:13 +02:00
{
context . editor ( ) . select ( m_func , mode ) ;
}
private :
T m_func ;
} ;
template < SelectMode mode , typename T >
constexpr Select < mode , T > select ( T func ) { return Select < mode , T > ( func ) ; }
2013-07-02 14:55:34 +02:00
template < typename Type , Direction direction , SelectMode mode = SelectMode : : Replace >
2013-10-10 22:22:20 +02:00
void move ( Context & context , int count )
2013-07-02 14:55:34 +02:00
{
2013-10-10 22:22:20 +02:00
Type offset ( std : : max ( count , 1 ) ) ;
2013-07-02 14:55:34 +02:00
context . editor ( ) . move_selections ( direction = = Backward ? - offset : offset , mode ) ;
}
2013-04-12 14:28:13 +02:00
KeyMap keymap =
{
2013-07-02 14:55:34 +02:00
{ { Key : : Modifiers : : None , ' h ' } , move < CharCount , Backward > } ,
{ { Key : : Modifiers : : None , ' j ' } , move < LineCount , Forward > } ,
{ { Key : : Modifiers : : None , ' k ' } , move < LineCount , Backward > } ,
{ { Key : : Modifiers : : None , ' l ' } , move < CharCount , Forward > } ,
2013-04-12 14:28:13 +02:00
2013-07-02 14:55:34 +02:00
{ { Key : : Modifiers : : None , ' H ' } , move < CharCount , Backward , SelectMode : : Extend > } ,
{ { Key : : Modifiers : : None , ' J ' } , move < LineCount , Forward , SelectMode : : Extend > } ,
{ { Key : : Modifiers : : None , ' K ' } , move < LineCount , Backward , SelectMode : : Extend > } ,
{ { Key : : Modifiers : : None , ' L ' } , move < CharCount , Forward , SelectMode : : Extend > } ,
2013-04-12 14:28:13 +02:00
{ { Key : : Modifiers : : None , ' t ' } , select_to_next_char < SelectFlags : : None > } ,
{ { Key : : Modifiers : : None , ' f ' } , select_to_next_char < SelectFlags : : Inclusive > } ,
{ { Key : : Modifiers : : None , ' T ' } , select_to_next_char < SelectFlags : : Extend > } ,
{ { Key : : Modifiers : : None , ' F ' } , select_to_next_char < SelectFlags : : Inclusive | SelectFlags : : Extend > } ,
{ { Key : : Modifiers : : Alt , ' t ' } , select_to_next_char < SelectFlags : : Reverse > } ,
{ { Key : : Modifiers : : Alt , ' f ' } , select_to_next_char < SelectFlags : : Inclusive | SelectFlags : : Reverse > } ,
{ { Key : : Modifiers : : Alt , ' T ' } , select_to_next_char < SelectFlags : : Extend | SelectFlags : : Reverse > } ,
{ { Key : : Modifiers : : Alt , ' F ' } , select_to_next_char < SelectFlags : : Inclusive | SelectFlags : : Extend | SelectFlags : : Reverse > } ,
2013-06-03 18:58:09 +02:00
{ { Key : : Modifiers : : None , ' d ' } , erase_selections } ,
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' c ' } , change } ,
{ { Key : : Modifiers : : None , ' i ' } , insert < InsertMode : : Insert > } ,
{ { Key : : Modifiers : : None , ' I ' } , insert < InsertMode : : InsertAtLineBegin > } ,
{ { Key : : Modifiers : : None , ' a ' } , insert < InsertMode : : Append > } ,
{ { Key : : Modifiers : : None , ' A ' } , insert < InsertMode : : AppendAtLineEnd > } ,
{ { Key : : Modifiers : : None , ' o ' } , insert < InsertMode : : OpenLineBelow > } ,
{ { Key : : Modifiers : : None , ' O ' } , insert < InsertMode : : OpenLineAbove > } ,
{ { Key : : Modifiers : : None , ' r ' } , replace_with_char } ,
2013-04-12 14:28:13 +02:00
2013-04-19 13:49:47 +02:00
{ { Key : : Modifiers : : None , ' g ' } , goto_commands < SelectMode : : Replace > } ,
{ { Key : : Modifiers : : None , ' G ' } , goto_commands < SelectMode : : Extend > } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' v ' } , view_commands } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' y ' } , yank } ,
{ { Key : : Modifiers : : None , ' Y ' } , cat_yank } ,
{ { Key : : Modifiers : : None , ' p ' } , repeated ( paste < InsertMode : : Append > ) } ,
{ { Key : : Modifiers : : None , ' P ' } , repeated ( paste < InsertMode : : Insert > ) } ,
{ { Key : : Modifiers : : Alt , ' p ' } , paste < InsertMode : : Replace > } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' s ' } , select_regex } ,
{ { Key : : Modifiers : : None , ' S ' } , split_regex } ,
{ { Key : : Modifiers : : Alt , ' s ' } , split_lines } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' . ' } , repeat_insert } ,
2013-04-12 14:28:13 +02:00
2013-10-10 22:22:20 +02:00
{ { Key : : Modifiers : : None , ' % ' } , [ ] ( Context & context , int ) { context . editor ( ) . clear_selections ( ) ; context . editor ( ) . select ( select_whole_buffer ) ; } } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' : ' } , command } ,
{ { Key : : Modifiers : : None , ' | ' } , pipe } ,
2013-10-10 22:22:20 +02:00
{ { Key : : Modifiers : : None , ' ' } , [ ] ( Context & context , int count ) { if ( count = = 0 ) context . editor ( ) . clear_selections ( ) ;
else context . editor ( ) . keep_selection ( count - 1 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' ' } , [ ] ( Context & context , int count ) { if ( count = = 0 ) context . editor ( ) . flip_selections ( ) ;
else context . editor ( ) . remove_selection ( count - 1 ) ; } } ,
2013-10-07 19:44:22 +02:00
{ { Key : : Modifiers : : None , ' w ' } , repeated ( select < SelectMode : : Replace > ( select_to_next_word < Word > ) ) } ,
{ { Key : : Modifiers : : None , ' e ' } , repeated ( select < SelectMode : : Replace > ( select_to_next_word_end < Word > ) ) } ,
{ { Key : : Modifiers : : None , ' b ' } , repeated ( select < SelectMode : : Replace > ( select_to_previous_word < Word > ) ) } ,
{ { Key : : Modifiers : : None , ' W ' } , repeated ( select < SelectMode : : Extend > ( select_to_next_word < Word > ) ) } ,
{ { Key : : Modifiers : : None , ' E ' } , repeated ( select < SelectMode : : Extend > ( select_to_next_word_end < Word > ) ) } ,
{ { Key : : Modifiers : : None , ' B ' } , repeated ( select < SelectMode : : Extend > ( select_to_previous_word < Word > ) ) } ,
{ { Key : : Modifiers : : Alt , ' w ' } , repeated ( select < SelectMode : : Replace > ( select_to_next_word < WORD > ) ) } ,
{ { Key : : Modifiers : : Alt , ' e ' } , repeated ( select < SelectMode : : Replace > ( select_to_next_word_end < WORD > ) ) } ,
{ { Key : : Modifiers : : Alt , ' b ' } , repeated ( select < SelectMode : : Replace > ( select_to_previous_word < WORD > ) ) } ,
{ { Key : : Modifiers : : Alt , ' W ' } , repeated ( select < SelectMode : : Extend > ( select_to_next_word < WORD > ) ) } ,
{ { Key : : Modifiers : : Alt , ' E ' } , repeated ( select < SelectMode : : Extend > ( select_to_next_word_end < WORD > ) ) } ,
{ { Key : : Modifiers : : Alt , ' B ' } , repeated ( select < SelectMode : : Extend > ( select_to_previous_word < WORD > ) ) } ,
2013-04-12 14:28:13 +02:00
{ { Key : : Modifiers : : Alt , ' l ' } , repeated ( select < SelectMode : : Replace > ( select_to_eol ) ) } ,
{ { Key : : Modifiers : : Alt , ' L ' } , repeated ( select < SelectMode : : Extend > ( select_to_eol ) ) } ,
{ { Key : : Modifiers : : Alt , ' h ' } , repeated ( select < SelectMode : : Replace > ( select_to_eol_reverse ) ) } ,
{ { Key : : Modifiers : : Alt , ' H ' } , repeated ( select < SelectMode : : Extend > ( select_to_eol_reverse ) ) } ,
{ { Key : : Modifiers : : None , ' x ' } , repeated ( select < SelectMode : : Replace > ( select_line ) ) } ,
{ { Key : : Modifiers : : None , ' X ' } , repeated ( select < SelectMode : : Extend > ( select_line ) ) } ,
{ { Key : : Modifiers : : Alt , ' x ' } , select < SelectMode : : Replace > ( select_whole_lines ) } ,
2013-04-16 14:30:11 +02:00
{ { Key : : Modifiers : : Alt , ' X ' } , select < SelectMode : : Replace > ( trim_partial_lines ) } ,
2013-04-12 14:28:13 +02:00
{ { Key : : Modifiers : : None , ' m ' } , select < SelectMode : : Replace > ( select_matching ) } ,
{ { Key : : Modifiers : : None , ' M ' } , select < SelectMode : : Extend > ( select_matching ) } ,
2013-07-02 14:55:34 +02:00
{ { Key : : Modifiers : : None , ' / ' } , search < SelectMode : : Replace , Forward > } ,
{ { Key : : Modifiers : : None , ' ? ' } , search < SelectMode : : Extend , Forward > } ,
{ { Key : : Modifiers : : Alt , ' / ' } , search < SelectMode : : Replace , Backward > } ,
{ { Key : : Modifiers : : Alt , ' ? ' } , search < SelectMode : : Extend , Backward > } ,
{ { Key : : Modifiers : : None , ' n ' } , search_next < SelectMode : : Replace , Forward > } ,
{ { Key : : Modifiers : : Alt , ' n ' } , search_next < SelectMode : : ReplaceMain , Forward > } ,
{ { Key : : Modifiers : : None , ' N ' } , search_next < SelectMode : : Append , Forward > } ,
2013-04-12 14:28:13 +02:00
{ { Key : : Modifiers : : None , ' * ' } , use_selection_as_search_pattern < true > } ,
{ { Key : : Modifiers : : Alt , ' * ' } , use_selection_as_search_pattern < false > } ,
2013-10-10 22:22:20 +02:00
{ { Key : : Modifiers : : None , ' u ' } , repeated ( [ ] ( Context & context , int ) { if ( not context . editor ( ) . undo ( ) ) context . print_status ( { " nothing left to undo " , get_color ( " Information " ) } ) ; } ) } ,
{ { Key : : Modifiers : : None , ' U ' } , repeated ( [ ] ( Context & context , int ) { if ( not context . editor ( ) . redo ( ) ) context . print_status ( { " nothing left to redo " , get_color ( " Information " ) } ) ; } ) } ,
2013-04-12 14:28:13 +02:00
2013-05-15 14:24:09 +02:00
{ { Key : : Modifiers : : Alt , ' i ' } , select_object < ObjectFlags : : ToBegin | ObjectFlags : : ToEnd | ObjectFlags : : Inner > } ,
{ { Key : : Modifiers : : Alt , ' a ' } , select_object < ObjectFlags : : ToBegin | ObjectFlags : : ToEnd > } ,
{ { Key : : Modifiers : : None , ' ] ' } , select_object < ObjectFlags : : ToEnd > } ,
{ { Key : : Modifiers : : None , ' [ ' } , select_object < ObjectFlags : : ToBegin > } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : Alt , ' j ' } , join } ,
2013-04-23 18:54:31 +02:00
{ { Key : : Modifiers : : Alt , ' J ' } , join_select_spaces } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : Alt , ' k ' } , keep < true > } ,
{ { Key : : Modifiers : : Alt , ' K ' } , keep < false > } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : None , ' < ' } , deindent } ,
{ { Key : : Modifiers : : None , ' > ' } , indent } ,
2013-04-12 14:28:13 +02:00
2013-07-02 14:55:34 +02:00
{ { Key : : Modifiers : : Control , ' i ' } , jump < Forward > } ,
{ { Key : : Modifiers : : Control , ' o ' } , jump < Backward > } ,
2013-10-02 19:48:50 +02:00
{ { Key : : Modifiers : : Control , ' s ' } , save_selections } ,
2013-04-12 14:28:13 +02:00
2013-04-16 14:08:15 +02:00
{ { Key : : Modifiers : : Alt , ' r ' } , rotate_selections } ,
2013-10-02 20:10:31 +02:00
{ { Key : : Modifiers : : Alt , ' R ' } , rotate_selections_content } ,
2013-04-12 14:28:13 +02:00
{ { Key : : Modifiers : : None , ' q ' } , start_or_end_macro_recording } ,
{ { Key : : Modifiers : : None , ' Q ' } , replay_macro } ,
2013-07-12 14:55:30 +02:00
{ { Key : : Modifiers : : None , ' ` ' } , for_each_char < to_lower > } ,
{ { Key : : Modifiers : : None , ' ~ ' } , for_each_char < to_upper > } ,
2013-09-02 14:30:46 +02:00
{ { Key : : Modifiers : : Alt , ' ` ' } , for_each_char < swap_case > } ,
2013-07-12 14:55:30 +02:00
2013-09-02 14:30:46 +02:00
{ { Key : : Modifiers : : None , ' & ' } , align < false > } ,
{ { Key : : Modifiers : : Alt , ' & ' } , align < true > } ,
2013-07-02 14:55:34 +02:00
{ Key : : Left , move < CharCount , Backward > } ,
{ Key : : Down , move < LineCount , Forward > } ,
{ Key : : Up , move < LineCount , Backward > } ,
{ Key : : Right , move < CharCount , Forward > } ,
{ Key : : PageUp , scroll < Key : : PageUp > } ,
{ Key : : PageDown , scroll < Key : : PageDown > } ,
2013-04-12 14:28:13 +02:00
} ;
}