fish-shell/history.h

321 lines
8.3 KiB
C
Raw Normal View History

/** \file history.h
Prototypes for history functions, part of the user interface.
*/
#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>
#include <list>
#include <set>
2012-02-06 08:42:24 +08:00
typedef std::vector<wcstring> path_list_t;
enum history_search_type_t
{
2012-02-07 02:52:13 +08:00
/** The history searches for strings containing the given string */
HISTORY_SEARCH_TYPE_CONTAINS,
2012-02-07 02:52:13 +08:00
/** The history searches for strings starting with the given string */
HISTORY_SEARCH_TYPE_PREFIX
};
class history_item_t
{
2012-02-06 08:42:24 +08:00
friend class history_t;
friend class history_lru_node_t;
friend class history_tests_t;
2012-02-06 08:42:24 +08:00
private:
explicit history_item_t(const wcstring &);
explicit history_item_t(const wcstring &, time_t, const path_list_t &paths = path_list_t());
/** 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;
/** Original creation time for the entry */
time_t creation_timestamp;
/** Paths that we require to be valid for this item to be autosuggested */
path_list_t required_paths;
public:
const wcstring &str() const
{
return contents;
}
bool empty() const
{
return contents.empty();
}
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;
time_t timestamp() const
{
return creation_timestamp;
}
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-05 12:24:42 +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
{
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);
/** 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;
/** 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;
/** Deleted item contents. */
std::set<wcstring> deleted_items;
2012-06-05 12:24:42 +08:00
/** How many items we've added without saving */
size_t unsaved_item_count;
2012-06-05 12:24:42 +08:00
/** The mmaped region for the history file */
const char *mmap_start;
2012-02-06 08:42:24 +08:00
/** The size of the mmap'd region */
size_t mmap_length;
2012-02-06 08:42:24 +08:00
/** The type of file we mmap'd */
history_file_type_t mmap_type;
/** Timestamp of when this history was created */
const time_t birth_timestamp;
/** Timestamp of last save */
time_t save_timestamp;
2012-02-06 08:42:24 +08:00
void populate_from_mmap(void);
2012-02-06 08:42:24 +08:00
/** List of old items, as offsets into out mmap data */
std::vector<size_t> old_item_offsets;
2012-02-06 08:42:24 +08:00
/** Whether we've loaded old items */
bool loaded_old;
2012-02-06 08:42:24 +08:00
/** Loads old if necessary */
bool load_old_if_needed(void);
/** Deletes duplicates in new_items. */
void compact_new_items();
2012-02-06 12:54:41 +08:00
/** Saves history */
void save_internal();
/* 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-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);
/** 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 */
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);
/** 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();
/** Irreversibly clears history */
void clear();
/** Populates from a bash history file */
void populate_from_bash(FILE *f);
/* 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);
/** 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-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
{
2012-02-06 08:42:24 +08:00
/** The history in which we are searching */
history_t * history;
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. */
typedef std::pair<size_t, history_item_t> prev_match_t;
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;
/** Additional strings to skip (sorted) */
wcstring_list_t external_skips;
bool should_skip_match(const wcstring &str) const;
public:
/** Gets the search term */
const wcstring &get_term() const
{
return term;
}
2012-02-06 08:42: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);
2012-02-06 08:42:24 +08:00
/** Finds the previous search result (backwards in time). Returns true if one was found. */
bool go_backwards(void);
2012-02-06 08:42:24 +08:00
/** Goes to the end (forwards) */
void go_to_end(void);
/** 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);
/** 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
};
/**
Init history library. The history file won't actually be loaded
until the first time a history search is performed.
*/
void history_init();
/**
2012-02-06 08:42:24 +08:00
Saves the new history to disc.
*/
void history_destroy();
/**
Perform sanity checks
*/
void history_sanity_check();
/* 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);
};
#endif