2005-09-20 21:26:39 +08:00
/** \file history.h
Prototypes for history functions , part of the user interface .
*/
2005-10-04 23:11:39 +08:00
# ifndef FISH_HISTORY_H
# define FISH_HISTORY_H
# include <wchar.h>
2012-02-06 08:42:24 +08:00
# include "common.h"
# include "pthread.h"
# include <vector>
2012-02-06 14:30:42 +08:00
# include <utility>
2012-02-16 03:33:41 +08:00
# include <list>
2012-02-06 08:42:24 +08:00
# include <tr1/memory>
2012-02-07 03:52:24 +08:00
# include <set>
2012-02-06 08:42:24 +08:00
2012-02-16 03:33:41 +08:00
typedef std : : list < wcstring > path_list_t ;
2012-02-07 02:52:13 +08:00
enum history_search_type_t {
/** The history searches for strings containing the given string */
HISTORY_SEARCH_TYPE_CONTAINS ,
/** The history searches for strings starting with the given string */
HISTORY_SEARCH_TYPE_PREFIX
} ;
2012-02-06 08:42:24 +08:00
class history_item_t {
friend class history_t ;
2012-02-16 16:24:27 +08:00
friend class history_lru_node_t ;
friend class history_tests_t ;
2012-02-06 08:42:24 +08:00
private :
2012-02-16 16:24:27 +08:00
explicit history_item_t ( const wcstring & ) ;
explicit history_item_t ( const wcstring & , time_t , const path_list_t & paths = path_list_t ( ) ) ;
2012-03-02 06:56:34 +08:00
/** Attempts to merge two compatible history items together */
bool merge ( const history_item_t & item ) ;
2012-02-06 08:42:24 +08:00
/** The actual contents of the entry */
wcstring contents ;
2012-03-02 06:56:34 +08:00
2012-02-06 08:42:24 +08:00
/** Original creation time for the entry */
2012-02-06 12:54:41 +08:00
time_t creation_timestamp ;
2012-02-06 08:42:24 +08:00
2012-02-16 03:33:41 +08:00
/** Paths that we require to be valid for this item to be autosuggested */
path_list_t required_paths ;
2012-02-06 08:42:24 +08:00
public :
const wcstring & str ( ) const { return contents ; }
bool empty ( ) const { return contents . empty ( ) ; }
2012-02-06 15:22:18 +08:00
2012-02-07 02:52:13 +08:00
/* Whether our contents matches a search term. */
bool matches_search ( const wcstring & term , enum history_search_type_t type ) const ;
2012-02-06 15:22:18 +08:00
2012-02-06 12:54:41 +08:00
time_t timestamp ( ) const { return creation_timestamp ; }
2012-02-16 16:24:27 +08:00
const path_list_t & get_required_paths ( ) const { return required_paths ; }
bool operator = = ( const history_item_t & other ) const {
return contents = = other . contents & &
creation_timestamp = = other . creation_timestamp & &
required_paths = = other . required_paths ;
}
2012-06-16 07:22:37 +08:00
} ;
2012-06-05 12:24:42 +08:00
2012-06-16 07:22:37 +08:00
/* The type of file that we mmap'd */
enum history_file_type_t {
history_type_unknown ,
history_type_fish_2_0 ,
history_type_fish_1_x
2012-02-06 08:42:24 +08:00
} ;
class history_t {
2012-02-16 16:24:27 +08:00
friend class history_tests_t ;
2012-02-06 08:42:24 +08:00
private :
/** No copying */
history_t ( const history_t & ) ;
history_t & operator = ( const history_t & ) ;
/** Private creator */
history_t ( const wcstring & pname ) ;
2012-02-16 16:24:27 +08:00
/** Privately add an item */
void add ( const history_item_t & item ) ;
2012-02-06 08:42:24 +08:00
/** Destructor */
~ history_t ( ) ;
/** Lock for thread safety */
pthread_mutex_t lock ;
2012-02-16 16:24:27 +08:00
/** Internal function */
void clear_file_state ( ) ;
2012-02-06 08:42:24 +08:00
/** The name of this list. Used for picking a suitable filename and for switching modes. */
const wcstring name ;
/** New items. */
std : : vector < history_item_t > new_items ;
2012-06-05 12:24:42 +08:00
2012-06-16 07:22:37 +08:00
/** Deleted item contents. */
std : : set < wcstring > deleted_items ;
2012-06-05 12:24:42 +08:00
2012-03-04 15:10:15 +08:00
/** How many items we've added without saving */
size_t unsaved_item_count ;
2012-02-06 08:42:24 +08:00
/** The mmaped region for the history file */
const char * mmap_start ;
2012-06-16 07:22:37 +08:00
/** The size of the mmap'd region */
2012-02-06 08:42:24 +08:00
size_t mmap_length ;
2012-06-16 07:22:37 +08:00
/** The type of file we mmap'd */
history_file_type_t mmap_type ;
2012-03-02 06:56:34 +08:00
/** Timestamp of when this history was created */
const time_t birth_timestamp ;
/** Timestamp of last save */
2012-02-06 08:42:24 +08:00
time_t save_timestamp ;
void populate_from_mmap ( void ) ;
/** List of old items, as offsets into out mmap data */
2012-07-18 03:47:01 +08:00
std : : vector < size_t > old_item_offsets ;
2012-02-06 08:42:24 +08:00
/** Whether we've loaded old items */
bool loaded_old ;
/** Loads old if necessary */
2012-03-26 16:21:10 +08:00
bool load_old_if_needed ( void ) ;
2012-02-06 08:42:24 +08:00
2012-03-02 06:56:34 +08:00
/** Deletes duplicates in new_items. */
void compact_new_items ( ) ;
2012-02-06 12:54:41 +08:00
/** Saves history */
void save_internal ( ) ;
2012-06-16 07:22:37 +08:00
/* Versioned decoding */
static history_item_t decode_item_fish_2_0 ( const char * base , size_t len ) ;
static history_item_t decode_item_fish_1_x ( const char * base , size_t len ) ;
static history_item_t decode_item ( const char * base , size_t len , history_file_type_t type ) ;
2012-02-16 16:24:27 +08:00
2012-02-06 08:42:24 +08:00
public :
/** Returns history with the given name, creating it if necessary */
static history_t & history_with_name ( const wcstring & name ) ;
2012-07-10 13:54:08 +08:00
/** Determines whether the history is empty. Unfortunately this cannot be const, since it may require populating the history. */
bool is_empty ( void ) ;
2012-02-06 08:42:24 +08:00
/** Add a new history item to the end */
2012-02-16 03:33:41 +08:00
void add ( const wcstring & str , const path_list_t & valid_paths = path_list_t ( ) ) ;
2012-06-05 12:24:42 +08:00
/** Remove a history item */
void remove ( const wcstring & str ) ;
2012-02-16 03:33:41 +08:00
/** Add a new history item to the end */
void add_with_file_detection ( const wcstring & str ) ;
2012-02-06 08:42:24 +08:00
/** Saves history */
void save ( ) ;
2012-02-16 16:24:27 +08:00
/** Irreversibly clears history */
void clear ( ) ;
2012-06-16 07:22:37 +08:00
/** Populates from a bash history file */
void populate_from_bash ( FILE * f ) ;
2012-03-20 02:52:18 +08:00
/* Gets all the history into a string with ARRAY_SEP_STR. This is intended for the $history environment variable. This may be long! */
void get_string_representation ( wcstring & str , const wcstring & separator ) ;
2012-02-16 16:24:27 +08:00
/** Return the specified history at the specified index. 0 is the index of the current commandline. (So the most recent item is at index 1.) */
2012-02-06 08:42:24 +08:00
history_item_t item_at_index ( size_t idx ) ;
2012-06-16 07:22:37 +08:00
2012-06-05 12:24:42 +08:00
bool is_deleted ( const history_item_t & item ) const ;
2012-02-06 08:42:24 +08:00
} ;
class history_search_t {
/** The history in which we are searching */
history_t * history ;
2012-02-06 14:30:42 +08:00
2012-02-07 02:52:13 +08:00
/** Our type */
enum history_search_type_t search_type ;
2012-02-06 14:30:42 +08:00
/** Our list of previous matches as index, value. The end is the current match. */
2012-02-16 16:24:27 +08:00
typedef std : : pair < size_t , history_item_t > prev_match_t ;
2012-07-18 03:47:01 +08:00
std : : vector < prev_match_t > prev_matches ;
2012-02-06 14:30:42 +08:00
/** Returns yes if a given term is in prev_matches. */
bool match_already_made ( const wcstring & match ) const ;
2012-02-06 08:42:24 +08:00
/** The search term */
wcstring term ;
2012-02-07 03:52:24 +08:00
/** Additional strings to skip (sorted) */
wcstring_list_t external_skips ;
bool should_skip_match ( const wcstring & str ) const ;
2012-02-06 14:30:42 +08:00
public :
2012-02-16 16:24:27 +08:00
/** Gets the search term */
const wcstring & get_term ( ) const { return term ; }
2012-02-06 08:42:24 +08:00
2012-02-07 03:52:24 +08:00
/** Sets additional string matches to skip */
void skip_matches ( const wcstring_list_t & skips ) ;
2012-02-06 08:42:24 +08:00
/** Finds the next search term (forwards in time). Returns true if one was found. */
bool go_forwards ( void ) ;
/** Finds the previous search result (backwards in time). Returns true if one was found. */
bool go_backwards ( void ) ;
/** Goes to the end (forwards) */
void go_to_end ( void ) ;
2012-02-06 15:22:18 +08:00
/** Returns if we are at the end. We start out at the end. */
bool is_at_end ( void ) const ;
2012-02-06 08:42:24 +08:00
/** Goes to the beginning (backwards) */
void go_to_beginning ( void ) ;
2012-02-16 16:24:27 +08:00
/** Returns the current search result item. asserts if there is no current item. */
history_item_t current_item ( void ) const ;
/** Returns the current search result item contents. asserts if there is no current item. */
wcstring current_string ( void ) const ;
2012-02-06 08:42:24 +08:00
/** Constructor */
2012-02-07 02:52:13 +08:00
history_search_t ( history_t & hist , const wcstring & str , enum history_search_type_t type = HISTORY_SEARCH_TYPE_CONTAINS ) :
2012-02-06 08:42:24 +08:00
history ( & hist ) ,
2012-02-07 02:52:13 +08:00
search_type ( type ) ,
2012-02-06 14:30:42 +08:00
term ( str )
2012-02-06 12:54:41 +08:00
{ }
2012-02-06 08:42:24 +08:00
/* Default constructor */
history_search_t ( ) :
history ( ) ,
2012-02-07 02:52:13 +08:00
search_type ( HISTORY_SEARCH_TYPE_CONTAINS ) ,
2012-02-06 14:30:42 +08:00
term ( )
2012-02-06 12:54:41 +08:00
{ }
2012-02-06 08:42:24 +08:00
} ;
2005-10-04 23:11:39 +08:00
2005-09-20 21:26:39 +08:00
/**
2006-02-06 23:08:10 +08:00
Init history library . The history file won ' t actually be loaded
until the first time a history search is performed .
2005-09-20 21:26:39 +08:00
*/
void history_init ( ) ;
/**
2012-02-06 08:42:24 +08:00
Saves the new history to disc .
2005-09-20 21:26:39 +08:00
*/
void history_destroy ( ) ;
/**
Perform sanity checks
*/
void history_sanity_check ( ) ;
2012-02-16 16:24:27 +08:00
/* A helper class for threaded detection of paths */
struct file_detection_context_t {
/* Constructor */
file_detection_context_t ( history_t * hist , const wcstring & cmd ) ;
/* Determine which of potential_paths are valid, and put them in valid_paths */
int perform_file_detection ( ) ;
/* The history associated with this context */
history_t * history ;
/* The command */
wcstring command ;
/* When the command was issued */
time_t when ;
/* The working directory at the time the command was issued */
wcstring working_directory ;
/* Paths to test */
path_list_t potential_paths ;
/* Paths that were found to be valid */
path_list_t valid_paths ;
/* Performs file detection. Returns 1 if every path in potential_paths is valid, 0 otherwise. If test_all is true, tests every path; otherwise stops as soon as it reaches an invalid path. */
int perform_file_detection ( bool test_all ) ;
/* Determine whether the given paths are all valid */
bool paths_are_valid ( const path_list_t & paths ) ;
} ;
2005-10-04 23:11:39 +08:00
# endif