shellCommand.c 18.1 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define __USE_XOPEN
S
Shengliang Guan 已提交
17
#include "shellInt.h"
H
hzcheng 已提交
18

19 20 21 22 23
#define LEFT  1
#define RIGHT 2
#define UP    3
#define DOWN  4
#define PSIZE shell.info.promptSize
wafwerar's avatar
wafwerar 已提交
24
#define SHELL_INPUT_MAX_COMMAND_SIZE 10000
S
Shengliang Guan 已提交
25

H
hzcheng 已提交
26
typedef struct {
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
  char    *buffer;
  char    *command;
  uint32_t commandSize;
  uint32_t bufferSize;
  uint32_t cursorOffset;
  uint32_t screenOffset;
  uint32_t endOffset;
} SShellCmd;

static int32_t shellCountPrefixOnes(uint8_t c);
static void    shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
static void    shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
static void    shellInsertChar(SShellCmd *cmd, char *c, int size);
static void    shellBackspaceChar(SShellCmd *cmd);
static void    shellClearLineBefore(SShellCmd *cmd);
static void    shellClearLineAfter(SShellCmd *cmd);
static void    shellDeleteChar(SShellCmd *cmd);
static void    shellMoveCursorLeft(SShellCmd *cmd);
static void    shellMoveCursorRight(SShellCmd *cmd);
static void    shellPositionCursorHome(SShellCmd *cmd);
static void    shellPositionCursorEnd(SShellCmd *cmd);
static void    shellPrintChar(char c, int32_t times);
static void    shellPositionCursor(int32_t step, int32_t direction);
static void    shellUpdateBuffer(SShellCmd *cmd);
static int32_t shellIsReadyGo(SShellCmd *cmd);
static void    shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width);
static void    shellResetCommand(SShellCmd *cmd, const char s[]);
static void    shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
static void    shellShowOnScreen(SShellCmd *cmd);

int32_t shellCountPrefixOnes(uint8_t c) {
  uint8_t mask = 127;
H
hzcheng 已提交
59
  mask = ~mask;
60
  int32_t ret = 0;
H
hzcheng 已提交
61 62 63 64 65 66 67 68
  while ((c & mask) != 0) {
    ret++;
    c <<= 1;
  }

  return ret;
}

69
void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
H
hzcheng 已提交
70 71
  assert(pos > 0);

wafwerar's avatar
wafwerar 已提交
72
  TdWchar wc;
H
hzcheng 已提交
73 74 75 76 77 78
  *size = 0;
  *width = 0;

  while (--pos >= 0) {
    *size += 1;

79
    if (str[pos] > 0 || shellCountPrefixOnes((uint8_t)str[pos]) > 1) break;
H
hzcheng 已提交
80 81
  }

wmmhello's avatar
wmmhello 已提交
82 83
  taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
  // assert(rc == *size); // it will be core, if str is encode by utf8 and taos charset is gbk
H
hzcheng 已提交
84

wafwerar's avatar
wafwerar 已提交
85
  *width = taosWcharWidth(wc);
H
hzcheng 已提交
86 87
}

88
void shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
H
hzcheng 已提交
89 90
  assert(pos >= 0);

wafwerar's avatar
wafwerar 已提交
91 92 93
  TdWchar wc;
  *size = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
  *width = taosWcharWidth(wc);
H
hzcheng 已提交
94 95
}

96
void shellInsertChar(SShellCmd *cmd, char *c, int32_t size) {
H
hzcheng 已提交
97 98
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

wafwerar's avatar
wafwerar 已提交
99 100
  TdWchar wc;
  if (taosMbToWchar(&wc, c, size) < 0) return;
H
hzcheng 已提交
101

102
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
H
hzcheng 已提交
103 104 105 106 107 108 109
  /* update the buffer */
  memmove(cmd->command + cmd->cursorOffset + size, cmd->command + cmd->cursorOffset,
          cmd->commandSize - cmd->cursorOffset);
  memcpy(cmd->command + cmd->cursorOffset, c, size);
  /* update the values */
  cmd->commandSize += size;
  cmd->cursorOffset += size;
wafwerar's avatar
wafwerar 已提交
110 111
  cmd->screenOffset += taosWcharWidth(wc);
  cmd->endOffset += taosWcharWidth(wc);
112 113
#ifdef WINDOWS
#else
114
  shellShowOnScreen(cmd);
115
#endif
H
hzcheng 已提交
116 117
}

