You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
6.9 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2019 Intel Corporation. All Rights Reserved.
#include "auto-complete.h"
#include <iostream>
#include <thread>
#include <algorithm>
#include <cmath>
using namespace std;
vector<string> auto_complete::search(const string& word) const
{
vector<string> finds;
for (auto it = _dictionary.begin(); it != _dictionary.end(); ++it)
{
it = find_if(it, _dictionary.end(), [&](string elemnt) -> bool {
return (elemnt.compare(0, word.size(), word) == 0) ? true : false;
});
if (it != _dictionary.end())
{
if (it->compare(word) == 0)
continue;
finds.push_back(it->substr(word.size(), it->size()));
}
else
{
break;
}
}
return finds;
}
auto_complete::auto_complete(set<string> dictionary, bool bypass)
: _dictionary(dictionary), _history_words_index(0), _num_of_chars2_in_line(0), _tab_index(0), _is_first_time_up_arrow(true), _bypass(bypass)
{}
string auto_complete::chars2_queue_to_string() const
{
auto temp_chars2_queue(_chars2_queue);
temp_chars2_queue.push_back('\0');
auto word = string(temp_chars2_queue.data());
return word;
}
string auto_complete::get_last_word(const string& line) const
{
auto index = line.find_last_of(' ');
if (index > line.size())
return line;
return line.substr(index + 1);
}
void auto_complete::backspace(const int num_of_backspaces)
{
for (auto i = 0; i < num_of_backspaces; ++i)
{
if (_num_of_chars2_in_line == 0)
break;
cout << '\b';
cout << BACKSLASH_ZERO;
cout << '\b';
if (_num_of_chars2_in_line != 0)
--_num_of_chars2_in_line;
if (!_chars2_queue.empty())
{
_chars2_queue.pop_back();
}
}
}
void auto_complete::handle_special_key(const vector<uint8_t>& chars)
{
auto up_arrow_key = vector<uint8_t>(UP_ARROW_KEY);
auto down_arrow_key = vector<uint8_t>(DOWN_ARROW_KEY);
if (up_arrow_key == chars && _history_words.size()) // Up arrow key
{
if (_history_words_index != 0 && !_is_first_time_up_arrow)
--_history_words_index;
_finds_vec.clear();
_tab_index = 0;
backspace(_num_of_chars2_in_line);
cout << _history_words[_history_words_index];
for (auto c : _history_words[_history_words_index])
{
_chars2_queue.push_back(c);
++_num_of_chars2_in_line;
}
if (_is_first_time_up_arrow)
{
_is_first_time_up_arrow = false;
}
}
else if (down_arrow_key == chars && _history_words.size()) // Down arrow key
{
if ((_history_words_index + 1) < _history_words.size())
++_history_words_index;
_finds_vec.clear();
_tab_index = 0;
backspace(_num_of_chars2_in_line);
cout << _history_words[_history_words_index];
for (auto c : _history_words[_history_words_index])
{
_chars2_queue.push_back(c);
++_num_of_chars2_in_line;
}
}
}
char auto_complete::getch_nolock(std::function <bool()> stop)
{
#if defined(_WIN32)
auto ch = static_cast<char>(_getch_nolock());
if (ch < 0)
{
vector<uint8_t> vec_ch = {static_cast<uint8_t>(_getch_nolock())};
handle_special_key(vec_ch);
return -1;
}
return ch;
#else
auto fd = fileno(stdin);
struct termios old_settings, new_settings;
tcgetattr(fd, &old_settings);
new_settings = old_settings;
new_settings.c_lflag &= (~ICANON & ~ECHO);
tcsetattr(fd, TCSANOW, &new_settings);
fd_set fds;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
while(!stop())
{
FD_ZERO(&fds);
FD_SET(fd, &fds);
auto res = select(fd+1, &fds, NULL, NULL, &tv );
if((res > 0) && (FD_ISSET(fd, &fds)))
{
uint8_t ch[10];
auto num_of_chars = read(fd, ch, 10 );
tcsetattr(fd, TCSAFLUSH, &old_settings );
if (num_of_chars == 1)
return ch[0];
//TODO: Arrow keys
vector<uint8_t> vec_ch;
for (auto i = 0; i < num_of_chars; ++i)
vec_ch.push_back(ch[i]);
handle_special_key(vec_ch);
return -1;
}
tcsetattr(fd, TCSAFLUSH, &old_settings );
return res;
}
return -1;
#endif
}
string auto_complete::get_line(std::function <bool()> to_stop)
{
if (_bypass)
{
string res;
std::getline(std::cin, res);
return res;
}
while (!to_stop())
{
auto ch = getch_nolock();
if (ch == -1)
{
cout.clear();
cin.clear();
fflush(nullptr);
continue;
}
if (ch == '\t')
{
if (_finds_vec.empty())
{
_finds_vec = search(get_last_word(chars2_queue_to_string()));
}
if (_finds_vec.empty() || _tab_index == _finds_vec.size())
continue;
if (_tab_index != 0)
{
backspace(int(_finds_vec[_tab_index - 1].length()));
}
auto vec_word = _finds_vec[_tab_index++];
cout << vec_word;
for (auto c : vec_word)
{
_chars2_queue.push_back(c);
++_num_of_chars2_in_line;
}
}
else if (ch == ' ')
{
_finds_vec.clear();
_tab_index = 0;
_chars2_queue.push_back(' ');
++_num_of_chars2_in_line;
cout << ch;
}
else if (ch == BACKSPACE)
{
_finds_vec.clear();
_tab_index = 0;
backspace(1);
}
else if (ch == NEW_LINE)
{
_finds_vec.clear();
_tab_index = 0;
cout << '\n';
cout << ch;
auto str = chars2_queue_to_string();
if (str.compare(""))
{
_history_words.push_back(str);
_history_words_index = int(_history_words.size()) - 1;
}
_is_first_time_up_arrow = true;
}
else if (isprint(ch))
{
_finds_vec.clear();
_tab_index = 0;
cout << ch;
_chars2_queue.push_back(ch);
++_num_of_chars2_in_line;
}
else if(ch != 0)
getch_nolock(); // TODO
if (ch == NEW_LINE)
{
auto ret_str = chars2_queue_to_string();
_chars2_queue.clear();
_num_of_chars2_in_line = 0;
return ret_str;
}
cout.clear();
cin.clear();
fflush(nullptr);
}
_chars2_queue.clear();
_num_of_chars2_in_line = 0;
cout.clear();
cin.clear();
fflush(nullptr);
return std::string{};
}