blob: e600cbe6f560e47c2c8e12694dbfa8ddfc3d1a42 [file] [log] [blame]
Gavin Howardb0faf442018-12-12 03:42:55 -07001/*
2 * *****************************************************************************
3 *
Gavin Howard29e00ba2020-06-30 09:25:21 -06004 * SPDX-License-Identifier: BSD-2-Clause
5 *
Zach van Rijn6d2cf3f2020-01-14 22:05:02 +00006 * Copyright (c) 2018-2020 Gavin D. Howard and contributors.
Gavin Howardb0faf442018-12-12 03:42:55 -07007 *
Gavin Howard7345cb92019-04-08 14:13:43 -06008 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
Gavin Howardb0faf442018-12-12 03:42:55 -070029 *
30 * *****************************************************************************
31 *
32 * Adapted from the following:
33 *
34 * linenoise.c -- guerrilla line editing library against the idea that a
35 * line editing lib needs to be 20,000 lines of C code.
36 *
37 * You can find the original source code at:
38 * http://github.com/antirez/linenoise
39 *
Gavin Howardf15f9042018-12-12 12:40:41 -070040 * You can find the fork that this code is based on at:
41 * https://github.com/rain-1/linenoise-mob
42 *
Gavin Howardb0faf442018-12-12 03:42:55 -070043 * ------------------------------------------------------------------------
44 *
45 * This code is also under the following license:
46 *
47 * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
48 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
49 *
Gavin Howardb0faf442018-12-12 03:42:55 -070050 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions are
52 * met:
53 *
54 * * Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
56 *
57 * * Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 *
61 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
64 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
65 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
66 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
67 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
68 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
69 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
70 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
71 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 *
73 * *****************************************************************************
74 *
75 * Definitions for line history.
76 *
77 */
78
Gavin Howard641fe972018-12-12 04:06:03 -070079#ifndef BC_HISTORY_H
80#define BC_HISTORY_H
Gavin Howardb0faf442018-12-12 03:42:55 -070081
Gavin Howard77d016f2019-04-22 09:44:43 -060082#ifndef BC_ENABLE_HISTORY
83#define BC_ENABLE_HISTORY (1)
84#endif // BC_ENABLE_HISTORY
85
Gavin Howard1545ffe2018-12-24 11:26:46 -070086#if BC_ENABLE_HISTORY
87
Gavin Howard7fa6a342018-12-24 11:57:54 -070088#ifdef _WIN32
Gavin Howard8c341912018-12-24 11:54:41 -070089#error History is not supported on Windows.
Gavin Howarddac1cb82020-04-09 14:01:49 -060090#endif // _WIN32
Gavin Howard8c341912018-12-24 11:54:41 -070091
Gavin Howardbceb32d2018-12-12 22:23:51 -070092#include <stdbool.h>
Gavin Howardb0faf442018-12-12 03:42:55 -070093#include <stddef.h>
94
Gavin Howard95e244b2019-06-14 23:33:33 -060095#include <signal.h>
96
Gavin Howardbceb32d2018-12-12 22:23:51 -070097#include <termios.h>
Gavin Howard95e244b2019-06-14 23:33:33 -060098#include <time.h>
Gavin Howardbceb32d2018-12-12 22:23:51 -070099#include <unistd.h>
Gavin Howard95e244b2019-06-14 23:33:33 -0600100#include <sys/select.h>
Gavin Howardbceb32d2018-12-12 22:23:51 -0700101
Gavin Howard7fd3e3f2018-12-13 16:19:46 -0700102#include <status.h>
Gavin Howard9f9bef42020-10-22 21:37:46 -0600103#include "vector.h"
104#include "read.h"
Gavin Howard7fd3e3f2018-12-13 16:19:46 -0700105
Gavin Howardc86dcd72020-05-22 19:23:57 -0600106#if BC_DEBUG_CODE
Gavin Howard9f9bef42020-10-22 21:37:46 -0600107#include "file.h"
Gavin Howardc86dcd72020-05-22 19:23:57 -0600108#endif // BC_DEBUG_CODE
109
Gavin Howard5f349d42019-04-09 14:14:00 -0600110#define BC_HIST_DEF_COLS (80)
111#define BC_HIST_MAX_LEN (128)
112#define BC_HIST_MAX_LINE (4095)
Gavin Howardaa0b7562019-06-17 22:34:11 -0600113#define BC_HIST_SEQ_SIZE (64)
Gavin Howard939bbe42018-12-12 12:04:49 -0700114
Gavin Howard5f349d42019-04-09 14:14:00 -0600115#define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1)
Gavin Howard1f1fab72020-06-04 19:13:44 -0600116#define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1)
Gavin Howard63c12c62018-12-13 18:20:55 -0700117
Gavin Howard5f349d42019-04-09 14:14:00 -0600118#define BC_HIST_NEXT (false)
119#define BC_HIST_PREV (true)
Gavin Howard20f6edb2018-12-13 00:41:19 -0700120
Gavin Howard15afde92019-04-11 10:05:32 -0600121#if BC_DEBUG_CODE
Gavin Howardc86dcd72020-05-22 19:23:57 -0600122
123#define BC_HISTORY_DEBUG_BUF_SIZE (1024)
124
125#define lndebug(...) \
126 do { \
127 if (bc_history_debug_fp.fd == 0) { \
128 bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \
129 bc_file_init(&bc_history_debug_fp, \
130 open("/tmp/lndebug.txt", O_APPEND), \
131 BC_HISTORY_DEBUG_BUF_SIZE); \
132 bc_file_printf(&bc_history_debug_fp, \
133 "[%zu %zu %zu] p: %d, rows: %d, " \
134 "rpos: %d, max: %zu, oldmax: %d\n", \
135 l->len, l->pos, l->oldcolpos, plen, rows, rpos, \
136 l->maxrows, old_rows); \
137 } \
138 bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \
139 bc_file_flush(&bc_history_debug_fp); \
Gavin Howard939bbe42018-12-12 12:04:49 -0700140 } while (0)
Gavin Howard15afde92019-04-11 10:05:32 -0600141#else // BC_DEBUG_CODE
Gavin Howard939bbe42018-12-12 12:04:49 -0700142#define lndebug(fmt, ...)
Gavin Howard15afde92019-04-11 10:05:32 -0600143#endif // BC_DEBUG_CODE
Gavin Howard7a64f2e2018-12-12 11:27:41 -0700144
Gavin Howard1444c9f2019-06-21 21:16:11 -0600145#if !BC_ENABLE_PROMPT
146#define bc_history_line(h, vec, prompt) bc_history_line(h, vec)
147#define bc_history_raw(h, prompt) bc_history_raw(h)
148#define bc_history_edit(h, prompt) bc_history_edit(h)
149#endif // BC_ENABLE_PROMPT
150
Gavin Howard800db282018-12-12 11:07:25 -0700151typedef enum BcHistoryAction {
Gavin Howard31488e42018-12-13 00:57:51 -0700152
Gavin Howarda5b39882018-12-12 11:27:08 -0700153 BC_ACTION_NULL = 0,
154 BC_ACTION_CTRL_A = 1,
155 BC_ACTION_CTRL_B = 2,
156 BC_ACTION_CTRL_C = 3,
157 BC_ACTION_CTRL_D = 4,
158 BC_ACTION_CTRL_E = 5,
159 BC_ACTION_CTRL_F = 6,
160 BC_ACTION_CTRL_H = 8,
Gavin Howard95e244b2019-06-14 23:33:33 -0600161 BC_ACTION_TAB = 9,
Gavin Howarda5b39882018-12-12 11:27:08 -0700162 BC_ACTION_LINE_FEED = 10,
163 BC_ACTION_CTRL_K = 11,
164 BC_ACTION_CTRL_L = 12,
165 BC_ACTION_ENTER = 13,
166 BC_ACTION_CTRL_N = 14,
167 BC_ACTION_CTRL_P = 16,
168 BC_ACTION_CTRL_T = 20,
169 BC_ACTION_CTRL_U = 21,
170 BC_ACTION_CTRL_W = 23,
Gavin Howard348cf2a2019-01-08 23:21:25 -0700171 BC_ACTION_CTRL_Z = 26,
Gavin Howarda5b39882018-12-12 11:27:08 -0700172 BC_ACTION_ESC = 27,
173 BC_ACTION_BACKSPACE = 127
Gavin Howard31488e42018-12-13 00:57:51 -0700174
Gavin Howard800db282018-12-12 11:07:25 -0700175} BcHistoryAction;
176
Gavin Howard31488e42018-12-13 00:57:51 -0700177/**
178 * This represents the state during line editing. We pass this state
179 * to functions implementing specific editing functionalities.
180 */
Gavin Howard6e04ac22018-12-12 22:33:53 -0700181typedef struct BcHistory {
Gavin Howard31488e42018-12-13 00:57:51 -0700182
Gavin Howard31488e42018-12-13 00:57:51 -0700183 /// Edited line buffer.
Gavin Howardfa9cb562018-12-13 17:06:24 -0700184 BcVec buf;
Gavin Howard31488e42018-12-13 00:57:51 -0700185
Gavin Howard22db8192019-01-04 10:52:21 -0700186 /// The history.
187 BcVec history;
188
Gavin Howard1444c9f2019-06-21 21:16:11 -0600189#if BC_ENABLE_PROMPT
Gavin Howard31488e42018-12-13 00:57:51 -0700190 /// Prompt to display.
191 const char *prompt;
192
193 /// Prompt length.
194 size_t plen;
Gavin Howard1444c9f2019-06-21 21:16:11 -0600195#endif // BC_ENABLE_PROMPT
Gavin Howard31488e42018-12-13 00:57:51 -0700196
Gavin Howard5e59c392019-05-20 07:51:10 -0600197 /// Prompt column length.
198 size_t pcol;
199
Gavin Howard31488e42018-12-13 00:57:51 -0700200 /// Current cursor position.
201 size_t pos;
202
203 /// Previous refresh cursor column position.
204 size_t oldcolpos;
205
Gavin Howard31488e42018-12-13 00:57:51 -0700206 /// Number of columns in terminal.
207 size_t cols;
208
209 /// The history index we are currently editing.
Gavin Howard09f5af32018-12-13 16:48:23 -0700210 size_t idx;
Gavin Howard31488e42018-12-13 00:57:51 -0700211
212 /// The original terminal state.
Gavin Howardbceb32d2018-12-12 22:23:51 -0700213 struct termios orig_termios;
Gavin Howard31488e42018-12-13 00:57:51 -0700214
Gavin Howard415cea62020-05-15 15:51:06 -0600215 /// These next three are here because pahole found a 4 byte hole here.
Gavin Howard95e244b2019-06-14 23:33:33 -0600216
217 /// This is to signal that there is more, so we don't process yet.
218 bool stdin_has_data;
219
Gavin Howard31488e42018-12-13 00:57:51 -0700220 /// Whether we are in rawmode.
Gavin Howard7fd3e3f2018-12-13 16:19:46 -0700221 bool rawMode;
Gavin Howard31488e42018-12-13 00:57:51 -0700222
Gavin Howard417446d2018-12-13 14:34:15 -0700223 /// Whether the terminal is bad.
224 bool badTerm;
225
Gavin Howard415cea62020-05-15 15:51:06 -0600226 /// This is to check if stdin has more data.
227 fd_set rdset;
228
229 /// This is to check if stdin has more data.
230 struct timespec ts;
231
232 /// This is to check if stdin has more data.
233 sigset_t sigmask;
234
Gavin Howard6e04ac22018-12-12 22:33:53 -0700235} BcHistory;
Gavin Howard939bbe42018-12-12 12:04:49 -0700236
Gavin Howard1d4c99d2018-12-13 22:43:37 -0700237BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt);
Gavin Howardb0faf442018-12-12 03:42:55 -0700238
Gavin Howard31488e42018-12-13 00:57:51 -0700239void bc_history_init(BcHistory *h);
240void bc_history_free(BcHistory *h);
Gavin Howardbceb32d2018-12-12 22:23:51 -0700241
Gavin Howard939bbe42018-12-12 12:04:49 -0700242extern const char *bc_history_bad_terms[];
Gavin Howard95e244b2019-06-14 23:33:33 -0600243extern const char bc_history_tab[];
244extern const size_t bc_history_tab_len;
Gavin Howard286da2a2018-12-20 12:33:53 -0700245extern const char bc_history_ctrlc[];
Gavin Howard1cbfe242019-01-09 17:13:11 -0700246extern const uint32_t bc_history_wchars[][2];
Gavin Howardf15f9042018-12-12 12:40:41 -0700247extern const size_t bc_history_wchars_len;
Gavin Howard1cbfe242019-01-09 17:13:11 -0700248extern const uint32_t bc_history_combo_chars[];
Gavin Howardf15f9042018-12-12 12:40:41 -0700249extern const size_t bc_history_combo_chars_len;
Gavin Howard15afde92019-04-11 10:05:32 -0600250#if BC_DEBUG_CODE
Gavin Howardc86dcd72020-05-22 19:23:57 -0600251extern BcFile bc_history_debug_fp;
252extern char *bc_history_debug_buf;
253void bc_history_printKeyCodes(BcHistory* l);
Gavin Howard15afde92019-04-11 10:05:32 -0600254#endif // BC_DEBUG_CODE
Gavin Howardb0faf442018-12-12 03:42:55 -0700255
Gavin Howard641fe972018-12-12 04:06:03 -0700256#endif // BC_ENABLE_HISTORY
Gavin Howardb0faf442018-12-12 03:42:55 -0700257
Gavin Howard641fe972018-12-12 04:06:03 -0700258#endif // BC_HISTORY_H