118
void shellBackspaceChar(SShellCmd *cmd) {
H
hzcheng 已提交
119 120 121
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset > 0) {
122 123 124 125
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    int32_t size = 0;
    int32_t width = 0;
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
H
hzcheng 已提交
126 127 128 129 130 131
    memmove(cmd->command + cmd->cursorOffset - size, cmd->command + cmd->cursorOffset,
            cmd->commandSize - cmd->cursorOffset);
    cmd->commandSize -= size;
    cmd->cursorOffset -= size;
    cmd->screenOffset -= width;
    cmd->endOffset -= width;
132
    shellShowOnScreen(cmd);
H
hzcheng 已提交
133 134 135
  }
}

136
void shellClearLineBefore(SShellCmd *cmd) {
137 138
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

139
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
S
Shengliang Guan 已提交
140
  memmove(cmd->command, cmd->command + cmd->cursorOffset, cmd->commandSize - cmd->cursorOffset);
141 142 143 144
  cmd->commandSize -= cmd->cursorOffset;
  cmd->cursorOffset = 0;
  cmd->screenOffset = 0;
  cmd->endOffset = cmd->commandSize;
145
  shellShowOnScreen(cmd);
146 147
}

148
void shellClearLineAfter(SShellCmd *cmd) {
149 150
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

151
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
152 153
  cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
  cmd->endOffset = cmd->cursorOffset;
154
  shellShowOnScreen(cmd);
155 156
}

157
void shellDeleteChar(SShellCmd *cmd) {
H
hzcheng 已提交
158 159 160
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset < cmd->commandSize) {
161 162 163 164
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    int32_t size = 0;
    int32_t width = 0;
    shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
H
hzcheng 已提交
165 166 167 168
    memmove(cmd->command + cmd->cursorOffset, cmd->command + cmd->cursorOffset + size,
            cmd->commandSize - cmd->cursorOffset - size);
    cmd->commandSize -= size;
    cmd->endOffset -= width;
169
    shellShowOnScreen(cmd);
H
hzcheng 已提交
170 171 172
  }
}

173
void shellMoveCursorLeft(SShellCmd *cmd) {
H
hzcheng 已提交
174 175 176
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset > 0) {
177 178 179 180
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    int32_t size = 0;
    int32_t width = 0;
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
H
hzcheng 已提交
181 182
    cmd->cursorOffset -= size;
    cmd->screenOffset -= width;
183
    shellShowOnScreen(cmd);
H
hzcheng 已提交
184 185 186
  }
}

187
void shellMoveCursorRight(SShellCmd *cmd) {
H
hzcheng 已提交
188 189 190
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset < cmd->commandSize) {
191 192 193 194
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    int32_t size = 0;
    int32_t width = 0;
    shellGetNextCharSize(cmd->command, cmd->cursorOffset, &size, &width);
H
hzcheng 已提交
195 196
    cmd->cursorOffset += size;
    cmd->screenOffset += width;
197
    shellShowOnScreen(cmd);
H
hzcheng 已提交
198 199 200
  }
}

201
void shellPositionCursorHome(SShellCmd *cmd) {
H
hzcheng 已提交
202 203 204
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset > 0) {
205
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
H
hzcheng 已提交
206 207
    cmd->cursorOffset = 0;
    cmd->screenOffset = 0;
208
    shellShowOnScreen(cmd);
H
hzcheng 已提交
209 210 211
  }
}

212
void shellPositionCursorEnd(SShellCmd *cmd) {
H
hzcheng 已提交
213 214 215
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset < cmd->commandSize) {
216
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
H
hzcheng 已提交
217 218
    cmd->cursorOffset = cmd->commandSize;
    cmd->screenOffset = cmd->endOffset;
219
    shellShowOnScreen(cmd);
H
hzcheng 已提交
220 221 222
  }
}

223 224
void shellPrintChar(char c, int32_t times) {
  for (int32_t i = 0; i < times; i++) {
H
hzcheng 已提交
225 226 227 228 229
    fprintf(stdout, "%c", c);
  }
  fflush(stdout);
}

230
void shellPositionCursor(int32_t step, int32_t direction) {
wafwerar's avatar
wafwerar 已提交
231
#ifndef WINDOWS
H
hzcheng 已提交
232 233 234 235 236 237 238 239 240 241 242 243
  if (step > 0) {
    if (direction == LEFT) {
      fprintf(stdout, "\033[%dD", step);
    } else if (direction == RIGHT) {
      fprintf(stdout, "\033[%dC", step);
    } else if (direction == UP) {
      fprintf(stdout, "\033[%dA", step);
    } else if (direction == DOWN) {
      fprintf(stdout, "\033[%dB", step);
    }
    fflush(stdout);
  }
wafwerar's avatar
wafwerar 已提交
244
#endif
H
hzcheng 已提交
245 246
}

