#ifndef REPLXX_HISTORY_HXX_INCLUDED #define REPLXX_HISTORY_HXX_INCLUDED 1 #include #include #include "unicodestring.hxx" #include "utf8string.hxx" #include "conversion.hxx" #include "util.hxx" namespace std { template<> struct hash { std::size_t operator()( replxx::UnicodeString const& us_ ) const { std::size_t h( 0 ); char32_t const* p( us_.get() ); char32_t const* e( p + us_.length() ); while ( p != e ) { h *= 31; h += *p; ++ p; } return ( h ); } }; } namespace replxx { class History { public: class Entry { std::string _timestamp; UnicodeString _text; public: Entry( std::string const& timestamp_, UnicodeString const& text_ ) : _timestamp( timestamp_ ) , _text( text_ ) { } std::string const& timestamp( void ) const { return ( _timestamp ); } UnicodeString const& text( void ) const { return ( _text ); } bool operator < ( Entry const& other_ ) const { return ( _timestamp < other_._timestamp ); } }; typedef std::list entries_t; typedef std::unordered_map locations_t; private: entries_t _entries; locations_t _locations; int _maxSize; entries_t::const_iterator _current; entries_t::const_iterator _yankPos; /* * _previous and _recallMostRecent are used to allow * HISTORY_NEXT action (a down-arrow key) to have a special meaning * if invoked after a line from history was accepted without * any modification. * Special meaning is: a down arrow shall jump to the line one * after previously accepted from history. */ entries_t::const_iterator _previous; bool _recallMostRecent; bool _unique; public: History( void ); void add( UnicodeString const& line, std::string const& when = now_ms_str() ); bool save( std::string const& filename, bool ); bool load( std::string const& filename ); void clear( void ); void set_max_size( int len ); void set_unique( bool unique_ ) { _unique = unique_; remove_duplicates(); } void reset_yank_iterator(); bool next_yank_position( void ); void reset_recall_most_recent( void ) { _recallMostRecent = false; } void commit_index( void ) { _previous = _current; _recallMostRecent = true; } bool is_empty( void ) const { return ( _entries.empty() ); } void update_last( UnicodeString const& ); void drop_last( void ); bool is_last( void ) const; bool move( bool ); UnicodeString const& current( void ) const { return ( _current->text() ); } UnicodeString const& yank_line( void ) const { return ( _yankPos->text() ); } void jump( bool, bool = true ); bool common_prefix_search( UnicodeString const&, int, bool ); int size( void ) const { return ( static_cast( _entries.size() ) ); } Replxx::HistoryScan::impl_t scan( void ) const; void save_pos( void ); void restore_pos( void ); private: History( History const& ) = delete; History& operator = ( History const& ) = delete; bool move( entries_t::const_iterator&, int, bool = false ) const; entries_t::const_iterator moved( entries_t::const_iterator, int, bool = false ) const; void erase( entries_t::const_iterator ); void trim_to_max_size( void ); void remove_duplicate( UnicodeString const& ); void remove_duplicates( void ); bool do_load( std::string const& ); entries_t::const_iterator last( void ) const; void sort( void ); void reset_iters( void ); }; class Replxx::HistoryScanImpl { History::entries_t const& _entries; History::entries_t::const_iterator _it; mutable Utf8String _utf8Cache; mutable Replxx::HistoryEntry _entryCache; mutable bool _cacheValid; public: HistoryScanImpl( History::entries_t const& ); bool next( void ); Replxx::HistoryEntry const& get( void ) const; }; } #endif