shellCommand.c 19.0 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"
A
Alex Duan 已提交
18
#include "shellAuto.h"
H
hzcheng 已提交
19

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

27 28

static int32_t shellCountPrefixOnes(uint8_t c);
A
Alex Duan 已提交
29

30
static void    shellGetNextCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
A
Alex Duan 已提交
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45
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[]);
A
Alex Duan 已提交
46 47 48 49
void           shellClearScreen(int32_t ecmd_pos, int32_t cursor_pos);
void           shellShowOnScreen(SShellCmd *cmd);
void           shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width);
void           shellInsertChar(SShellCmd *cmd, char *c, int size);
50 51 52

int32_t shellCountPrefixOnes(uint8_t c) {
  uint8_t mask = 127;
H
hzcheng 已提交
53
  mask = ~mask;
54
  int32_t ret = 0;
H
hzcheng 已提交
55 56 57 58 59 60 61 62
  while ((c & mask) != 0) {
    ret++;
    c <<= 1;
  }

  return ret;
}

63
void shellGetPrevCharSize(const char *str, int32_t pos, int32_t *size, int32_t *width) {
H
hzcheng 已提交
64 65
  assert(pos > 0);

wafwerar's avatar
wafwerar 已提交
66
  TdWchar wc;
H
hzcheng 已提交
67 68 69 70 71 72
  *size = 0;
  *width = 0;

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

73
    if (str[pos] > 0 || shellCountPrefixOnes((uint8_t)str[pos]) > 1) break;
H
hzcheng 已提交
74 75
  }

wmmhello's avatar
wmmhello 已提交
76 77
  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 已提交
78

wafwerar's avatar
wafwerar 已提交
79
  *width = taosWcharWidth(wc);
H
hzcheng 已提交
80 81
}

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

wafwerar's avatar
wafwerar 已提交
85 86 87
  TdWchar wc;
  *size = taosMbToWchar(&wc, str + pos, MB_CUR_MAX);
  *width = taosWcharWidth(wc);
H
hzcheng 已提交
88 89
}

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

wafwerar's avatar
wafwerar 已提交
93 94
  TdWchar wc;
  if (taosMbToWchar(&wc, c, size) < 0) return;
H
hzcheng 已提交
95

96
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
H
hzcheng 已提交
97 98 99 100 101 102 103
  /* 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;
A
Alex Duan 已提交
104 105 106 107 108
  for (int i = 0; i < size; i++) {
    taosMbToWchar(&wc, c + i, size);
    cmd->screenOffset += taosWcharWidth(wc);
    cmd->endOffset    += taosWcharWidth(wc);
  }  
109 110
#ifdef WINDOWS
#else
111
  shellShowOnScreen(cmd);
112
#endif
H
hzcheng 已提交
113 114
}

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

  if (cmd->cursorOffset > 0) {
119 120 121 122
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    int32_t size = 0;
    int32_t width = 0;
    shellGetPrevCharSize(cmd->command, cmd->cursorOffset, &size, &width);
H
hzcheng 已提交
123 124 125 126 127 128
    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;
129
    shellShowOnScreen(cmd);
H
hzcheng 已提交
130 131 132
  }
}

133
void shellClearLineBefore(SShellCmd *cmd) {
134 135
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

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

145
void shellClearLineAfter(SShellCmd *cmd) {
146 147
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

148
  shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
149 150
  cmd->commandSize -= cmd->endOffset - cmd->cursorOffset;
  cmd->endOffset = cmd->cursorOffset;
151
  shellShowOnScreen(cmd);
152 153
}

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

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

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

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

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

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

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

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

A
Alex Duan 已提交
209 210 211 212 213 214 215 216 217
void positionCursorMiddle(SShellCmd *cmd) {
  if (cmd->endOffset > 0) {
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
    cmd->cursorOffset = cmd->commandSize/2;
    cmd->screenOffset = cmd->endOffset/2;
    shellShowOnScreen(cmd);
  }
}

218
void shellPositionCursorEnd(SShellCmd *cmd) {
H
hzcheng 已提交
219 220 221
  assert(cmd->cursorOffset <= cmd->commandSize && cmd->endOffset >= cmd->screenOffset);

  if (cmd->cursorOffset < cmd->commandSize) {
222
    shellClearScreen(cmd->endOffset + PSIZE, cmd->screenOffset + PSIZE);
H
hzcheng 已提交
223 224
    cmd->cursorOffset = cmd->commandSize;
    cmd->screenOffset = cmd->endOffset;
225
    shellShowOnScreen(cmd);
H
hzcheng 已提交
226 227 228
  }
}

229 230
void shellPrintChar(char c, int32_t times) {
  for (int32_t i = 0; i < times; i++) {
H
hzcheng 已提交
231 232 233 234 235
    fprintf(stdout, "%c", c);
  }
  fflush(stdout);
}

236
void shellPositionCursor(int32_t step, int32_t direction) {
wafwerar's avatar
wafwerar 已提交
237
#ifndef WINDOWS
H
hzcheng 已提交
238 239 240 241 242 243 244 245 246 247 248 249
  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 已提交
250
#endif
H
hzcheng 已提交
251 252
}

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

256
  if (shellRegexMatch(cmd->buffer, "(\\s+$)|(^$)", REG_EXTENDED)) strcat(cmd->command, " ");
H
hzcheng 已提交
257 258 259
  strcat(cmd->buffer, cmd->command);
  cmd->bufferSize += cmd->commandSize;

260
  memset(cmd->command, 0, SHELL_MAX_COMMAND_SIZE);
H
hzcheng 已提交
261 262 263 264
  cmd->cursorOffset = 0;
  cmd->screenOffset = 0;
  cmd->commandSize = 0;
  cmd->endOffset = 0;
265
  shellShowOnScreen(cmd);
H
hzcheng 已提交
266 267
}

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

271 272
  char *total = (char *)taosMemoryCalloc(1, SHELL_MAX_COMMAND_SIZE);
  memset(cmd->command + cmd->commandSize, 0, SHELL_MAX_COMMAND_SIZE - cmd->commandSize);
H
hzcheng 已提交
273 274 275
  sprintf(total, "%s%s", cmd->buffer, cmd->command);

  char *reg_str =
S
Shengliang Guan 已提交
276 277
      "(^.*;\\s*$)|(^\\s*$)|(^\\s*exit\\s*$)|(^\\s*q\\s*$)|(^\\s*quit\\s*$)|(^"
      "\\s*clear\\s*$)";
278
  if (shellRegexMatch(total, reg_str, REG_EXTENDED | REG_ICASE)) {
wafwerar's avatar
wafwerar 已提交
279
    taosMemoryFree(total);
H
hzcheng 已提交
280 281 282
    return 1;
  }

wafwerar's avatar
wafwerar 已提交
283
  taosMemoryFree(total);
H
hzcheng 已提交
284 285 286
  return 0;
}

287 288
void shellGetMbSizeInfo(const char *str, int32_t *size, int32_t *width) {
  TdWchar *wc = (TdWchar *)taosMemoryCalloc(sizeof(TdWchar), SHELL_MAX_COMMAND_SIZE);
H
hzcheng 已提交
289
  *size = strlen(str);
290 291
  taosMbsToWchars(wc, str, SHELL_MAX_COMMAND_SIZE);
  *width = taosWcharsWidth(wc, SHELL_MAX_COMMAND_SIZE);
wafwerar's avatar
wafwerar 已提交
292
  taosMemoryFree(wc);
H
hzcheng 已提交
293 294
}

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

298 299 300 301 302 303 304
  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 已提交
305 306 307 308 309
  cmd->bufferSize = 0;
  cmd->commandSize = size;
  cmd->cursorOffset = size;
  cmd->screenOffset = width;
  cmd->endOffset = width;
310
  shellShowOnScreen(cmd);
H
hzcheng 已提交
311
}
312

313 314 315 316 317 318 319 320

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
321 322
  struct winsize w;
  if (ioctl(0, TIOCGWINSZ, &w) < 0 || w.ws_col == 0 || w.ws_row == 0) {
wafwerar's avatar
wafwerar 已提交
323
    // fprintf(stderr, "No stream device, and use default value(col 120, row 30)\r\n");
324 325 326 327 328
    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;
329
  }
330 331 332 333 334 335
#endif
}

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

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

void shellShowOnScreen(SShellCmd *cmd) {
355 356
  int32_t ws_col;
  shellGetScreenSize(&ws_col, NULL);
357 358 359 360 361 362 363 364 365 366 367 368

  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);
  }
369
  int32_t remain_column = ws_col;
370 371 372 373 374 375 376 377 378 379 380 381
  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);
382
        remain_column = ws_col;
383 384
      } else {
        printf("\n\r%lc", wc);
385
        remain_column = ws_col - width;
386 387 388 389 390 391 392 393 394 395 396
      }
    }

    str = total_string + size;
  }

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

397 398 399 400 401 402
  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;
403 404 405 406 407 408 409
  shellPositionCursor(command_y, LEFT);
  shellPositionCursor(command_x, UP);
  shellPositionCursor(cursor_x, DOWN);
  shellPositionCursor(cursor_y, RIGHT);
  fflush(stdout);
}

wafwerar's avatar
wafwerar 已提交
410 411 412 413 414 415 416 417 418 419
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;
wafwerar's avatar
wafwerar 已提交
420
  CONSOLE_READCONSOLE_CONTROL inputControl={ sizeof(CONSOLE_READCONSOLE_CONTROL), 0, 1<<TAB_KEY, 0 };
wafwerar's avatar
wafwerar 已提交
421
  while (bufLen == 0) {
wafwerar's avatar
wafwerar 已提交
422
    ReadConsoleW(console, buf, SHELL_INPUT_MAX_COMMAND_SIZE, &bufLen, &inputControl);
wafwerar's avatar
wafwerar 已提交
423
    if (bufLen > 0 && buf[0] == 0) bufLen = 0;
wafwerar's avatar
wafwerar 已提交
424 425 426
    bufIndex = 0;
  }
  if (mbStrLen == 0){
wafwerar's avatar
wafwerar 已提交
427 428 429
    if (buf[bufIndex] == '\r') {
      bufIndex++;
    }
wafwerar's avatar
wafwerar 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
    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
}

447 448 449 450 451 452 453 454 455 456 457 458 459
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 已提交
460
    c = taosGetConsoleChar();
461 462 463 464 465 466 467 468 469

    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 已提交
470
        c = taosGetConsoleChar();
471 472 473
        utf8_array[k] = c;
      }
      shellInsertChar(&cmd, utf8_array, count);
A
Alex Duan 已提交
474 475 476 477
      pressOtherKey(c);
    } else if (c == TAB_KEY) {
      // press TAB key
      pressTabKey(&cmd);
478
    } else if (c < '\033') {
A
Alex Duan 已提交
479
      pressOtherKey(c);      
480 481
      // Ctrl keys.  TODO: Implement ctrl combinations
      switch (c) {
wafwerar's avatar
wafwerar 已提交
482 483
        case 0:
          break;
484 485 486 487
        case 1:  // ctrl A
          shellPositionCursorHome(&cmd);
          break;
        case 3:
wafwerar's avatar
wafwerar 已提交
488
          printf("\r\n");
489
          shellResetCommand(&cmd, "");
490 491 492 493 494
          #ifdef WINDOWS
            raise(SIGINT);
          #else
            kill(0, SIGINT);
          #endif
495 496
          break;
        case 4:  // EOF or Ctrl+D
wafwerar's avatar
wafwerar 已提交
497
          taosResetTerminalMode();
wafwerar's avatar
wafwerar 已提交
498
          printf("\r\n");
499 500 501 502 503 504 505 506 507
          return -1;
        case 5:  // ctrl E
          shellPositionCursorEnd(&cmd);
          break;
        case 8:
          shellBackspaceChar(&cmd);
          break;
        case '\n':
        case '\r':
508 509
        #ifdef WINDOWS 
        #else
wafwerar's avatar
wafwerar 已提交
510
          printf("\r\n");
511
        #endif
512 513 514 515 516 517 518 519 520 521 522 523 524
          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;
525 526
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
527
          system("clear");
528
#pragma GCC diagnostic pop
529 530 531 532 533
          shellShowOnScreen(&cmd);
          break;
        case 21:  // Ctrl + U;
          shellClearLineBefore(&cmd);
          break;
A
Alex Duan 已提交
534 535 536
        case 23:  // Ctrl + W;
          positionCursorMiddle(&cmd);
          break;          
537 538
      }
    } else if (c == '\033') {
A
Alex Duan 已提交
539
      pressOtherKey(c);
wafwerar's avatar
wafwerar 已提交
540
      c = taosGetConsoleChar();
541 542
      switch (c) {
        case '[':
wafwerar's avatar
wafwerar 已提交
543
          c = taosGetConsoleChar();
544 545
          switch (c) {
            case 'A':  // Up arrow
wafwerar's avatar
wafwerar 已提交
546
              hist_counter = (hist_counter + SHELL_MAX_HISTORY_SIZE - 1) % SHELL_MAX_HISTORY_SIZE;
wafwerar's avatar
wafwerar 已提交
547 548 549 550 551
              if (pHistory->hist[hist_counter] == NULL) {
                hist_counter = (hist_counter + SHELL_MAX_HISTORY_SIZE + 1) % SHELL_MAX_HISTORY_SIZE;
              } else {
                shellResetCommand(&cmd, pHistory->hist[hist_counter]);
              }
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
              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 已提交
572
              if ((c = taosGetConsoleChar()) == '~') {
573 574 575 576 577
                // Home key
                shellPositionCursorHome(&cmd);
              }
              break;
            case '2':
wafwerar's avatar
wafwerar 已提交
578
              if ((c = taosGetConsoleChar()) == '~') {
579 580 581 582
                // Insert key
              }
              break;
            case '3':
wafwerar's avatar
wafwerar 已提交
583
              if ((c = taosGetConsoleChar()) == '~') {
584 585 586 587 588
                // Delete key
                shellDeleteChar(&cmd);
              }
              break;
            case '4':
wafwerar's avatar
wafwerar 已提交
589
              if ((c = taosGetConsoleChar()) == '~') {
590 591 592 593 594
                // End key
                shellPositionCursorEnd(&cmd);
              }
              break;
            case '5':
wafwerar's avatar
wafwerar 已提交
595
              if ((c = taosGetConsoleChar()) == '~') {
596 597 598 599
                // Page up key
              }
              break;
            case '6':
wafwerar's avatar
wafwerar 已提交
600
              if ((c = taosGetConsoleChar()) == '~') {
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
                // Page down key
              }
              break;
            case 72:
              // Home key
              shellPositionCursorHome(&cmd);
              break;
            case 70:
              // End key
              shellPositionCursorEnd(&cmd);
              break;
          }
          break;
      }
    } else if (c == 0x7f) {
A
Alex Duan 已提交
616
      pressOtherKey(c);
617 618 619
      // press delete key
      shellBackspaceChar(&cmd);
    } else {
A
Alex Duan 已提交
620
      pressOtherKey(c);
621 622 623 624 625 626
      shellInsertChar(&cmd, &c, 1);
    }
  }

  return 0;
}