247
void shellUpdateBuffer(SShellCmd *cmd) {
H
hzcheng 已提交
248 249
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

250
  if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
H
hzcheng 已提交
251 252 253
  strcat(cmd->buffer, cmd->command);
  cmd->bufferSize += cmd->commandSize;

254
  memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
H
hzcheng 已提交
255 256 257 258
  cmd->cursorOffset = 0;
  cmd->screenOffset = 0;
  cmd->commandSize = 0;
  cmd->endOffset = 0;
259
  shellShowOnScreen(cmd);
H
hzcheng 已提交
260 261
}

262
int32_t shellIsReadyGo(SShellCmd *cmd) {
H
hzcheng 已提交
263 264
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

265 266
  char *total = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
  memset(cmd->command + cmd->commandSize, 0, SHELL_MAX_COMMAND_SIZE - cmd->commandSize);
H
hzcheng 已提交
267 268 269
  sprintf(total, "%s%s", cmd->buffer, cmd->command);

  char *reg_str =
S
Shengliang Guan 已提交
270 271
      "(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
      "\\s*clear\\s*$)";
272
  if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
wafwerar's avatar
wafwerar 已提交
273
    taosMemoryFree(total);
H
hzcheng 已提交
274 275 276
    return 1;
  }

wafwerar's avatar
wafwerar 已提交
277
  taosMemoryFree(total);
H
hzcheng 已提交
278 279 280
  return 0;
}

281 282
void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width) {
  TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), SHELL_MAX_COMMAND_SIZE);
H
hzcheng 已提交
283
  *size = strlen(str);
284 285
  taosMbsToWchars(wc, str, SHELL_MAX_COMMAND_SIZE);
  *width = taosWcharsWidth(wc, SHELL_MAX_COMMAND_SIZE);
wafwerar's avatar
wafwerar 已提交
286
  taosMemoryFree(wc);
H
hzcheng 已提交
287 288
}

289
void shellResetCommand(SShellCmd *cmd, const char s[]) {
H
hzcheng 已提交
290 291
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

292 293 294 295 296 297 298
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
  memset(cmd->buffer, 0, SHELL_MAX_COMMAND_SIZE);
  memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
  strncpy(cmd->command, s, SHELL_MAX_COMMAND_SIZE);
  int32_t size = 0;
  int32_t width = 0;
  shellGetMbSizeInfo(s, &size, &width);
H
hzcheng 已提交
299 300 301 302 303
  cmd->bufferSize = 0;
  cmd->commandSize = size;
  cmd->cursorOffset = size;
  cmd->screenOffset = width;
  cmd->endOffset = width;
304
  shellShowOnScreen(cmd);
H
hzcheng 已提交
305
}
306

307 308 309 310 311 312 313 314

void shellGetScreenSize(int32_t *ws_col, int32_t *ws_row) {
#ifdef WINDOWS
  CONSOLE_SCREEN_BUFFER_INFO csbi;
  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
  if (ws_col != NULL) *ws_col = csbi.srWindow.Right - csbi.srWindow.Left + 1;
  if (ws_row != NULL) *ws_row = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
#else
315 316 317
  struct winsize w;
  if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
    // fprintf(stderr, "No stream device, and use default value(col 120, row 30)\n");
318 319 320 321 322
    if (ws_col != NULL) *ws_col = 120;
    if (ws_row != NULL) *ws_row = 30;
  } else {
    if (ws_col != NULL) *ws_col = w.ws_col;
    if (ws_row != NULL) *ws_row = w.ws_row;
323
  }
324 325 326 327 328 329
#endif
}

void shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos) {
  int32_t ws_col;
  shellGetScreenSize(&ws_col, NULL);
330

331 332 333
  int32_t cursor_x = cursor_pos / ws_col;
  int32_t cursor_y = cursor_pos % ws_col;
  int32_t command_x = ecmd_pos / ws_col;
334 335
  shellPositionCursor(cursor_y, LEFT);
  shellPositionCursor(command_x - cursor_x, DOWN);
wafwerar's avatar
wafwerar 已提交
336
#ifndef WINDOWS
337
  fprintf(stdout, "\033[2K");
wafwerar's avatar
wafwerar 已提交
338
#endif
339 340
  for (int32_t i = 0; i < command_x; i++) {
    shellPositionCursor(1, UP);
wafwerar's avatar
wafwerar 已提交
341
  #ifndef WINDOWS
342
    fprintf(stdout, "\033[2K");
wafwerar's avatar
wafwerar 已提交
343
  #endif
344 345
  }
  fflush(stdout);
H
hzcheng 已提交
346
}
347 348

