xaizek / pipedial (License: GPLv3 only) (since 2019-01-08)
One more tool for selecting something in console.
Commit ae261a73cb7919615d421856f88ce9417ef0d5c2

Add support for completion on the prompt
Author: xaizek
Author date (UTC): 2019-03-23 15:50
Committer name: xaizek
Committer date (UTC): 2019-03-23 15:50
Parent(s): ece70b3af838304bda33b3dea61c226f96f7e103
Signing key: 99DC5E4DB05F6BE2
Tree: e7b753da137fb343d205a23c1ee0190b178aed7b
File Lines added Lines deleted
src/PromptRequest.cpp 42 0
src/PromptRequest.hpp 10 0
File src/PromptRequest.cpp changed (mode: 100644) (index 80efa15..3e637d7)
... ... PromptRequest::setOnInputChanged(inputChangedFunc newOnInputChanged)
107 107 onInputChanged = std::move(newOnInputChanged); onInputChanged = std::move(newOnInputChanged);
108 108 } }
109 109
110 void
111 PromptRequest::setCompleter(completerFunc newCompleter)
112 {
113 completer = std::move(newCompleter);
114 }
115
110 116 PromptResult PromptResult
111 117 PromptRequest::prompt(const std::wstring &invitation, PromptRequest::prompt(const std::wstring &invitation,
112 118 const std::wstring &initial) const std::wstring &initial)
 
... ... PromptRequest::prompt(const std::wstring &invitation,
125 131 return nullptr; return nullptr;
126 132 }; };
127 133
134 if (completer) {
135 rl_attempted_completion_function = [](const char text[], int start,
136 int end) {
137 return instance->rlComplete(text, start, end);
138 };
139 } else {
140 rl_attempted_completion_function = nullptr;
141 }
142
128 143 rl_startup_hook = []() { instance->rlStartup(); return 0; }; rl_startup_hook = []() { instance->rlStartup(); return 0; };
129 144 rl_redisplay_function = []() { instance->rlRedisplay(); }; rl_redisplay_function = []() { instance->rlRedisplay(); };
130 145 rl_input_available_hook = []() { return instance->rlInputAvailable(); }; rl_input_available_hook = []() { return instance->rlInputAvailable(); };
 
... ... PromptRequest::updateScreen()
256 271 screen.resize(); screen.resize();
257 272 screen.draw(); screen.draw();
258 273 } }
274
275 char **
276 PromptRequest::rlComplete(const char text[], int start, int /*end*/)
277 {
278 std::string prefix(rl_line_buffer, rl_line_buffer + start);
279 std::vector<std::wstring> completions = completer(cursed::toWide(prefix),
280 cursed::toWide(text));
281 if (completions.empty()) {
282 return nullptr;
283 }
284
285 const std::size_t n = completions.size();
286 auto array = static_cast<char **>(std::malloc(sizeof(char *)*(n + 1U)));
287 for (unsigned int i = 0U; i < n; ++i) {
288 try {
289 array[i] = strdup(cursed::toNarrow(completions[i]).c_str());
290 } catch (...) {
291 for (unsigned int j = 0U; j < i; ++j) {
292 std::free(array[j]);
293 }
294 std::free(array);
295 throw;
296 }
297 }
298 array[n] = nullptr;
299 return array;
300 }
File src/PromptRequest.hpp changed (mode: 100644) (index f75531b..51b0cca)
... ... class PromptRequest
63 63 { {
64 64 // Type of callback function invoked when input is changed. // Type of callback function invoked when input is changed.
65 65 using inputChangedFunc = std::function<void(const std::wstring &newInput)>; using inputChangedFunc = std::function<void(const std::wstring &newInput)>;
66 // Type of callback function invoked to generate completions.
67 typedef std::function<
68 std::vector<std::wstring>(const std::wstring &prefix,
69 const std::wstring &what)
70 > completerFunc;
66 71
67 72 public: public:
68 73 // Remembers arguments and makes cursor visible. // Remembers arguments and makes cursor visible.
 
... ... public:
84 89 public: public:
85 90 // Sets callback to be invoked when input is changed. // Sets callback to be invoked when input is changed.
86 91 void setOnInputChanged(inputChangedFunc newOnInputChanged); void setOnInputChanged(inputChangedFunc newOnInputChanged);
92 // Sets callback to be invoked to perform completion.
93 void setCompleter(completerFunc newCompleter);
87 94
88 95 // Performs the prompting. Blocks until it's done. Might throw // Performs the prompting. Blocks until it's done. Might throw
89 96 // `std::runtime_error`. // `std::runtime_error`.
 
... ... private:
99 106 int rlInputAvailable(); int rlInputAvailable();
100 107 // Readline's callback for getting input. // Readline's callback for getting input.
101 108 int rlGetcFunction(); int rlGetcFunction();
109 // Readline's callback for getting completions.
110 char ** rlComplete(const char text[], int start, int end);
102 111
103 112 // Reads more input if `inputBuf` is empty populating it as a result. After // Reads more input if `inputBuf` is empty populating it as a result. After
104 113 // the function is invoked `inputBuf` is never empty. // the function is invoked `inputBuf` is never empty.
 
... ... private:
112 121 cursed::Screen &screen; // Screen manager. cursed::Screen &screen; // Screen manager.
113 122 cursed::Prompt &promptArea; // Widget that displays the prompt. cursed::Prompt &promptArea; // Widget that displays the prompt.
114 123 inputChangedFunc onInputChanged; // Callback invoked when input is changed. inputChangedFunc onInputChanged; // Callback invoked when input is changed.
124 completerFunc completer; // Completion generator.
115 125 std::string initialValue; // Initial value of the prompt. std::string initialValue; // Initial value of the prompt.
116 126 std::string lastValue; // Last seen input value. std::string lastValue; // Last seen input value.
117 127 std::vector<int> inputBuf; // Input queue. std::vector<int> inputBuf; // Input queue.
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/pipedial

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/pipedial

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master