2005-09-20 23:26:39 +10:00
/** \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 .
*/
2006-08-11 11:18:35 +10:00
# include "config.h"
2005-09-20 23:26:39 +10:00
# 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>
2012-03-04 16:57:41 +05:30
# include <algorithm>
2005-09-20 23:26:39 +10:00
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-09-20 23:26:39 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-09-20 23:26:39 +10:00
# include "wutil.h"
# include "kill.h"
# include "proc.h"
# include "sanity.h"
# include "common.h"
# include "env.h"
# include "exec.h"
2006-10-19 21:50:23 +10:00
# include "path.h"
2005-09-20 23:26:39 +10:00
/**
Maximum entries in killring
*/
# define KILL_MAX 8192
2012-03-03 19:37:55 -08:00
/** Last kill string */
2012-03-03 21:46:06 -08:00
//static ll_node_t *kill_last=0;
2012-03-03 19:37:55 -08:00
/** Current kill string */
2012-03-03 21:46:06 -08:00
//static ll_node_t *kill_current=0;
2012-03-03 19:37:55 -08:00
/** Kill ring */
2012-03-03 21:46:06 -08:00
typedef std : : list < wcstring > kill_list_t ;
static kill_list_t kill_list ;
2005-09-20 23:26:39 +10:00
/**
Contents of the X clipboard , at last time we checked it
*/
static wchar_t * cut_buffer = 0 ;
/**
2010-11-12 02:07:14 +11:00
Test if the xsel command is installed . Since this is called often ,
2010-11-05 09:22:28 -06:00
cache the result .
2005-09-20 23:26:39 +10:00
*/
static int has_xsel ( )
{
2010-11-12 02:07:14 +11:00
static int called = 0 ;
2010-11-05 09:22:28 -06:00
static int res = 0 ;
2012-01-29 23:22:42 -08:00
2010-11-12 02:07:14 +11:00
if ( ! called ) {
2012-01-29 23:22:42 -08:00
wchar_t * path = path_get_path ( L " xsel " ) ;
2010-11-12 02:07:14 +11:00
res = ! ! path ;
2012-01-29 23:22:42 -08:00
free ( path ) ;
2010-11-12 02:07:14 +11:00
called = 1 ;
2012-01-29 23:22:42 -08:00
}
2010-11-05 09:22:28 -06:00
return res ;
}
2005-09-20 23:26:39 +10:00
2012-03-03 19:37:55 -08:00
void kill_add ( const wcstring & str )
2005-09-20 23:26:39 +10:00
{
2012-03-03 21:46:06 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
if ( str . empty ( ) )
return ;
2010-11-05 09:32:05 -06:00
wchar_t * cmd = NULL ;
2010-11-12 02:07:14 +11:00
wchar_t * escaped_str ;
2012-03-03 21:46:06 -08:00
kill_list . push_front ( str ) ;
2005-09-20 23:26:39 +10:00
2010-11-12 02:07:14 +11:00
/*
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 .
*/
2012-01-12 23:07:10 +05:30
2012-01-14 02:42:17 -08:00
const env_var_t clipboard_wstr = env_get_string ( L " FISH_CLIPBOARD_CMD " ) ;
if ( ! clipboard_wstr . missing ( ) )
2010-11-12 02:07:14 +11:00
{
2012-03-03 19:37:55 -08:00
escaped_str = escape ( str . c_str ( ) , 1 ) ;
2012-01-12 23:07:10 +05:30
cmd = wcsdupcat ( L " echo -n " , escaped_str , clipboard_wstr . c_str ( ) ) ;
2010-11-12 02:07:14 +11:00
}
else
{
2011-12-26 19:18:46 -08:00
/* This is for sending the kill to the X copy-and-paste buffer */
2010-11-12 02:07:14 +11:00
if ( ! has_xsel ( ) ) {
return ;
}
2012-01-14 02:42:17 -08:00
const env_var_t disp_wstr = env_get_string ( L " DISPLAY " ) ;
if ( ! disp_wstr . missing ( ) )
2011-12-26 19:18:46 -08:00
{
2012-03-03 19:37:55 -08:00
escaped_str = escape ( str . c_str ( ) , 1 ) ;
2010-11-12 02:07:14 +11:00
cmd = wcsdupcat ( L " echo " , escaped_str , L " |xsel -b " ) ;
}
}
if ( cmd ! = NULL )
2005-09-20 23:26:39 +10:00
{
2012-02-07 23:35:41 -08:00
if ( exec_subshell ( cmd ) = = - 1 )
2006-10-20 01:36:03 +10:00
{
2011-12-26 19:18:46 -08:00
/*
Do nothing on failiure
2006-10-20 01:36:03 +10:00
*/
}
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
free ( cut_buffer ) ;
free ( cmd ) ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
cut_buffer = escaped_str ;
}
}
2006-10-12 23:27:32 +10:00
/**
Remove first match for specified string from circular list
*/
2012-03-03 19:37:55 -08:00
static void kill_remove ( const wcstring & s )
2006-10-12 23:27:32 +10:00
{
2012-03-03 21:46:06 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
kill_list_t : : iterator iter = std : : find ( kill_list . begin ( ) , kill_list . end ( ) , s ) ;
if ( iter ! = kill_list . end ( ) )
kill_list . erase ( iter ) ;
2006-10-12 23:27:32 +10:00
}
2011-12-26 19:18:46 -08:00
2010-09-18 09:51:16 +08:00
2012-03-03 19:37:55 -08:00
void kill_replace ( const wcstring & old , const wcstring & newv )
2006-10-12 23:27:32 +10:00
{
kill_remove ( old ) ;
2011-12-26 19:18:46 -08:00
kill_add ( newv ) ;
2006-10-12 23:27:32 +10:00
}
2005-09-20 23:26:39 +10:00
2012-01-14 03:41:50 -08:00
const wchar_t * kill_yank_rotate ( )
2005-09-20 23:26:39 +10:00
{
2012-03-03 21:46:06 -08:00
ASSERT_IS_MAIN_THREAD ( ) ;
// Move the first element to the end
if ( kill_list . empty ( ) ) {
return NULL ;
} else {
kill_list . splice ( kill_list . end ( ) , kill_list , kill_list . begin ( ) ) ;
return kill_list . front ( ) . c_str ( ) ;
}
2005-09-20 23:26:39 +10:00
}
/**
Check the X clipboard . If it has been changed , add the new
clipboard contents to the fish killring .
*/
static void kill_check_x_buffer ( )
2012-01-14 02:42:17 -08:00
{
2005-09-20 23:26:39 +10:00
if ( ! has_xsel ( ) )
return ;
2011-12-26 19:18:46 -08:00
2012-01-14 02:42:17 -08:00
const env_var_t disp = env_get_string ( L " DISPLAY " ) ;
if ( ! disp . missing ( ) )
2005-09-20 23:26:39 +10:00
{
2011-12-31 15:57:30 -08:00
size_t i ;
wcstring cmd = L " xsel -t 500 -b " ;
wcstring new_cut_buffer = L " " ;
wcstring_list_t list ;
2012-02-07 23:35:41 -08:00
if ( exec_subshell ( cmd , list ) ! = - 1 )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
2011-12-31 15:57:30 -08:00
for ( i = 0 ; i < list . size ( ) ; i + + )
2005-09-20 23:26:39 +10:00
{
2011-12-31 15:57:30 -08:00
wcstring next_line = escape_string ( list . at ( i ) , 0 ) ;
if ( i > 0 ) new_cut_buffer + = L " \\ n " ;
new_cut_buffer + = next_line ;
2005-09-20 23:26:39 +10:00
}
2011-12-26 19:18:46 -08:00
2011-12-31 15:57:30 -08:00
if ( new_cut_buffer . size ( ) > 0 )
2005-09-20 23:26:39 +10:00
{
2011-12-26 19:18:46 -08:00
/*
2006-10-20 01:36:03 +10:00
The buffer is inserted with backslash escapes ,
since we don ' t really like tabs , newlines ,
etc . anyway .
*/
2011-12-26 19:18:46 -08:00
2011-12-31 15:57:30 -08:00
if ( cut_buffer = = NULL | | cut_buffer ! = new_cut_buffer )
{
free ( cut_buffer ) ;
cut_buffer = wcsdup ( new_cut_buffer . c_str ( ) ) ;
2012-03-03 21:46:06 -08:00
kill_list . push_front ( new_cut_buffer ) ;
2011-12-31 15:57:30 -08:00
}
2005-09-20 23:26:39 +10:00
}
}
}
}
2012-01-14 03:41:50 -08:00
const wchar_t * kill_yank ( )
2005-09-20 23:26:39 +10:00
{
kill_check_x_buffer ( ) ;
2012-03-03 21:46:06 -08:00
if ( kill_list . empty ( ) ) {
return L " " ;
} else {
return kill_list . front ( ) . c_str ( ) ;
}
2005-09-20 23:26:39 +10:00
}
void kill_sanity_check ( )
{
}
void kill_init ( )
{
}
void kill_destroy ( )
{
if ( cut_buffer )
free ( cut_buffer ) ;
}