Skip to content

Commit

Permalink
Merge pull request #212 from pit-ray/add-186
Browse files Browse the repository at this point in the history
Tab Completion for Commands
  • Loading branch information
pit-ray authored Jan 4, 2024
2 parents f608c73 + 2673c61 commit 6a196a8
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 45 deletions.
14 changes: 13 additions & 1 deletion docs/cheat_sheet/functions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ disable_anchors: true
## Mode

### **`<to_command>`**
Enter the command mode. Generally, this command is called with `:`. In the command mode, the typed characters are displayed on the virtual command line, the command can be executed with the `<enter>` key, and you can delete characters with `<bs>`. You can also use the `<up>` and `<down>` keys to move thr class="dash"ough the executed history.
Enter the command mode, which is generally called with `:`.
In the command mode, the typed characters are displayed on the virtual command line.
You can operate the virtual command line as shown in the following table.

|**Key**|**Operation**|
|:---:|:---:|
|`<enter>`|Execute the current command|
|`<bs>`|Delete characters|
|`<up>`|Backward history|
|`<down>`|Forward history|
|`<tab>`|Complete commands|

<br>

<p align="center">
<img src="https://pit-ray.github.io/win-vind/imgs/cmdline_demo.gif" class="img-fluid"/>
Expand Down
7 changes: 1 addition & 6 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,4 @@ endif()


link_wxWidgets(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME}
psapi
dwmapi
userenv
icuuc
)
target_link_libraries(${PROJECT_NAME} psapi dwmapi userenv icuuc)
123 changes: 115 additions & 8 deletions src/bind/mode/command_mode.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
#include "command_mode.hpp"

#include <algorithm>
#include <memory>
#include <sstream>
#include <windows.h>

#include <vector>

#include "bind/bindedfunc.hpp"
#include "core/autocmd.hpp"
#include "core/background.hpp"
#include "core/cmdunit.hpp"
#include "core/errlogger.hpp"
#include "core/inputgate.hpp"
#include "core/inputhub.hpp"
Expand All @@ -26,6 +20,15 @@
#include "util/def.hpp"


#include <algorithm>
#include <memory>
#include <set>
#include <sstream>
#include <windows.h>

#include <vector>


namespace
{
using namespace vind ;
Expand Down Expand Up @@ -86,13 +89,20 @@ namespace vind
core::Background bg_ ;
int hist_idx_ ;

std::vector<std::vector<core::CmdUnit::SPtr>> candidates_ ;
std::vector<std::vector<std::string>> print_candidates_ ;
int candidate_idx_ ;

Impl()
: hists_(),
bg_(opt::ref_global_options_bynames(
opt::AsyncUIACacheBuilder().name(),
opt::VCmdLine().name()
)),
hist_idx_(0)
hist_idx_(0),
candidates_(),
print_candidates_(),
candidate_idx_(0)
{}

void update_cmdline_display() {
Expand Down Expand Up @@ -183,6 +193,95 @@ namespace vind
return result ;
}

void complement_command() {
if(candidates_.empty()) { // find candidates
auto& ihub = core::InputHub::get_instance() ;
auto solver = ihub.get_solver(core::Mode::COMMAND) ;

// Load the current command
auto& latest = hists_.back() ;

// Match with matchers
solver->reset_state() ;
for(std::size_t i = 0 ; i < latest->size() ; i ++) {
for(auto& unit : latest->fetched_logs_[i]) {
solver->map_command_from(*unit, false) ;
}
}

std::set<std::string> candidate_set ;
auto matchers = solver->get_trigger_matchers() ;
for(auto matcher : matchers) {
if(!matcher->is_rejected()) {
const auto& trigger_cmd = matcher->get_command() ;
std::vector<core::CmdUnit::SPtr> cmd_no_args ;
std::vector<std::string> print_cmd_no_args ;

for(const auto& unit : trigger_cmd) {
bool break_flag = false ;
std::vector<core::CmdUnit::SPtr> cmd ;
std::stringstream ss ;
for(const auto& key : *unit) {
// For simplicity, ignore a command with arguments such as `:! <any>`.
// It just considers the pure command like `:!`.
auto uni = core::keycode_to_unicode(key, *unit) ;
if(uni.empty() || uni == " ") {
break_flag = true ;
break ;
}
ss << uni ;
}
if(break_flag) {
break ;
}
cmd_no_args.push_back(unit) ;
print_cmd_no_args.push_back(ss.str()) ;
}

std::string cmd_str ;
for(const auto& s : print_cmd_no_args) {
cmd_str += s ;
}

if(candidate_set.find(cmd_str) == candidate_set.end()) { // Avoid the duplicated candidates.
candidates_.push_back(std::move(cmd_no_args)) ;
print_candidates_.push_back(std::move(print_cmd_no_args)) ;
candidate_set.insert(std::move(cmd_str)) ;
}
}
}

// Show the candidates in the virtual command line.
if(!candidates_.empty()) {
std::stringstream ss ;
for(const auto& s : candidate_set) {
ss << ":" << s << " " ;
}
opt::VCmdLine::print(opt::StaticMessage(ss.str())) ;
}
candidate_idx_ = -1 ;

return ; // At the first time, show a list of candidates without selection.
}

// Rotate the candidates
candidate_idx_ = (candidate_idx_ + 1) % candidates_.size() ;

// Overwrite the latest command line with the candidate.
auto& latest = hists_.back() ;
latest->fetched_logs_.clear() ;
for(const auto& unit : candidates_[candidate_idx_]) {
latest->fetched_logs_.push_back({unit}) ;
}
latest->print_logs_ = print_candidates_[candidate_idx_] ;
update_cmdline_display() ;
}

void clear_candidates() {
candidates_.clear() ;
print_candidates_.clear() ;
}

void write_as_printable(const core::CmdUnit::SPtr& input) {
// Aggregate the printable keys into this vector from input and outputs.
std::vector<core::CmdUnit::SPtr> printables ;
Expand Down Expand Up @@ -285,11 +384,19 @@ namespace vind
pimpl->forward_history() ;
continue ;
}
if(input->is_containing(KEYCODE_TAB)) {
pimpl->complement_command() ;
continue ;
}
if(input->is_containing(KEYCODE_ENTER)) {
result = pimpl->decide() ;
break_flag = true ;
break ;
}

if(!pimpl->candidates_.empty()) {
pimpl->clear_candidates() ;
}
pimpl->write_as_printable(input) ;
} while(!ihub.is_empty_queue()) ;

Expand Down
Loading

0 comments on commit 6a196a8

Please sign in to comment.