X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/b1b144d19f0469a958449e39b17d68158f6546bd..73180f9a88e81f417fec82aae68ea2c48977418e:/Console.cpp diff --git a/Console.cpp b/Console.cpp index 463189c..76ad553 100644 --- a/Console.cpp +++ b/Console.cpp @@ -381,13 +381,45 @@ class History { } }; +template +static Type_ *CYmemrchr(Type_ *data, Type_ value, size_t size) { + while (size != 0) + if (data[--size] == value) + return data + size; + return NULL; +} + static int CYConsoleKeyReturn(int count, int key) { - rl_insert(count, '\n'); + if (rl_point != rl_end) { + if (memchr(rl_line_buffer, '\n', rl_end) == NULL) + return rl_newline(count, key); + + insert: + char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); + if (before == NULL) + before = rl_line_buffer; + + int space(before + 1 - rl_line_buffer); + while (space != rl_point && rl_line_buffer[space] == ' ') + ++space; + + int adjust(rl_line_buffer + space - 1 - before); + if (space == rl_point && adjust != 0) + rl_rubout(adjust, '\b'); - if (rl_end != 0 && rl_point == rl_end && rl_line_buffer[0] == '?') - rl_done = 1; - else if (rl_point == rl_end) { + rl_insert(count, '\n'); + if (adjust != 0) + rl_insert(adjust, ' '); + + return 0; + } + + bool done(false); + if (rl_line_buffer[0] == '?') + done = true; + else { std::string command(rl_line_buffer, rl_end); + command += '\n'; std::istringstream stream(command); size_t last(std::string::npos); @@ -399,69 +431,154 @@ static int CYConsoleKeyReturn(int count, int key) { if (driver.Parse() || !driver.errors_.empty()) for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) { if (error->location_.begin.line != last + 1) - rl_done = 1; + done = true; break; } else - rl_done = 1; + done = true; } - if (rl_done) - std::cout << std::endl; - return 0; -} + if (done) + return rl_newline(count, key); -template -static Type_ *CYmemrchr(Type_ *data, Type_ value, size_t size) { - while (size != 0) - if (data[--size] == value) - return data + size; - return NULL; + // XXX: this was the most obvious fix, but is seriously dumb + goto insert; } static int CYConsoleKeyUp(int count, int key) { - char *after(CYmemrchr(rl_line_buffer, '\n', rl_point)); - if (after == NULL) { - if (int value = rl_get_previous_history(count, key)) - return value; - return 0; - } + while (count-- != 0) { + char *after(CYmemrchr(rl_line_buffer, '\n', rl_point)); + if (after == NULL) { + if (int value = rl_get_previous_history(1, key)) + return value; + continue; + } - char *before(CYmemrchr(rl_line_buffer, '\n', after - rl_line_buffer)); - if (before == NULL) - before = rl_line_buffer - 1; + char *before(CYmemrchr(rl_line_buffer, '\n', after - rl_line_buffer)); + if (before == NULL) + before = rl_line_buffer - 1; - ptrdiff_t offset(rl_line_buffer + rl_point - after); - if (offset > after - before) - rl_point = after - 1 - rl_line_buffer; - else - rl_point = before + offset - rl_line_buffer; + ptrdiff_t offset(rl_line_buffer + rl_point - after); + if (offset > after - before) + rl_point = after - rl_line_buffer; + else + rl_point = before + offset - rl_line_buffer; + } return 0; } static int CYConsoleKeyDown(int count, int key) { - char *after(static_cast(memchr(rl_line_buffer + rl_point, '\n', rl_end - rl_point))); - if (after == NULL) { - if (int value = rl_get_next_history(count, key)) - return value; - rl_point = 0; - return 0; + while (count-- != 0) { + char *after(static_cast(memchr(rl_line_buffer + rl_point, '\n', rl_end - rl_point))); + if (after == NULL) { + int where(where_history()); + if (int value = rl_get_next_history(1, key)) + return value; + if (where != where_history()) { + char *first(static_cast(memchr(rl_line_buffer, '\n', rl_end))); + if (first != NULL) + rl_point = first - 1 - rl_line_buffer; + } + continue; + } + + char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); + if (before == NULL) + before = rl_line_buffer - 1; + + char *next(static_cast(memchr(after + 1, '\n', rl_line_buffer + rl_end - after - 1))); + if (next == NULL) + next = rl_line_buffer + rl_end; + + ptrdiff_t offset(rl_line_buffer + rl_point - before); + if (offset > next - after) + rl_point = next - rl_line_buffer; + else + rl_point = after + offset - rl_line_buffer; } - char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); - if (before == NULL) - before = rl_line_buffer - 1; + return 0; +} - ptrdiff_t offset(rl_line_buffer + rl_point - before); - if (offset > rl_line_buffer + rl_end - after) - rl_point = rl_end; - else - rl_point = after + offset - rl_line_buffer; +static int CYConsoleLineBegin(int count, int key) { + while (rl_point != 0 && rl_line_buffer[rl_point - 1] != '\n') + --rl_point; + return 0; +} + +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) { + char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); + if (before == NULL) + return rl_rubout(count, key); + + int start(before + 1 - rl_line_buffer); + if (start == rl_point) rubout: { + 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); + } return 0; } +static int CYConsoleKeyTab(int count, int key) { + char *before(CYmemrchr(rl_line_buffer, '\n', rl_point)); + if (before == NULL) complete: + return rl_complete_internal(rl_completion_mode(&CYConsoleKeyTab)); + int start(before + 1 - rl_line_buffer); + for (int i(start); i != rl_point; ++i) + if (rl_line_buffer[i] != ' ') + goto complete; + return rl_insert(4 - (rl_point - start) % 4, ' '); +} + +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_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); + + 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) { std::string basedir; if (const char *home = getenv("HOME")) @@ -492,24 +609,9 @@ static void Console(CYOptions &options) { rl_completer_word_break_characters = break_; rl_attempted_completion_function = &Complete; - rl_bind_key('\t', rl_complete); rl_redisplay_function = CYDisplayUpdate; - -#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 + rl_prep_term_function = CYConsolePrepTerm; struct sigaction action; sigemptyset(&action.sa_mask); @@ -524,10 +626,13 @@ static void Console(CYOptions &options) { continue; } - if (bypass) + if (bypass) { rl_bind_key('\r', &rl_newline); - else + rl_bind_key('\n', &rl_newline); + } else { rl_bind_key('\r', &CYConsoleKeyReturn); + rl_bind_key('\n', &CYConsoleKeyReturn); + } mode_ = Parsing; char *line(readline("cy# ")); @@ -540,11 +645,9 @@ static void Console(CYOptions &options) { std::string command(line); free(line); - _assert(!command.empty()); - _assert(command[command.size() - 1] == '\n'); - command.resize(command.size() - 1); if (command.empty()) continue; + history += command; if (command[0] == '?') { std::string data(command.substr(1)); @@ -570,14 +673,13 @@ static void Console(CYOptions &options) { *out_ << "lower == " << (lower ? "true" : "false") << std::endl; } - history += command; continue; } std::string code; if (bypass) code = command; - else { + else try { std::istringstream stream(command); CYPool pool; @@ -606,7 +708,6 @@ static void Console(CYOptions &options) { std::cerr << " | "; std::cerr << error->message_ << std::endl; - history += command; break; } @@ -621,10 +722,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); @@ -997,6 +1100,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);