/* * Copyright (c) 2019 Stefan Strobel * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * @file shellmatta_autocomplete.c * @brief autocomplete function of shellmatta * @author Stefan Strobel */ /** * @addtogroup shellmatta_autocomplete * @{ */ #include "shellmatta.h" #include "shellmatta_autocomplete.h" #include "shellmatta_utils.h" #include #include /** * @brief searches the registered commands for matching ones and prints * the common part of all matching commands on the output * if called twice all matching commands are printed * @param[in] inst pointer to a shellmatta instance */ void autocomplete_run(shellmatta_instance_t *inst) { shellmatta_cmd_t *cmd = inst->cmdList; char *tempCmd = NULL; uint32_t minLen = 0u; uint32_t sizeDiff = 0u; bool exactMatch = true; uint32_t printedLen = 0u; uint32_t tempCursor = 0u; /** -# increase the tab counter to print all matching commands next time */ inst->tabCounter++; /** -# on douple tab show all matching commands */ if (1u < inst->tabCounter) { inst->tabCounter = 0u; /** -# loop through all registered commands */ while (NULL != cmd) { /** -# check if command matches the input */ if( (strlen(cmd->cmd) >= inst->cursor) && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor))) { /** -# add newline on first find */ if(0u == printedLen) { inst->write("\r\n", 2u); } inst->write(cmd->cmd, strlen(cmd->cmd)); printedLen += strlen(cmd->cmd); inst->write(" ", 4u); printedLen += 4u; } /** -# check if command alias matches the input */ if( (strlen(cmd->cmdAlias) >= inst->cursor) && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor))) { /** -# add newline on first find */ if(0u == printedLen) { inst->write("\r\n", 2u); } inst->write(cmd->cmdAlias, strlen(cmd->cmdAlias)); printedLen += strlen(cmd->cmdAlias); inst->write(" ", 4u); printedLen += 4u; } cmd = cmd->next; } /** -# print input again if a commands was found */ if(printedLen > 0u) { utils_writeEcho(inst, "\r\n", 2u); utils_writeEcho(inst, inst->prompt, strlen(inst->prompt)); utils_writeEcho(inst, inst->buffer, inst->inputCount); tempCursor = inst->cursor; inst->cursor = inst->inputCount; utils_rewindCursor(inst, inst->inputCount - tempCursor); } } /** -# on single tab autocomplete as far as possible */ else if(0u != inst->cursor) { /** -# loop through all registered commands */ while (NULL != cmd) { /** -# check if command matches the input */ if( (strlen(cmd->cmd) >= inst->cursor) && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor))) { /** -# store first match */ if(NULL == tempCmd) { tempCmd = cmd->cmd; minLen = strlen(cmd->cmd); } /** -# find common part of the matching commands */ else { exactMatch = false; minLen = SHELLMATTA_MIN(strlen(cmd->cmd), minLen); for(uint32_t i = 0u; i < minLen; i++) { if(cmd->cmd[i] != tempCmd[i]) { minLen = i; } } } } /** -# check if command Alias matches the input */ if( (strlen(cmd->cmdAlias) >= inst->cursor) && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor))) { /** -# store first match */ if(NULL == tempCmd) { tempCmd = cmd->cmdAlias; minLen = strlen(cmd->cmdAlias); } /** -# find common part of the matches */ else { exactMatch = false; minLen = SHELLMATTA_MIN(strlen(cmd->cmdAlias), minLen); for(uint32_t i = 0u; i < minLen; i++) { if(cmd->cmdAlias[i] != tempCmd[i]) { minLen = i; } } } } cmd = cmd->next; } /** -# autocomplete found command */ if(NULL != tempCmd) { /** -# calculate the size of the command to be inserted */ sizeDiff = minLen - inst->cursor; /** -# copy the found part into the buffer and display it */ utils_insertChars(inst, &(tempCmd[inst->cursor]), sizeDiff); /** -# on exact match there is no need to double Tab to display all */ if(true == exactMatch) { inst->tabCounter = 0u; } } } else { /* nothing to do here */ } } /** * @} */