Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F3074183
readline.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
readline.c
View Options
#include
<ctype.h>
#include
<signal.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<sys/stat.h>
#ifdef _WIN32
#include
<conio.h>
#define WIN32_LEAN_AND_MEAN
#include
<windows.h>
#include
<direct.h>
#define STDIN_FILENO 0
#define mkdir_p(path) _mkdir(path)
#else
#include
<sys/ioctl.h>
#include
<termios.h>
#include
<unistd.h>
#define mkdir_p(path) mkdir(path, 0755)
#endif
#include
<crprintf.h>
#include
"highlight.h"
#include
"readline.h"
#include
"utf8.h"
#define MAX_LINE_LENGTH 4096
static
volatile
sig_atomic_t
ctrl_c_pressed
=
0
;
static
crprintf_compiled
*
hl_prog
=
NULL
;
static
highlight_state
hl_line_state
=
HL_STATE_INIT
;
static
int
repl_last_cursor_row
=
0
;
static
void
sigint_handler
(
int
sig
)
{
(
void
)
sig
;
ctrl_c_pressed
++
;
}
void
ant_readline_install_signal_handler
(
void
)
{
#ifdef _WIN32
signal
(
SIGINT
,
sigint_handler
);
#else
struct
sigaction
sa
;
memset
(
&
sa
,
0
,
sizeof
(
sa
));
sa
.
sa_handler
=
sigint_handler
;
sigemptyset
(
&
sa
.
sa_mask
);
sigaction
(
SIGINT
,
&
sa
,
NULL
);
#endif
}
void
ant_readline_shutdown
(
void
)
{
if
(
hl_prog
)
{
crprintf_compiled_free
(
hl_prog
);
hl_prog
=
NULL
;
}
}
void
ant_history_init
(
ant_history_t
*
hist
,
int
capacity
)
{
hist
->
capacity
=
(
capacity
>
0
)
?
capacity
:
512
;
hist
->
lines
=
malloc
(
sizeof
(
char
*
)
*
(
size_t
)
hist
->
capacity
);
if
(
!
hist
->
lines
)
hist
->
capacity
=
0
;
hist
->
count
=
0
;
hist
->
current
=
-1
;
}
void
ant_history_add
(
ant_history_t
*
hist
,
const
char
*
line
)
{
if
(
!
hist
||
!
hist
->
lines
||
hist
->
capacity
<=
0
||
!
line
||
line
[
0
]
==
'\0'
)
return
;
if
(
hist
->
count
>
0
&&
strcmp
(
hist
->
lines
[
hist
->
count
-
1
],
line
)
==
0
)
return
;
if
(
hist
->
count
>=
hist
->
capacity
)
{
free
(
hist
->
lines
[
0
]);
memmove
(
hist
->
lines
,
hist
->
lines
+
1
,
sizeof
(
char
*
)
*
(
size_t
)(
hist
->
capacity
-
1
));
hist
->
count
--
;
}
hist
->
lines
[
hist
->
count
++
]
=
strdup
(
line
);
hist
->
current
=
hist
->
count
;
}
const
char
*
ant_history_prev
(
ant_history_t
*
hist
)
{
if
(
!
hist
||
!
hist
->
lines
||
hist
->
count
==
0
)
return
NULL
;
if
(
hist
->
current
>
0
)
hist
->
current
--
;
return
hist
->
lines
[
hist
->
current
];
}
const
char
*
ant_history_next
(
ant_history_t
*
hist
)
{
if
(
!
hist
||
!
hist
->
lines
||
hist
->
count
==
0
)
return
NULL
;
if
(
hist
->
current
<
hist
->
count
-
1
)
{
hist
->
current
++
;
return
hist
->
lines
[
hist
->
current
];
}
hist
->
current
=
hist
->
count
;
return
""
;
}
void
ant_history_free
(
ant_history_t
*
hist
)
{
if
(
!
hist
||
!
hist
->
lines
)
return
;
for
(
int
i
=
0
;
i
<
hist
->
count
;
i
++
)
free
(
hist
->
lines
[
i
]);
free
(
hist
->
lines
);
hist
->
lines
=
NULL
;
hist
->
count
=
0
;
hist
->
capacity
=
0
;
hist
->
current
=
-1
;
}
static
char
*
get_history_path
(
void
)
{
const
char
*
home
=
getenv
(
"HOME"
);
if
(
!
home
)
home
=
getenv
(
"USERPROFILE"
);
if
(
!
home
)
return
NULL
;
size_t
len
=
strlen
(
home
)
+
32
;
char
*
path
=
malloc
(
len
);
snprintf
(
path
,
len
,
"%s/.ant"
,
home
);
mkdir_p
(
path
);
snprintf
(
path
,
len
,
"%s/.ant/repl_history"
,
home
);
return
path
;
}
void
ant_history_load
(
ant_history_t
*
hist
)
{
if
(
!
hist
||
!
hist
->
lines
||
hist
->
capacity
<=
0
)
return
;
char
*
path
=
get_history_path
();
if
(
!
path
)
return
;
FILE
*
fp
=
fopen
(
path
,
"r"
);
free
(
path
);
if
(
!
fp
)
return
;
char
line
[
MAX_LINE_LENGTH
];
while
(
fgets
(
line
,
sizeof
(
line
),
fp
))
{
size_t
len
=
strlen
(
line
);
if
(
len
>
0
&&
line
[
len
-
1
]
==
'\n'
)
line
[
len
-
1
]
=
'\0'
;
if
(
line
[
0
])
ant_history_add
(
hist
,
line
);
}
fclose
(
fp
);
}
void
ant_history_save
(
const
ant_history_t
*
hist
)
{
if
(
!
hist
||
!
hist
->
lines
)
return
;
char
*
path
=
get_history_path
();
if
(
!
path
)
return
;
FILE
*
fp
=
fopen
(
path
,
"w"
);
free
(
path
);
if
(
!
fp
)
return
;
for
(
int
i
=
0
;
i
<
hist
->
count
;
i
++
)
{
fprintf
(
fp
,
"%s
\n
"
,
hist
->
lines
[
i
]);
}
fclose
(
fp
);
}
typedef
enum
{
KEY_NONE
,
KEY_UP
,
KEY_DOWN
,
KEY_LEFT
,
KEY_RIGHT
,
KEY_HOME
,
KEY_END
,
KEY_DELETE
,
KEY_BACKSPACE
,
KEY_ENTER
,
KEY_EOF
,
KEY_CHAR
}
key_type_t
;
typedef
struct
{
key_type_t
type
;
int
ch
;
}
key_event_t
;
static
int
repl_terminal_cols
(
void
)
{
int
cols
=
80
;
#ifdef _WIN32
CONSOLE_SCREEN_BUFFER_INFO
csbi
;
if
(
GetConsoleScreenBufferInfo
(
GetStdHandle
(
STD_OUTPUT_HANDLE
),
&
csbi
))
{
cols
=
csbi
.
srWindow
.
Right
-
csbi
.
srWindow
.
Left
+
1
;
}
#else
struct
winsize
ws
;
if
(
ioctl
(
STDOUT_FILENO
,
TIOCGWINSZ
,
&
ws
)
==
0
&&
ws
.
ws_col
>
0
)
{
cols
=
ws
.
ws_col
;
}
#endif
return
(
cols
>
0
)
?
cols
:
80
;
}
static
void
repl_jump_cursor
(
int
x_pos
,
int
y_offset
)
{
#ifdef _WIN32
if
(
y_offset
!=
0
)
{
char
seq
[
32
];
snprintf
(
seq
,
sizeof
(
seq
),
"
\033
[%d%c"
,
abs
(
y_offset
),
(
y_offset
>
0
)
?
'B'
:
'A'
);
fputs
(
seq
,
stdout
);
}
char
seq
[
32
];
snprintf
(
seq
,
sizeof
(
seq
),
"
\033
[%dG"
,
x_pos
+
1
);
fputs
(
seq
,
stdout
);
#else
if
(
y_offset
!=
0
)
{
char
seq
[
32
];
snprintf
(
seq
,
sizeof
(
seq
),
"
\033
[%d%c"
,
abs
(
y_offset
),
(
y_offset
>
0
)
?
'B'
:
'A'
);
fputs
(
seq
,
stdout
);
}
char
seq
[
32
];
snprintf
(
seq
,
sizeof
(
seq
),
"
\033
[%dG"
,
x_pos
+
1
);
fputs
(
seq
,
stdout
);
#endif
}
static
void
repl_clear_to_end
(
void
)
{
fputs
(
"
\033
[J"
,
stdout
);
}
static
void
repl_set_cursor_visible
(
bool
visible
)
{
#ifdef _WIN32
(
void
)
visible
;
#else
fputs
(
visible
?
"
\033
[?25h"
:
"
\033
[?25l"
,
stdout
);
#endif
}
static
size_t
repl_skip_ansi_escape
(
const
char
*
s
,
size_t
len
,
size_t
i
)
{
if
(
i
>=
len
||
(
unsigned
char
)
s
[
i
]
!=
0x1B
)
return
i
;
if
(
i
+
1
>=
len
)
return
i
+
1
;
unsigned
char
next
=
(
unsigned
char
)
s
[
i
+
1
];
if
(
next
==
'['
)
{
i
+=
2
;
while
(
i
<
len
)
{
unsigned
char
ch
=
(
unsigned
char
)
s
[
i
++
];
if
(
ch
>=
0x40
&&
ch
<=
0x7E
)
break
;
}
return
i
;
}
if
(
next
==
']'
)
{
i
+=
2
;
while
(
i
<
len
)
{
unsigned
char
ch
=
(
unsigned
char
)
s
[
i
];
if
(
ch
==
'\a'
)
return
i
+
1
;
if
(
ch
==
0x1B
&&
i
+
1
<
len
&&
s
[
i
+
1
]
==
'\\'
)
return
i
+
2
;
i
++
;
}
return
i
;
}
return
i
+
2
;
}
static
void
repl_virtual_render
(
const
char
*
s
,
size_t
n
,
int
screen_cols
,
int
prompt_len
,
int
*
x
,
int
*
y
)
{
bool
wrapped
=
false
;
size_t
i
=
0
;
while
(
i
<
n
)
{
unsigned
char
c
=
(
unsigned
char
)
s
[
i
];
if
(
c
==
'\n'
||
c
==
'\r'
)
{
if
(
c
==
'\n'
&&
!
wrapped
)
(
*
y
)
++
;
*
x
=
prompt_len
;
i
++
;
wrapped
=
false
;
continue
;
}
if
(
c
==
0x1B
)
{
i
=
repl_skip_ansi_escape
(
s
,
n
,
i
);
continue
;
}
utf8proc_int32_t
cp
=
0
;
utf8proc_ssize_t
clen
=
utf8_next
((
const
utf8proc_uint8_t
*
)(
s
+
i
),
(
utf8proc_ssize_t
)(
n
-
i
),
&
cp
);
if
(
clen
<=
0
)
{
clen
=
1
;
cp
=
c
;
}
int
w
=
utf8proc_charwidth
(
cp
);
if
(
w
<
0
)
w
=
1
;
if
(
w
>
0
)
{
*
x
+=
w
;
wrapped
=
false
;
if
(
*
x
>=
screen_cols
)
{
*
x
=
0
;
(
*
y
)
++
;
wrapped
=
true
;
}
}
i
+=
(
size_t
)
clen
;
}
}
static
int
repl_prompt_width
(
const
char
*
prompt
,
int
cols
)
{
int
x
=
0
;
int
y
=
0
;
repl_virtual_render
(
prompt
,
strlen
(
prompt
),
cols
,
0
,
&
x
,
&
y
);
return
x
;
}
static
void
refresh_line
(
const
char
*
line
,
int
len
,
int
pos
,
const
char
*
prompt
)
{
int
cols
=
repl_terminal_cols
();
int
prompt_len
=
repl_prompt_width
(
prompt
,
cols
);
int
x_cursor
=
prompt_len
;
int
y_cursor
=
0
;
int
x_end
=
prompt_len
;
int
y_end
=
0
;
repl_virtual_render
(
line
,
(
size_t
)
pos
,
cols
,
prompt_len
,
&
x_cursor
,
&
y_cursor
);
repl_virtual_render
(
line
,
(
size_t
)
len
,
cols
,
prompt_len
,
&
x_end
,
&
y_end
);
repl_set_cursor_visible
(
false
);
repl_jump_cursor
(
prompt_len
,
-
repl_last_cursor_row
);
repl_clear_to_end
();
if
(
crprintf_get_color
()
&&
len
>
0
)
{
if
(
len
<=
2048
)
{
char
tagged
[
8192
];
char
rendered
[
8192
];
highlight_state
state
=
hl_line_state
;
ant_highlight_stateful
(
line
,
(
size_t
)
len
,
tagged
,
sizeof
(
tagged
),
&
state
);
hl_prog
=
crprintf_recompile
(
hl_prog
,
tagged
);
crprintf_state
*
rs
=
crprintf_state_new
();
crsprintf_compiled
(
rendered
,
sizeof
(
rendered
),
rs
,
hl_prog
);
crprintf_state_free
(
rs
);
fputs
(
rendered
,
stdout
);
}
else
{
fwrite
(
line
,
1
,
(
size_t
)
len
,
stdout
);
}
}
else
if
(
len
>
0
)
{
fwrite
(
line
,
1
,
(
size_t
)
len
,
stdout
);
}
#ifndef _WIN32
if
((
x_end
==
0
)
&&
(
y_end
>
0
)
&&
(
len
>
0
)
&&
(
line
[
len
-
1
]
!=
'\n'
))
{
fputs
(
"
\n
"
,
stdout
);
}
#endif
repl_jump_cursor
(
x_cursor
,
-
(
y_end
-
y_cursor
));
repl_set_cursor_visible
(
true
);
repl_last_cursor_row
=
y_cursor
;
fflush
(
stdout
);
}
static
void
move_cursor_only
(
const
char
*
line
,
int
pos
,
const
char
*
prompt
)
{
int
cols
=
repl_terminal_cols
();
int
prompt_len
=
repl_prompt_width
(
prompt
,
cols
);
int
x_cursor
=
prompt_len
;
int
y_cursor
=
0
;
repl_virtual_render
(
line
,
(
size_t
)
pos
,
cols
,
prompt_len
,
&
x_cursor
,
&
y_cursor
);
repl_jump_cursor
(
x_cursor
,
-
(
repl_last_cursor_row
-
y_cursor
));
repl_last_cursor_row
=
y_cursor
;
fflush
(
stdout
);
}
static
int
utf8_prev_pos
(
const
char
*
line
,
int
pos
)
{
if
(
pos
<=
0
)
return
0
;
int
prev
=
0
;
int
i
=
0
;
while
(
i
<
pos
)
{
prev
=
i
;
utf8proc_int32_t
cp
=
0
;
utf8proc_ssize_t
n
=
utf8_next
(
(
const
utf8proc_uint8_t
*
)(
line
+
i
),
(
utf8proc_ssize_t
)(
pos
-
i
),
&
cp
);
i
+=
(
int
)((
n
>
0
)
?
n
:
1
);
}
return
prev
;
}
static
int
utf8_next_pos
(
const
char
*
line
,
int
len
,
int
pos
)
{
if
(
pos
>=
len
)
return
len
;
utf8proc_int32_t
cp
=
0
;
utf8proc_ssize_t
n
=
utf8_next
(
(
const
utf8proc_uint8_t
*
)(
line
+
pos
),
(
utf8proc_ssize_t
)(
len
-
pos
),
&
cp
);
int
next
=
pos
+
(
int
)((
n
>
0
)
?
n
:
1
);
return
(
next
>
len
)
?
len
:
next
;
}
static
void
line_set
(
char
*
line
,
int
*
pos
,
int
*
len
,
const
char
*
str
,
const
char
*
prompt
)
{
size_t
n
=
strlen
(
str
);
if
(
n
>=
(
size_t
)
MAX_LINE_LENGTH
)
n
=
(
size_t
)
MAX_LINE_LENGTH
-
1
;
memcpy
(
line
,
str
,
n
);
line
[
n
]
=
'\0'
;
*
len
=
(
int
)
strlen
(
line
);
*
pos
=
*
len
;
refresh_line
(
line
,
*
len
,
*
pos
,
prompt
);
}
static
void
line_backspace
(
char
*
line
,
int
*
pos
,
int
*
len
,
const
char
*
prompt
)
{
if
(
*
pos
<=
0
)
return
;
int
prev
=
utf8_prev_pos
(
line
,
*
pos
);
memmove
(
line
+
prev
,
line
+
*
pos
,
(
size_t
)(
*
len
-
*
pos
+
1
));
*
len
-=
(
*
pos
-
prev
);
*
pos
=
prev
;
refresh_line
(
line
,
*
len
,
*
pos
,
prompt
);
}
static
void
line_delete
(
char
*
line
,
int
*
pos
,
int
*
len
,
const
char
*
prompt
)
{
if
(
*
pos
>=
*
len
)
return
;
int
next
=
utf8_next_pos
(
line
,
*
len
,
*
pos
);
memmove
(
line
+
*
pos
,
line
+
next
,
(
size_t
)(
*
len
-
next
+
1
));
*
len
-=
(
next
-
*
pos
);
refresh_line
(
line
,
*
len
,
*
pos
,
prompt
);
}
static
void
line_insert
(
char
*
line
,
int
*
pos
,
int
*
len
,
int
c
,
const
char
*
prompt
)
{
if
(
*
len
>=
MAX_LINE_LENGTH
-
1
)
return
;
memmove
(
line
+
*
pos
+
1
,
line
+
*
pos
,
(
size_t
)(
*
len
-
*
pos
+
1
));
line
[
*
pos
]
=
(
char
)
c
;
(
*
pos
)
++
;
(
*
len
)
++
;
refresh_line
(
line
,
*
len
,
*
pos
,
prompt
);
}
#ifdef _WIN32
static
key_event_t
read_key
(
void
)
{
if
(
ctrl_c_pressed
>
0
)
return
(
key_event_t
){
KEY_EOF
,
0
};
int
c
=
_getch
();
if
(
c
==
0
||
c
==
0xE0
)
{
int
ext
=
_getch
();
switch
(
ext
)
{
case
72
:
return
(
key_event_t
){
KEY_UP
,
0
};
case
80
:
return
(
key_event_t
){
KEY_DOWN
,
0
};
case
77
:
return
(
key_event_t
){
KEY_RIGHT
,
0
};
case
75
:
return
(
key_event_t
){
KEY_LEFT
,
0
};
case
71
:
return
(
key_event_t
){
KEY_HOME
,
0
};
case
79
:
return
(
key_event_t
){
KEY_END
,
0
};
case
83
:
return
(
key_event_t
){
KEY_DELETE
,
0
};
default
:
return
(
key_event_t
){
KEY_NONE
,
0
};
}
}
if
(
c
==
8
)
return
(
key_event_t
){
KEY_BACKSPACE
,
0
};
if
(
c
==
'\r'
||
c
==
'\n'
)
return
(
key_event_t
){
KEY_ENTER
,
0
};
if
(
c
==
3
)
{
ctrl_c_pressed
++
;
return
(
key_event_t
){
KEY_EOF
,
0
};
}
if
(
c
==
4
||
c
==
26
)
return
(
key_event_t
){
KEY_EOF
,
0
};
if
(
isprint
(
c
)
||
(
unsigned
char
)
c
>=
0x80
)
return
(
key_event_t
){
KEY_CHAR
,
c
};
return
(
key_event_t
){
KEY_NONE
,
0
};
}
#else
static
struct
termios
saved_tio
;
static
key_event_t
read_key
(
void
)
{
if
(
ctrl_c_pressed
>
0
)
return
(
key_event_t
){
KEY_EOF
,
0
};
int
c
=
getchar
();
if
(
c
==
EOF
&&
!
feof
(
stdin
))
{
clearerr
(
stdin
);
return
(
key_event_t
){
KEY_EOF
,
0
};
}
if
(
c
==
EOF
)
return
(
key_event_t
){
KEY_EOF
,
0
};
if
(
c
==
27
)
{
int
seq1
=
getchar
();
if
(
seq1
==
EOF
)
return
(
key_event_t
){
KEY_NONE
,
0
};
if
(
seq1
==
'O'
)
{
int
seq2
=
getchar
();
if
(
seq2
==
'H'
)
return
(
key_event_t
){
KEY_HOME
,
0
};
if
(
seq2
==
'F'
)
return
(
key_event_t
){
KEY_END
,
0
};
return
(
key_event_t
){
KEY_NONE
,
0
};
}
if
(
seq1
!=
'['
)
return
(
key_event_t
){
KEY_NONE
,
0
};
int
seq2
=
getchar
();
if
(
seq2
==
EOF
)
return
(
key_event_t
){
KEY_NONE
,
0
};
switch
(
seq2
)
{
case
'A'
:
return
(
key_event_t
){
KEY_UP
,
0
};
case
'B'
:
return
(
key_event_t
){
KEY_DOWN
,
0
};
case
'C'
:
return
(
key_event_t
){
KEY_RIGHT
,
0
};
case
'D'
:
return
(
key_event_t
){
KEY_LEFT
,
0
};
case
'H'
:
return
(
key_event_t
){
KEY_HOME
,
0
};
case
'F'
:
return
(
key_event_t
){
KEY_END
,
0
};
default
:
{
if
(
seq2
>=
'0'
&&
seq2
<=
'9'
)
{
int
seq3
=
getchar
();
if
(
seq3
==
'~'
)
{
if
(
seq2
==
'1'
||
seq2
==
'7'
)
return
(
key_event_t
){
KEY_HOME
,
0
};
if
(
seq2
==
'4'
||
seq2
==
'8'
)
return
(
key_event_t
){
KEY_END
,
0
};
if
(
seq2
==
'3'
)
return
(
key_event_t
){
KEY_DELETE
,
0
};
}
}
return
(
key_event_t
){
KEY_NONE
,
0
};
}
}
}
if
(
c
==
127
||
c
==
8
)
return
(
key_event_t
){
KEY_BACKSPACE
,
0
};
if
(
c
==
'\n'
||
c
==
'\r'
)
return
(
key_event_t
){
KEY_ENTER
,
0
};
if
(
isprint
(
c
)
||
(
unsigned
char
)
c
>=
0x80
)
return
(
key_event_t
){
KEY_CHAR
,
c
};
return
(
key_event_t
){
KEY_NONE
,
0
};
}
#endif
static
void
term_restore
(
void
)
{
#ifndef _WIN32
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
saved_tio
);
#endif
}
static
char
*
read_line_with_history
(
ant_history_t
*
hist
,
const
char
*
prompt
)
{
char
*
line
=
malloc
(
MAX_LINE_LENGTH
);
if
(
!
line
)
return
NULL
;
int
pos
=
0
;
int
len
=
0
;
line
[
0
]
=
'\0'
;
repl_last_cursor_row
=
0
;
#ifndef _WIN32
struct
termios
new_tio
;
tcgetattr
(
STDIN_FILENO
,
&
saved_tio
);
new_tio
=
saved_tio
;
new_tio
.
c_lflag
&=
~
(
ICANON
|
ECHO
);
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
new_tio
);
#endif
for
(;;)
{
key_event_t
key
=
read_key
();
static
const
void
*
dispatch
[]
=
{
[
KEY_NONE
]
=
&&
l_none
,
[
KEY_UP
]
=
&&
l_up
,
[
KEY_DOWN
]
=
&&
l_down
,
[
KEY_LEFT
]
=
&&
l_left
,
[
KEY_RIGHT
]
=
&&
l_right
,
[
KEY_HOME
]
=
&&
l_home
,
[
KEY_END
]
=
&&
l_end
,
[
KEY_DELETE
]
=
&&
l_delete
,
[
KEY_BACKSPACE
]
=
&&
l_backspace
,
[
KEY_ENTER
]
=
&&
l_enter
,
[
KEY_EOF
]
=
&&
l_eof
,
[
KEY_CHAR
]
=
&&
l_char
,
};
unsigned
int
t
=
(
unsigned
int
)
key
.
type
;
if
(
t
<
(
sizeof
(
dispatch
)
/
sizeof
(
*
dispatch
))
&&
dispatch
[
t
])
goto
*
dispatch
[
t
];
goto
l_none
;
l_enter
:
putchar
(
'\n'
);
term_restore
();
return
line
;
l_eof
:
putchar
(
'\n'
);
term_restore
();
free
(
line
);
return
NULL
;
l_up
:
{
const
char
*
h
=
ant_history_prev
(
hist
);
if
(
h
)
line_set
(
line
,
&
pos
,
&
len
,
h
,
prompt
);
continue
;
}
l_down
:
{
const
char
*
h
=
ant_history_next
(
hist
);
if
(
h
)
line_set
(
line
,
&
pos
,
&
len
,
h
,
prompt
);
continue
;
}
l_left
:
if
(
pos
>
0
)
{
pos
=
utf8_prev_pos
(
line
,
pos
);
move_cursor_only
(
line
,
pos
,
prompt
);
}
continue
;
l_right
:
if
(
pos
<
len
)
{
pos
=
utf8_next_pos
(
line
,
len
,
pos
);
move_cursor_only
(
line
,
pos
,
prompt
);
}
continue
;
l_home
:
if
(
pos
!=
0
)
{
pos
=
0
;
move_cursor_only
(
line
,
pos
,
prompt
);
}
continue
;
l_end
:
if
(
pos
!=
len
)
{
pos
=
len
;
move_cursor_only
(
line
,
pos
,
prompt
);
}
continue
;
l_delete
:
line_delete
(
line
,
&
pos
,
&
len
,
prompt
);
continue
;
l_backspace
:
line_backspace
(
line
,
&
pos
,
&
len
,
prompt
);
continue
;
l_char
:
line_insert
(
line
,
&
pos
,
&
len
,
key
.
ch
,
prompt
);
continue
;
l_none
:
continue
;
}
}
ant_readline_result_t
ant_readline
(
ant_history_t
*
hist
,
const
char
*
prompt
,
highlight_state
line_state
,
char
**
out_line
)
{
if
(
out_line
)
*
out_line
=
NULL
;
hl_line_state
=
line_state
;
ctrl_c_pressed
=
0
;
char
*
line
=
read_line_with_history
(
hist
,
prompt
);
if
(
ctrl_c_pressed
>
0
)
{
if
(
line
)
free
(
line
);
return
ANT_READLINE_INTERRUPT
;
}
if
(
!
line
)
return
ANT_READLINE_EOF
;
if
(
out_line
)
*
out_line
=
line
;
return
ANT_READLINE_LINE
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Apr 4, 2:04 AM (1 d, 23 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
520775
Default Alt Text
readline.c (15 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment