diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:11:54 -0800 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2011-12-26 19:11:54 -0800 |
commit | 3f16ace6784caab54fb054836ee93902e9701913 (patch) | |
tree | 6ae6170f86bd45ce7fd0dae4a4242bb8dc67c505 /kill.cpp | |
parent | 834ea94eb97d37c65fcbf2fcc3b69303f6fb7e24 (diff) |
Initial C++ conversion
Diffstat (limited to 'kill.cpp')
-rw-r--r-- | kill.cpp | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/kill.cpp b/kill.cpp new file mode 100644 index 00000000..f8843ca2 --- /dev/null +++ b/kill.cpp @@ -0,0 +1,353 @@ +/** \file kill.c + The killring. + + Works like the killring in emacs and readline. The killring is cut + and paste with a memory of previous cuts. It supports integration + with the X clipboard. +*/ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <wchar.h> +#include <termios.h> +#include <unistd.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> + + +#include "fallback.h" +#include "util.h" + +#include "wutil.h" +#include "kill.h" +#include "proc.h" +#include "sanity.h" +#include "common.h" +#include "env.h" +#include "exec.h" +#include "halloc.h" +#include "path.h" + +/** + Maximum entries in killring +*/ +#define KILL_MAX 8192 + + +static ll_node_t /** Last kill string */*kill_last=0, /** Current kill string */*kill_current =0; +/** + Contents of the X clipboard, at last time we checked it +*/ +static wchar_t *cut_buffer=0; + +/** + Test if the xsel command is installed. Since this is called often, + cache the result. +*/ +static int has_xsel() +{ + static int called=0; + static int res = 0; + + if (!called) { + void *context = halloc(0, 0); + wchar_t *path = path_get_path( context, L"xsel" ); + res = !!path; + halloc_free( context ); + called = 1; + } + + return res; +} + +/** + Add the string to the internal killring +*/ +static void kill_add_internal( wchar_t *str ) +{ + if( wcslen( str ) == 0 ) + return; + + if( kill_last == 0 ) + { + kill_current = kill_last=malloc( sizeof( ll_node_t ) ); + kill_current->data = wcsdup(str); + kill_current->prev = kill_current; + } + else + { + kill_current = malloc( sizeof( ll_node_t ) ); + kill_current->data = kill_last->data; + kill_last->data = wcsdup(str); + kill_current->prev = kill_last->prev; + kill_last->prev = kill_current; + kill_current = kill_last; + } +} + + +void kill_add( wchar_t *str ) +{ + wchar_t *cmd = NULL; + wchar_t *escaped_str; + kill_add_internal(str); + + + /* + Check to see if user has set the FISH_CLIPBOARD_CMD variable, + and, if so, use it instead of checking the display, etc. + + I couldn't think of a safe way to allow overide of the echo + command too, so, the command used must accept the input via stdin. + */ + wchar_t *clipboard; + if( (clipboard = env_get(L"FISH_CLIPBOARD_CMD")) ) + { + escaped_str = escape( str, 1 ); + cmd = wcsdupcat(L"echo -n ", escaped_str, clipboard); + } + else + { + /* This is for sending the kill to the X copy-and-paste buffer */ + if( !has_xsel() ) { + return; + } + + wchar_t *disp; + if( (disp = env_get( L"DISPLAY" )) ) + { + escaped_str = escape( str, 1 ); + cmd = wcsdupcat(L"echo ", escaped_str, L"|xsel -b" ); + } + } + + if (cmd != NULL) + { + if( exec_subshell( cmd, 0 ) == -1 ) + { + /* + Do nothing on failiure + */ + } + + free( cut_buffer ); + free( cmd ); + + cut_buffer = escaped_str; + } +} + +/** + Remove the specified node from the circular list +*/ +static void kill_remove_node( ll_node_t *n ) +{ + if( n->prev == n ) + { + kill_last=kill_current = 0; + } + else + { + ll_node_t *nxt = n->prev; + while( nxt->prev != n ) + { + nxt=nxt->prev; + } + nxt->prev = n->prev; + if( kill_last == n ) + { + kill_last = n->prev; + } + kill_current=kill_last; + free( n->data ); + free( n ); + } +} + +/** + Remove first match for specified string from circular list +*/ +static void kill_remove( wchar_t *s ) +{ + ll_node_t *n, *next=0; + + if( !kill_last ) + { + return; + } + + for( n=kill_last; + n!=kill_last || next == 0 ; + n=n->prev ) + { + if( wcscmp( (wchar_t *)n->data, s ) == 0 ) + { + kill_remove_node( n ); + break; + } + next = n; + } +} + + + +void kill_replace( wchar_t *old, wchar_t *new ) +{ + kill_remove( old ); + kill_add( new ); +} + +wchar_t *kill_yank_rotate() +{ + if( kill_current == 0 ) + return L""; + kill_current = kill_current->prev; + return (wchar_t *)kill_current->data; +} + +/** + Check the X clipboard. If it has been changed, add the new + clipboard contents to the fish killring. +*/ +static void kill_check_x_buffer() +{ + wchar_t *disp; + + if( !has_xsel() ) + return; + + + if( (disp = env_get( L"DISPLAY" )) ) + { + int i; + wchar_t *cmd = L"xsel -t 500 -b"; + wchar_t *new_cut_buffer=0; + array_list_t list; + al_init( &list ); + if( exec_subshell( cmd, &list ) != -1 ) + { + + for( i=0; i<al_get_count( &list ); i++ ) + { + wchar_t *next_line = escape( (wchar_t *)al_get( &list, i ), 0 ); + if( i==0 ) + { + new_cut_buffer = next_line; + } + else + { + wchar_t *old = new_cut_buffer; + new_cut_buffer= wcsdupcat( new_cut_buffer, L"\\n", next_line ); + free( old ); + free( next_line ); + } + } + + if( new_cut_buffer ) + { + /* + The buffer is inserted with backslash escapes, + since we don't really like tabs, newlines, + etc. anyway. + */ + + if( cut_buffer != 0 ) + { + if( wcscmp( new_cut_buffer, cut_buffer ) == 0 ) + { + free( new_cut_buffer ); + new_cut_buffer = 0; + } + else + { + free( cut_buffer ); + cut_buffer = 0; + } + } + if( cut_buffer == 0 ) + { + cut_buffer = new_cut_buffer; + kill_add_internal( cut_buffer ); + } + } + } + + al_foreach( &list, &free ); + al_destroy( &list ); + } +} + + +wchar_t *kill_yank() +{ + kill_check_x_buffer(); + if( kill_current == 0 ) + return L""; + kill_current=kill_last; + return (wchar_t *)kill_current->data; +} + +void kill_sanity_check() +{ + int i; + if( is_interactive ) + { + /* Test that the kill-ring is consistent */ + if( kill_current != 0 ) + { + int kill_ok = 0; + ll_node_t *tmp = kill_current->prev; + for( i=0; i<KILL_MAX; i++ ) + { + if( tmp == 0 ) + break; + if( tmp->data == 0 ) + break; + + if( tmp == kill_current ) + { + kill_ok = 1; + break; + } + tmp = tmp->prev; + } + if( !kill_ok ) + { + debug( 0, + L"Killring inconsistent" ); + sanity_lose(); + } + } + + } +} + +void kill_init() +{ +} + +void kill_destroy() +{ + if( cut_buffer ) + free( cut_buffer ); + + if( kill_current != 0 ) + { + kill_current = kill_last->prev; + kill_last->prev = 0; + + while( kill_current ) + { + ll_node_t *tmp = kill_current; + kill_current = kill_current->prev; + free( tmp->data ); + free( tmp ); + } + } + +} + |