]> git.saurik.com Git - cycript.git/blob - Display.cpp
On Mac OS X 10.9, cstddef is needed for offsetof.
[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 #include <sys/ioctl.h>
32
33 #include "Highlight.hpp"
34
35 #include <term.h>
36
37 typedef std::complex<int> CYCursor;
38
39 CYCursor current_;
40 int width_;
41 size_t point_;
42
43 unsigned CYDisplayWidth() {
44 struct winsize info;
45 if (ioctl(1, TIOCGWINSZ, &info) != -1)
46 return info.ws_col;
47 return tgetnum(const_cast<char *>("co"));
48 }
49
50 void CYDisplayOutput_(int (*put)(int), const char *&data) {
51 for (;; ++data) {
52 char next(*data);
53 if (next == '\0' || next == CYIgnoreEnd)
54 return;
55 if (put != NULL)
56 put(next);
57 }
58 }
59
60 CYCursor CYDisplayOutput(int (*put)(int), int width, const char *data, ssize_t offset = 0) {
61 CYCursor point(current_);
62
63 for (;;) {
64 if (offset-- == 0)
65 point = current_;
66
67 char next(*data++);
68 switch (next) {
69 case '\0':
70 return point;
71 break;
72
73 case CYIgnoreStart:
74 CYDisplayOutput_(put, data);
75 case CYIgnoreEnd:
76 ++offset;
77 break;
78
79 default:
80 current_ += CYCursor(0, 1);
81 if (current_.imag() == width)
82 case '\n':
83 current_ = CYCursor(current_.real() + 1, 0);
84 if (put != NULL)
85 put(next);
86 break;
87
88 }
89 }
90 }
91
92 void CYDisplayMove_(char *negative, char *positive, int offset) {
93 if (offset < 0)
94 putp(tparm(negative, -offset));
95 else if (offset > 0)
96 putp(tparm(positive, offset));
97 }
98
99 void CYDisplayMove(CYCursor target) {
100 CYCursor offset(target - current_);
101
102 CYDisplayMove_(parm_up_cursor, parm_down_cursor, offset.real());
103
104 if (char *parm = tparm(column_address, target.imag()))
105 putp(parm);
106 else
107 CYDisplayMove_(parm_left_cursor, parm_right_cursor, offset.imag());
108
109 current_ = target;
110 }
111
112 void CYDisplayStart(int meta) {
113 rl_prep_terminal(meta);
114 current_ = CYCursor();
115 }
116
117 void CYDisplayUpdate() {
118 #if RL_READLINE_VERSION >= 0x0600
119 const char *prompt(rl_display_prompt);
120 #else
121 const char *prompt(rl_prompt);
122 #endif
123
124 std::ostringstream stream;
125 CYLexerHighlight(rl_line_buffer, rl_end, stream, true);
126 std::string string(stream.str());
127 const char *buffer(string.c_str());
128
129 int width(CYDisplayWidth());
130 if (width_ != width) {
131 current_ = CYCursor();
132 CYDisplayOutput(NULL, width, prompt);
133 current_ = CYDisplayOutput(NULL, width, buffer, point_);
134 }
135
136 CYDisplayMove(CYCursor());
137 CYDisplayOutput(putchar, width, prompt);
138 CYCursor target(CYDisplayOutput(putchar, width, stream.str().c_str(), rl_point));
139
140 if (current_.imag() == 0)
141 CYDisplayOutput(putchar, width, " ");
142 putp(clr_eos);
143
144 CYDisplayMove(target);
145 fflush(stdout);
146
147 width_ = width;
148 point_ = rl_point;
149 }
150
151 void CYDisplayFinish() {
152 rl_deprep_terminal();
153 }