Diff
Not logged in

Differences From Artifact [c9e953e2f3]:

To Artifact [2ae333dd88]:


890
891
892
893
894
895
896

897
898
899
900
901
902
903
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904







+







    int colsright; /* refreshLine() cached cols for insert_char() optimisation */
    int colsleft;  /* refreshLine() cached cols for remove_char() optimisation */
    const char *prompt;
    stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
    stringbuf *output;  /* used only during refreshLine() - output accumulator */
#if defined(USE_TERMIOS)
    int fd;     /* Terminal fd */
    int pending; /* pending char fd_read_char() */
#elif defined(USE_WINCONSOLE)
    HANDLE outh; /* Console output handle */
    HANDLE inh; /* Console input handle */
    int rows;   /* Screen rows */
    int x;      /* Current column during output */
    int y;      /* Current row */
#ifdef USE_UTF8
1119
1120
1121
1122
1123
1124
1125
1126
1127





1128
1129
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143

1144
1145
1146
1147
1148
1149
1150
1120
1121
1122
1123
1124
1125
1126


1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139

1140
1141
1142
1143
1144
1145
1146

1147
1148
1149
1150
1151
1152
1153
1154







-
-
+
+
+
+
+








-
+






-
+







    /* local modes - choing off, canonical off, no extended functions,
     * no signal chars (^Z,^C) */
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    /* control chars - set return condition: min number of bytes and timer.
     * We want read to return every single byte, without timeout. */
    raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */

    /* put terminal in raw mode after flushing */
    if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
    /* put terminal in raw mode. Because we aren't changing any output
     * settings we don't need to use TCSADRAIN and I have seen that hang on
     * OpenBSD when running under a pty
     */
    if (tcsetattr(current->fd,TCSANOW,&raw) < 0) {
        goto fatal;
    }
    rawmode = 1;
    return 0;
}

static void disableRawMode(struct current *current) {
    /* Don't even check the return value as it's too late. */
    if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
    if (rawmode && tcsetattr(current->fd,TCSANOW,&orig_termios) != -1)
        rawmode = 0;
}

/* At exit we'll try to fix the terminal to the initial conditions. */
static void linenoiseAtExit(void) {
    if (rawmode) {
        tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
        tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
    }
    linenoiseHistoryFree();
}

/* gcc/glibc insists that we care about the return code of write!
 * Clarification: This means that a void-cast like "(void) (EXPR)"
 * does not work.
1228
1229
1230
1231
1232
1233
1234
1235

1236
1237
1238
1239
1240
1241

1242
1243
1244
1245






1246

1247
1248
1249
1250
1251
1252
1253

1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270




1271

1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287

1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299









1300
1301
1302
1303
1304
1305
1306
1307
1308
1309

1310
1311
1312
1313
1314
1315
1316
1317
1318
1319


1320
1321
1322
1323
1324

1325
1326
1327
1328
1329
1330
1331
1232
1233
1234
1235
1236
1237
1238

1239
1240
1241
1242
1243
1244

1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255

1256
1257
1258
1259
1260
1261
1262

1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284

1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300

1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331

1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357







-
+





-
+




+
+
+
+
+
+
-
+






-
+

















+
+
+
+
-
+















-
+












+
+
+
+
+
+
+
+
+









-
+










+
+





+








void linenoiseClearScreen(void)
{
    IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
}

/**
 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
 * Reads a char from 'current->fd', waiting at most 'timeout' milliseconds.
 *
 * A timeout of -1 means to wait forever.
 *
 * Returns -1 if no char is received within the time or an error occurs.
 */
