shellmatta/src/shellmatta_autocomplete.c

179 lines
5.9 KiB
C
Raw Normal View History

/*
* Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
*
* 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 <stefan.strobel@shimatta.net>
*/
/**
* @addtogroup shellmatta_autocomplete
* @{
*/
#include "shellmatta.h"
#include "shellmatta_autocomplete.h"
#include "shellmatta_utils.h"
#include <stdint.h>
#include <string.h>
/**
* @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)
2020-12-02 15:47:23 +01:00
&& (0 == strncmp(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( (NULL != cmd->cmdAlias)
&& (strlen(cmd->cmdAlias) >= inst->cursor)
2020-12-02 15:47:23 +01:00
&& (0 == strncmp(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)
2020-12-02 15:47:23 +01:00
&& (0 == strncmp(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( (NULL != cmd->cmdAlias)
&& (strlen(cmd->cmdAlias) >= inst->cursor)
2020-12-02 15:47:23 +01:00
&& (0 == strncmp(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 */
}
}
/**
* @}
*/