Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linenoise update #2307

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions tests/tool_i.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ proc ly_completion {input output} {
global prompt

send -- "${input}\t"
# expecting echoing input, output and 10 terminal control characters
expect -re "^${input}\r${prompt}${output}.*\r.*$"
expect -re "${input}${output}"
}

# Send a completion request and check if the anchored regex hint options match.
Expand All @@ -146,11 +145,13 @@ proc ly_hint {input prev_input hints} {
set output {}
foreach i $hints {
# each element might have some number of spaces and CRLF around it
append output "${i} *(?:\\r\\n)?"
append output "${i} *(\\r\\n)?"
}
set termcode1 "\r\\u001b\\\[0K"
set termcode2 ".*"

send -- "${input}\t"
# expecting the hints, previous input from which the hints were generated
# and some number of terminal control characters
expect -re "${output}\r${prompt}${prev_input}.*\r.*$"
expect -re "${output}${termcode1}${prompt}${prev_input}${termcode2}"
}
2 changes: 1 addition & 1 deletion tests/yanglint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if(WIN32)
if(WIN32 OR NOT ENABLE_YANGLINT_INTERACTIVE)
set(YANGLINT_INTERACTIVE OFF)
else()
set(YANGLINT_INTERACTIVE ON)
Expand Down
19 changes: 12 additions & 7 deletions tests/yanglint/interactive/completion.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ test completion_hints_ietf_ip {Completion and hints for ietf-ip.yang} {
ly_cmd "add $mdir/ietf-ip.yang"

# completion and hint
ly_completion "print -f info -P " "print -f info -P /ietf-"
ly_completion "print -f info -P " "/ietf-"

set hints {"/ietf-yang-schema-mount:schema-mounts" "/ietf-interfaces:interfaces" "/ietf-interfaces:interfaces-state"}
ly_hint "" "print -f info -P /ietf-" $hints

# double completion
ly_completion "i" "print -f info -P /ietf-interfaces:interfaces"
ly_completion "/" "print -f info -P /ietf-interfaces:interfaces/interface"
ly_completion "i" "nterfaces:interfaces"
ly_completion "/" "interface"
# current cli: print -f info -P /ietf-interfaces:interfaces/interface

# a lot of hints
set hints {"/ietf-interfaces:interfaces/interface"
Expand All @@ -31,16 +32,20 @@ test completion_hints_ietf_ip {Completion and hints for ietf-ip.yang} {
ly_hint "" "print -f info -P /ietf-interfaces:interfaces/interface" $hints

# double tab
ly_completion "/i" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv"
ly_completion "4" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4"
ly_completion "/i" "etf-ip:ipv"
# current cli: print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv
ly_completion "4" ""
# current cli: print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4

set hints { "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/enabled"
"/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/forwarding" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/mtu"
"/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address" "/ietf-interfaces:interfaces/interface/ietf-ip:ipv4/neighbor"
}
ly_hint "\t" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv" $hints
ly_hint "\t" "print -f info -P /ietf-interfaces:interfaces/interface" $hints

# no more completion
ly_completion "/e" "print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4/enabled "
ly_completion "/e" "nabled "
# current cli: print -f info -P /ietf-interfaces:interfaces/interface/ietf-ip:ipv4/enabled
}}

# Note that somehow a command is automatically sent again (\t\t replaced by \r) after the hints.
Expand Down
3 changes: 2 additions & 1 deletion tools/lint/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ if(ENABLE_YANGLINT_INTERACTIVE)
main.c
completion.c
configuration.c
linenoise/linenoise.c)
linenoise/linenoise.c
linenoise/utf8.c)
else()
set(lintsrc ${lintsrc}
main_ni_only.c)
Expand Down
115 changes: 90 additions & 25 deletions tools/lint/completion.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L /* strdup */

#include <dirent.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include "libyang.h"

Expand All @@ -28,6 +30,70 @@
#include "compat.h"
#include "linenoise/linenoise.h"