void shellShowOnScreen(SShellCmd *cmd) {
349 350
  int32_t ws_col;
  shellGetScreenSize(&ws_col, NULL);
351 352 353 354 355 356 357 358 359 360 361 362

  TdWchar wc;
  int32_t size = 0;

  // Print out the command.
  char *total_string = taosMemoryMalloc(SHELL_MAX_COMMAND_SIZE);
  memset(total_string, '\0', SHELL_MAX_COMMAND_SIZE);
  if (strcmp(cmd->buffer, "") == 0) {
    sprintf(total_string, "%s%s", shell.info.promptHeader, cmd->command);
  } else {
    sprintf(total_string, "%s%s", shell.info.promptContinue, cmd->command);
  }
363
  int32_t remain_column = ws_col;
364 365 366 367 368 369 370 371 372 373 374 375
  for (char *str = total_string; size < cmd->commandSize + PSIZE;) {
    int32_t ret = taosMbToWchar(&wc, str, MB_CUR_MAX);
    if (ret < 0) break;
    size += ret;
    /* assert(size >= 0); */
    int32_t width = taosWcharWidth(wc);
    if (remain_column > width) {
      printf("%lc", wc);
      remain_column -= width;
    } else {
      if (remain_column == width) {
        printf("%lc\n\r", wc);
376
        remain_column = ws_col;
377 378
      } else {
        printf("\n\r%lc", wc);
379
        remain_column = ws_col - width;
380 381 382 383 384 385 386 387 388 389 390
      }
    }

    str = total_string + size;
  }

  taosMemoryFree(total_string);
  // Position the cursor
  int32_t cursor_pos = cmd->screenOffset + PSIZE;
  int32_t ecmd_pos = cmd->endOffset + PSIZE;

391 392 393 394 395 396
  int32_t cursor_x = cursor_pos / ws_col;
  int32_t cursor_y = cursor_pos % ws_col;
  // int32_t cursor_y = cursor % ws_col;
  int32_t command_x = ecmd_pos / ws_col;
  int32_t command_y = ecmd_pos % ws_col;
  // int32_t command_y = (command.size() + PSIZE) % ws_col;
397 398 399 400 401 402 403
  shellPositionCursor(command_y, LEFT);
  shellPositionCursor(command_x, UP);
  shellPositionCursor(cursor_x, DOWN);
  shellPositionCursor(cursor_y, RIGHT);
  fflush(stdout);
}

wafwerar's avatar
wafwerar 已提交
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
char taosGetConsoleChar() {
#ifdef WINDOWS
  static void *console = NULL;
  if (console == NULL) {
    console = GetStdHandle(STD_INPUT_HANDLE);
  }
  static TdWchar buf[SHELL_INPUT_MAX_COMMAND_SIZE];
  static char mbStr[5];
  static unsigned long bufLen = 0;
  static uint16_t bufIndex = 0, mbStrIndex = 0, mbStrLen = 0;
  if (bufLen == 0) {
    ReadConsoleW(console, buf, SHELL_INPUT_MAX_COMMAND_SIZE, &bufLen, NULL);
    bufIndex = 0;
  }
  if (mbStrLen == 0){
    mbStrLen = WideCharToMultiByte(CP_UTF8, 0, &buf[bufIndex], 1, mbStr, sizeof(mbStr), NULL, NULL);
    mbStrIndex = 0;
    bufIndex++;
  }
  mbStrIndex++;
  if (mbStrIndex == mbStrLen) {
    mbStrLen = 0;
    if (bufIndex == bufLen) {
      bufLen = 0;
    }
  }
  return mbStr[mbStrIndex-1];
#else
  return (char)getchar();  // getchar() return an 'int32_t' value
#endif
}

