Skip to content

Commit

Permalink
Shell: Improve tab completion behaviour
Browse files Browse the repository at this point in the history
A space is added if only one match is found, but we avoid adding
redundant spaces.

We complete "empty" tokens, i.e. when the cursor is at the start of the
line or in front of a space. For example:
    mkdir test
    cd test
    touch test
    chmod +x test
    export PATH=/home/anon/test
Now if you press tab, or space and then tab, you will get "test". Notice
that you also get a space.

Completion is now done relative to the cursor. You can enter two words
and then go back and complete the first one.
  • Loading branch information
willmcpherson2 authored and awesomekling committed Dec 11, 2019
1 parent 244e525 commit 4ae8d92
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 14 deletions.
40 changes: 27 additions & 13 deletions Shell/LineEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,8 @@ void LineEditor::cut_mismatching_chars(String& completion, const String& program
completion = completion.substring(0, i);
}

void LineEditor::tab_complete_first_token()
void LineEditor::tab_complete_first_token(const String& token)
{
String token = String::copy(m_buffer);

auto match = binary_search(m_path.data(), m_path.size(), token, [](const String& token, const String& program) -> int {
return strncmp(token.characters(), program.characters(), token.length());
});
Expand All @@ -122,15 +120,23 @@ void LineEditor::tab_complete_first_token()
// other program names starting with our token and cut off any mismatching
// characters.

bool seen_others = false;
int index = match - m_path.data();
for (int i = index - 1; i >= 0 && m_path[i].starts_with(token); --i)
for (int i = index - 1; i >= 0 && m_path[i].starts_with(token); --i) {
cut_mismatching_chars(completion, m_path[i], token.length());
for (int i = index + 1; i < m_path.size() && m_path[i].starts_with(token); ++i)
seen_others = true;
}
for (int i = index + 1; i < m_path.size() && m_path[i].starts_with(token); ++i) {
cut_mismatching_chars(completion, m_path[i], token.length());
seen_others = true;
}

if (token.length() == completion.length())
return;
insert(completion.substring(token.length(), completion.length() - token.length()));
// If we have characters to add, add them.
if (completion.length() > token.length())
insert(completion.substring(token.length(), completion.length() - token.length()));
// If we have a single match, we add a space, unless we already have one.
if (!seen_others && (m_cursor == (size_t)m_buffer.size() || m_buffer[(int)m_cursor] != ' '))
insert(' ');
}

String LineEditor::get_line(const String& prompt)
Expand Down Expand Up @@ -270,20 +276,28 @@ String LineEditor::get_line(const String& prompt)
}

if (ch == '\t') {
if (m_buffer.is_empty())
continue;
bool is_empty_token = m_cursor == 0 || m_buffer[(int)m_cursor - 1] == ' ';

int token_start = (int)m_cursor - 1;
if (!is_empty_token) {
while (token_start >= 0 && m_buffer[token_start] != ' ')
--token_start;
++token_start;
}

bool is_first_token = true;
for (const auto& character : m_buffer) {
if (isspace(character)) {
for (int i = token_start - 1; i >= 0; --i) {
if (m_buffer[i] != ' ') {
is_first_token = false;
break;
}
}

String token = is_empty_token ? String() : String(&m_buffer[token_start], m_cursor - (size_t)token_start);

// FIXME: Implement tab-completion for other tokens (paths).
if (is_first_token)
tab_complete_first_token();
tab_complete_first_token(token);

continue;
}
Expand Down
2 changes: 1 addition & 1 deletion Shell/LineEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class LineEditor {
void insert(const String&);
void insert(const char);
void cut_mismatching_chars(String& completion, const String& program, size_t token_length);
void tab_complete_first_token();
void tab_complete_first_token(const String&);
void vt_save_cursor();
void vt_restore_cursor();
void vt_clear_to_end_of_line();
Expand Down

0 comments on commit 4ae8d92

Please sign in to comment.