/**
* @brief Fill path completion.
*
* @param[in] hint Path to directory.
* @param[in] lc For adding completions.
*/
static void
path_completion(const char *hint, linenoiseCompletions *lc)
{
const char *ptr;
char *full_path, *hint_ptr, match[FILENAME_MAX + 2];
DIR *dir;
struct dirent *ent;
struct stat st;

lc->path = 1;

ptr = strrchr(hint, '/');

/* new relative path */
if (ptr == NULL) {
full_path = malloc(2 + FILENAME_MAX + 1);
strcpy(full_path, "./");

ptr = hint;
} else {
full_path = malloc((int)(ptr - hint) + FILENAME_MAX + 1);
++ptr;
sprintf(full_path, "%.*s", (int)(ptr - hint), hint);
github-advanced-security[bot] marked this conversation as resolved.
Dismissed
Show resolved Hide resolved
}
hint_ptr = full_path + strlen(full_path);

dir = opendir(full_path);
if (dir == NULL) {
free(full_path);
return;
}

while ((ent = readdir(dir))) {
if (ent->d_name[0] == '.') {
continue;
}

if (!strncmp(ptr, ent->d_name, strlen(ptr))) {
/* is it a directory? */
strcpy(hint_ptr, ent->d_name);
if (stat(full_path, &st)) {
/* skip this item */
continue;
}

strcpy(match, ent->d_name);
if (S_ISDIR(st.st_mode)) {
strcat(match, "/");
}

linenoiseAddCompletion(lc, match);
}
}

free(full_path);
closedir(dir);
}

/* from the main.c */
extern struct ly_ctx *ctx;

Expand Down Expand Up @@ -430,29 +496,28 @@
struct autocomplete {
enum COMMAND_INDEX ci; /**< command index to global variable 'commands' */
const char *opt; /**< optional option */
void (*ln_cb)(const char *, const char *, linenoiseCompletions *); /**< linenoise callback to call */
void (*yl_cb)(const char *, char ***, unsigned int *); /**< yanglint callback to call */
void (*yl_cb)(const char *, char ***, unsigned int *); /**< yanglint callback to call */
} ac[] = {
{CMD_ADD, NULL, linenoisePathCompletion, NULL},
{CMD_PRINT, "-f", NULL, get_print_format_arg},
{CMD_PRINT, "-P", NULL, get_schema_completion},
{CMD_PRINT, "-o", linenoisePathCompletion, NULL},
{CMD_PRINT, NULL, NULL, get_model_completion},
{CMD_SEARCHPATH, NULL, linenoisePathCompletion, NULL},
{CMD_EXTDATA, NULL, linenoisePathCompletion, NULL},
{CMD_CLEAR, "-Y", linenoisePathCompletion, NULL},
{CMD_DATA, "-t", NULL, get_data_type_arg},
{CMD_DATA, "-O", linenoisePathCompletion, NULL},
{CMD_DATA, "-R", linenoisePathCompletion, NULL},
{CMD_DATA, "-f", NULL, get_data_in_format_arg},
{CMD_DATA, "-F", NULL, get_data_in_format_arg},
{CMD_DATA, "-d", NULL, get_data_default_arg},
{CMD_DATA, "-o", linenoisePathCompletion, NULL},
{CMD_DATA, NULL, linenoisePathCompletion, NULL},
{CMD_LIST, NULL, NULL, get_list_format_arg},
{CMD_FEATURE, NULL, NULL, get_model_completion},
{CMD_VERB, NULL, NULL, get_verb_arg},
{CMD_DEBUG, NULL, NULL, get_debug_arg},
{CMD_ADD, NULL, NULL},
{CMD_PRINT, "-f", get_print_format_arg},
{CMD_PRINT, "-P", get_schema_completion},
{CMD_PRINT, "-o", NULL},
{CMD_PRINT, NULL, get_model_completion},
{CMD_SEARCHPATH, NULL, NULL},
{CMD_EXTDATA, NULL, NULL},
{CMD_CLEAR, "-Y", NULL},
{CMD_DATA, "-t", get_data_type_arg},
{CMD_DATA, "-O", NULL},
{CMD_DATA, "-R", NULL},
{CMD_DATA, "-f", get_data_in_format_arg},
{CMD_DATA, "-F", get_data_in_format_arg},
{CMD_DATA, "-d", get_data_default_arg},
{CMD_DATA, "-o", NULL},
{CMD_DATA, NULL, NULL},
{CMD_LIST, NULL, get_list_format_arg},
{CMD_FEATURE, NULL, get_model_completion},
{CMD_VERB, NULL, get_verb_arg},
{CMD_DEBUG, NULL, get_debug_arg},
};
size_t name_len;
const char *last, *name, *getoptstr;
Expand Down Expand Up @@ -490,10 +555,10 @@
}

/* callback */
if (ac[i].ln_cb) {
ac[i].ln_cb(buf, hint, lc);
} else {
if (ac[i].yl_cb) {
ac[i].yl_cb(hint, &matches, &match_count);
} else {
path_completion(hint, lc);
}
break;
}
Expand Down
Loading
Loading