From 742961730553cdf21649744cc212d309a56bd0f0 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Tue, 11 Sep 2012 19:45:37 -0700 Subject: [PATCH] Syntax highlight commands as the user types them. --- Console.cpp | 7 +++ Display.cpp | 152 +++++++++++++++++++++++++++++++++++++++++++++++++ Display.hpp | 29 ++++++++++ GNUmakefile.in | 3 +- Highlight.cpp | 19 ++++++- Highlight.hpp | 5 +- ios.sh | 2 +- todo.txt | 1 + 8 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 Display.cpp create mode 100644 Display.hpp diff --git a/Console.cpp b/Console.cpp index 596f804..14a6590 100644 --- a/Console.cpp +++ b/Console.cpp @@ -64,6 +64,7 @@ #include #include "Replace.hpp" +#include "Display.hpp" static volatile enum { Working, @@ -398,6 +399,12 @@ static void Console(CYOptions &options) { rl_initialize(); rl_readline_name = name_; +#if RL_READLINE_VERSION >= 0x0600 + rl_prep_term_function = CYDisplayStart; + rl_redisplay_function = CYDisplayUpdate; + rl_deprep_term_function = CYDisplayFinish; +#endif + mkdir(basedir, 0700); read_history(histfile); diff --git a/Display.cpp b/Display.cpp new file mode 100644 index 0000000..56cbb5e --- /dev/null +++ b/Display.cpp @@ -0,0 +1,152 @@ +/* Cycript - Optimizing JavaScript Compiler/Runtime + * Copyright (C) 2009-2012 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Cycript is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Cycript is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cycript. If not, see . +**/ +/* }}} */ + +#include +#include + +#ifdef HAVE_READLINE_H +#include +#else +#include +#endif + +#include + +#include "Highlight.hpp" + +#include + +typedef std::complex CYCursor; + +CYCursor current_; +int width_; +size_t point_; + +const char *CYDisplayPrompt() { +#if RL_READLINE_VERSION >= 0x0600 + return rl_display_prompt; +#else + return rl_prompt; +#endif +} + +unsigned CYDisplayWidth() { + struct winsize info; + if (ioctl(1, TIOCGWINSZ, &info) != -1) + return info.ws_col; + return tgetnum(const_cast("co")); +} + +void CYDisplayOutput_(int (*put)(int), const char *&data) { + for (;; ++data) { + char next(*data); + if (next == '\0' || next == CYIgnoreEnd) + return; + if (put != NULL) + put(next); + } +} + +CYCursor CYDisplayOutput(int (*put)(int), int width, const char *data, ssize_t offset = 0) { + CYCursor point(current_); + + for (;;) { + if (offset-- == 0) + point = current_; + + char next(*data++); + switch (next) { + case '\0': + return point; + break; + + case CYIgnoreStart: + CYDisplayOutput_(put, data); + ++offset; + break; + + case CYIgnoreEnd: + ++offset; + break; + + default: + if (put != NULL) + put(next); + + current_ += CYCursor(0, 1); + if (current_.imag() == width) + current_ = CYCursor(current_.real() + 1, 0); + break; + } + } + + return point; +} + +void CYDisplayMove(CYCursor target) { + int offset(target.real() - current_.real()); + + if (offset < 0) + putp(tparm(parm_up_cursor, -offset)); + else if (offset > 0) + putp(tparm(parm_down_cursor, offset)); + + putp(tparm(column_address, target.imag())); + current_ = target; +} + +void CYDisplayStart(int meta) { + rl_prep_terminal(meta); + current_ = CYCursor(); +} + +void CYDisplayUpdate() { + std::ostringstream stream; + CYLexerHighlight(rl_line_buffer, rl_end, stream, true); + std::string string(stream.str()); + const char *buffer(string.c_str()); + + int width(CYDisplayWidth()); + if (width_ != width) { + current_ = CYCursor(); + CYDisplayOutput(NULL, width, CYDisplayPrompt()); + CYDisplayOutput(NULL, width, buffer, point_); + } + + CYDisplayMove(CYCursor()); + CYDisplayOutput(putchar, width, CYDisplayPrompt()); + + CYCursor target(CYDisplayOutput(putchar, width, stream.str().c_str(), rl_point)); + if (target.imag() == 0) + putp(cursor_down); + + putp(clr_eos); + CYDisplayMove(target); + + fflush(stdout); + + width_ = width; + point_ = rl_point; +} + +void CYDisplayFinish() { + rl_deprep_terminal(); +} diff --git a/Display.hpp b/Display.hpp new file mode 100644 index 0000000..d30e444 --- /dev/null +++ b/Display.hpp @@ -0,0 +1,29 @@ +/* Cycript - Optimizing JavaScript Compiler/Runtime + * Copyright (C) 2009-2012 Jay Freeman (saurik) +*/ + +/* GNU Lesser General Public License, Version 3 {{{ */ +/* + * Cycript is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Cycript is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cycript. If not, see . +**/ +/* }}} */ + +#ifndef CYCRIPT_DISPLAY_HPP +#define CYCRIPT_DISPLAY_HPP + +void CYDisplayStart(int meta); +void CYDisplayUpdate(); +void CYDisplayFinish(); + +#endif/*CYCRIPT_DISPLAY_HPP*/ diff --git a/GNUmakefile.in b/GNUmakefile.in index ff8c1be..941bb2d 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -82,7 +82,8 @@ all := cycript header := Cycript.tab.hh Parser.hpp Pooling.hpp List.hpp Local.hpp cycript.hpp Internal.hpp Error.hpp String.hpp Exception.hpp Standard.hpp code := -code += Replace.lo Output.lo Highlight.lo +code += Replace.lo Output.lo +code += Highlight.lo Display.lo code += Cycript.tab.lo lex.cy.lo code += Network.lo Parser.lo code += JavaScriptCore.lo Library.lo diff --git a/Highlight.cpp b/Highlight.cpp index 371722e..7505167 100644 --- a/Highlight.cpp +++ b/Highlight.cpp @@ -53,7 +53,7 @@ struct CYColor { } }; -void CYLexerHighlight(const char *data, size_t size, std::ostream &output) { +void CYLexerHighlight(const char *data, size_t size, std::ostream &output, bool ignore) { CYStream stream(data, data + size); CYDriver driver(stream); @@ -82,11 +82,24 @@ void CYLexerHighlight(const char *data, size_t size, std::ostream &output) { } Skip(data, size, output, offset, current, location.begin); - if (color.code_ != 0) + + if (color.code_ != 0) { + if (ignore) + output << CYIgnoreStart; output << "\e[" << (color.bold_ ? '1' : '0') << ";" << color.code_ << "m"; + if (ignore) + output << CYIgnoreEnd; + } + Skip(data, size, output, offset, current, location.end); - if (color.code_ != 0) + + if (color.code_ != 0) { + if (ignore) + output << CYIgnoreStart; output << "\e[0m"; + if (ignore) + output << CYIgnoreEnd; + } } output.write(data + offset, size - offset); diff --git a/Highlight.hpp b/Highlight.hpp index a3eae0c..ba90876 100644 --- a/Highlight.hpp +++ b/Highlight.hpp @@ -37,6 +37,9 @@ namespace hi { enum Value { Type, }; } -void CYLexerHighlight(const char *data, size_t size, std::ostream &output); +void CYLexerHighlight(const char *data, size_t size, std::ostream &output, bool ignore = false); + +const char CYIgnoreStart = '\x01'; +const char CYIgnoreEnd = '\x02'; #endif/*CYCRIPT_HIGHLIGHT_HPP*/ diff --git a/ios.sh b/ios.sh index 46cac85..46c8ecb 100755 --- a/ios.sh +++ b/ios.sh @@ -5,7 +5,7 @@ set -e rm -rf sysroot.ios mkdir -p sysroot.ios -for deb in apr-lib_1.3.3-2 libffi_1:3.0.10-5 readline_6.0-7; do +for deb in apr-lib_1.3.3-2 libffi_1:3.0.10-5 ncurses_5.7-12 readline_6.0-7; do deb=${deb}_iphoneos-arm.deb [[ -f "${deb}" ]] || wget http://apt.saurik.com/debs/"${deb}" tar=data.tar.lzma diff --git a/todo.txt b/todo.txt index 7285880..f6b5863 100644 --- a/todo.txt +++ b/todo.txt @@ -104,3 +104,4 @@ Objective-C strings might should be cyonified using double-quotes apparently you can have random escape sequences in strings, like \! cycript -p with processes that have spaces doesn't work CYDriver uses std::istream, but it should use std::streambuf +the mechanism I used to autodetect readline is horrible: use autoconf -- 2.47.2