Skip to content

Commit

Permalink
yanglint FEATURE multiline for interactive mode
Browse files Browse the repository at this point in the history
The tcl-tests needed to be modified because ANSI escape codes
are sent differently.
  • Loading branch information
lePici authored and michalvasko committed Dec 4, 2024
1 parent ab1b5f9 commit 0abfcc3
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 13 deletions.
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}"
}
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
26 changes: 24 additions & 2 deletions tools/lint/linenoise/linenoise.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,12 @@ static size_t columnPos(const char *buf, size_t buf_len, size_t pos) {
static size_t columnPosForMultiLine(const char *buf, size_t buf_len, size_t pos, size_t cols, size_t ini_pos) {
size_t ret = 0;
size_t colwid = ini_pos;
size_t len;

size_t off = 0;
while (off < buf_len) {
size_t col_len;
size_t len = nextCharLen(buf,buf_len,off,&col_len);
len = nextCharLen(buf,buf_len,off,&col_len);

int dif = (int)(colwid + col_len) - (int)cols;
if (dif > 0) {
Expand Down Expand Up @@ -799,7 +800,7 @@ static void refreshSingleLine(struct linenoiseState *l, int flags) {
static void refreshMultiLine(struct linenoiseState *l, int flags) {
char seq[64];
size_t pcollen = promptTextColumnLen(l->prompt,strlen(l->prompt));
int colpos = columnPosForMultiLine(l->buf, l->len, l->len, l->cols, pcollen);
size_t colpos = columnPosForMultiLine(l->buf, l->len, l->len, l->cols, pcollen);
int colpos2; /* cursor column position. */
int rows = (pcollen+colpos+l->cols-1)/l->cols; /* rows used by current buf. */
int rpos = (pcollen+l->oldcolpos+l->cols)/l->cols; /* cursor relative row. */
Expand All @@ -815,6 +816,23 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
* going to the last row. */
abInit(&ab);

if ((l->oldcollen < l->len) && // some character was added
(l->pos == l->len) && // at the end of the line
(l->pos <= l->cols) && // no multiline break
(l->prev_history_index == l->history_index) // no buffer change based on history
) {
/* Ignore flags and just add one character.
* This code was added because redundant ANSI escape codes make tcl-tests incapable.
*/
abAppend(&ab,l->buf + l->oldcollen,strlen(l->buf) - l->oldcollen);
l->oldcolpos = colpos;
l->oldcollen = l->len;
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
abFree(&ab);
l->prev_history_index = l->history_index;
return;
}

if (flags & REFRESH_CLEAN) {
if (old_rows-rpos > 0) {
lndebug("go down %d", old_rows-rpos);
Expand Down Expand Up @@ -890,6 +908,8 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {

lndebug("\n");
l->oldcolpos = colpos2;
l->oldcollen = l->len;
l->prev_history_index = l->history_index;

if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
abFree(&ab);
Expand Down Expand Up @@ -1096,6 +1116,7 @@ int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, ch
l->prompt = prompt;
l->plen = strlen(prompt);
l->oldcolpos = l->pos = 0;
l->oldcollen = 0;
l->len = 0;

/* Enter raw mode. */
Expand All @@ -1104,6 +1125,7 @@ int linenoiseEditStart(struct linenoiseState *l, int stdin_fd, int stdout_fd, ch
l->cols = getColumns(stdin_fd, stdout_fd);
l->oldrows = 0;
l->history_index = 0;
l->prev_history_index = 0;

/* Buffer starts empty. */
l->buf[0] = '\0';
Expand Down
2 changes: 2 additions & 0 deletions tools/lint/linenoise/linenoise.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ struct linenoiseState {
size_t plen; /* Prompt length. */
size_t pos; /* Current cursor position. */
size_t oldcolpos; /* Previous refresh cursor column position. */
size_t oldcollen; /* Previous length of buffer. */
size_t len; /* Current edited line length. */
size_t cols; /* Number of columns in terminal. */
size_t oldrows; /* Rows used by last refrehsed line (multiline mode) */
int history_index; /* The history index we are currently editing. */
int prev_history_index; /* Previous history index. */
};

typedef struct linenoiseCompletions {
Expand Down
1 change: 1 addition & 0 deletions tools/lint/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ main(int argc, char *argv[])
/* continue in interactive mode */
linenoiseSetCompletionCallback(complete_cmd);
linenoiseSetEncodingFunctions(linenoiseUtf8PrevCharLen, linenoiseUtf8NextCharLen, linenoiseUtf8ReadCode);
linenoiseSetMultiLine(1);
load_config();

if (ly_ctx_new(NULL, YL_DEFAULT_CTX_OPTIONS, &ctx)) {
Expand Down

0 comments on commit 0abfcc3

Please sign in to comment.