]> git.saurik.com Git - cycript.git/commitdiff
Syntax highlight commands as the user types them.
authorJay Freeman (saurik) <saurik@saurik.com>
Wed, 12 Sep 2012 02:45:37 +0000 (19:45 -0700)
committerJay Freeman (saurik) <saurik@saurik.com>
Wed, 12 Sep 2012 02:48:19 +0000 (19:48 -0700)
Console.cpp
Display.cpp [new file with mode: 0644]
Display.hpp [new file with mode: 0644]
GNUmakefile.in
Highlight.cpp
Highlight.hpp
ios.sh
todo.txt

index 596f804b19b4472b6374297cf2a85a6b38de6411..14a659017ec4855202485ef48334322f95c03153 100644 (file)
@@ -64,6 +64,7 @@
 #include <dlfcn.h>
 
 #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 (file)
index 0000000..56cbb5e
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#include <complex>
+#include <sstream>
+
+#ifdef HAVE_READLINE_H
+#include <readline.h>
+#else
+#include <readline/readline.h>
+#endif
+
+#include <sys/ioctl.h>
+
+#include "Highlight.hpp"
+
+#include <term.h>
+
+typedef std::complex<int> 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<char *>("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 (file)
index 0000000..d30e444
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#ifndef CYCRIPT_DISPLAY_HPP
+#define CYCRIPT_DISPLAY_HPP
+
+void CYDisplayStart(int meta);
+void CYDisplayUpdate();
+void CYDisplayFinish();
+
+#endif/*CYCRIPT_DISPLAY_HPP*/
index ff8c1bee9c9cf95fbf36e39e3efc5f80a3b99dde..941bb2d26823a8fa128e7a01b95da6441630ee8f 100644 (file)
@@ -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
index 371722e5e0659efede1c69df89e165071fdc76d6..750516775fa06f44b039373ef4f0cc996e6a6c25 100644 (file)
@@ -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);
index a3eae0c0d7af6aad7c4c14dc6f25a83e569c7076..ba90876b688cd676a58f75e6dd1e373de5004e33 100644 (file)
@@ -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 46cac8557c61873e7d42eae4abb50016bb6e2607..46c8ecb8b3a383a0cc011ed62c252035635cc6fc 100755 (executable)
--- 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
index 7285880eae9b1f37dd6a8f7021ed07c8e9e04e07..f6b586347ae0609c0800c7cccc21840745032167 100644 (file)
--- 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