aboutsummaryrefslogtreecommitdiffhomepage
path: root/history.h
blob: b4fbb326c1a8e0c204bb0c1410e5e5288c37c675 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/** \file history.h
  Prototypes for history functions, part of the user interface.
*/

#ifndef FISH_HISTORY_H
#define FISH_HISTORY_H

#include <wchar.h>
#include "common.h"
#include "pthread.h"
#include <vector>
#include <deque>
#include <utility>
#include <tr1/memory>
#include <set>
using std::tr1::shared_ptr;

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
};

class history_item_t {
    friend class history_t;

    private:
    history_item_t(const wcstring &);
    history_item_t(const wcstring &, time_t);

	/** The actual contents of the entry */
	wcstring contents;
    	
	/** Original creation time for the entry */
	time_t creation_timestamp;
    
    public:
    const wcstring &str() const { return contents; }
    bool empty() const { return contents.empty(); }
    
    /* 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; }
    
    bool write_to_file(FILE *f) const;
};

class history_t {
private:
    /** No copying */
    history_t(const history_t&);
    history_t &operator=(const history_t&);

    /** Private creator */
    history_t(const wcstring &pname);
    
    /** Destructor */
    ~history_t();

    /** Lock for thread safety */
    pthread_mutex_t lock;

	/** 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;
    
	/** The mmaped region for the history file */
	const char *mmap_start;

	/** The size of the mmaped region */
	size_t mmap_length;

	/**
	   Timestamp of last save
	*/
	time_t save_timestamp;
    
    static history_item_t decode_item(const char *ptr, size_t len);
    
    void populate_from_mmap(void);
    
    /** List of old items, as offsets into out mmap data */
    std::vector<size_t> old_item_offsets;
    
    /** Whether we've loaded old items */
    bool loaded_old;
    
    /** Loads old if necessary */
    void load_old_if_needed(void);
    
    /** Saves history */
    void save_internal();
    
public:
    /** Returns history with the given name, creating it if necessary */
    static history_t & history_with_name(const wcstring &name);
    
    /** Add a new history item to the end */
    void add(const wcstring &str);
    
    /** Saves history */
    void save();
    
    /** Return the specified history at the specified index. 0 is the index of the current commandline. */
    history_item_t item_at_index(size_t idx);
};

class history_search_t {

    /** The history in which we are searching */
    history_t * history;
    
    /** Our type */
    enum history_search_type_t search_type;
    
    /** Our list of previous matches as index, value. The end is the current match. */
    typedef std::pair<size_t, wcstring> prev_match_t;
    std::deque<prev_match_t> prev_matches;

    /** Returns yes if a given term is in prev_matches. */
    bool match_already_made(const wcstring &match) const;

    /** The search term */
    wcstring term;
    
    /** Additional strings to skip (sorted) */
    wcstring_list_t external_skips;
    
    bool should_skip_match(const wcstring &str) const;
    
    public:

    /** Sets additional string matches to skip */
    void skip_matches(const wcstring_list_t &skips);

    /** 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);
    
    /** Returns if we are at the end. We start out at the end. */
    bool is_at_end(void) const;
    
    /** Goes to the beginning (backwards) */
    void go_to_beginning(void);
    
    /** Returns the current search result. asserts if there is no current item. */
    wcstring current_item(void) const;

    /** Constructor */
    history_search_t(history_t &hist, const wcstring &str, enum history_search_type_t type = HISTORY_SEARCH_TYPE_CONTAINS) :
        history(&hist),
        search_type(type),
        term(str)
    {}
    
    /* Default constructor */
    history_search_t() :
        history(),
        search_type(HISTORY_SEARCH_TYPE_CONTAINS),
        term()
    {}
    
};



/**
   Init history library. The history file won't actually be loaded
   until the first time a history search is performed.
*/
void history_init();

/**
   Saves the new history to disc.
*/
void history_destroy();

/**
   Perform sanity checks
*/
void history_sanity_check();

#endif