436 437 438 439 440 441 442 443 444 445 446 447 448
int32_t shellReadCommand(char *command) {
  SShellHistory *pHistory = &shell.history;
  SShellCmd      cmd = {0};
  uint32_t       hist_counter = pHistory->hend;
  char           utf8_array[10] = "\0";

  cmd.buffer = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
  cmd.command = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
  shellShowOnScreen(&cmd);

  // Read input.
  char c;
  while (1) {
wafwerar's avatar
wafwerar 已提交
449
    c = taosGetConsoleChar();
450 451 452 453 454 455 456 457 458

    if (c == EOF) {
      return c;
    }

    if (c < 0) {  // For UTF-8
      int32_t count = shellCountPrefixOnes(c);
      utf8_array[0] = c;
      for (int32_t k = 1; k < count; k++) {
wafwerar's avatar
wafwerar 已提交
459
        c = taosGetConsoleChar();
460 461 462 463 464 465 466 467 468 469 470 471
        utf8_array[k] = c;
      }
      shellInsertChar(&cmd, utf8_array, count);
    } else if (c < '\033') {
      // Ctrl keys.  TODO: Implement ctrl combinations
      switch (c) {
        case 1:  // ctrl A
          shellPositionCursorHome(&cmd);
          break;
        case 3:
          printf("\n");
          shellResetCommand(&cmd, "");
472 473 474 475 476
          #ifdef WINDOWS
            raise(SIGINT);
          #else
            kill(0, SIGINT);
          #endif
477 478 479 480 481 482 483 484 485 486 487
          break;
        case 4:  // EOF or Ctrl+D
          printf("\n");
          return -1;
        case 5:  // ctrl E
          shellPositionCursorEnd(&cmd);
          break;
        case 8:
          shellBackspaceChar(&cmd);
          break;
        case '\n':
wafwerar's avatar
wafwerar 已提交
488
          break;
489
        case '\r':
490 491
        #ifdef WINDOWS 
        #else
492
          printf("\n");
493
        #endif
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
          if (shellIsReadyGo(&cmd)) {
            sprintf(command, "%s%s", cmd.buffer, cmd.command);
            taosMemoryFreeClear(cmd.buffer);
            taosMemoryFreeClear(cmd.command);
            return 0;
          } else {
            shellUpdateBuffer(&cmd);
          }
          break;
        case 11:  // Ctrl + K;
          shellClearLineAfter(&cmd);
          break;
        case 12:  // Ctrl + L;
          system("clear");
          shellShowOnScreen(&cmd);
          break;
        case 21:  // Ctrl + U;
          shellClearLineBefore(&cmd);
          break;
      }
    } else if (c == '\033') {
wafwerar's avatar
wafwerar 已提交
515
      c = taosGetConsoleChar();
516 517
      switch (c) {
        case '[':
wafwerar's avatar
wafwerar 已提交
518
          c = taosGetConsoleChar();
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
          switch (c) {
            case 'A':  // Up arrow
              if (hist_counter != pHistory->hstart) {
                hist_counter = (hist_counter + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE;
                shellResetCommand(&cmd, (pHistory->hist[hist_counter] == NULL) ? "" : pHistory->hist[hist_counter]);
              }
              break;
            case 'B':  // Down arrow
              if (hist_counter != pHistory->hend) {
                int32_t next_hist = (hist_counter + 1) % SHELL_MAX_HISTORY_SIZE;

                if (next_hist != pHistory->hend) {
                  shellResetCommand(&cmd, (pHistory->hist[next_hist] == NULL) ? "" : pHistory->hist[next_hist]);
                } else {
                  shellResetCommand(&cmd, "");
                }
                hist_counter = next_hist;
              }
              break;
            case 'C':  // Right arrow
              shellMoveCursorRight(&cmd);
              break;
            case 'D':  // Left arrow
              shellMoveCursorLeft(&cmd);
              break;
            case '1':
wafwerar's avatar
wafwerar 已提交
545
              if ((c = taosGetConsoleChar()) == '~') {
546 547 548 549 550
                // Home key
                shellPositionCursorHome(&cmd);
              }
              break;
            case '2':
wafwerar's avatar
wafwerar 已提交
551
              if ((c = taosGetConsoleChar()) == '~') {
552 553 554 555
                // Insert key
              }
              break;
            case '3':
wafwerar's avatar
wafwerar 已提交
556
              if ((c = taosGetConsoleChar()) == '~') {
557 558 559 560 561
                // Delete key
                shellDeleteChar(&cmd);
              }
              break;
            case '4':
wafwerar's avatar
wafwerar 已提交
562
              if ((c = taosGetConsoleChar()) == '~') {
563 564 565 566 567
                // End key
                shellPositionCursorEnd(&cmd);
              }
              break;
            case '5':
wafwerar's avatar
wafwerar 已提交
568
              if ((c = taosGetConsoleChar()) == '~') {
569 570 571 572
                // Page up key
              }
              break;
            case '6':
wafwerar's avatar
wafwerar 已提交
573
              if ((c = taosGetConsoleChar()) == '~') {
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
                // Page down key
              }
              break;
            case 72:
              // Home key
              shellPositionCursorHome(&cmd);
              break;
            case 70:
              // End key
              shellPositionCursorEnd(&cmd);
              break;
          }
          break;
      }
    } else if (c == 0x7f) {
      // press delete key
      shellBackspaceChar(&cmd);
    } else {
      shellInsertChar(&cmd, &c, 1);
    }
  }

  return 0;
}