2011-09-02 18:51:20 +02:00
# include "window.hh"
# include "buffer.hh"
# include "file.hh"
2012-05-03 09:25:13 +02:00
# include "shell_manager.hh"
2011-09-07 20:16:56 +02:00
# include "command_manager.hh"
2011-09-08 16:30:36 +02:00
# include "buffer_manager.hh"
2011-09-23 16:31:57 +02:00
# include "register_manager.hh"
2011-09-21 16:37:09 +02:00
# include "selectors.hh"
2011-09-09 21:24:18 +02:00
# include "assert.hh"
2011-10-07 16:16:38 +02:00
# include "debug.hh"
2011-11-29 23:37:20 +01:00
# include "highlighters.hh"
# include "highlighter_registry.hh"
2011-12-02 15:28:27 +01:00
# include "filters.hh"
# include "filter_registry.hh"
2012-04-03 14:01:01 +02:00
# include "hook_manager.hh"
2012-04-03 15:39:20 +02:00
# include "option_manager.hh"
2012-01-23 14:56:43 +01:00
# include "context.hh"
2012-02-16 15:25:16 +01:00
# include "ncurses.hh"
2012-04-14 03:17:09 +02:00
# include "regex.hh"
2011-09-02 18:51:20 +02:00
# include <unordered_map>
2011-12-28 20:04:06 +01:00
# include <sys/types.h>
# include <sys/wait.h>
2011-09-02 18:51:20 +02:00
2012-01-20 22:12:57 +01:00
# if defined(__APPLE__)
# include <mach-o/dyld.h>
# endif
2011-09-02 18:51:20 +02:00
using namespace Kakoune ;
2011-09-23 16:27:34 +02:00
using namespace std : : placeholders ;
2011-09-02 18:51:20 +02:00
2012-02-02 21:48:03 +01:00
void draw_editor_ifn ( Editor & editor )
{
Window * window = dynamic_cast < Window * > ( & editor ) ;
if ( window )
2012-02-16 15:25:16 +01:00
NCurses : : draw_window ( * window ) ;
2012-02-02 21:48:03 +01:00
}
2012-02-16 15:25:16 +01:00
PromptFunc prompt_func ;
2012-04-14 03:17:09 +02:00
String prompt ( const String & text , Completer completer = complete_nothing )
2011-12-20 20:22:05 +01:00
{
return prompt_func ( text , completer ) ;
}
2012-02-16 15:25:16 +01:00
GetKeyFunc get_key_func ;
2012-01-25 00:18:59 +01:00
Key get_key ( )
{
return get_key_func ( ) ;
}
2011-12-05 15:28:45 +01:00
struct InsertSequence
{
IncrementalInserter : : Mode mode ;
2012-01-23 15:17:31 +01:00
std : : vector < Key > keys ;
2011-12-05 15:28:45 +01:00
InsertSequence ( ) : mode ( IncrementalInserter : : Mode : : Insert ) { }
} ;
InsertSequence last_insert_sequence ;
2012-02-02 21:48:03 +01:00
bool insert_char ( IncrementalInserter & inserter , const Key & key )
2011-12-05 15:28:45 +01:00
{
2012-01-23 15:17:31 +01:00
switch ( key . modifiers )
2011-12-05 15:28:45 +01:00
{
2012-01-23 15:17:31 +01:00
case Key : : Modifiers : : None :
switch ( key . key )
{
case 27 :
return false ;
default :
2012-04-14 03:17:09 +02:00
inserter . insert ( String ( ) + key . key ) ;
2012-01-23 15:17:31 +01:00
}
2011-12-05 15:28:45 +01:00
break ;
2012-01-23 15:17:31 +01:00
case Key : : Modifiers : : Control :
switch ( key . key )
{
2012-01-24 20:08:57 +01:00
case ' r ' :
{
Key next_key = get_key ( ) ;
last_insert_sequence . keys . push_back ( next_key ) ;
if ( next_key . modifiers = = Key : : Modifiers : : None )
{
switch ( next_key . key )
{
case ' % ' :
2012-02-02 21:48:03 +01:00
inserter . insert ( inserter . buffer ( ) . name ( ) ) ;
2012-01-24 20:08:57 +01:00
break ;
default :
2012-02-10 00:47:55 +01:00
inserter . insert ( RegisterManager : : instance ( ) [ next_key . key ] ) ;
2012-01-24 20:08:57 +01:00
}
}
break ;
}
2012-01-25 00:19:26 +01:00
case ' m ' :
2012-04-14 03:17:09 +02:00
inserter . insert ( String ( ) + ' \n ' ) ;
2012-01-25 00:19:26 +01:00
break ;
2012-04-03 15:38:01 +02:00
case ' i ' :
2012-04-14 03:17:09 +02:00
inserter . insert ( String ( ) + ' \t ' ) ;
2012-04-03 15:38:01 +02:00
break ;
2012-01-23 15:17:31 +01:00
case ' d ' :
2012-01-25 15:23:02 +01:00
inserter . move_cursors ( { 0 , - 1 } ) ;
2012-01-23 15:17:31 +01:00
break ;
case ' e ' :
2012-01-25 15:23:02 +01:00
inserter . move_cursors ( { 0 , 1 } ) ;
2012-01-23 15:17:31 +01:00
break ;
case ' g ' :
inserter . erase ( ) ;
break ;
}
2011-12-05 15:28:45 +01:00
break ;
}
return true ;
}
2012-02-02 21:48:03 +01:00
void do_insert ( Editor & editor , IncrementalInserter : : Mode mode )
2011-09-20 00:00:29 +02:00
{
2011-12-05 15:28:45 +01:00
last_insert_sequence . mode = mode ;
last_insert_sequence . keys . clear ( ) ;
2012-02-02 21:48:03 +01:00
IncrementalInserter inserter ( editor , mode ) ;
draw_editor_ifn ( editor ) ;
2011-09-02 18:51:20 +02:00
while ( true )
{
2012-01-23 15:17:31 +01:00
Key key = get_key ( ) ;
2011-09-20 00:00:29 +02:00
2012-02-02 21:48:03 +01:00
if ( not insert_char ( inserter , key ) )
2012-01-31 20:12:06 +01:00
break ;
2011-09-20 00:00:29 +02:00
2012-01-23 15:17:31 +01:00
last_insert_sequence . keys . push_back ( key ) ;
2012-02-02 21:48:03 +01:00
draw_editor_ifn ( editor ) ;
2011-09-02 18:51:20 +02:00
}
}
2012-02-02 21:48:03 +01:00
void do_repeat_insert ( Editor & editor , int count )
2011-12-05 15:28:45 +01:00
{
2012-02-02 21:48:03 +01:00
IncrementalInserter inserter ( editor , last_insert_sequence . mode ) ;
2012-01-23 15:17:31 +01:00
for ( const Key & key : last_insert_sequence . keys )
2011-12-05 15:28:45 +01:00
{
2012-02-02 21:48:03 +01:00
insert_char ( inserter , key ) ;
2011-12-05 15:28:45 +01:00
}
2012-02-02 21:48:03 +01:00
draw_editor_ifn ( editor ) ;
2011-12-05 15:28:45 +01:00
}
2011-10-10 16:24:17 +02:00
template < bool append >
2012-02-02 21:48:03 +01:00
void do_go ( Editor & editor , int count )
2011-09-22 16:02:07 +02:00
{
if ( count ! = 0 )
2011-10-10 16:24:17 +02:00
{
BufferIterator target =
2012-02-02 21:48:03 +01:00
editor . buffer ( ) . iterator_at ( BufferCoord ( count - 1 , 0 ) ) ;
2011-10-10 16:24:17 +02:00
2012-02-02 21:48:03 +01:00
editor . select ( target ) ;
2011-10-10 16:24:17 +02:00
}
2011-09-22 16:02:07 +02:00
else
{
2012-01-25 00:18:59 +01:00
Key key = get_key ( ) ;
if ( key . modifiers ! = Key : : Modifiers : : None )
return ;
switch ( key . key )
2011-09-22 16:02:07 +02:00
{
case ' g ' :
case ' t ' :
2011-10-10 16:24:17 +02:00
{
BufferIterator target =
2012-02-02 21:48:03 +01:00
editor . buffer ( ) . iterator_at ( BufferCoord ( 0 , 0 ) ) ;
editor . select ( target ) ;
2011-09-24 15:08:04 +02:00
break ;
2011-10-10 16:24:17 +02:00
}
2011-09-24 15:08:04 +02:00
case ' l ' :
2011-10-10 16:24:17 +02:00
case ' L ' :
2012-02-02 21:48:03 +01:00
editor . select ( select_to_eol , append ) ;
2011-09-24 15:08:04 +02:00
break ;
case ' h ' :
2011-10-10 16:24:17 +02:00
case ' H ' :
2012-02-02 21:48:03 +01:00
editor . select ( select_to_eol_reverse , append ) ;
2011-09-22 16:02:07 +02:00
break ;
case ' b ' :
2011-10-10 16:24:17 +02:00
{
2012-02-02 21:48:03 +01:00
BufferIterator target = editor . buffer ( ) . iterator_at (
BufferCoord ( editor . buffer ( ) . line_count ( ) - 1 , 0 ) ) ;
editor . select ( target ) ;
2011-09-22 16:02:07 +02:00
break ;
}
2011-10-10 16:24:17 +02:00
}
2011-09-22 16:02:07 +02:00
}
}
2011-11-26 19:32:57 +01:00
Context main_context ;
2011-09-02 18:51:20 +02:00
2012-04-14 03:17:09 +02:00
Buffer * open_or_create ( const String & filename )
2011-09-02 18:51:20 +02:00
{
2011-09-08 16:30:36 +02:00
Buffer * buffer = NULL ;
2011-09-02 18:51:20 +02:00
try
{
2011-09-08 16:30:36 +02:00
buffer = create_buffer_from_file ( filename ) ;
2011-09-02 20:02:29 +02:00
}
catch ( file_not_found & what )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " new file " + filename ) ;
2012-01-31 15:01:48 +01:00
buffer = new Buffer ( filename , Buffer : : Type : : NewFile ) ;
2011-09-02 18:51:20 +02:00
}
2011-11-09 15:17:46 +01:00
return buffer ;
}
2012-02-13 22:48:16 +01:00
template < bool force_reload >
2011-11-26 19:32:57 +01:00
void edit ( const CommandParameters & params , const Context & context )
2011-11-09 15:17:46 +01:00
{
2012-02-13 22:54:30 +01:00
if ( params . size ( ) = = 0 or params . size ( ) > 3 )
2011-11-09 15:17:46 +01:00
throw wrong_argument_count ( ) ;
2012-04-14 03:17:09 +02:00
String filename = params [ 0 ] ;
2012-02-13 22:48:16 +01:00
Buffer * buffer = nullptr ;
if ( not force_reload )
buffer = BufferManager : : instance ( ) . get_buffer ( filename ) ;
if ( not buffer )
buffer = open_or_create ( filename ) ;
2012-02-13 22:54:30 +01:00
Window & window = * buffer - > get_or_create_window ( ) ;
if ( params . size ( ) > 1 )
{
int line = std : : max ( 0 , atoi ( params [ 1 ] . c_str ( ) ) - 1 ) ;
int column = params . size ( ) > 2 ?
std : : max ( 0 , atoi ( params [ 2 ] . c_str ( ) ) - 1 ) : 0 ;
window . select ( window . buffer ( ) . iterator_at ( { line , column } ) ) ;
}
main_context = Context ( window ) ;
2011-09-02 18:51:20 +02:00
}
2011-11-26 19:32:57 +01:00
void write_buffer ( const CommandParameters & params , const Context & context )
2011-09-02 18:51:20 +02:00
{
2011-09-07 20:16:56 +02:00
if ( params . size ( ) > 1 )
throw wrong_argument_count ( ) ;
2012-01-15 22:33:35 +01:00
Buffer & buffer = context . window ( ) . buffer ( ) ;
2012-04-14 03:17:09 +02:00
String filename = params . empty ( ) ? buffer . name ( )
2012-01-29 23:24:43 +01:00
: parse_filename ( params [ 0 ] ) ;
2011-09-07 20:16:56 +02:00
write_buffer_to_file ( buffer , filename ) ;
2011-10-05 16:21:24 +02:00
buffer . notify_saved ( ) ;
2011-09-02 18:51:20 +02:00
}
bool quit_requested = false ;
2011-10-05 20:43:47 +02:00
template < bool force >
2011-11-26 19:32:57 +01:00
void quit ( const CommandParameters & params , const Context & context )
2011-09-02 18:51:20 +02:00
{
2011-09-07 20:16:56 +02:00
if ( params . size ( ) ! = 0 )
throw wrong_argument_count ( ) ;
2011-10-05 20:43:47 +02:00
if ( not force )
{
2012-04-14 03:17:09 +02:00
std : : vector < String > names ;
2011-10-05 20:43:47 +02:00
for ( auto & buffer : BufferManager : : instance ( ) )
{
2012-01-31 15:01:48 +01:00
if ( buffer . type ( ) ! = Buffer : : Type : : Scratch and buffer . is_modified ( ) )
2012-03-25 22:12:35 +02:00
names . push_back ( buffer . name ( ) ) ;
}
if ( not names . empty ( ) )
{
2012-04-14 03:17:09 +02:00
String message = " modified buffers remaining: [ " ;
2012-03-25 22:12:35 +02:00
for ( auto it = names . begin ( ) ; it ! = names . end ( ) ; + + it )
2011-10-05 20:43:47 +02:00
{
2012-03-25 22:12:35 +02:00
if ( it ! = names . begin ( ) )
message + = " , " ;
message + = * it ;
2011-10-05 20:43:47 +02:00
}
2012-03-25 22:12:35 +02:00
message + = " ] " ;
NCurses : : print_status ( message ) ;
return ;
2011-10-05 20:43:47 +02:00
}
}
2011-09-02 18:51:20 +02:00
quit_requested = true ;
}
2011-11-26 20:11:24 +01:00
template < bool force >
void write_and_quit ( const CommandParameters & params , const Context & context )
{
write_buffer ( params , context ) ;
quit < force > ( CommandParameters ( ) , context ) ;
}
2011-11-26 19:32:57 +01:00
void show_buffer ( const CommandParameters & params , const Context & context )
2011-09-08 16:32:36 +02:00
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
Buffer * buffer = BufferManager : : instance ( ) . get_buffer ( params [ 0 ] ) ;
if ( not buffer )
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " buffer " + params [ 0 ] + " does not exists " ) ;
2011-09-08 16:32:36 +02:00
else
2011-11-26 19:32:57 +01:00
main_context = Context ( * buffer - > get_or_create_window ( ) ) ;
2011-09-08 16:32:36 +02:00
}
2011-11-29 23:37:20 +01:00
void add_highlighter ( const CommandParameters & params , const Context & context )
2011-11-08 15:29:52 +01:00
{
if ( params . size ( ) < 1 )
throw wrong_argument_count ( ) ;
try
{
2011-11-29 23:37:20 +01:00
HighlighterRegistry & registry = HighlighterRegistry : : instance ( ) ;
2012-01-18 01:15:10 +01:00
HighlighterParameters highlighter_params ( params . begin ( ) + 1 , params . end ( ) ) ;
registry . add_highlighter_to_window ( context . window ( ) , params [ 0 ] ,
highlighter_params ) ;
}
catch ( runtime_error & err )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " error: " + err . description ( ) ) ;
2012-01-18 01:15:10 +01:00
}
}
2012-01-15 14:47:12 +01:00
2012-01-18 01:15:10 +01:00
void add_group_highlighter ( const CommandParameters & params , const Context & context )
{
if ( params . size ( ) < 2 )
throw wrong_argument_count ( ) ;
try
{
HighlighterRegistry & registry = HighlighterRegistry : : instance ( ) ;
2012-01-19 21:37:29 +01:00
HighlighterGroup & group = context . window ( ) . highlighters ( ) . get_group ( params [ 0 ] ) ;
2012-01-18 01:15:10 +01:00
HighlighterParameters highlighter_params ( params . begin ( ) + 2 , params . end ( ) ) ;
registry . add_highlighter_to_group ( context . window ( ) , group ,
params [ 1 ] , highlighter_params ) ;
2011-11-08 15:29:52 +01:00
}
catch ( runtime_error & err )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " error: " + err . description ( ) ) ;
2011-11-08 15:29:52 +01:00
}
}
2011-11-29 23:37:20 +01:00
void rm_highlighter ( const CommandParameters & params , const Context & context )
2011-11-08 15:29:52 +01:00
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
2012-01-19 21:37:29 +01:00
context . window ( ) . highlighters ( ) . remove ( params [ 0 ] ) ;
2011-11-08 15:29:52 +01:00
}
2012-01-18 01:15:10 +01:00
void rm_group_highlighter ( const CommandParameters & params , const Context & context )
{
if ( params . size ( ) ! = 2 )
throw wrong_argument_count ( ) ;
try
{
2012-01-19 21:37:29 +01:00
HighlighterGroup & group = context . window ( ) . highlighters ( ) . get_group ( params [ 0 ] ) ;
group . remove ( params [ 1 ] ) ;
2012-01-18 01:15:10 +01:00
}
catch ( runtime_error & err )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " error: " + err . description ( ) ) ;
2012-01-18 01:15:10 +01:00
}
}
2011-12-02 15:28:27 +01:00
void add_filter ( const CommandParameters & params , const Context & context )
{
if ( params . size ( ) < 1 )
throw wrong_argument_count ( ) ;
try
{
FilterRegistry & registry = FilterRegistry : : instance ( ) ;
FilterParameters filter_params ( params . begin ( ) + 1 , params . end ( ) ) ;
2012-01-15 22:33:35 +01:00
registry . add_filter_to_window ( context . window ( ) , params [ 0 ] ,
2011-12-02 15:28:27 +01:00
filter_params ) ;
}
catch ( runtime_error & err )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " error: " + err . description ( ) ) ;
2011-12-02 15:28:27 +01:00
}
}
void rm_filter ( const CommandParameters & params , const Context & context )
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
2012-01-15 22:33:35 +01:00
context . window ( ) . remove_filter ( params [ 0 ] ) ;
2011-12-02 15:28:27 +01:00
}
2011-11-26 19:41:55 +01:00
void add_hook ( const CommandParameters & params , const Context & context )
{
2012-01-23 14:58:43 +01:00
if ( params . size ( ) < 4 )
2011-11-26 19:41:55 +01:00
throw wrong_argument_count ( ) ;
2012-04-14 03:17:09 +02:00
String regex = params [ 2 ] ;
std : : vector < String > hook_params ( params . begin ( ) + 3 , params . end ( ) ) ;
2011-11-26 19:41:55 +01:00
2012-04-14 03:17:09 +02:00
auto hook_func = [ = ] ( const String & param , const Context & context ) {
if ( boost : : regex_match ( param . begin ( ) , param . end ( ) ,
Regex ( regex . begin ( ) , regex . end ( ) ) ) )
2012-01-23 14:58:43 +01:00
CommandManager : : instance ( ) . execute ( hook_params , context ) ;
} ;
if ( params [ 0 ] = = " global " )
2012-04-03 14:01:01 +02:00
GlobalHookManager : : instance ( ) . add_hook ( params [ 1 ] , hook_func ) ;
2012-01-23 14:58:43 +01:00
else if ( params [ 0 ] = = " window " )
2012-04-03 14:01:01 +02:00
context . window ( ) . hook_manager ( ) . add_hook ( params [ 1 ] , hook_func ) ;
2012-01-23 14:58:43 +01:00
else
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " error: no such hook container " + params [ 0 ] ) ;
2011-11-26 19:41:55 +01:00
}
2012-02-13 22:40:09 +01:00
void define_command ( const CommandParameters & params , const Context & context )
{
if ( params . size ( ) < 2 )
throw wrong_argument_count ( ) ;
2012-02-15 14:58:08 +01:00
if ( params [ 0 ] = = " -env-params " )
{
2012-04-14 03:17:09 +02:00
std : : vector < String > cmd_params ( params . begin ( ) + 2 , params . end ( ) ) ;
2012-02-15 14:58:08 +01:00
CommandManager : : instance ( ) . register_command ( params [ 1 ] ,
[ = ] ( const CommandParameters & params , const Context & context ) {
char param_name [ ] = " kak_param0 " ;
for ( size_t i = 0 ; i < 10 ; + + i )
{
param_name [ sizeof ( param_name ) - 2 ] = ' 0 ' + i ;
if ( params . size ( ) > i )
setenv ( param_name , params [ i ] . c_str ( ) , 1 ) ;
else
unsetenv ( param_name ) ;
}
CommandManager : : instance ( ) . execute ( cmd_params , context ) ;
} ) ;
}
else if ( params [ 0 ] = = " -append-params " )
{
2012-04-14 03:17:09 +02:00
std : : vector < String > cmd_params ( params . begin ( ) + 2 , params . end ( ) ) ;
2012-02-15 14:58:08 +01:00
CommandManager : : instance ( ) . register_command ( params [ 1 ] ,
[ = ] ( const CommandParameters & params , const Context & context ) {
2012-04-14 03:17:09 +02:00
std : : vector < String > merged_params = cmd_params ;
2012-02-15 14:58:08 +01:00
for ( auto & param : params )
merged_params . push_back ( param ) ;
CommandManager : : instance ( ) . execute ( merged_params , context ) ;
} ) ;
}
else
{
2012-04-14 03:17:09 +02:00
std : : vector < String > cmd_params ( params . begin ( ) + 1 , params . end ( ) ) ;
2012-02-15 14:58:08 +01:00
CommandManager : : instance ( ) . register_command ( params [ 0 ] ,
[ = ] ( const CommandParameters & params , const Context & context ) {
if ( not params . empty ( ) )
throw wrong_argument_count ( ) ;
CommandManager : : instance ( ) . execute ( cmd_params , context ) ;
} ) ;
}
2012-02-13 22:40:09 +01:00
}
2012-02-15 15:24:52 +01:00
void echo_message ( const CommandParameters & params , const Context & context )
{
2012-04-14 03:17:09 +02:00
String message ;
2012-02-15 15:24:52 +01:00
for ( auto & param : params )
message + = param + " " ;
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( message ) ;
2012-02-15 15:24:52 +01:00
}
2011-11-27 13:59:59 +01:00
void exec_commands_in_file ( const CommandParameters & params ,
const Context & context )
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
2012-04-14 03:17:09 +02:00
String file_content = read_file ( parse_filename ( params [ 0 ] ) ) ;
2011-11-27 13:59:59 +01:00
CommandManager & cmd_manager = CommandManager : : instance ( ) ;
size_t pos = 0 ;
2012-02-13 22:39:41 +01:00
size_t length = file_content . length ( ) ;
2012-01-14 14:50:45 +01:00
bool cat_with_previous = false ;
2012-04-14 03:17:09 +02:00
String command_line ;
2011-11-27 13:59:59 +01:00
while ( true )
{
2012-01-14 14:50:45 +01:00
if ( not cat_with_previous )
command_line . clear ( ) ;
2012-02-13 22:39:41 +01:00
size_t end_pos = pos ;
while ( file_content [ end_pos ] ! = ' \n ' and end_pos ! = length )
{
if ( file_content [ end_pos ] = = ' " ' or file_content [ end_pos ] = = ' \' ' or
file_content [ end_pos ] = = ' ` ' )
{
char delimiter = file_content [ end_pos ] ;
+ + end_pos ;
2012-02-27 15:25:07 +01:00
while ( ( file_content [ end_pos ] ! = delimiter or
file_content [ end_pos - 1 ] = = ' \\ ' ) and end_pos ! = length )
2012-02-13 22:39:41 +01:00
+ + end_pos ;
if ( end_pos = = length )
{
2012-04-14 03:17:09 +02:00
NCurses : : print_status ( String ( " unterminated ' " ) + delimiter + " ' string " ) ;
2012-02-13 22:39:41 +01:00
return ;
}
+ + end_pos ;
}
2012-02-27 15:25:07 +01:00
if ( end_pos ! = length )
+ + end_pos ;
2012-02-13 22:39:41 +01:00
}
if ( end_pos ! = pos and end_pos ! = length and
2012-01-14 14:50:45 +01:00
file_content [ end_pos - 1 ] = = ' \\ ' )
{
command_line + = file_content . substr ( pos , end_pos - pos - 1 ) ;
cat_with_previous = true ;
}
else
{
command_line + = file_content . substr ( pos , end_pos - pos ) ;
cmd_manager . execute ( command_line , context ) ;
cat_with_previous = false ;
}
2012-02-13 22:39:41 +01:00
if ( end_pos = = length )
2012-01-14 14:50:45 +01:00
{
if ( cat_with_previous )
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " while executing commands in \" " + params [ 0 ] +
2012-01-14 14:50:45 +01:00
" \" : last command not complete " ) ;
2011-11-27 13:59:59 +01:00
break ;
2012-01-14 14:50:45 +01:00
}
2011-11-27 13:59:59 +01:00
pos = end_pos + 1 ;
}
}
2012-01-15 18:34:05 +01:00
void exec_commands_in_runtime_file ( const CommandParameters & params ,
const Context & context )
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
2012-04-14 03:17:09 +02:00
const String & filename = params [ 0 ] ;
2012-01-15 18:34:05 +01:00
char buffer [ 2048 ] ;
2012-01-20 22:12:57 +01:00
# if defined(__linux__)
2012-03-08 21:49:10 +01:00
ssize_t res = readlink ( " /proc/self/exe " , buffer , 2048 - filename . length ( ) ) ;
assert ( res ! = - 1 ) ;
buffer [ res ] = ' \0 ' ;
2012-01-20 22:12:57 +01:00
# elif defined(__APPLE__)
uint32_t bufsize = 2048 - filename . length ( ) ;
_NSGetExecutablePath ( buffer , & bufsize ) ;
# else
# error "finding executable path is not implemented on this platform"
# endif
2012-01-15 18:34:05 +01:00
char * ptr = strrchr ( buffer , ' / ' ) ;
if ( ptr )
{
strcpy ( ptr + 1 , filename . c_str ( ) ) ;
2012-02-03 20:14:35 +01:00
exec_commands_in_file ( CommandParameters ( buffer ) , main_context ) ;
2012-01-15 18:34:05 +01:00
}
}
2012-04-03 16:04:02 +02:00
void set_option ( OptionManager & option_manager , const CommandParameters & params )
{
if ( params . size ( ) ! = 2 )
throw wrong_argument_count ( ) ;
option_manager [ params [ 0 ] ] = params [ 1 ] ;
}
2011-09-02 18:51:20 +02:00
void do_command ( )
{
try
{
2011-09-23 16:29:42 +02:00
auto cmdline = prompt ( " : " , std : : bind ( & CommandManager : : complete ,
& CommandManager : : instance ( ) ,
_1 , _2 ) ) ;
2011-11-26 19:32:57 +01:00
CommandManager : : instance ( ) . execute ( cmdline , main_context ) ;
2011-09-02 18:51:20 +02:00
}
catch ( prompt_aborted & ) { }
}
2012-02-02 21:48:03 +01:00
void do_pipe ( Editor & editor , int count )
2011-12-28 20:04:06 +01:00
{
try
{
auto cmdline = prompt ( " | " , complete_nothing ) ;
2012-02-02 21:48:03 +01:00
editor . buffer ( ) . begin_undo_group ( ) ;
for ( auto & sel : const_cast < const Editor & > ( editor ) . selections ( ) )
2011-12-28 20:04:06 +01:00
{
int write_pipe [ 2 ] ;
int read_pipe [ 2 ] ;
pipe ( write_pipe ) ;
pipe ( read_pipe ) ;
if ( pid_t pid = fork ( ) )
{
close ( write_pipe [ 0 ] ) ;
close ( read_pipe [ 1 ] ) ;
2012-04-14 03:17:09 +02:00
String content = editor . buffer ( ) . string ( sel . begin ( ) , sel . end ( ) ) ;
2012-04-14 03:23:20 +02:00
memoryview < char > data = content . data ( ) ;
write ( write_pipe [ 1 ] , data . pointer ( ) , data . size ( ) ) ;
2011-12-28 20:04:06 +01:00
close ( write_pipe [ 1 ] ) ;
2012-04-14 03:17:09 +02:00
String new_content ;
2011-12-28 20:04:06 +01:00
char buffer [ 1024 ] ;
while ( size_t size = read ( read_pipe [ 0 ] , buffer , 1024 ) )
{
2012-04-14 03:17:09 +02:00
new_content + = String ( buffer , buffer + size ) ;
2011-12-28 20:04:06 +01:00
}
close ( read_pipe [ 0 ] ) ;
waitpid ( pid , NULL , 0 ) ;
2012-02-02 21:48:03 +01:00
editor . buffer ( ) . modify ( Modification : : make_erase ( sel . begin ( ) , sel . end ( ) ) ) ;
editor . buffer ( ) . modify ( Modification : : make_insert ( sel . begin ( ) , new_content ) ) ;
2011-12-28 20:04:06 +01:00
}
else
{
close ( write_pipe [ 1 ] ) ;
close ( read_pipe [ 0 ] ) ;
dup2 ( read_pipe [ 1 ] , 1 ) ;
dup2 ( write_pipe [ 0 ] , 0 ) ;
execlp ( " sh " , " sh " , " -c " , cmdline . c_str ( ) , NULL ) ;
}
}
2012-02-02 21:48:03 +01:00
editor . buffer ( ) . end_undo_group ( ) ;
2011-12-28 20:04:06 +01:00
}
catch ( prompt_aborted & ) { }
}
2012-02-28 21:50:47 +01:00
template < bool append >
2012-02-02 21:48:03 +01:00
void do_search ( Editor & editor )
2011-09-02 18:51:20 +02:00
{
try
{
2012-04-14 03:17:09 +02:00
String ex = prompt ( " / " ) ;
2011-09-24 14:48:58 +02:00
if ( ex . empty ( ) )
2012-02-08 00:01:02 +01:00
ex = RegisterManager : : instance ( ) [ ' / ' ] . get ( ) ;
2011-09-24 14:48:58 +02:00
else
2012-02-10 00:47:55 +01:00
RegisterManager : : instance ( ) [ ' / ' ] = ex ;
2011-09-24 14:48:58 +02:00
2012-02-28 21:50:47 +01:00
editor . select ( std : : bind ( select_next_match , _1 , ex ) , append ) ;
2011-09-02 18:51:20 +02:00
}
catch ( prompt_aborted & ) { }
}
2012-02-28 21:50:47 +01:00
template < bool append >
2012-02-02 21:48:03 +01:00
void do_search_next ( Editor & editor )
2011-09-24 14:48:58 +02:00
{
2012-04-14 03:17:09 +02:00
const String & ex = RegisterManager : : instance ( ) [ ' / ' ] . get ( ) ;
2011-09-24 14:48:58 +02:00
if ( not ex . empty ( ) )
2012-02-28 21:50:47 +01:00
editor . select ( std : : bind ( select_next_match , _1 , ex ) , append ) ;
2011-09-24 14:48:58 +02:00
else
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( " no search pattern " ) ;
2011-09-24 14:48:58 +02:00
}
2012-02-02 21:48:03 +01:00
void do_yank ( Editor & editor , int count )
2011-09-23 16:31:57 +02:00
{
2012-02-10 00:47:55 +01:00
RegisterManager : : instance ( ) [ ' " ' ] = editor . selections_content ( ) ;
2011-09-23 16:31:57 +02:00
}
2012-02-02 21:48:03 +01:00
void do_erase ( Editor & editor , int count )
2011-09-26 10:59:32 +02:00
{
2012-02-10 00:47:55 +01:00
RegisterManager : : instance ( ) [ ' " ' ] = editor . selections_content ( ) ;
2012-02-02 21:48:03 +01:00
editor . erase ( ) ;
2011-09-26 10:59:32 +02:00
}
2012-02-02 21:48:03 +01:00
void do_change ( Editor & editor , int count )
2011-09-26 10:59:32 +02:00
{
2012-02-10 00:47:55 +01:00
RegisterManager : : instance ( ) [ ' " ' ] = editor . selections_content ( ) ;
2012-02-02 21:48:03 +01:00
do_insert ( editor , IncrementalInserter : : Mode : : Change ) ;
2011-09-26 10:59:32 +02:00
}
2011-09-27 16:15:20 +02:00
template < bool append >
2012-02-02 21:48:03 +01:00
void do_paste ( Editor & editor , int count )
2011-09-23 16:31:57 +02:00
{
2012-02-10 15:00:21 +01:00
Register & reg = RegisterManager : : instance ( ) [ ' " ' ] ;
if ( count = = 0 )
{
if ( append )
editor . append ( reg ) ;
else
editor . insert ( reg ) ;
}
2011-09-27 16:15:20 +02:00
else
2012-02-10 15:00:21 +01:00
{
if ( append )
editor . append ( reg . get ( count - 1 ) ) ;
else
editor . insert ( reg . get ( count - 1 ) ) ;
}
2011-09-23 16:31:57 +02:00
}
2012-02-02 21:48:03 +01:00
void do_select_regex ( Editor & editor , int count )
2011-11-16 15:06:01 +01:00
{
try
{
2012-04-14 03:17:09 +02:00
String ex = prompt ( " select: " ) ;
2012-02-02 21:48:03 +01:00
editor . multi_select ( std : : bind ( select_all_matches , _1 , ex ) ) ;
2011-11-16 15:06:01 +01:00
}
catch ( prompt_aborted & ) { }
}
2012-02-02 21:48:03 +01:00
void do_split_regex ( Editor & editor , int count )
2011-11-21 20:30:44 +01:00
{
try
{
2012-04-14 03:17:09 +02:00
String ex = prompt ( " split: " ) ;
2012-02-02 21:48:03 +01:00
editor . multi_select ( std : : bind ( split_selection , _1 , ex ) ) ;
2011-11-21 20:30:44 +01:00
}
catch ( prompt_aborted & ) { }
}
2012-02-02 21:48:03 +01:00
void do_join ( Editor & editor , int count )
2011-11-22 15:24:50 +01:00
{
2012-02-07 15:26:51 +01:00
editor . select ( select_whole_lines ) ;
2012-02-02 21:48:03 +01:00
editor . select ( select_to_eol , true ) ;
editor . multi_select ( std : : bind ( select_all_matches , _1 , " \n \\ h* " ) ) ;
editor . replace ( " " ) ;
editor . clear_selections ( ) ;
editor . move_selections ( { 0 , - 1 } ) ;
2011-11-22 15:24:50 +01:00
}
2012-03-12 15:23:30 +01:00
template < bool inner >
void do_select_object ( Editor & editor , int count )
2012-01-04 15:18:08 +01:00
{
2012-03-12 15:23:30 +01:00
typedef std : : function < SelectionAndCaptures ( const Selection & ) > Selector ;
static const std : : unordered_map < Key , Selector > key_to_selector =
2012-01-04 15:18:08 +01:00
{
2012-03-12 15:23:30 +01:00
{ { Key : : Modifiers : : None , ' ( ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' ( ' , ' ) ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' ) ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' ( ' , ' ) ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' b ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' ( ' , ' ) ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' { ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' { ' , ' } ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' } ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' { ' , ' } ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' B ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' { ' , ' } ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' [ ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' [ ' , ' ] ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' ] ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' [ ' , ' ] ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' < ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' < ' , ' > ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' > ' } , std : : bind ( select_surrounding , _1 , std : : pair < char , char > { ' < ' , ' > ' } , inner ) } ,
{ { Key : : Modifiers : : None , ' w ' } , std : : bind ( select_whole_word < false > , _1 , inner ) } ,
{ { Key : : Modifiers : : None , ' W ' } , std : : bind ( select_whole_word < true > , _1 , inner ) } ,
2012-01-04 15:18:08 +01:00
} ;
2012-03-12 15:23:30 +01:00
Key key = get_key ( ) ;
auto it = key_to_selector . find ( key ) ;
if ( it ! = key_to_selector . end ( ) )
editor . select ( it - > second ) ;
2012-01-04 15:18:08 +01:00
}
2012-02-02 21:48:03 +01:00
std : : unordered_map < Key , std : : function < void ( Editor & editor , int count ) > > keymap =
2011-09-02 18:51:20 +02:00
{
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' h ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( 0 , - std : : max ( count , 1 ) ) ) ; } } ,
{ { Key : : Modifiers : : None , ' j ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( std : : max ( count , 1 ) , 0 ) ) ; } } ,
{ { Key : : Modifiers : : None , ' k ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( - std : : max ( count , 1 ) , 0 ) ) ; } } ,
{ { Key : : Modifiers : : None , ' l ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( 0 , std : : max ( count , 1 ) ) ) ; } } ,
2011-10-14 16:29:53 +02:00
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' H ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( 0 , - std : : max ( count , 1 ) ) , true ) ; } } ,
{ { Key : : Modifiers : : None , ' J ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( std : : max ( count , 1 ) , 0 ) , true ) ; } } ,
{ { Key : : Modifiers : : None , ' K ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( - std : : max ( count , 1 ) , 0 ) , true ) ; } } ,
{ { Key : : Modifiers : : None , ' L ' } , [ ] ( Editor & editor , int count ) { editor . move_selections ( BufferCoord ( 0 , std : : max ( count , 1 ) ) , true ) ; } } ,
2011-10-07 16:03:25 +02:00
2012-02-16 15:25:16 +01:00
{ { Key : : Modifiers : : None , ' t ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to , _1 , get_key ( ) . key , count , false ) ) ; } } ,
{ { Key : : Modifiers : : None , ' f ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to , _1 , get_key ( ) . key , count , true ) ) ; } } ,
{ { Key : : Modifiers : : None , ' T ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to , _1 , get_key ( ) . key , count , false ) , true ) ; } } ,
{ { Key : : Modifiers : : None , ' F ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to , _1 , get_key ( ) . key , count , true ) , true ) ; } } ,
2011-09-22 16:35:28 +02:00
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : None , ' d ' } , do_erase } ,
{ { Key : : Modifiers : : None , ' c ' } , do_change } ,
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' i ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : Insert ) ; } } ,
{ { Key : : Modifiers : : None , ' I ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : InsertAtLineBegin ) ; } } ,
{ { Key : : Modifiers : : None , ' a ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : Append ) ; } } ,
{ { Key : : Modifiers : : None , ' A ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : AppendAtLineEnd ) ; } } ,
{ { Key : : Modifiers : : None , ' o ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : OpenLineBelow ) ; } } ,
{ { Key : : Modifiers : : None , ' O ' } , [ ] ( Editor & editor , int count ) { do_insert ( editor , IncrementalInserter : : Mode : : OpenLineAbove ) ; } } ,
2011-09-22 11:24:16 +02:00
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : None , ' g ' } , do_go < false > } ,
{ { Key : : Modifiers : : None , ' G ' } , do_go < true > } ,
2011-09-22 11:24:16 +02:00
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : None , ' y ' } , do_yank } ,
{ { Key : : Modifiers : : None , ' p ' } , do_paste < true > } ,
{ { Key : : Modifiers : : None , ' P ' } , do_paste < false > } ,
2011-09-23 16:31:57 +02:00
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : None , ' s ' } , do_select_regex } ,
2011-11-16 15:06:01 +01:00
2011-12-05 15:28:45 +01:00
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : None , ' . ' } , do_repeat_insert } ,
2011-12-05 15:28:45 +01:00
2012-02-07 15:26:51 +01:00
{ { Key : : Modifiers : : None , ' % ' } , [ ] ( Editor & editor , int count ) { editor . clear_selections ( ) ; editor . select ( select_whole_buffer ) ; } } ,
2011-09-24 15:45:25 +02:00
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' : ' } , [ ] ( Editor & editor , int count ) { do_command ( ) ; } } ,
2011-12-28 20:04:06 +01:00
{ { Key : : Modifiers : : None , ' | ' } , do_pipe } ,
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' ' } , [ ] ( Editor & editor , int count ) { if ( count = = 0 ) editor . clear_selections ( ) ;
else editor . keep_selection ( count - 1 ) ; } } ,
2012-03-07 20:20:32 +01:00
{ { Key : : Modifiers : : None , ' w ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word < false > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' e ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word_end < false > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' b ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_previous_word < false > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' W ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word < false > , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' E ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word_end < false > , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' B ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_previous_word < false > , true ) ; } while ( - - count > 0 ) ; } } ,
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : None , ' x ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_line , false ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' X ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_line , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' m ' } , [ ] ( Editor & editor , int count ) { editor . select ( select_matching ) ; } } ,
{ { Key : : Modifiers : : None , ' M ' } , [ ] ( Editor & editor , int count ) { editor . select ( select_matching , true ) ; } } ,
2012-02-28 21:50:47 +01:00
{ { Key : : Modifiers : : None , ' / ' } , [ ] ( Editor & editor , int count ) { do_search < false > ( editor ) ; } } ,
{ { Key : : Modifiers : : None , ' ? ' } , [ ] ( Editor & editor , int count ) { do_search < true > ( editor ) ; } } ,
{ { Key : : Modifiers : : None , ' n ' } , [ ] ( Editor & editor , int count ) { do_search_next < false > ( editor ) ; } } ,
{ { Key : : Modifiers : : None , ' N ' } , [ ] ( Editor & editor , int count ) { do_search_next < true > ( editor ) ; } } ,
2012-02-16 15:25:16 +01:00
{ { Key : : Modifiers : : None , ' u ' } , [ ] ( Editor & editor , int count ) { do { if ( not editor . undo ( ) ) { NCurses : : print_status ( " nothing left to undo " ) ; break ; } } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : None , ' U ' } , [ ] ( Editor & editor , int count ) { do { if ( not editor . redo ( ) ) { NCurses : : print_status ( " nothing left to redo " ) ; break ; } } while ( - - count > 0 ) ; } } ,
2011-12-21 15:29:28 +01:00
2012-03-12 15:23:30 +01:00
{ { Key : : Modifiers : : Alt , ' i ' } , do_select_object < true > } ,
{ { Key : : Modifiers : : Alt , ' a ' } , do_select_object < false > } ,
2012-01-04 15:18:08 +01:00
2012-02-16 15:25:16 +01:00
{ { Key : : Modifiers : : Alt , ' t ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to_reverse , _1 , get_key ( ) . key , count , false ) ) ; } } ,
{ { Key : : Modifiers : : Alt , ' f ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to_reverse , _1 , get_key ( ) . key , count , true ) ) ; } } ,
{ { Key : : Modifiers : : Alt , ' T ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to_reverse , _1 , get_key ( ) . key , count , false ) , true ) ; } } ,
{ { Key : : Modifiers : : Alt , ' F ' } , [ ] ( Editor & editor , int count ) { editor . select ( std : : bind ( select_to_reverse , _1 , get_key ( ) . key , count , true ) , true ) ; } } ,
2011-12-21 15:29:28 +01:00
2012-03-07 20:20:32 +01:00
{ { Key : : Modifiers : : Alt , ' w ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word < true > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' e ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word_end < true > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' b ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_previous_word < true > ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' W ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word < true > , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' E ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_next_word_end < true > , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' B ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_previous_word < true > , true ) ; } while ( - - count > 0 ) ; } } ,
2011-12-21 15:29:28 +01:00
2012-02-02 21:48:03 +01:00
{ { Key : : Modifiers : : Alt , ' l ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_eol , false ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' L ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_eol , true ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' h ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_eol_reverse , false ) ; } while ( - - count > 0 ) ; } } ,
{ { Key : : Modifiers : : Alt , ' H ' } , [ ] ( Editor & editor , int count ) { do { editor . select ( select_to_eol_reverse , true ) ; } while ( - - count > 0 ) ; } } ,
2011-12-21 15:29:28 +01:00
{ { Key : : Modifiers : : Alt , ' s ' } , do_split_regex } ,
{ { Key : : Modifiers : : Alt , ' j ' } , do_join } ,
2012-02-07 15:26:51 +01:00
{ { Key : : Modifiers : : Alt , ' x ' } , [ ] ( Editor & editor , int count ) { editor . select ( select_whole_lines ) ; } } ,
2011-10-25 16:28:20 +02:00
} ;
2012-02-27 20:51:30 +01:00
class RegisterRestorer
{
public :
RegisterRestorer ( char name )
: m_name ( name ) ,
m_save ( RegisterManager : : instance ( ) [ name ] . content ( ) )
{ }
~ RegisterRestorer ( )
{ RegisterManager : : instance ( ) [ m_name ] = m_save ; }
private :
2012-04-14 03:17:09 +02:00
std : : vector < String > m_save ;
char m_name ;
2012-02-27 20:51:30 +01:00
} ;
2012-02-07 14:35:41 +01:00
void exec_keys ( const KeyList & keys ,
const Context & context )
2011-12-20 20:22:05 +01:00
{
2012-01-25 00:18:59 +01:00
auto prompt_save = prompt_func ;
auto get_key_save = get_key_func ;
auto restore_funcs = on_scope_end ( [ & ] ( ) {
prompt_func = prompt_save ;
get_key_func = get_key_save ;
} ) ;
2012-02-07 14:35:41 +01:00
size_t pos = 0 ;
2012-04-14 03:17:09 +02:00
prompt_func = [ & ] ( const String & , Completer ) {
2011-12-20 20:22:05 +01:00
size_t begin = pos ;
while ( pos < keys . size ( ) and keys [ pos ] . key ! = ' \n ' )
+ + pos ;
2012-04-14 03:17:09 +02:00
String result ;
2011-12-20 20:22:05 +01:00
for ( size_t i = begin ; i < pos ; + + i )
2012-04-14 03:17:09 +02:00
result + = String ( ) + keys [ i ] . key ;
2011-12-20 20:22:05 +01:00
+ + pos ;
return result ;
} ;
2012-01-25 00:18:59 +01:00
get_key_func = [ & ] ( ) {
if ( pos > = keys . size ( ) )
throw runtime_error ( " no more characters " ) ;
return keys [ pos + + ] ;
} ;
2011-12-20 20:22:05 +01:00
2012-02-27 20:51:30 +01:00
RegisterRestorer quote ( ' " ' ) ;
RegisterRestorer slash ( ' / ' ) ;
2012-02-03 14:55:22 +01:00
Editor batch_editor ( context . buffer ( ) ) ;
Editor & editor = context . has_window ( ) ? static_cast < Editor & > ( context . window ( ) )
: static_cast < Editor & > ( batch_editor ) ;
2012-02-08 00:41:10 +01:00
scoped_edition edition ( editor ) ;
2012-01-31 15:03:10 +01:00
2011-12-20 20:22:05 +01:00
int count = 0 ;
while ( pos < keys . size ( ) )
{
const Key & key = keys [ pos + + ] ;
if ( key . modifiers = = Key : : Modifiers : : None and isdigit ( key . key ) )
count = count * 10 + key . key - ' 0 ' ;
else
{
2011-12-21 15:29:28 +01:00
auto it = keymap . find ( key ) ;
if ( it ! = keymap . end ( ) )
2012-02-02 21:48:03 +01:00
it - > second ( editor , count ) ;
2011-12-20 20:22:05 +01:00
count = 0 ;
}
}
}
2012-02-07 14:35:41 +01:00
void exec_string ( const CommandParameters & params ,
const Context & context )
{
if ( params . size ( ) ! = 1 )
throw wrong_argument_count ( ) ;
KeyList keys = parse_keys ( params [ 0 ] ) ;
exec_keys ( keys , context ) ;
}
2012-05-03 09:24:27 +02:00
void eval_string ( const CommandParameters & params ,
const Context & context )
{
CommandManager : : instance ( ) . execute ( params , context ) ;
}
2012-03-21 20:27:36 +01:00
void run_unit_tests ( ) ;
2011-09-21 16:37:09 +02:00
int main ( int argc , char * argv [ ] )
2011-09-02 18:51:20 +02:00
{
2012-02-16 15:25:16 +01:00
NCurses : : init ( prompt_func , get_key_func ) ;
2011-09-23 16:29:42 +02:00
2012-05-03 09:25:13 +02:00
ShellManager shell_manager ;
2011-11-29 23:37:20 +01:00
CommandManager command_manager ;
BufferManager buffer_manager ;
RegisterManager register_manager ;
HighlighterRegistry highlighter_registry ;
2011-12-02 15:28:27 +01:00
FilterRegistry filter_registry ;
2012-04-03 14:01:01 +02:00
GlobalHookManager hook_manager ;
2012-04-03 15:39:20 +02:00
GlobalOptionManager option_manager ;
2011-09-23 16:29:42 +02:00
2012-03-21 20:27:36 +01:00
run_unit_tests ( ) ;
2012-05-03 09:25:13 +02:00
shell_manager . register_env_var ( " bufname " ,
[ ] ( const Context & context )
{ return context . buffer ( ) . name ( ) ; } ) ;
2012-02-13 22:48:16 +01:00
command_manager . register_commands ( { " e " , " edit " } , edit < false > ,
CommandManager : : None ,
PerArgumentCommandCompleter ( { complete_filename } ) ) ;
command_manager . register_commands ( { " e! " , " edit! " } , edit < true > ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( { complete_filename } ) ) ;
command_manager . register_commands ( { " q " , " quit " } , quit < false > ) ;
command_manager . register_commands ( { " q! " , " quit! " } , quit < true > ) ;
command_manager . register_commands ( { " w " , " write " } , write_buffer ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( { complete_filename } ) ) ;
command_manager . register_command ( " wq " , write_and_quit < false > ) ;
command_manager . register_command ( " wq! " , write_and_quit < true > ) ;
command_manager . register_commands ( { " b " , " buffer " } , show_buffer ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2011-11-12 15:06:49 +01:00
std : : bind ( & BufferManager : : complete_buffername , & buffer_manager , _1 , _2 )
2012-02-03 20:14:35 +01:00
} ) ) ;
command_manager . register_commands ( { " ah " , " addhl " } , add_highlighter ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2011-11-29 23:37:20 +01:00
std : : bind ( & HighlighterRegistry : : complete_highlighter , & highlighter_registry , _1 , _2 )
2012-02-03 20:14:35 +01:00
} ) ) ;
command_manager . register_commands ( { " agh " , " addgrouphl " } , add_group_highlighter ,
2012-01-18 12:33:58 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-01-19 21:37:29 +01:00
{ return main_context . window ( ) . highlighters ( ) . complete_group_id ( prefix , cursor_pos ) ; } ,
2012-01-18 12:33:58 +01:00
std : : bind ( & HighlighterRegistry : : complete_highlighter , & highlighter_registry , _1 , _2 )
2012-02-03 20:14:35 +01:00
} ) ) ;
command_manager . register_commands ( { " rh " , " rmhl " } , rm_highlighter ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-01-19 21:37:29 +01:00
{ return main_context . window ( ) . highlighters ( ) . complete_group_id ( prefix , cursor_pos ) ; }
2012-02-03 20:14:35 +01:00
} ) ) ;
command_manager . register_commands ( { " rgh " , " rmgrouphl " } , rm_group_highlighter ,
2012-01-18 12:33:58 +01:00
CommandManager : : None ,
[ & ] ( const CommandParameters & params , size_t token_to_complete , size_t pos_in_token )
{
Window & w = main_context . window ( ) ;
2012-04-14 03:17:09 +02:00
const String & arg = token_to_complete < params . size ( ) ?
params [ token_to_complete ] : String ( ) ;
2012-01-18 12:33:58 +01:00
if ( token_to_complete = = 0 )
2012-01-19 21:37:29 +01:00
return w . highlighters ( ) . complete_group_id ( arg , pos_in_token ) ;
2012-01-18 12:33:58 +01:00
else if ( token_to_complete = = 1 )
2012-01-19 21:37:29 +01:00
return w . highlighters ( ) . get_group ( params [ 0 ] ) . complete_id ( arg , pos_in_token ) ;
2012-01-18 12:33:58 +01:00
} ) ;
2012-02-03 20:14:35 +01:00
command_manager . register_commands ( { " af " , " addfilter " } , add_filter ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2011-12-02 15:28:27 +01:00
std : : bind ( & FilterRegistry : : complete_filter , & filter_registry , _1 , _2 )
2012-02-03 20:14:35 +01:00
} ) ) ;
command_manager . register_commands ( { " rf " , " rmfilter " } , rm_filter ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-01-15 22:33:35 +01:00
{ return main_context . window ( ) . complete_filterid ( prefix , cursor_pos ) ; }
2012-02-03 20:14:35 +01:00
} ) ) ;
2012-02-13 22:38:07 +01:00
command_manager . register_command ( " hook " , add_hook , CommandManager : : IgnoreSemiColons | CommandManager : : DeferredShellEval ) ;
2011-09-07 20:16:56 +02:00
2012-02-03 20:14:35 +01:00
command_manager . register_command ( " source " , exec_commands_in_file ,
2012-01-15 04:02:08 +01:00
CommandManager : : None ,
2012-02-03 20:14:35 +01:00
PerArgumentCommandCompleter ( { complete_filename } ) ) ;
command_manager . register_command ( " runtime " , exec_commands_in_runtime_file ) ;
2011-11-27 13:59:59 +01:00
2012-02-03 20:14:35 +01:00
command_manager . register_command ( " exec " , exec_string ) ;
2012-05-03 09:24:27 +02:00
command_manager . register_command ( " eval " , eval_string ) ;
2011-12-20 20:22:05 +01:00
2012-02-13 22:40:09 +01:00
command_manager . register_command ( " def " , define_command , CommandManager : : IgnoreSemiColons | CommandManager : : DeferredShellEval ) ;
2012-02-15 15:24:52 +01:00
command_manager . register_command ( " echo " , echo_message ) ;
2012-02-13 22:40:09 +01:00
2012-04-03 16:04:02 +02:00
command_manager . register_commands ( { " setg " , " setglobal " } ,
[ & ] ( const CommandParameters & params , const Context & ) { set_option ( option_manager , params ) ; } ,
2012-04-03 20:25:27 +02:00
CommandManager : : None ,
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-04-03 20:25:27 +02:00
{ return option_manager . complete_option_name ( prefix , cursor_pos ) ; }
} ) ) ;
2012-04-03 16:04:02 +02:00
command_manager . register_commands ( { " setb " , " setbuffer " } ,
[ & ] ( const CommandParameters & params , const Context & context )
{ set_option ( context . buffer ( ) . option_manager ( ) , params ) ; } ,
2012-04-03 20:25:27 +02:00
CommandManager : : None ,
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-04-03 20:25:27 +02:00
{ return main_context . buffer ( ) . option_manager ( ) . complete_option_name ( prefix , cursor_pos ) ; }
} ) ) ;
2012-04-03 16:04:02 +02:00
command_manager . register_commands ( { " setw " , " setwindow " } ,
[ & ] ( const CommandParameters & params , const Context & context )
{ set_option ( context . window ( ) . option_manager ( ) , params ) ; } ,
2012-04-03 20:25:27 +02:00
CommandManager : : None ,
PerArgumentCommandCompleter ( {
2012-04-14 03:17:09 +02:00
[ & ] ( const String & prefix , size_t cursor_pos )
2012-04-03 20:25:27 +02:00
{ return main_context . window ( ) . option_manager ( ) . complete_option_name ( prefix , cursor_pos ) ; }
} ) ) ;
2012-04-03 16:04:02 +02:00
2011-11-29 23:37:20 +01:00
register_highlighters ( ) ;
2011-12-02 15:28:27 +01:00
register_filters ( ) ;
2011-11-08 15:28:01 +01:00
2011-11-27 13:59:59 +01:00
try
{
2012-01-15 18:34:05 +01:00
exec_commands_in_runtime_file ( { " kakrc " } , main_context ) ;
2011-11-27 13:59:59 +01:00
}
catch ( Kakoune : : runtime_error & error )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( error . description ( ) ) ;
2011-11-27 13:59:59 +01:00
}
2011-09-02 18:51:20 +02:00
try
{
2011-11-28 19:52:29 +01:00
write_debug ( " *** This is the debug buffer, where debug info will be written *** \n " ) ;
2012-04-14 03:17:09 +02:00
write_debug ( " utf-8 test: é á ï " ) ;
2011-11-28 19:52:29 +01:00
2011-11-09 15:17:46 +01:00
auto buffer = ( argc > 1 ) ? open_or_create ( argv [ 1 ] ) : new Buffer ( " *scratch* " , Buffer : : Type : : Scratch ) ;
2011-11-26 19:32:57 +01:00
main_context = Context ( * buffer - > get_or_create_window ( ) ) ;
2011-09-02 18:51:20 +02:00
2012-02-16 15:25:16 +01:00
NCurses : : draw_window ( main_context . window ( ) ) ;
2011-09-02 18:51:20 +02:00
int count = 0 ;
while ( not quit_requested )
{
2011-09-09 20:40:59 +02:00
try
2011-09-02 18:51:20 +02:00
{
2012-01-23 15:17:31 +01:00
Key key = get_key ( ) ;
if ( key . modifiers = = Key : : Modifiers : : None and isdigit ( key . key ) )
count = count * 10 + key . key - ' 0 ' ;
2011-09-09 20:40:59 +02:00
else
2011-09-02 18:51:20 +02:00
{
2011-12-21 15:29:28 +01:00
auto it = keymap . find ( key ) ;
if ( it ! = keymap . end ( ) )
2011-09-09 20:40:59 +02:00
{
2012-01-15 22:33:35 +01:00
it - > second ( main_context . window ( ) , count ) ;
2012-02-16 15:25:16 +01:00
NCurses : : draw_window ( main_context . window ( ) ) ;
2011-09-09 20:40:59 +02:00
}
count = 0 ;
2011-09-02 18:51:20 +02:00
}
2011-09-09 20:40:59 +02:00
}
catch ( Kakoune : : runtime_error & error )
{
2012-02-16 15:25:16 +01:00
NCurses : : print_status ( error . description ( ) ) ;
2011-09-02 18:51:20 +02:00
}
}
2012-02-16 15:25:16 +01:00
NCurses : : deinit ( ) ;
2011-09-02 18:51:20 +02:00
}
2011-09-09 21:24:18 +02:00
catch ( Kakoune : : exception & error )
{
2012-02-16 15:25:16 +01:00
NCurses : : deinit ( ) ;
2011-09-09 21:24:18 +02:00
puts ( " uncaught exception: \n " ) ;
puts ( error . description ( ) . c_str ( ) ) ;
return - 1 ;
}
2011-09-02 19:05:44 +02:00
catch ( . . . )
2011-09-02 18:51:20 +02:00
{
2012-02-16 15:25:16 +01:00
NCurses : : deinit ( ) ;
2011-09-02 19:05:44 +02:00
throw ;
2011-09-02 18:51:20 +02:00
}
return 0 ;
}