]> git.saurik.com Git - cycript.git/blob - Display.cpp
cafdc57443e1b53cfa12238cf2f8f295f521279b
[cycript.git] / Display.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <complex>
23 #include <sstream>
24
25 #ifdef HAVE_READLINE_H
26 #include <readline.h>
27 #else
28 #include <readline/readline.h>
29 #endif
30
31 #if RL_READLINE_VERSION >= 0x0600
32
33 #include <sys/ioctl.h>
34
35 #include "Highlight.hpp"
36
37 #include <term.h>
38
39 typedef std::complex<int> CYCursor;
40
41 extern "C" int _rl_vis_botlin;
42 extern "C" int _rl_last_c_pos;
43 extern "C" int _rl_last_v_pos;
44
45 CYCursor current_;
46 int width_;
47 size_t point_;
48
49 unsigned CYDisplayWidth() {
50 struct winsize info;
51 if (ioctl(1, TIOCGWINSZ, &info) != -1)
52 return info.ws_col;
53 return tgetnum(const_cast<char *>("co"));
54 }
55
56 void CYDisplayOutput_(int (*put)(int), const char *&data) {
57 for (;; ++data) {
58 char next(*data);
59 if (next == '\0' || next == CYIgnoreEnd)
60 return;
61 if (put != NULL)
62 put(next);
63 }
64 }
65
66 CYCursor CYDisplayOutput(int (*put)(int), int width, const char *data, ssize_t offset = 0) {
67 CYCursor point(current_);
68
69 for (;;) {
70 if (offset-- == 0)
71 point = current_;
72
73 char next(*data++);
74 switch (next) {
75 case '\0':
76 return point;
77 break;
78
79 case CYIgnoreStart:
80 CYDisplayOutput_(put, data);
81 case CYIgnoreEnd:
82 ++offset;
83 break;
84
85 default:
86 current_ += CYCursor(0, 1);
87 if (current_.imag() == width)
88 case '\n':
89 current_ = CYCursor(current_.real() + 1, 0);
90 if (put != NULL)
91 put(next);
92 break;
93
94 }
95 }
96 }
97
98 void CYDisplayMove_(char *negative, char *positive, int offset) {
99 if (offset < 0)
100 putp(tparm(negative, -offset));
101 else if (offset > 0)
102 putp(tparm(positive, offset));
103 }
104
105 void CYDisplayMove(CYCursor target) {
106 CYCursor offset(target - current_);
107
108 CYDisplayMove_(parm_up_cursor, parm_down_cursor, offset.real());
109
110 if (char *parm = tparm(column_address, target.imag()))
111 putp(parm);
112 else
113 CYDisplayMove_(parm_left_cursor, parm_right_cursor, offset.imag());
114
115 current_ = target;
116 }
117
118 void CYDisplayStart(int meta) {
119 rl_prep_terminal(meta);
120 current_ = CYCursor();
121 }
122
123 void CYDisplayUpdate() {
124 #if RL_READLINE_VERSION >= 0x0600
125 const char *prompt(rl_display_prompt);
126 #else
127 const char *prompt(rl_prompt);
128 #endif
129
130 std::ostringstream stream;
131 CYLexerHighlight(rl_line_buffer, rl_end, stream, true);
132 std::string string(stream.str());
133 const char *buffer(string.c_str());
134
135 int width(CYDisplayWidth());
136 if (width_ != width) {
137 current_ = CYCursor();
138 CYDisplayOutput(NULL, width, prompt);
139 current_ = CYDisplayOutput(NULL, width, buffer, point_);
140 }
141
142 CYDisplayMove(CYCursor());
143 CYDisplayOutput(putchar, width, prompt);
144 CYCursor target(CYDisplayOutput(putchar, width, stream.str().c_str(), rl_point));
145
146 _rl_vis_botlin = current_.real();
147 _rl_last_c_pos = current_.imag();
148 _rl_last_v_pos = target.real();
149
150 // XXX: readline crashes trying to avoid an empty line if this is left at 0 :(
151 if (_rl_last_c_pos == 0)
152 _rl_last_c_pos = 1;
153
154 if (current_.imag() == 0)
155 CYDisplayOutput(putchar, width, " ");
156 putp(clr_eos);
157
158 CYDisplayMove(target);
159 fflush(stdout);
160
161 width_ = width;
162 point_ = rl_point;
163 }
164
165 void CYDisplayFinish() {
166 rl_deprep_terminal();
167 }
168
169 #endif