Mercurial > code > home > repos > light9
annotate lib/ipython_view.py @ 2445:af83aeef8b0a
fancier spectrograms
author | drewp@bigasterisk.com |
---|---|
date | Sat, 01 Jun 2024 12:58:25 -0700 |
parents | 3c523c71da29 |
children |
rev | line source |
---|---|
709 | 1 # this version is adapted from http://wiki.ipython.org/Old_Embedding/GTK |
2 | |
3 """ | |
4 Backend to the console plugin. | |
5 | |
6 @author: Eitan Isaacson | |
7 @organization: IBM Corporation | |
8 @copyright: Copyright (c) 2007 IBM Corporation | |
9 @license: BSD | |
10 | |
11 All rights reserved. This program and the accompanying materials are made | |
12 available under the terms of the BSD which accompanies this distribution, and | |
13 is available at U{http://www.opensource.org/licenses/bsd-license.php} | |
14 """ | |
15 # this file is a modified version of source code from the Accerciser project | |
16 # http://live.gnome.org/accerciser | |
17 | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
18 from gi.repository import Gtk |
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
19 from gi.repository import Gdk |
709 | 20 import re |
21 import sys | |
22 import os | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
23 from gi.repository import Pango |
1866
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
24 from io import StringIO |
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
25 from functools import reduce |
709 | 26 |
27 try: | |
1866
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
28 import IPython |
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
29 except Exception as e: |
709 | 30 raise "Error importing IPython (%s)" % str(e) |
31 | |
32 ansi_colors = {'0;30': 'Black', | |
33 '0;31': 'Red', | |
34 '0;32': 'Green', | |
35 '0;33': 'Brown', | |
36 '0;34': 'Blue', | |
37 '0;35': 'Purple', | |
38 '0;36': 'Cyan', | |
39 '0;37': 'LightGray', | |
40 '1;30': 'DarkGray', | |
41 '1;31': 'DarkRed', | |
42 '1;32': 'SeaGreen', | |
43 '1;33': 'Yellow', | |
44 '1;34': 'LightBlue', | |
45 '1;35': 'MediumPurple', | |
46 '1;36': 'LightCyan', | |
47 '1;37': 'White'} | |
48 | |
49 class IterableIPShell: | |
50 def __init__(self,argv=None,user_ns=None,user_global_ns=None, | |
51 cin=None, cout=None,cerr=None, input_func=None): | |
52 if input_func: | |
53 IPython.iplib.raw_input_original = input_func | |
54 if cin: | |
55 IPython.Shell.Term.cin = cin | |
56 if cout: | |
57 IPython.Shell.Term.cout = cout | |
58 if cerr: | |
59 IPython.Shell.Term.cerr = cerr | |
60 | |
61 if argv is None: | |
62 argv=[] | |
63 | |
64 # This is to get rid of the blockage that occurs during | |
65 # IPython.Shell.InteractiveShell.user_setup() | |
66 IPython.iplib.raw_input = lambda x: None | |
67 | |
68 self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr) | |
69 os.environ['TERM'] = 'dumb' | |
70 excepthook = sys.excepthook | |
71 self.IP = IPython.Shell.make_IPython(argv,user_ns=user_ns, | |
72 user_global_ns=user_global_ns, | |
73 embedded=True, | |
74 shell_class=IPython.Shell.InteractiveShell) | |
75 self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd), | |
76 header='IPython system call: ', | |
77 verbose=self.IP.rc.system_verbose) | |
78 sys.excepthook = excepthook | |
79 self.iter_more = 0 | |
80 self.history_level = 0 | |
81 self.complete_sep = re.compile('[\s\{\}\[\]\(\)]') | |
82 | |
83 def execute(self): | |
84 self.history_level = 0 | |
85 orig_stdout = sys.stdout | |
86 sys.stdout = IPython.Shell.Term.cout | |
87 try: | |
88 line = self.IP.raw_input(None, self.iter_more) | |
89 if self.IP.autoindent: | |
90 self.IP.readline_startup_hook(None) | |
91 except KeyboardInterrupt: | |
92 self.IP.write('\nKeyboardInterrupt\n') | |
93 self.IP.resetbuffer() | |
94 # keep cache in sync with the prompt counter: | |
95 self.IP.outputcache.prompt_count -= 1 | |
96 | |
97 if self.IP.autoindent: | |
98 self.IP.indent_current_nsp = 0 | |
99 self.iter_more = 0 | |
100 except: | |
101 self.IP.showtraceback() | |
102 else: | |
103 self.iter_more = self.IP.push(line) | |
104 if (self.IP.SyntaxTB.last_syntax_error and | |
105 self.IP.rc.autoedit_syntax): | |
106 self.IP.edit_syntax_error() | |
107 if self.iter_more: | |
108 self.prompt = str(self.IP.outputcache.prompt2).strip() | |
109 if self.IP.autoindent: | |
110 self.IP.readline_startup_hook(self.IP.pre_readline) | |
111 else: | |
112 self.prompt = str(self.IP.outputcache.prompt1).strip() | |
113 sys.stdout = orig_stdout | |
114 | |
115 def historyBack(self): | |
116 self.history_level -= 1 | |
117 return self._getHistory() | |
118 | |
119 def historyForward(self): | |
120 self.history_level += 1 | |
121 return self._getHistory() | |
122 | |
123 def _getHistory(self): | |
124 try: | |
125 rv = self.IP.user_ns['In'][self.history_level].strip('\n') | |
126 except IndexError: | |
127 self.history_level = 0 | |
128 rv = '' | |
129 return rv | |
130 | |
131 def updateNamespace(self, ns_dict): | |
132 self.IP.user_ns.update(ns_dict) | |
133 | |
134 def complete(self, line): | |
135 split_line = self.complete_sep.split(line) | |
136 possibilities = self.IP.complete(split_line[-1]) | |
137 if possibilities: | |
138 common_prefix = reduce(self._commonPrefix, possibilities) | |
139 completed = line[:-len(split_line[-1])]+common_prefix | |
140 else: | |
141 completed = line | |
142 return completed, possibilities | |
143 | |
144 def _commonPrefix(self, str1, str2): | |
145 for i in range(len(str1)): | |
146 if not str2.startswith(str1[:i+1]): | |
147 return str1[:i] | |
148 return str1 | |
149 | |
150 def shell(self, cmd,verbose=0,debug=0,header=''): | |
151 stat = 0 | |
1866
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
152 if verbose or debug: print(header+cmd) |
709 | 153 # flush stdout so we don't mangle python's buffering |
154 if not debug: | |
155 input, output = os.popen4(cmd) | |
1866
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1056
diff
changeset
|
156 print(output.read()) |
709 | 157 output.close() |
158 input.close() | |
159 | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
160 class ConsoleView(Gtk.TextView): |
709 | 161 def __init__(self): |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
162 Gtk.TextView.__init__(self) |
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
163 self.modify_font(Pango.FontDescription('Mono')) |
709 | 164 self.set_cursor_visible(True) |
165 self.text_buffer = self.get_buffer() | |
166 self.mark = self.text_buffer.create_mark('scroll_mark', | |
167 self.text_buffer.get_end_iter(), | |
168 False) | |
169 for code in ansi_colors: | |
170 self.text_buffer.create_tag(code, | |
171 foreground=ansi_colors[code], | |
172 weight=700) | |
173 self.text_buffer.create_tag('0') | |
174 self.text_buffer.create_tag('notouch', editable=False) | |
175 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') | |
176 self.line_start = \ | |
177 self.text_buffer.create_mark('line_start', | |
178 self.text_buffer.get_end_iter(), True | |
179 ) | |
180 self.connect('key-press-event', self._onKeypress) | |
181 self.last_cursor_pos = 0 | |
182 | |
183 def write(self, text, editable=False): | |
184 segments = self.color_pat.split(text) | |
185 segment = segments.pop(0) | |
186 start_mark = self.text_buffer.create_mark(None, | |
187 self.text_buffer.get_end_iter(), | |
188 True) | |
189 self.text_buffer.insert(self.text_buffer.get_end_iter(), segment) | |
190 | |
191 if segments: | |
192 ansi_tags = self.color_pat.findall(text) | |
193 for tag in ansi_tags: | |
194 i = segments.index(tag) | |
195 self.text_buffer.insert_with_tags_by_name(self.text_buffer.get_end_iter(), | |
196 segments[i+1], tag) | |
197 segments.pop(i) | |
198 if not editable: | |
199 self.text_buffer.apply_tag_by_name('notouch', | |
200 self.text_buffer.get_iter_at_mark(start_mark), | |
201 self.text_buffer.get_end_iter()) | |
202 self.text_buffer.delete_mark(start_mark) | |
203 self.scroll_mark_onscreen(self.mark) | |
204 | |
205 def showPrompt(self, prompt): | |
206 self.write(prompt) | |
207 self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter()) | |
208 | |
209 def changeLine(self, text): | |
210 iter = self.text_buffer.get_iter_at_mark(self.line_start) | |
211 iter.forward_to_line_end() | |
212 self.text_buffer.delete(self.text_buffer.get_iter_at_mark(self.line_start), iter) | |
213 self.write(text, True) | |
214 | |
215 def getCurrentLine(self): | |
216 rv = self.text_buffer.get_slice(self.text_buffer.get_iter_at_mark(self.line_start), | |
217 self.text_buffer.get_end_iter(), False) | |
218 return rv | |
219 | |
220 def showReturned(self, text): | |
221 iter = self.text_buffer.get_iter_at_mark(self.line_start) | |
222 iter.forward_to_line_end() | |
223 self.text_buffer.apply_tag_by_name('notouch', | |
224 self.text_buffer.get_iter_at_mark(self.line_start), | |
225 iter) | |
226 self.write('\n'+text) | |
227 if text: | |
228 self.write('\n') | |
229 self.showPrompt(self.prompt) | |
230 self.text_buffer.move_mark(self.line_start,self.text_buffer.get_end_iter()) | |
231 self.text_buffer.place_cursor(self.text_buffer.get_end_iter()) | |
232 | |
233 def _onKeypress(self, obj, event): | |
234 if not event.string: | |
235 return | |
236 insert_mark = self.text_buffer.get_insert() | |
237 insert_iter = self.text_buffer.get_iter_at_mark(insert_mark) | |
238 selection_mark = self.text_buffer.get_selection_bound() | |
239 selection_iter = self.text_buffer.get_iter_at_mark(selection_mark) | |
240 start_iter = self.text_buffer.get_iter_at_mark(self.line_start) | |
241 if start_iter.compare(insert_iter) <= 0 and \ | |
242 start_iter.compare(selection_iter) <= 0: | |
243 return | |
244 elif start_iter.compare(insert_iter) > 0 and \ | |
245 start_iter.compare(selection_iter) > 0: | |
246 self.text_buffer.place_cursor(start_iter) | |
247 elif insert_iter.compare(selection_iter) < 0: | |
248 self.text_buffer.move_mark(insert_mark, start_iter) | |
249 elif insert_iter.compare(selection_iter) > 0: | |
250 self.text_buffer.move_mark(selection_mark, start_iter) | |
251 | |
252 | |
253 class IPythonView(ConsoleView, IterableIPShell): | |
254 def __init__(self, **kw): | |
255 ConsoleView.__init__(self) | |
256 self.cout = StringIO() | |
257 IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout, | |
258 input_func=self.raw_input, **kw) | |
259 self.connect('key_press_event', self.keyPress) | |
260 self.execute() | |
261 self.cout.truncate(0) | |
262 self.showPrompt(self.prompt) | |
263 self.interrupt = False | |
264 | |
265 def raw_input(self, prompt=''): | |
266 if self.interrupt: | |
267 self.interrupt = False | |
268 raise KeyboardInterrupt | |
269 return self.getCurrentLine() | |
270 | |
271 def keyPress(self, widget, event): | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
272 if event.state & Gdk.ModifierType.CONTROL_MASK and event.keyval == 99: |
709 | 273 self.interrupt = True |
274 self._processLine() | |
275 return True | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
276 elif event.keyval == Gtk.keysyms.Return: |
709 | 277 self._processLine() |
278 return True | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
279 elif event.keyval == Gtk.keysyms.Up: |
709 | 280 self.changeLine(self.historyBack()) |
281 return True | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
282 elif event.keyval == Gtk.keysyms.Down: |
709 | 283 self.changeLine(self.historyForward()) |
284 return True | |
285 # todo: Home needs to advance past the ipython prompt | |
1056
547d65ea9902
port curvecalc to gtk3. mostly worked, but there are severe bugs with redraws
Drew Perttula <drewp@bigasterisk.com>
parents:
709
diff
changeset
|
286 elif event.keyval == Gtk.keysyms.Tab: |
709 | 287 if not self.getCurrentLine().strip(): |
288 return False | |
289 completed, possibilities = self.complete(self.getCurrentLine()) | |
290 if len(possibilities) > 1: | |
291 slice = self.getCurrentLine() | |
292 self.write('\n') | |
293 for symbol in possibilities: | |
294 self.write(symbol+'\n') | |
295 self.showPrompt(self.prompt) | |
296 self.changeLine(completed or slice) | |
297 return True | |
298 | |
299 def _processLine(self): | |
300 self.history_pos = 0 | |
301 self.execute() | |
302 rv = self.cout.getvalue() | |
303 if rv: rv = rv.strip('\n') | |
304 self.showReturned(rv) | |
305 self.cout.truncate(0) |