mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Improve linenoise and get it working on Windows
Some progress has been made on introducing completion but there's been difficulties using the Python C API to get local shell variables.
This commit is contained in:
parent
968474d291
commit
5029e20bef
23 changed files with 408 additions and 209 deletions
|
@ -16,6 +16,7 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/rand/xorshift.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
|
@ -25,6 +26,12 @@
|
|||
#include "libc/testlib/hyperion.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define B 4096
|
||||
|
||||
bool isdone;
|
||||
bool isbinary;
|
||||
unsigned long count = -1;
|
||||
|
||||
uint64_t bcast(uint64_t f(void)) {
|
||||
unsigned i;
|
||||
uint64_t x;
|
||||
|
@ -95,6 +102,28 @@ uint64_t vigna(void) {
|
|||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
uint64_t rngset64(void) {
|
||||
static unsigned i;
|
||||
static uint64_t s;
|
||||
if (!i) {
|
||||
s = rand64();
|
||||
i = (s + 1) & (511);
|
||||
}
|
||||
return MarsagliaXorshift64(&s);
|
||||
}
|
||||
|
||||
uint64_t xorshift64(void) {
|
||||
static uint64_t s = kMarsagliaXorshift64Seed;
|
||||
return MarsagliaXorshift64(&s);
|
||||
}
|
||||
|
||||
uint64_t xorshift32(void) {
|
||||
static uint32_t s = kMarsagliaXorshift32Seed;
|
||||
uint64_t a = MarsagliaXorshift32(&s);
|
||||
uint64_t b = MarsagliaXorshift32(&s);
|
||||
return (uint64_t)a << 32 | b;
|
||||
}
|
||||
|
||||
uint64_t libc(void) {
|
||||
uint64_t x;
|
||||
CHECK_EQ(8, getrandom(&x, 8, 0));
|
||||
|
@ -151,27 +180,26 @@ const struct Function {
|
|||
const char *s;
|
||||
uint64_t (*f)(void);
|
||||
} kFunctions[] = {
|
||||
{"ape", ape}, //
|
||||
{"hardware", hardware}, //
|
||||
{"inc", inc}, //
|
||||
{"kernel", kernel}, //
|
||||
{"knuth", knuth}, //
|
||||
{"libc", libc}, //
|
||||
{"moby", moby}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rdrand", rdrnd}, //
|
||||
{"rdrnd", rdrnd}, //
|
||||
{"rdseed", rdseed}, //
|
||||
{"unixv6", unixv6}, //
|
||||
{"unixv7", unixv7}, //
|
||||
{"vigna", vigna}, //
|
||||
{"zero", zero}, //
|
||||
{"ape", ape}, //
|
||||
{"hardware", hardware}, //
|
||||
{"inc", inc}, //
|
||||
{"kernel", kernel}, //
|
||||
{"knuth", knuth}, //
|
||||
{"libc", libc}, //
|
||||
{"moby", moby}, //
|
||||
{"rand64", rand64}, //
|
||||
{"rdrand", rdrnd}, //
|
||||
{"rdrnd", rdrnd}, //
|
||||
{"rdseed", rdseed}, //
|
||||
{"rngset64", rngset64}, //
|
||||
{"unixv6", unixv6}, //
|
||||
{"unixv7", unixv7}, //
|
||||
{"vigna", vigna}, //
|
||||
{"xorshift32", xorshift32}, //
|
||||
{"xorshift64", xorshift64}, //
|
||||
{"zero", zero}, //
|
||||
};
|
||||
|
||||
bool isdone;
|
||||
bool isbinary;
|
||||
unsigned long count = -1;
|
||||
|
||||
void OnInt(int sig) {
|
||||
isdone = true;
|
||||
}
|
||||
|
@ -182,16 +210,19 @@ wontreturn void PrintUsage(FILE *f, int rc) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *p;
|
||||
int i, opt;
|
||||
ssize_t rc;
|
||||
uint64_t x;
|
||||
static char buf[B];
|
||||
uint64_t (*f)(void);
|
||||
|
||||
while ((opt = getopt(argc, argv, "hbn:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hbc:n:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
isbinary = true;
|
||||
break;
|
||||
case 'c':
|
||||
case 'n':
|
||||
count = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
|
@ -235,10 +266,23 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
while (count && !isdone) {
|
||||
x = f();
|
||||
rc = write(1, &x, MIN(8, count));
|
||||
if (count >= B) {
|
||||
for (i = 0; i < B / 8; ++i) {
|
||||
x = f();
|
||||
p = buf + i * 8;
|
||||
WRITE64LE(p, x);
|
||||
}
|
||||
for (i = 0; i < B; i += rc) {
|
||||
rc = write(1, buf + i, B - i);
|
||||
if (rc == -1 && errno == EPIPE) exit(1);
|
||||
if (rc == -1) perror("write"), exit(1);
|
||||
}
|
||||
} else {
|
||||
x = f();
|
||||
rc = write(1, &x, MIN(8, count));
|
||||
}
|
||||
if (!rc) break;
|
||||
if (rc == -1 && errno == EPIPE) return 1;
|
||||
if (rc == -1 && errno == EPIPE) exit(1);
|
||||
if (rc == -1) perror("write"), exit(1);
|
||||
count -= rc;
|
||||
}
|
||||
|
|
|
@ -267,8 +267,12 @@ int editorReadKey(int64_t fd) {
|
|||
if (read(fd, seq + 2, 1) == 0) return CTRL('[');
|
||||
if (seq[2] == '~') {
|
||||
switch (seq[1]) {
|
||||
case '1':
|
||||
return HOME_KEY;
|
||||
case '3':
|
||||
return DEL_KEY;
|
||||
case '4':
|
||||
return END_KEY;
|
||||
case '5':
|
||||
return PAGE_UP;
|
||||
case '6':
|
||||
|
|
|
@ -41,7 +41,8 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) {
|
|||
if (inmode & kNtEnableProcessedInput) tio->c_lflag |= IEXTEN | ISIG;
|
||||
}
|
||||
if (outok) {
|
||||
if (inmode & kNtEnableProcessedInput) tio->c_lflag |= IEXTEN | ISIG;
|
||||
if (outmode & kNtEnableProcessedOutput) tio->c_oflag |= OPOST;
|
||||
if (!(outmode & kNtDisableNewlineAutoReturn)) tio->c_oflag |= ONLCR;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -51,8 +51,8 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
|
|||
}
|
||||
if (outok) {
|
||||
outmode |= kNtEnableWrapAtEolOutput;
|
||||
outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & OPOST)) outmode |= kNtDisableNewlineAutoReturn;
|
||||
if (tio->c_oflag & OPOST) outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & ONLCR)) outmode |= kNtDisableNewlineAutoReturn;
|
||||
if (NtGetVersion() >= kNtVersionWindows10) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ ssize_t readansi(int fd, char *buf, size_t size) {
|
|||
break;
|
||||
case kCsi:
|
||||
switch (c) {
|
||||
case '[':
|
||||
case ':':
|
||||
case ';':
|
||||
case '<':
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
||||
/**
|
||||
|
@ -29,6 +30,7 @@
|
|||
relegated wontreturn void __die(void) {
|
||||
static bool once;
|
||||
if (cmpxchg(&once, false, true)) {
|
||||
__restore_tty();
|
||||
if (IsDebuggerPresent(false)) DebugBreak();
|
||||
ShowBacktrace(2, NULL);
|
||||
}
|
||||
|
|
|
@ -2,16 +2,19 @@
|
|||
#define COSMOPOLITAN_LIBC_LOG_INTERNAL_H_
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern int kCrashSigs[8] hidden;
|
||||
extern struct termios g_oldtermios hidden;
|
||||
extern struct sigaction g_oldcrashacts[8] hidden;
|
||||
|
||||
void __start_fatal(const char *, int) hidden;
|
||||
void __start_fatal_ndebug(void) hidden;
|
||||
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;
|
||||
void __restore_tty(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
45
libc/log/oldtermios.c
Normal file
45
libc/log/oldtermios.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define SHOW_CURSOR "\e[?25h"
|
||||
#define DISABLE_MOUSE "\e[?1000;1002;1015;1006l"
|
||||
#define ANSI_RESTORE SHOW_CURSOR DISABLE_MOUSE
|
||||
|
||||
struct termios g_oldtermios;
|
||||
|
||||
static textstartup void g_oldtermios_init() {
|
||||
if (isatty(1)) {
|
||||
tcgetattr(1, &g_oldtermios);
|
||||
}
|
||||
}
|
||||
|
||||
const void *const g_oldtermios_ctor[] initarray = {
|
||||
g_oldtermios_init,
|
||||
};
|
||||
|
||||
void __restore_tty(void) {
|
||||
if (isatty(1)) {
|
||||
write(1, ANSI_RESTORE, strlen(ANSI_RESTORE));
|
||||
tcsetattr(1, TCSAFLUSH, &g_oldtermios);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,9 @@
|
|||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/utsname.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
|
@ -41,6 +43,7 @@
|
|||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Abnormal termination handling & GUI debugging.
|
||||
|
@ -262,6 +265,7 @@ relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
|
|||
: 0);
|
||||
}
|
||||
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
|
||||
__restore_tty();
|
||||
ShowCrashReport(err, STDERR_FILENO, sig, si, ctx);
|
||||
exit(128 + sig);
|
||||
unreachable;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/check.h"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
relegated void __start_fatal(const char *file, int line) {
|
||||
bool colorful;
|
||||
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p = s;
|
||||
__restore_tty();
|
||||
colorful = cancolor();
|
||||
*p++ = '\r';
|
||||
if (colorful) p = stpcpy(p, "\e[J\e[30;101m");
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
*/
|
||||
relegated void __start_fatal_ndebug(void) {
|
||||
char s[16 + 16 + 16 + 16 + PATH_MAX + 16], *p = s;
|
||||
__restore_tty();
|
||||
*p++ = '\r';
|
||||
if (cancolor()) p = stpcpy(p, "\e[J");
|
||||
p = stpcpy(p, "error:");
|
||||
|
|
|
@ -45,10 +45,11 @@ static bool have_getrandom;
|
|||
* This random number seed generator blends information from:
|
||||
*
|
||||
* - getrandom() on Linux
|
||||
* - RtlGenRandom() on Windows
|
||||
* - getentropy() on XNU and OpenBSD
|
||||
* - sysctl(KERN_ARND) on FreeBSD and NetBSD
|
||||
* - RDSEED on Broadwell+ and Xen+ unless GRND_NORDRND
|
||||
* - RDRAND on Ivybridge+ and Xen+ unless GRND_NORDRND|GRND_RANDOM
|
||||
* - RDRAND on Ivybridge+ and Xen+ unless GRND_NORDRND
|
||||
*
|
||||
* The following flags may be specified:
|
||||
*
|
||||
|
@ -75,7 +76,9 @@ ssize_t getrandom(void *p, size_t n, unsigned f) {
|
|||
sigset_t neu, old;
|
||||
if (n > 256) n = 256;
|
||||
if (!IsTiny() &&
|
||||
(f & ~(GRND_RANDOM | GRND_NONBLOCK | GRND_NORDRND | GRND_NOSYSTEM))) {
|
||||
((f & ~(GRND_RANDOM | GRND_NONBLOCK | GRND_NORDRND | GRND_NOSYSTEM)) ||
|
||||
(f & (GRND_NORDRND | GRND_NOSYSTEM)) ==
|
||||
(GRND_NORDRND | GRND_NOSYSTEM))) {
|
||||
return einval();
|
||||
}
|
||||
if (!(f & GRND_NOSYSTEM)) {
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
/**
|
||||
* Fills memory with random bytes, e.g.
|
||||
*
|
||||
* char buf[1024];
|
||||
* rngset(buf, sizeof(buf), rand64, -1);
|
||||
* char buf[1024];
|
||||
* rngset(buf, sizeof(buf), rand64, -1);
|
||||
*
|
||||
* @param seed can be rand64() and is always called at least once
|
||||
* @param reseed is bytes between seed() calls and -1 disables it
|
||||
|
|
|
@ -53,6 +53,7 @@ void *xunbinga(size_t, const char16_t *) attributeallocalign((1)) _XMAL _XRET;
|
|||
void *xunbing(const char16_t *) _XMAL _XRET;
|
||||
char16_t *utf8toutf16(const char *, size_t, size_t *) nodiscard;
|
||||
char *utf16toutf8(const char16_t *, size_t, size_t *) nodiscard;
|
||||
char *xhomedir(void) nodiscard;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § eXtended apis » files ─╬─│┼
|
||||
|
|
43
libc/x/xhomedir.c
Normal file
43
libc/x/xhomedir.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Returns home directory.
|
||||
*/
|
||||
char *xhomedir(void) {
|
||||
int fd;
|
||||
const char *a, *b;
|
||||
if ((a = getenv("HOME"))) {
|
||||
b = "";
|
||||
} else if (IsWindows()) {
|
||||
a = getenv("HOMEDRIVE");
|
||||
b = getenv("HOMEPATH");
|
||||
if (!a || !b) {
|
||||
a = "C:";
|
||||
b = "";
|
||||
}
|
||||
} else {
|
||||
a = ".";
|
||||
b = "";
|
||||
}
|
||||
return xasprintf("%s%s", a, b);
|
||||
}
|
261
third_party/linenoise/linenoise.c
vendored
261
third_party/linenoise/linenoise.c
vendored
|
@ -15,6 +15,7 @@
|
|||
│ │
|
||||
│ Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> │
|
||||
│ Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> │
|
||||
│ Copyright (c) 2018-2020, Justine Tunney <jtunney at gmail dot com> │
|
||||
│ │
|
||||
│ All rights reserved. │
|
||||
│ │
|
||||
|
@ -43,67 +44,22 @@
|
|||
│ │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ │
|
||||
│ Todo list: │
|
||||
│ - Filter bogus Ctrl+<char> combinations. │
|
||||
│ - Win32 support │
|
||||
│ CHANGES │
|
||||
│ │
|
||||
│ Bloat: [say what?!] MUST DO: │
|
||||
│ - History search like Ctrl+r in readline? │
|
||||
│ - Remove bell │
|
||||
│ - Windows support │
|
||||
│ - Filters out unsupported control sequences │
|
||||
│ - Filters out Thompson-Pike input sequences │
|
||||
│ │
|
||||
│ List of escape sequences used by this program, we do everything just │
|
||||
│ with three sequences. In order to be so cheap we may have some │
|
||||
│ flickering effect with some slow terminal, but the lesser sequences │
|
||||
│ the more compatible. │
|
||||
│ TODO │
|
||||
│ │
|
||||
│ EL (Erase Line) │
|
||||
│ Sequence: ESC [ n K │
|
||||
│ Effect: if n is 0 or missing, clear from cursor to end of line │
|
||||
│ Effect: if n is 1, clear from beginning of line to cursor │
|
||||
│ Effect: if n is 2, clear entire line │
|
||||
│ │
|
||||
│ CUF (CUrsor Forward) │
|
||||
│ Sequence: ESC [ n C │
|
||||
│ Effect: moves cursor forward n chars │
|
||||
│ │
|
||||
│ CUB (CUrsor Backward) │
|
||||
│ Sequence: ESC [ n D │
|
||||
│ Effect: moves cursor backward n chars │
|
||||
│ │
|
||||
│ The following is used to get the terminal width if getting │
|
||||
│ the width with the TIOCGWINSZ ioctl fails │
|
||||
│ │
|
||||
│ DSR (Device Status Report) │
|
||||
│ Sequence: ESC [ 6 n │
|
||||
│ Effect: reports the current cusor position as ESC [ n ; m R │
|
||||
│ where n is the row and m is the column │
|
||||
│ │
|
||||
│ When multi line mode is enabled, we also use an additional escape │
|
||||
│ sequence. However multi line editing is disabled by default. │
|
||||
│ │
|
||||
│ CUU (Cursor Up) │
|
||||
│ Sequence: ESC [ n A │
|
||||
│ Effect: moves cursor up of n chars. │
|
||||
│ │
|
||||
│ CUD (Cursor Down) │
|
||||
│ Sequence: ESC [ n B │
|
||||
│ Effect: moves cursor down of n chars. │
|
||||
│ │
|
||||
│ When linenoiseClearScreen() is called, two additional escape sequences │
|
||||
│ are used in order to clear the screen and position the cursor at home │
|
||||
│ position. │
|
||||
│ │
|
||||
│ CUP (Cursor position) │
|
||||
│ Sequence: ESC [ H │
|
||||
│ Effect: moves the cursor to upper left corner │
|
||||
│ │
|
||||
│ ED (Erase display) │
|
||||
│ Sequence: ESC [ 2 J │
|
||||
│ Effect: clear the whole screen │
|
||||
│ │
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ - Kill ring │
|
||||
│ - History search │
|
||||
│ - Thompson-Pike Encoding │
|
||||
│ │
|
||||
│ REFERENCE │
|
||||
│ the big scary coding you 𝘮𝘶𝘴𝘵 use curses to abstract │
|
||||
│ │
|
||||
│ The big scary coding you 𝘮𝘶𝘴𝘵 use curses to abstract. │
|
||||
│ │
|
||||
│ \t TAB │
|
||||
│ \a BELL │
|
||||
|
@ -221,6 +177,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/calls/ttydefaults.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
@ -267,28 +224,6 @@ struct linenoiseState {
|
|||
int history_index; /* The history index we are currently editing. */
|
||||
};
|
||||
|
||||
enum KEY_ACTION{
|
||||
KEY_NULL = 0, /* NULL */
|
||||
CTRL_A = 1, /* Ctrl+a */
|
||||
CTRL_B = 2, /* Ctrl-b */
|
||||
CTRL_C = 3, /* Ctrl-c */
|
||||
CTRL_D = 4, /* Ctrl-d */
|
||||
CTRL_E = 5, /* Ctrl-e */
|
||||
CTRL_F = 6, /* Ctrl-f */
|
||||
CTRL_H = 8, /* Ctrl-h */
|
||||
TAB = 9, /* Tab */
|
||||
CTRL_K = 11, /* Ctrl+k */
|
||||
CTRL_L = 12, /* Ctrl+l */
|
||||
ENTER = 13, /* Enter */
|
||||
CTRL_N = 14, /* Ctrl-n */
|
||||
CTRL_P = 16, /* Ctrl-p */
|
||||
CTRL_T = 20, /* Ctrl-t */
|
||||
CTRL_U = 21, /* Ctrl+u */
|
||||
CTRL_W = 23, /* Ctrl+w */
|
||||
ESC = 27, /* Escape */
|
||||
BACKSPACE = 127 /* Backspace */
|
||||
};
|
||||
|
||||
static void linenoiseAtExit(void);
|
||||
static void refreshLine(struct linenoiseState *);
|
||||
|
||||
|
@ -362,7 +297,7 @@ static int enableRawMode(int fd) {
|
|||
raw.c_oflag &= ~(OPOST);
|
||||
/* control modes - set 8 bit chars */
|
||||
raw.c_cflag |= (CS8);
|
||||
/* local modes - choing off, canonical off, no extended functions,
|
||||
/* local modes - echoing off, canonical off, no extended functions,
|
||||
* no signal chars (^Z,^C) */
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
|
||||
/* control chars - set return condition: min number of bytes and timer.
|
||||
|
@ -391,7 +326,7 @@ static int getCursorPosition(int ifd, int ofd) {
|
|||
int cols, rows;
|
||||
unsigned int i = 0;
|
||||
/* Report cursor location */
|
||||
if (write(ofd, "\x1b[6n", 4) != 4) return -1;
|
||||
if (write(ofd, "\e[6n", 4) != 4) return -1;
|
||||
/* Read the response: ESC [ rows ; cols R */
|
||||
while (i < sizeof(buf)-1) {
|
||||
if (read(ifd,buf+i,1) != 1) break;
|
||||
|
@ -400,7 +335,7 @@ static int getCursorPosition(int ifd, int ofd) {
|
|||
}
|
||||
buf[i] = '\0';
|
||||
/* Parse it. */
|
||||
if (buf[0] != ESC || buf[1] != '[') return -1;
|
||||
if (buf[0] != '\e' || buf[1] != '[') return -1;
|
||||
if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1;
|
||||
return cols;
|
||||
}
|
||||
|
@ -416,13 +351,13 @@ static int getColumns(int ifd, int ofd) {
|
|||
start = getCursorPosition(ifd,ofd);
|
||||
if (start == -1) goto failed;
|
||||
/* Go to right margin and get position. */
|
||||
if (write(ofd,"\x1b[999C",6) != 6) goto failed;
|
||||
if (write(ofd,"\e[999C",6) != 6) goto failed;
|
||||
cols = getCursorPosition(ifd,ofd);
|
||||
if (cols == -1) goto failed;
|
||||
/* Restore position. */
|
||||
if (cols > start) {
|
||||
char seq[32];
|
||||
snprintf(seq,32,"\x1b[%dD",cols-start);
|
||||
snprintf(seq,32,"\e[%dD",cols-start);
|
||||
if (write(ofd,seq,strlen(seq)) == -1) {
|
||||
/* Can't recover... */
|
||||
}
|
||||
|
@ -437,7 +372,7 @@ failed:
|
|||
|
||||
/* Clear the screen. Used to handle ctrl+l */
|
||||
void linenoiseClearScreen(void) {
|
||||
if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) {
|
||||
if (write(STDOUT_FILENO,"\e[H\e[2J",7) <= 0) {
|
||||
/* nothing to do, just to avoid warning. */
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +380,8 @@ void linenoiseClearScreen(void) {
|
|||
/* Beep, used for completion when there is nothing to complete or when all
|
||||
* the choices were already shown. */
|
||||
static void linenoiseBeep(void) {
|
||||
fprintf(stderr, "\x7");
|
||||
/* NOOOO */
|
||||
/* fprintf(stderr, "\x7"); */
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
@ -494,11 +430,11 @@ static int completeLine(struct linenoiseState *ls) {
|
|||
return -1;
|
||||
}
|
||||
switch(c) {
|
||||
case 9: /* tab */
|
||||
case '\t':
|
||||
i = (i+1) % (lc.len+1);
|
||||
if (i == lc.len) linenoiseBeep();
|
||||
break;
|
||||
case 27: /* escape */
|
||||
case '\e':
|
||||
/* Re-show original buffer */
|
||||
if (i < lc.len) refreshLine(ls);
|
||||
stop = 1;
|
||||
|
@ -595,13 +531,13 @@ void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
|
|||
if (hintlen > hintmaxlen) hintlen = hintmaxlen;
|
||||
if (bold == 1 && color == -1) color = 37;
|
||||
if (color != -1 || bold != 0)
|
||||
snprintf(seq,64,"\033[%d;%d;49m",bold,color);
|
||||
snprintf(seq,64,"\e[%d;%d;49m",bold,color);
|
||||
else
|
||||
seq[0] = '\0';
|
||||
abAppend(ab,seq,strlen(seq));
|
||||
abAppend(ab,hint,hintlen);
|
||||
if (color != -1 || bold != 0)
|
||||
abAppend(ab,"\033[0m",4);
|
||||
abAppend(ab,"\e[0m",4);
|
||||
/* Call the function to free the hint returned. */
|
||||
if (freeHintsCallback) freeHintsCallback(hint);
|
||||
}
|
||||
|
@ -642,10 +578,10 @@ static void refreshSingleLine(struct linenoiseState *l) {
|
|||
/* Show hits if any. */
|
||||
refreshShowHints(&ab,l,plen);
|
||||
/* Erase to right */
|
||||
snprintf(seq,64,"\x1b[0K");
|
||||
snprintf(seq,64,"\e[0K");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
/* Move cursor to original position. */
|
||||
snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen));
|
||||
snprintf(seq,64,"\r\e[%dC", (int)(pos+plen));
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
|
||||
abFree(&ab);
|
||||
|
@ -672,18 +608,18 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
|||
abInit(&ab);
|
||||
if (old_rows-rpos > 0) {
|
||||
lndebug("go down %d", old_rows-rpos);
|
||||
snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
|
||||
snprintf(seq,64,"\e[%dB", old_rows-rpos);
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
}
|
||||
/* Now for every row clear it, go up. */
|
||||
for (j = 0; j < old_rows-1; j++) {
|
||||
lndebug("clear+up");
|
||||
snprintf(seq,64,"\r\x1b[0K\x1b[1A");
|
||||
snprintf(seq,64,"\r\e[0K\e[1A");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
}
|
||||
/* Clean the top line. */
|
||||
lndebug("clear");
|
||||
snprintf(seq,64,"\r\x1b[0K");
|
||||
snprintf(seq,64,"\r\e[0K");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
/* Write the prompt and the current buffer content */
|
||||
abAppend(&ab,l->prompt,strlen(l->prompt));
|
||||
|
@ -714,14 +650,14 @@ static void refreshMultiLine(struct linenoiseState *l) {
|
|||
/* Go up till we reach the expected positon. */
|
||||
if (rows-rpos2 > 0) {
|
||||
lndebug("go-up %d", rows-rpos2);
|
||||
snprintf(seq,64,"\x1b[%dA", rows-rpos2);
|
||||
snprintf(seq,64,"\e[%dA", rows-rpos2);
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
}
|
||||
/* Set column. */
|
||||
col = (plen+(int)l->pos) % (int)l->cols;
|
||||
lndebug("set col %d", 1+col);
|
||||
if (col)
|
||||
snprintf(seq,64,"\r\x1b[%dC", col);
|
||||
snprintf(seq,64,"\r\e[%dC", col);
|
||||
else
|
||||
snprintf(seq,64,"\r");
|
||||
abAppend(&ab,seq,strlen(seq));
|
||||
|
@ -778,6 +714,28 @@ void linenoiseEditMoveLeft(struct linenoiseState *l) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Move cursor on the left. */
|
||||
void linenoiseEditMoveLeftWord(struct linenoiseState *l) {
|
||||
if (l->pos > 0) {
|
||||
while (l->pos > 0 && l->buf[l->pos-1] == ' ')
|
||||
l->pos--;
|
||||
while (l->pos > 0 && l->buf[l->pos-1] != ' ')
|
||||
l->pos--;
|
||||
refreshLine(l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move cursor on the right. */
|
||||
void linenoiseEditMoveRightWord(struct linenoiseState *l) {
|
||||
if (l->pos != l->len) {
|
||||
while (l->pos < l->len && l->buf[l->pos] == ' ')
|
||||
l->pos++;
|
||||
while (l->pos < l->len && l->buf[l->pos] != ' ')
|
||||
l->pos++;
|
||||
refreshLine(l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move cursor on the right. */
|
||||
void linenoiseEditMoveRight(struct linenoiseState *l) {
|
||||
if (l->pos != l->len) {
|
||||
|
@ -896,15 +854,17 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
linenoiseHistoryAdd("");
|
||||
if (write(l.ofd,prompt,l.plen) == -1) return -1;
|
||||
while(1) {
|
||||
char c;
|
||||
int i;
|
||||
int c;
|
||||
int nread;
|
||||
char seq[3];
|
||||
nread = read(l.ifd,&c,1);
|
||||
char seq[32];
|
||||
nread = readansi(l.ifd,seq,sizeof(seq));
|
||||
if (nread <= 0) return l.len;
|
||||
c = seq[0];
|
||||
/* Only autocomplete when the callback is set. It returns < 0 when
|
||||
* there was an error reading from fd. Otherwise it will return the
|
||||
* character that should be handled next. */
|
||||
if (c == 9 && completionCallback != NULL) {
|
||||
if (c == '\t' && completionCallback) {
|
||||
c = completeLine(&l);
|
||||
/* Return on errors */
|
||||
if (c < 0) return l.len;
|
||||
|
@ -912,7 +872,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
if (c == 0) continue;
|
||||
}
|
||||
switch(c) {
|
||||
case ENTER: /* enter */
|
||||
case '\r': /* enter */
|
||||
history_len--;
|
||||
free(history[history_len]);
|
||||
if (mlmode) linenoiseEditMoveEnd(&l);
|
||||
|
@ -925,15 +885,15 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
hintsCallback = hc;
|
||||
}
|
||||
return (int)l.len;
|
||||
case CTRL_C: /* ctrl-c */
|
||||
case CTRL('C'):
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
case BACKSPACE: /* backspace */
|
||||
case 8: /* ctrl-h */
|
||||
case CTRL('?'): /* backspace a.k.a. 0177 a.k.a. 127 */
|
||||
case CTRL('H'):
|
||||
linenoiseEditBackspace(&l);
|
||||
break;
|
||||
case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the
|
||||
line is empty, act as end-of-file. */
|
||||
case CTRL('D'): /* remove char at right of cursor, or if the
|
||||
line is empty, act as end-of-file. */
|
||||
if (l.len > 0) {
|
||||
linenoiseEditDelete(&l);
|
||||
} else {
|
||||
|
@ -942,7 +902,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
case CTRL_T: /* ctrl-t, swaps current character with previous. */
|
||||
case CTRL('T'): /* swaps current character with previous. */
|
||||
if (l.pos > 0 && l.pos < l.len) {
|
||||
int aux = buf[l.pos-1];
|
||||
buf[l.pos-1] = buf[l.pos];
|
||||
|
@ -951,95 +911,110 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
|
|||
refreshLine(&l);
|
||||
}
|
||||
break;
|
||||
case CTRL_B: /* ctrl-b */
|
||||
case CTRL('B'):
|
||||
linenoiseEditMoveLeft(&l);
|
||||
break;
|
||||
case CTRL_F: /* ctrl-f */
|
||||
case CTRL('F'):
|
||||
linenoiseEditMoveRight(&l);
|
||||
break;
|
||||
case CTRL_P: /* ctrl-p */
|
||||
case CTRL('P'):
|
||||
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
|
||||
break;
|
||||
case CTRL_N: /* ctrl-n */
|
||||
case CTRL('N'):
|
||||
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
|
||||
break;
|
||||
case ESC: /* escape sequence */
|
||||
case '\e': /* escape sequence */
|
||||
/* Read the next two bytes representing the escape sequence.
|
||||
* Use two calls to handle slow terminals returning the two
|
||||
* chars at different times. */
|
||||
if (read(l.ifd,seq,1) == -1) break;
|
||||
if (read(l.ifd,seq+1,1) == -1) break;
|
||||
/* ESC [ sequences. */
|
||||
if (seq[0] == '[') {
|
||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||
/* Extended escape, read additional byte. */
|
||||
if (read(l.ifd,seq+2,1) == -1) break;
|
||||
if (seq[2] == '~') {
|
||||
switch(seq[1]) {
|
||||
case '3': /* Delete key. */
|
||||
if (nread < 2) break;
|
||||
if (seq[1] == '[') {
|
||||
if (nread < 3) break;
|
||||
if (seq[2] >= '0' && seq[2] <= '9') {
|
||||
if (nread < 4) break;
|
||||
if (seq[3] == '~') {
|
||||
switch(seq[2]) {
|
||||
case '1': /* "\e[1~" is home */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case '3': /* "\e[3~" is delete */
|
||||
linenoiseEditDelete(&l);
|
||||
break;
|
||||
case '4': /* "\e[4~" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch(seq[1]) {
|
||||
case 'A': /* Up */
|
||||
switch(seq[2]) {
|
||||
case 'A': /* "\e[A" is up */
|
||||
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV);
|
||||
break;
|
||||
case 'B': /* Down */
|
||||
case 'B': /* "\e[B" is down */
|
||||
linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT);
|
||||
break;
|
||||
case 'C': /* Right */
|
||||
case 'C': /* "\e[C" is right */
|
||||
linenoiseEditMoveRight(&l);
|
||||
break;
|
||||
case 'D': /* Left */
|
||||
case 'D': /* "\e[D" is left */
|
||||
linenoiseEditMoveLeft(&l);
|
||||
break;
|
||||
case 'H': /* Home */
|
||||
case 'H': /* "\e[H" is home */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case 'F': /* End*/
|
||||
case 'F': /* "\e[F" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ESC O sequences. */
|
||||
else if (seq[0] == 'O') {
|
||||
switch(seq[1]) {
|
||||
case 'H': /* Home */
|
||||
else if (seq[1] == 'O') {
|
||||
if (nread < 3) break;
|
||||
switch(seq[2]) {
|
||||
case 'H': /* "\eOH" is home */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case 'F': /* End*/
|
||||
case 'F': /* "\eOF" is end */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (seq[1] == 'b') { /* "\eb" is alt-b */
|
||||
linenoiseEditMoveLeftWord(&l);
|
||||
} else if (seq[1] == 'f') { /* "\ef" is alt-f */
|
||||
linenoiseEditMoveRightWord(&l);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (linenoiseEditInsert(&l,c)) return -1;
|
||||
if (32 <= seq[0] && seq[0] < 127) {
|
||||
if (linenoiseEditInsert(&l,seq[0])==-1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CTRL_U: /* Ctrl+u, delete the whole line. */
|
||||
case CTRL('U'): /* delete the whole line */
|
||||
/* TODO(jart): delete backwards */
|
||||
buf[0] = '\0';
|
||||
l.pos = l.len = 0;
|
||||
refreshLine(&l);
|
||||
break;
|
||||
case CTRL_K: /* Ctrl+k, delete from current to end of line. */
|
||||
case CTRL('K'): /* delete from current to end of line */
|
||||
/* TODO(jart): add to kill ring */
|
||||
buf[l.pos] = '\0';
|
||||
l.len = l.pos;
|
||||
refreshLine(&l);
|
||||
break;
|
||||
case CTRL_A: /* Ctrl+a, go to the start of the line */
|
||||
case CTRL('A'): /* go to the start of the line */
|
||||
linenoiseEditMoveHome(&l);
|
||||
break;
|
||||
case CTRL_E: /* ctrl+e, go to the end of the line */
|
||||
case CTRL('E'): /* go to the end of the line */
|
||||
linenoiseEditMoveEnd(&l);
|
||||
break;
|
||||
case CTRL_L: /* ctrl+l, clear screen */
|
||||
case CTRL('L'): /* clear screen */
|
||||
linenoiseClearScreen();
|
||||
refreshLine(&l);
|
||||
break;
|
||||
case CTRL_W: /* ctrl+w, delete previous word */
|
||||
case CTRL('W'): /* delete previous word */
|
||||
linenoiseEditDeletePrevWord(&l);
|
||||
break;
|
||||
}
|
||||
|
@ -1083,7 +1058,7 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
|
|||
if (enableRawMode(STDIN_FILENO) == -1) return -1;
|
||||
count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
|
||||
linenoiseDisableRawMode(STDIN_FILENO);
|
||||
printf("\n");
|
||||
if (count != -1) printf("\n");
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1154,8 +1129,6 @@ void linenoiseFree(void *ptr) {
|
|||
free(ptr);
|
||||
}
|
||||
|
||||
/* ================================ History ================================= */
|
||||
|
||||
/* Free the history, but does not reset it. Only used when we have to
|
||||
* exit() to avoid memory leaks are reported by valgrind & co. */
|
||||
static void freeHistory(void) {
|
||||
|
|
13
third_party/python/Modules/getbuildinfo.c
vendored
13
third_party/python/Modules/getbuildinfo.c
vendored
|
@ -38,18 +38,7 @@
|
|||
const char *
|
||||
Py_GetBuildInfo(void)
|
||||
{
|
||||
static char buildinfo[50 + sizeof(GITVERSION) +
|
||||
((sizeof(GITTAG) > sizeof(GITBRANCH)) ?
|
||||
sizeof(GITTAG) : sizeof(GITBRANCH))];
|
||||
const char *revision = _Py_gitversion();
|
||||
const char *sep = *revision ? ":" : "";
|
||||
const char *gitid = _Py_gitidentifier();
|
||||
if (!(*gitid))
|
||||
gitid = "default";
|
||||
PyOS_snprintf(buildinfo, sizeof(buildinfo),
|
||||
"%s%s%s, %.20s, %.9s", gitid, sep, revision,
|
||||
DATE, TIME);
|
||||
return buildinfo;
|
||||
return "cosmopolitan";
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
1
third_party/python/Modules/getpath.c
vendored
1
third_party/python/Modules/getpath.c
vendored
|
@ -492,7 +492,6 @@ calculate_path(void)
|
|||
|
||||
if(IsWindows())
|
||||
{
|
||||
fprintf(stderr, "python APE on Windows\n");
|
||||
delimiter[0] = L';';
|
||||
separator[0] = L'\\';
|
||||
}
|
||||
|
|
80
third_party/python/Programs/python.c
vendored
80
third_party/python/Programs/python.c
vendored
|
@ -7,17 +7,24 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/unicode/locale.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
#include "third_party/python/Include/ceval.h"
|
||||
#include "third_party/python/Include/dictobject.h"
|
||||
#include "third_party/python/Include/fileutils.h"
|
||||
#include "third_party/python/Include/import.h"
|
||||
#include "third_party/python/Include/pylifecycle.h"
|
||||
#include "third_party/python/Include/pymem.h"
|
||||
#include "third_party/python/Include/pyport.h"
|
||||
#include "third_party/python/Include/pythonrun.h"
|
||||
#include "third_party/python/Include/unicodeobject.h"
|
||||
/* clang-format off */
|
||||
|
||||
static jmp_buf jbuf;
|
||||
|
@ -28,6 +35,77 @@ OnKeyboardInterrupt(int sig)
|
|||
longjmp(jbuf, 1);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
GetMember(const char *s, Py_ssize_t n, PyObject *o)
|
||||
{
|
||||
const char *t;
|
||||
PyObject *k, *v;
|
||||
Py_ssize_t i, m;
|
||||
if (!o) return 0;
|
||||
for (i = 0; PyDict_Next(o, &i, &k, &v);) {
|
||||
if (v != Py_None && PyUnicode_Check(k)) {
|
||||
t = PyUnicode_AsUTF8AndSize(k, &m);
|
||||
printf("\r%`'.*s vs. %`'.*s\n", n, s, m, t);
|
||||
if (n == m && !memcmp(s, t, n)) {
|
||||
Py_INCREF(v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
GetVar(const char *s, Py_ssize_t n)
|
||||
{
|
||||
PyObject *o;
|
||||
/*
|
||||
* TODO: Why doesn't PyEval_GetLocals() work?
|
||||
*/
|
||||
if ((o = GetMember(s, n, PyEval_GetLocals()))) return o;
|
||||
if ((o = GetMember(s, n, PyEval_GetGlobals()))) return o;
|
||||
if ((o = GetMember(s, n, PyEval_GetBuiltins()))) return o;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
TerminalComplete(const char *s, linenoiseCompletions *c, PyObject *o)
|
||||
{
|
||||
const char *t;
|
||||
PyObject *k, *v;
|
||||
Py_ssize_t i, n, m;
|
||||
if (!o) return;
|
||||
for (n = strlen(s), i = 0; PyDict_Next(o, &i, &k, &v);) {
|
||||
if (v != Py_None && PyUnicode_Check(k)) {
|
||||
t = PyUnicode_AsUTF8AndSize(k, &m);
|
||||
if (m > n && !memcmp(t, s, n)) {
|
||||
c->cvec = realloc(c->cvec, ++c->len * sizeof(*c->cvec));
|
||||
c->cvec[c->len - 1] = strdup(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TerminalCompletion(const char *s, linenoiseCompletions *c)
|
||||
{
|
||||
const char *p;
|
||||
PyObject *o, *q;
|
||||
if ((p = strchr(s, '.'))) {
|
||||
if (!(o = GetVar(s, p - s))) return;
|
||||
for (s = p + 1; (p = strchr(s, '.')); o = q) {
|
||||
if ((q = GetMember(s, p - s, o))) return;
|
||||
Py_DECREF(o);
|
||||
}
|
||||
TerminalComplete(s, c, o);
|
||||
Py_DECREF(o);
|
||||
} else {
|
||||
TerminalComplete(s, c, PyEval_GetLocals());
|
||||
TerminalComplete(s, c, PyEval_GetGlobals());
|
||||
TerminalComplete(s, c, PyEval_GetBuiltins());
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
|
||||
{
|
||||
|
@ -66,6 +144,8 @@ main(int argc, char **argv)
|
|||
int i, res;
|
||||
char *oldloc;
|
||||
|
||||
showcrashreports();
|
||||
linenoiseSetCompletionCallback(TerminalCompletion);
|
||||
PyOS_ReadlineFunctionPointer = TerminalReadline;
|
||||
|
||||
/* Force malloc() allocator to bootstrap Python */
|
||||
|
|
1
third_party/python/Python/pylifecycle.c
vendored
1
third_party/python/Python/pylifecycle.c
vendored
|
@ -14,6 +14,7 @@
|
|||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/unicode/locale.h"
|
||||
#include "third_party/python/Include/Python-ast.h"
|
||||
#include "third_party/python/Include/abstract.h"
|
||||
|
|
|
@ -16,15 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/psk.h"
|
||||
|
||||
/**
|
||||
|
@ -32,23 +28,9 @@
|
|||
*/
|
||||
void *GetRunitPsk(void) {
|
||||
int fd;
|
||||
char *r, *p;
|
||||
struct stat st;
|
||||
const char *a, *b;
|
||||
char *r, p[PATH_MAX + 1];
|
||||
if ((a = getenv("HOME"))) {
|
||||
b = "";
|
||||
} else if (IsWindows()) {
|
||||
a = getenv("HOMEDRIVE");
|
||||
b = getenv("HOMEPATH");
|
||||
if (!a || !b) {
|
||||
a = "C:";
|
||||
b = "";
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "need $HOME\n");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(p, sizeof(p), "%s%s/.runit.psk", a, b);
|
||||
p = gc(xasprintf("%s/.runit.psk", gc(xhomedir())));
|
||||
if (stat(p, &st) == -1 || st.st_size != 32) {
|
||||
fprintf(stderr, "need o//examples/getrandom.com -bn32 >~/.runit.psk\n");
|
||||
exit(1);
|
||||
|
|
|
@ -1216,6 +1216,27 @@ static optimizesize void ReadKeyboard(void) {
|
|||
case 'S': /* \eOS is F4 */
|
||||
pf4_ = !pf4_;
|
||||
break;
|
||||
case 'T': /* \eOT is F5 */
|
||||
pf5_ = !pf5_;
|
||||
break;
|
||||
case 'U': /* \eOU is F6 */
|
||||
pf6_ = !pf6_;
|
||||
break;
|
||||
case 'V': /* \eOV is F7 */
|
||||
pf7_ = !pf7_;
|
||||
break;
|
||||
case 'W': /* \eOW is F8 */
|
||||
pf8_ = !pf8_;
|
||||
break;
|
||||
case 'Y': /* \eOY is F10 */
|
||||
pf10_ = !pf10_;
|
||||
break;
|
||||
case 'Z': /* \eOZ is F11 */
|
||||
pf11_ = !pf11_;
|
||||
break;
|
||||
case '[': /* \eO[ is F12 */
|
||||
pf12_ = !pf12_;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue