X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/66c347f0b58437382b83f20c9faf84a7303764f5..7341eedbaf526ef2f0986b576c656906050e270a:/Console.cpp diff --git a/Console.cpp b/Console.cpp index c0d0f76..6587106 100644 --- a/Console.cpp +++ b/Console.cpp @@ -1,5 +1,5 @@ -/* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2015 Jay Freeman (saurik) +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) */ /* GNU Affero General Public License, Version 3 {{{ */ @@ -389,11 +389,25 @@ static Type_ *CYmemrchr(Type_ *data, Type_ value, size_t size) { return NULL; } +static void _lblcall(int (*command)(int, int), int count, int key) { + int last(_rl_last_c_pos); + // rl_rubout crashes in _rl_erase_at_end_of_line if _rl_last_c_pos != 0 + if (command == &rl_rubout) + _rl_last_c_pos = 0; + for (int i(0); i != count; ++i) + if (command(1, key) != 0) + _assert(false); + _rl_last_c_pos = last; +} + static int CYConsoleKeyReturn(int count, int key) { if (rl_point != rl_end) { - if (memchr(rl_line_buffer, '\n', rl_end) == NULL) - return rl_newline(count, key); + if (memchr(rl_line_buffer, '\n', rl_end) == NULL) { + _lblcall(&rl_newline, count, key); + return 0; + } + insert: char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); if (before == NULL) before = rl_line_buffer; @@ -404,11 +418,11 @@ static int CYConsoleKeyReturn(int count, int key) { int adjust(rl_line_buffer + space - 1 - before); if (space == rl_point && adjust != 0) - rl_rubout(adjust, '\b'); + _lblcall(&rl_rubout, adjust, '\b'); - rl_insert(count, '\n'); + _lblcall(&rl_insert, count, '\n'); if (adjust != 0) - rl_insert(adjust, ' '); + _lblcall(&rl_insert, adjust, ' '); return 0; } @@ -419,7 +433,7 @@ static int CYConsoleKeyReturn(int count, int key) { else { std::string command(rl_line_buffer, rl_end); command += '\n'; - std::istringstream stream(command); + std::stringbuf stream(command); size_t last(std::string::npos); for (size_t i(0); i != std::string::npos; i = command.find('\n', i + 1)) @@ -437,15 +451,17 @@ static int CYConsoleKeyReturn(int count, int key) { done = true; } - if (done) - return rl_newline(count, key); + if (done) { + _lblcall(&rl_newline, count, key); + return 0; + } - rl_insert(count, '\n'); - return 0; + // XXX: this was the most obvious fix, but is seriously dumb + goto insert; } static int CYConsoleKeyUp(int count, int key) { - while (count-- != 0) { + for (; count != 0; --count) { char *after(CYmemrchr(rl_line_buffer, '\n', rl_point)); if (after == NULL) { if (int value = rl_get_previous_history(1, key)) @@ -468,7 +484,7 @@ static int CYConsoleKeyUp(int count, int key) { } static int CYConsoleKeyDown(int count, int key) { - while (count-- != 0) { + for (; count != 0; --count) { char *after(static_cast(memchr(rl_line_buffer + rl_point, '\n', rl_end - rl_point))); if (after == NULL) { int where(where_history()); @@ -509,25 +525,34 @@ static int CYConsoleLineBegin(int count, int key) { static int CYConsoleLineEnd(int count, int key) { while (rl_point != rl_end && rl_line_buffer[rl_point] != '\n') ++rl_point; + if (rl_point != rl_end && rl_editing_mode == 0) + --rl_point; return 0; } static int CYConsoleKeyBack(int count, int key) { - while (count-- != 0) { + for (; count != 0; --count) { + if (rl_point == 0) + return 1; + char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); - if (before == NULL) - return rl_rubout(count, key); + if (before == NULL) { + int adjust(std::min(count, rl_point)); + _lblcall(&rl_rubout, adjust, key); + count -= adjust - 1; + continue; + } int start(before + 1 - rl_line_buffer); if (start == rl_point) rubout: { - rl_rubout(1, key); + _lblcall(&rl_rubout, 1, key); continue; } for (int i(start); i != rl_point; ++i) if (rl_line_buffer[i] != ' ') goto rubout; - rl_rubout((rl_point - start) % 4 ?: 4, key); + _lblcall(&rl_rubout, (rl_point - start) % 4 ?: 4, key); } return 0; @@ -541,26 +566,40 @@ static int CYConsoleKeyTab(int count, int key) { for (int i(start); i != rl_point; ++i) if (rl_line_buffer[i] != ' ') goto complete; - return rl_insert(4 - (rl_point - start) % 4, ' '); + _lblcall(&rl_insert, 4 - (rl_point - start) % 4, ' '); + return 0; } -static void CYConsoleRemapBind(rl_command_func_t *from, rl_command_func_t *to) { - char **keyseqs(rl_invoking_keyseqs(from)); +static void CYConsoleRemapBind(Keymap map, rl_command_func_t *from, rl_command_func_t *to) { + char **keyseqs(rl_invoking_keyseqs_in_map(from, map)); if (keyseqs == NULL) return; for (char **keyseq(keyseqs); *keyseq != NULL; ++keyseq) { - rl_bind_keyseq(*keyseq, to); + rl_bind_keyseq_in_map(*keyseq, to, map); free(*keyseq); } free(keyseqs); } +static void CYConsoleRemapKeys(Keymap map) { + CYConsoleRemapBind(map, &rl_beg_of_line, &CYConsoleLineBegin); + CYConsoleRemapBind(map, &rl_end_of_line, &CYConsoleLineEnd); + + CYConsoleRemapBind(map, &rl_get_previous_history, &CYConsoleKeyUp); + CYConsoleRemapBind(map, &rl_get_next_history, &CYConsoleKeyDown); + + CYConsoleRemapBind(map, &rl_rubout, &CYConsoleKeyBack); + CYConsoleRemapBind(map, &rl_complete, &CYConsoleKeyTab); +} + static void CYConsolePrepTerm(int meta) { rl_prep_terminal(meta); - CYConsoleRemapBind(&rl_beg_of_line, &CYConsoleLineBegin); - CYConsoleRemapBind(&rl_end_of_line, &CYConsoleLineEnd); - CYConsoleRemapBind(&rl_rubout, &CYConsoleKeyBack); + CYConsoleRemapKeys(emacs_standard_keymap); + CYConsoleRemapKeys(emacs_meta_keymap); + CYConsoleRemapKeys(emacs_ctlx_keymap); + CYConsoleRemapKeys(vi_insertion_keymap); + CYConsoleRemapKeys(vi_movement_keymap); } static void Console(CYOptions &options) { @@ -594,26 +633,9 @@ static void Console(CYOptions &options) { rl_completer_word_break_characters = break_; rl_attempted_completion_function = &Complete; - rl_bind_key(TAB, &CYConsoleKeyTab); - rl_redisplay_function = CYDisplayUpdate; rl_prep_term_function = CYConsolePrepTerm; -#if defined (__MSDOS__) - rl_bind_keyseq("\033[0A", &CYConsoleKeyUp); - rl_bind_keyseq("\033[0D", &CYConsoleKeyDown); -#endif - rl_bind_keyseq("\033[A", &CYConsoleKeyUp); - rl_bind_keyseq("\033[B", &CYConsoleKeyDown); - rl_bind_keyseq("\033OA", &CYConsoleKeyUp); - rl_bind_keyseq("\033OB", &CYConsoleKeyDown); -#if defined (__MINGW32__) - rl_bind_keyseq("\340H", &CYConsoleKeyUp); - rl_bind_keyseq("\340P", &CYConsoleKeyDown); - rl_bind_keyseq("\\000H", &CYConsoleKeyUp); - rl_bind_keyseq("\\000P", &CYConsoleKeyDown); -#endif - struct sigaction action; sigemptyset(&action.sa_mask); action.sa_handler = &sigint; @@ -648,6 +670,7 @@ static void Console(CYOptions &options) { free(line); if (command.empty()) continue; + history += command; if (command[0] == '?') { std::string data(command.substr(1)); @@ -673,15 +696,14 @@ static void Console(CYOptions &options) { *out_ << "lower == " << (lower ? "true" : "false") << std::endl; } - history += command; continue; } std::string code; if (bypass) code = command; - else { - std::istringstream stream(command); + else try { + std::stringbuf stream(command); CYPool pool; CYDriver driver(pool, stream); @@ -709,7 +731,6 @@ static void Console(CYOptions &options) { std::cerr << " | "; std::cerr << error->message_ << std::endl; - history += command; break; } @@ -724,10 +745,12 @@ static void Console(CYOptions &options) { Setup(out, driver, options, lower); out << *driver.script_; code = str.str(); + } catch (const CYException &error) { + CYPool pool; + std::cout << error.PoolCString(pool) << std::endl; + continue; } - history += command; - if (debug) { std::cout << "cy= "; CYLexerHighlight(code.c_str(), code.size(), std::cout); @@ -1066,7 +1089,7 @@ int Main(int argc, char * const argv[], char const * const envp[]) { stream = new std::istringstream(buffer.str()); CYPool pool; - CYDriver driver(pool, *stream, script); + CYDriver driver(pool, *stream->rdbuf(), script); Setup(driver); uint64_t begin(CYGetTime()); @@ -1092,7 +1115,7 @@ int Main(int argc, char * const argv[], char const * const envp[]) { } CYPool pool; - CYDriver driver(pool, *stream, script); + CYDriver driver(pool, *stream->rdbuf(), script); Setup(driver); bool failed(driver.Parse()); @@ -1100,6 +1123,7 @@ int Main(int argc, char * const argv[], char const * const envp[]) { if (failed || !driver.errors_.empty()) { for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) std::cerr << i->location_.begin << ": " << i->message_ << std::endl; + return 1; } else if (driver.script_ != NULL) { std::stringbuf str; CYOutput out(str, options);