static int fd_read_char(int fd, int timeout)
static int fd_read_char(struct current *current, int timeout)
{
    struct pollfd p;
    unsigned char c;

    if (current->pending) {
        c = current->pending;
        current->pending = 0;
        return c;
    }

    p.fd = fd;
    p.fd = current->fd;
    p.events = POLLIN;

    if (poll(&p, 1, timeout) == 0) {
        /* timeout */
        return -1;
    }
    if (read(fd, &c, 1) != 1) {
    if (read(current->fd, &c, 1) != 1) {
        return -1;
    }
    return c;
}

/**
 * Reads a complete utf-8 character
 * and returns the unicode value, or -1 on error.
 */
static int fd_read(struct current *current)
{
#ifdef USE_UTF8
    char buf[MAX_UTF8_LEN];
    int n;
    int i;
    int c;

    if (current->pending) {
        buf[0] = current->pending;
        current->pending = 0;
    }
    if (read(current->fd, &buf[0], 1) != 1) {
    else if (read(current->fd, &buf[0], 1) != 1) {
        return -1;
    }
    n = utf8_charlen(buf[0]);
    if (n < 1) {
        return -1;
    }
    for (i = 1; i < n; i++) {
        if (read(current->fd, &buf[i], 1) != 1) {
            return -1;
        }
    }
    /* decode and return the character */
    utf8_tounicode(buf, &c);
    return c;
#else
    return fd_read_char(current->fd, -1);
    return fd_read_char(current, -1);
#endif
}


/**
 * Stores the current cursor column in '*cols'.
 * Returns 1 if OK, or 0 if failed to determine cursor pos.
 */
static int queryCursor(struct current *current, int* cols)
{
    struct esc_parser parser;
    int ch;
    /* Unfortunately we don't have any persistent state, so assume
     * a process will only ever interact with one terminal at a time.
     */
    static int query_cursor_failed;

    if (query_cursor_failed) {
        /* If it ever fails, don't try again */
        return 0;
    }

    /* Should not be buffering this output, it needs to go immediately */
    assert(current->output == NULL);

    /* control sequence - report cursor location */
    outputChars(current, "\x1b[6n", -1);

    /* Parse the response: ESC [ rows ; cols R */
    initParseEscapeSeq(&parser, 'R');
    while ((ch = fd_read_char(current->fd, 100)) > 0) {
    while ((ch = fd_read_char(current, 100)) > 0) {
        switch (parseEscapeSequence(&parser, ch)) {
            default:
                continue;
            case EP_END:
                if (parser.numprops == 2 && parser.props[1] < 1000) {
                    *cols = parser.props[1];
                    return 1;
                }
                break;
            case EP_ERROR:
                /* Push back the character that caused the error */
                current->pending = ch;
                break;
        }
        /* failed */
        break;
    }
    query_cursor_failed = 1;
    return 0;
}

/**
 * Updates current->cols with the current window size (width)
 */
static int getWindowSize(struct current *current)
1384
1385
1386
1387
1388
1389
1390
1391

1392
1393

1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404

1405
1406
1407
1408
1409
1410
1411
1410
1411
1412
1413
1414
1415
1416

1417
1418

1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429

1430
1431
1432
1433
1434
1435
1436
1437







-
+

-
+










-
+







 * chars to determine if this is a known special key.
 *
 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
 *
 * If no additional char is received within a short time,
 * CHAR_ESCAPE is returned.
 */
static int check_special(int fd)
static int check_special(struct current *current)
{
    int c = fd_read_char(fd, 50);
    int c = fd_read_char(current, 50);
    int c2;

    if (c < 0) {
        return CHAR_ESCAPE;
    }
    else if (c >= 'a' && c <= 'z') {
        /* esc-a => meta-a */
        return meta(c);
    }

    c2 = fd_read_char(fd, 50);
    c2 = fd_read_char(current, 50);
    if (c2 < 0) {
        return c2;
    }
    if (c == '[' || c == 'O') {
        /* Potential arrow key */
        switch (c2) {
            case 'A':
1420
1421
1422
1423
1424
1425
1426
1427

1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446

1447
1448
1449
1450
1451
1452
1453
1446
1447
1448
1449
1450
1451
1452

1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471

1472
1473
1474
1475
1476
1477
1478
1479







-
+


















-
+







                return SPECIAL_END;
            case 'H':
                return SPECIAL_HOME;
        }
    }
    if (c == '[' && c2 >= '1' && c2 <= '8') {
        /* extended escape */
        c = fd_read_char(fd, 50);
        c = fd_read_char(current, 50);
        if (c == '~') {
            switch (c2) {
                case '2':
                    return SPECIAL_INSERT;
                case '3':
                    return SPECIAL_DELETE;
                case '5':
                    return SPECIAL_PAGE_UP;
                case '6':
                    return SPECIAL_PAGE_DOWN;
                case '7':
                    return SPECIAL_HOME;
                case '8':
                    return SPECIAL_END;
            }
        }
        while (c != -1 && c != '~') {
            /* .e.g \e[12~ or '\e[11;2~   discard the complete sequence */
            c = fd_read_char(fd, 50);
            c = fd_read_char(current, 50);
        }
    }

    return SPECIAL_NONE;
}
#endif

2232
2233
2234
2235
2236
2237
2238
2239

2240
2241
2242
2243
2244
2245
2246
2258
2259
2260
2261
2262
2263
2264

2265
2266
2267
2268
2269
2270
2271
2272







-
+







                rbuf[p_ind] = 0;
                rlen = strlen(rbuf);
            }
            continue;
        }
#ifdef USE_TERMIOS
        if (c == CHAR_ESCAPE) {
            c = check_special(current->fd);
            c = check_special(current);
        }
#endif
        if (c == ctrl('R')) {
            /* Search for the previous (earlier) match */
            if (searchpos > 0) {
                searchpos--;
            }
2344
2345
2346
2347
2348
2349
2350
2351

2352
2353
2354
2355
2356
2357
2358
2370
2371
2372
2373
2374
2375
2376

2377
2378
2379
2380
2381
2382
2383
2384







-
+







            /* reverse incremental search will provide an alternative keycode or 0 for none */
            c = reverseIncrementalSearch(current);
            /* go on to process the returned char normally */
        }

#ifdef USE_TERMIOS
        if (c == CHAR_ESCAPE) {   /* escape sequence */
            c = check_special(current->fd);
            c = check_special(current);
        }
#endif
        if (c == -1) {
            /* Return on errors */
            return sb_len(current->buf);
        }