Show More
@@ -0,0 +1,109 b'' | |||||
|
1 | { | |||
|
2 | "worksheets": [ | |||
|
3 | { | |||
|
4 | "cells": [ | |||
|
5 | { | |||
|
6 | "source": "A demonstration of the ability to clear the output of a cell during execution.", | |||
|
7 | "cell_type": "markdown" | |||
|
8 | }, | |||
|
9 | { | |||
|
10 | "cell_type": "code", | |||
|
11 | "language": "python", | |||
|
12 | "outputs": [], | |||
|
13 | "collapsed": true, | |||
|
14 | "prompt_number": 8, | |||
|
15 | "input": "from IPython.core.display import clear_output, display" | |||
|
16 | }, | |||
|
17 | { | |||
|
18 | "cell_type": "code", | |||
|
19 | "language": "python", | |||
|
20 | "outputs": [], | |||
|
21 | "collapsed": true, | |||
|
22 | "prompt_number": 4, | |||
|
23 | "input": "import time" | |||
|
24 | }, | |||
|
25 | { | |||
|
26 | "source": "First we show how this works with ``display``:", | |||
|
27 | "cell_type": "markdown" | |||
|
28 | }, | |||
|
29 | { | |||
|
30 | "cell_type": "code", | |||
|
31 | "language": "python", | |||
|
32 | "outputs": [ | |||
|
33 | { | |||
|
34 | "output_type": "stream", | |||
|
35 | "stream": "stdout", | |||
|
36 | "text": "\nTime step: 9" | |||
|
37 | }, | |||
|
38 | { | |||
|
39 | "output_type": "stream", | |||
|
40 | "stream": "stdout", | |||
|
41 | "text": "\n" | |||
|
42 | } | |||
|
43 | ], | |||
|
44 | "collapsed": false, | |||
|
45 | "prompt_number": 20, | |||
|
46 | "input": "for i in range(10):\n clear_output()\n print \"Time step: %i\" % i\n time.sleep(0.5)\n" | |||
|
47 | }, | |||
|
48 | { | |||
|
49 | "source": "Next, we show that ``clear_output`` can also be used to create a primitive form of animation using\nmatplotlib:", | |||
|
50 | "cell_type": "markdown" | |||
|
51 | }, | |||
|
52 | { | |||
|
53 | "cell_type": "code", | |||
|
54 | "language": "python", | |||
|
55 | "outputs": [ | |||
|
56 | { | |||
|
57 | "output_type": "display_data", | |||
|
58 | "png": "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\n8P8BdhDzr6dIpNsAAAAASUVORK5CYII=\n" | |||
|
59 | } | |||
|
60 | ], | |||
|
61 | "collapsed": false, | |||
|
62 | "prompt_number": 18, | |||
|
63 | "input": "for i in range(10):\n figure()\n plot(rand(100))\n clear_output()\n show()\n time.sleep(0.25)\n" | |||
|
64 | }, | |||
|
65 | { | |||
|
66 | "source": "And we can even selectively clear only a subset of stdout/stderr/other display such as figures\n(all are cleared by default).", | |||
|
67 | "cell_type": "markdown" | |||
|
68 | }, | |||
|
69 | { | |||
|
70 | "cell_type": "code", | |||
|
71 | "language": "python", | |||
|
72 | "outputs": [ | |||
|
73 | { | |||
|
74 | "output_type": "stream", | |||
|
75 | "stream": "stdout", | |||
|
76 | "text": "Time step: 0\n" | |||
|
77 | }, | |||
|
78 | { | |||
|
79 | "output_type": "stream", | |||
|
80 | "stream": "stdout", | |||
|
81 | "text": "Time step: 1\n" | |||
|
82 | }, | |||
|
83 | { | |||
|
84 | "output_type": "stream", | |||
|
85 | "stream": "stdout", | |||
|
86 | "text": "Time step: 2\n" | |||
|
87 | }, | |||
|
88 | { | |||
|
89 | "output_type": "stream", | |||
|
90 | "stream": "stdout", | |||
|
91 | "text": "Time step: 3\n" | |||
|
92 | }, | |||
|
93 | { | |||
|
94 | "output_type": "display_data", | |||
|
95 | "png": "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\nZjzrn0OUXq0AAAAASUVORK5CYII=\n" | |||
|
96 | } | |||
|
97 | ], | |||
|
98 | "collapsed": false, | |||
|
99 | "prompt_number": 19, | |||
|
100 | "input": "for i in range(4):\n print \"Time step: %i\" % i\n figure()\n plot(rand(100))\n # clear plots, but not stdout:\n clear_output(stdout=False)\n show()\n time.sleep(0.25)\n" | |||
|
101 | } | |||
|
102 | ] | |||
|
103 | } | |||
|
104 | ], | |||
|
105 | "metadata": { | |||
|
106 | "name": "clear_output" | |||
|
107 | }, | |||
|
108 | "nbformat": 2 | |||
|
109 | } No newline at end of file |
@@ -1,383 +1,407 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """Top-level display functions for displaying object in different formats. |
|
2 | """Top-level display functions for displaying object in different formats. | |
3 |
|
3 | |||
4 | Authors: |
|
4 | Authors: | |
5 |
|
5 | |||
6 | * Brian Granger |
|
6 | * Brian Granger | |
7 | """ |
|
7 | """ | |
8 |
|
8 | |||
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 | # Copyright (C) 2008-2010 The IPython Development Team |
|
10 | # Copyright (C) 2008-2010 The IPython Development Team | |
11 | # |
|
11 | # | |
12 | # Distributed under the terms of the BSD License. The full license is in |
|
12 | # Distributed under the terms of the BSD License. The full license is in | |
13 | # the file COPYING, distributed as part of this software. |
|
13 | # the file COPYING, distributed as part of this software. | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 | # Imports |
|
17 | # Imports | |
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 |
|
19 | |||
20 | from .displaypub import ( |
|
20 | from .displaypub import ( | |
21 | publish_pretty, publish_html, |
|
21 | publish_pretty, publish_html, | |
22 | publish_latex, publish_svg, |
|
22 | publish_latex, publish_svg, | |
23 | publish_png, publish_json, |
|
23 | publish_png, publish_json, | |
24 | publish_javascript, publish_jpeg |
|
24 | publish_javascript, publish_jpeg | |
25 | ) |
|
25 | ) | |
26 |
|
26 | |||
27 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
28 | # Main functions |
|
28 | # Main functions | |
29 | #----------------------------------------------------------------------------- |
|
29 | #----------------------------------------------------------------------------- | |
30 |
|
30 | |||
31 | def display(*objs, **kwargs): |
|
31 | def display(*objs, **kwargs): | |
32 | """Display a Python object in all frontends. |
|
32 | """Display a Python object in all frontends. | |
33 |
|
33 | |||
34 | By default all representations will be computed and sent to the frontends. |
|
34 | By default all representations will be computed and sent to the frontends. | |
35 | Frontends can decide which representation is used and how. |
|
35 | Frontends can decide which representation is used and how. | |
36 |
|
36 | |||
37 | Parameters |
|
37 | Parameters | |
38 | ---------- |
|
38 | ---------- | |
39 | objs : tuple of objects |
|
39 | objs : tuple of objects | |
40 | The Python objects to display. |
|
40 | The Python objects to display. | |
41 | include : list or tuple, optional |
|
41 | include : list or tuple, optional | |
42 | A list of format type strings (MIME types) to include in the |
|
42 | A list of format type strings (MIME types) to include in the | |
43 | format data dict. If this is set *only* the format types included |
|
43 | format data dict. If this is set *only* the format types included | |
44 | in this list will be computed. |
|
44 | in this list will be computed. | |
45 | exclude : list or tuple, optional |
|
45 | exclude : list or tuple, optional | |
46 | A list of format type string (MIME types) to exclue in the format |
|
46 | A list of format type string (MIME types) to exclue in the format | |
47 | data dict. If this is set all format types will be computed, |
|
47 | data dict. If this is set all format types will be computed, | |
48 | except for those included in this argument. |
|
48 | except for those included in this argument. | |
49 | """ |
|
49 | """ | |
50 | include = kwargs.get('include') |
|
50 | include = kwargs.get('include') | |
51 | exclude = kwargs.get('exclude') |
|
51 | exclude = kwargs.get('exclude') | |
52 |
|
52 | |||
53 | from IPython.core.interactiveshell import InteractiveShell |
|
53 | from IPython.core.interactiveshell import InteractiveShell | |
54 | inst = InteractiveShell.instance() |
|
54 | inst = InteractiveShell.instance() | |
55 | format = inst.display_formatter.format |
|
55 | format = inst.display_formatter.format | |
56 | publish = inst.display_pub.publish |
|
56 | publish = inst.display_pub.publish | |
57 |
|
57 | |||
58 | for obj in objs: |
|
58 | for obj in objs: | |
59 | format_dict = format(obj, include=include, exclude=exclude) |
|
59 | format_dict = format(obj, include=include, exclude=exclude) | |
60 | publish('IPython.core.display.display', format_dict) |
|
60 | publish('IPython.core.display.display', format_dict) | |
61 |
|
61 | |||
62 |
|
62 | |||
63 | def display_pretty(*objs, **kwargs): |
|
63 | def display_pretty(*objs, **kwargs): | |
64 | """Display the pretty (default) representation of an object. |
|
64 | """Display the pretty (default) representation of an object. | |
65 |
|
65 | |||
66 | Parameters |
|
66 | Parameters | |
67 | ---------- |
|
67 | ---------- | |
68 | objs : tuple of objects |
|
68 | objs : tuple of objects | |
69 | The Python objects to display, or if raw=True raw text data to |
|
69 | The Python objects to display, or if raw=True raw text data to | |
70 | display. |
|
70 | display. | |
71 | raw : bool |
|
71 | raw : bool | |
72 | Are the data objects raw data or Python objects that need to be |
|
72 | Are the data objects raw data or Python objects that need to be | |
73 | formatted before display? [default: False] |
|
73 | formatted before display? [default: False] | |
74 | """ |
|
74 | """ | |
75 | raw = kwargs.pop('raw',False) |
|
75 | raw = kwargs.pop('raw',False) | |
76 | if raw: |
|
76 | if raw: | |
77 | for obj in objs: |
|
77 | for obj in objs: | |
78 | publish_pretty(obj) |
|
78 | publish_pretty(obj) | |
79 | else: |
|
79 | else: | |
80 | display(*objs, include=['text/plain']) |
|
80 | display(*objs, include=['text/plain']) | |
81 |
|
81 | |||
82 |
|
82 | |||
83 | def display_html(*objs, **kwargs): |
|
83 | def display_html(*objs, **kwargs): | |
84 | """Display the HTML representation of an object. |
|
84 | """Display the HTML representation of an object. | |
85 |
|
85 | |||
86 | Parameters |
|
86 | Parameters | |
87 | ---------- |
|
87 | ---------- | |
88 | objs : tuple of objects |
|
88 | objs : tuple of objects | |
89 | The Python objects to display, or if raw=True raw HTML data to |
|
89 | The Python objects to display, or if raw=True raw HTML data to | |
90 | display. |
|
90 | display. | |
91 | raw : bool |
|
91 | raw : bool | |
92 | Are the data objects raw data or Python objects that need to be |
|
92 | Are the data objects raw data or Python objects that need to be | |
93 | formatted before display? [default: False] |
|
93 | formatted before display? [default: False] | |
94 | """ |
|
94 | """ | |
95 | raw = kwargs.pop('raw',False) |
|
95 | raw = kwargs.pop('raw',False) | |
96 | if raw: |
|
96 | if raw: | |
97 | for obj in objs: |
|
97 | for obj in objs: | |
98 | publish_html(obj) |
|
98 | publish_html(obj) | |
99 | else: |
|
99 | else: | |
100 | display(*objs, include=['text/plain','text/html']) |
|
100 | display(*objs, include=['text/plain','text/html']) | |
101 |
|
101 | |||
102 |
|
102 | |||
103 | def display_svg(*objs, **kwargs): |
|
103 | def display_svg(*objs, **kwargs): | |
104 | """Display the SVG representation of an object. |
|
104 | """Display the SVG representation of an object. | |
105 |
|
105 | |||
106 | Parameters |
|
106 | Parameters | |
107 | ---------- |
|
107 | ---------- | |
108 | objs : tuple of objects |
|
108 | objs : tuple of objects | |
109 | The Python objects to display, or if raw=True raw svg data to |
|
109 | The Python objects to display, or if raw=True raw svg data to | |
110 | display. |
|
110 | display. | |
111 | raw : bool |
|
111 | raw : bool | |
112 | Are the data objects raw data or Python objects that need to be |
|
112 | Are the data objects raw data or Python objects that need to be | |
113 | formatted before display? [default: False] |
|
113 | formatted before display? [default: False] | |
114 | """ |
|
114 | """ | |
115 | raw = kwargs.pop('raw',False) |
|
115 | raw = kwargs.pop('raw',False) | |
116 | if raw: |
|
116 | if raw: | |
117 | for obj in objs: |
|
117 | for obj in objs: | |
118 | publish_svg(obj) |
|
118 | publish_svg(obj) | |
119 | else: |
|
119 | else: | |
120 | display(*objs, include=['text/plain','image/svg+xml']) |
|
120 | display(*objs, include=['text/plain','image/svg+xml']) | |
121 |
|
121 | |||
122 |
|
122 | |||
123 | def display_png(*objs, **kwargs): |
|
123 | def display_png(*objs, **kwargs): | |
124 | """Display the PNG representation of an object. |
|
124 | """Display the PNG representation of an object. | |
125 |
|
125 | |||
126 | Parameters |
|
126 | Parameters | |
127 | ---------- |
|
127 | ---------- | |
128 | objs : tuple of objects |
|
128 | objs : tuple of objects | |
129 | The Python objects to display, or if raw=True raw png data to |
|
129 | The Python objects to display, or if raw=True raw png data to | |
130 | display. |
|
130 | display. | |
131 | raw : bool |
|
131 | raw : bool | |
132 | Are the data objects raw data or Python objects that need to be |
|
132 | Are the data objects raw data or Python objects that need to be | |
133 | formatted before display? [default: False] |
|
133 | formatted before display? [default: False] | |
134 | """ |
|
134 | """ | |
135 | raw = kwargs.pop('raw',False) |
|
135 | raw = kwargs.pop('raw',False) | |
136 | if raw: |
|
136 | if raw: | |
137 | for obj in objs: |
|
137 | for obj in objs: | |
138 | publish_png(obj) |
|
138 | publish_png(obj) | |
139 | else: |
|
139 | else: | |
140 | display(*objs, include=['text/plain','image/png']) |
|
140 | display(*objs, include=['text/plain','image/png']) | |
141 |
|
141 | |||
142 |
|
142 | |||
143 | def display_jpeg(*objs, **kwargs): |
|
143 | def display_jpeg(*objs, **kwargs): | |
144 | """Display the JPEG representation of an object. |
|
144 | """Display the JPEG representation of an object. | |
145 |
|
145 | |||
146 | Parameters |
|
146 | Parameters | |
147 | ---------- |
|
147 | ---------- | |
148 | objs : tuple of objects |
|
148 | objs : tuple of objects | |
149 | The Python objects to display, or if raw=True raw JPEG data to |
|
149 | The Python objects to display, or if raw=True raw JPEG data to | |
150 | display. |
|
150 | display. | |
151 | raw : bool |
|
151 | raw : bool | |
152 | Are the data objects raw data or Python objects that need to be |
|
152 | Are the data objects raw data or Python objects that need to be | |
153 | formatted before display? [default: False] |
|
153 | formatted before display? [default: False] | |
154 | """ |
|
154 | """ | |
155 | raw = kwargs.pop('raw',False) |
|
155 | raw = kwargs.pop('raw',False) | |
156 | if raw: |
|
156 | if raw: | |
157 | for obj in objs: |
|
157 | for obj in objs: | |
158 | publish_jpeg(obj) |
|
158 | publish_jpeg(obj) | |
159 | else: |
|
159 | else: | |
160 | display(*objs, include=['text/plain','image/jpeg']) |
|
160 | display(*objs, include=['text/plain','image/jpeg']) | |
161 |
|
161 | |||
162 |
|
162 | |||
163 | def display_latex(*objs, **kwargs): |
|
163 | def display_latex(*objs, **kwargs): | |
164 | """Display the LaTeX representation of an object. |
|
164 | """Display the LaTeX representation of an object. | |
165 |
|
165 | |||
166 | Parameters |
|
166 | Parameters | |
167 | ---------- |
|
167 | ---------- | |
168 | objs : tuple of objects |
|
168 | objs : tuple of objects | |
169 | The Python objects to display, or if raw=True raw latex data to |
|
169 | The Python objects to display, or if raw=True raw latex data to | |
170 | display. |
|
170 | display. | |
171 | raw : bool |
|
171 | raw : bool | |
172 | Are the data objects raw data or Python objects that need to be |
|
172 | Are the data objects raw data or Python objects that need to be | |
173 | formatted before display? [default: False] |
|
173 | formatted before display? [default: False] | |
174 | """ |
|
174 | """ | |
175 | raw = kwargs.pop('raw',False) |
|
175 | raw = kwargs.pop('raw',False) | |
176 | if raw: |
|
176 | if raw: | |
177 | for obj in objs: |
|
177 | for obj in objs: | |
178 | publish_latex(obj) |
|
178 | publish_latex(obj) | |
179 | else: |
|
179 | else: | |
180 | display(*objs, include=['text/plain','text/latex']) |
|
180 | display(*objs, include=['text/plain','text/latex']) | |
181 |
|
181 | |||
182 |
|
182 | |||
183 | def display_json(*objs, **kwargs): |
|
183 | def display_json(*objs, **kwargs): | |
184 | """Display the JSON representation of an object. |
|
184 | """Display the JSON representation of an object. | |
185 |
|
185 | |||
186 | Parameters |
|
186 | Parameters | |
187 | ---------- |
|
187 | ---------- | |
188 | objs : tuple of objects |
|
188 | objs : tuple of objects | |
189 | The Python objects to display, or if raw=True raw json data to |
|
189 | The Python objects to display, or if raw=True raw json data to | |
190 | display. |
|
190 | display. | |
191 | raw : bool |
|
191 | raw : bool | |
192 | Are the data objects raw data or Python objects that need to be |
|
192 | Are the data objects raw data or Python objects that need to be | |
193 | formatted before display? [default: False] |
|
193 | formatted before display? [default: False] | |
194 | """ |
|
194 | """ | |
195 | raw = kwargs.pop('raw',False) |
|
195 | raw = kwargs.pop('raw',False) | |
196 | if raw: |
|
196 | if raw: | |
197 | for obj in objs: |
|
197 | for obj in objs: | |
198 | publish_json(obj) |
|
198 | publish_json(obj) | |
199 | else: |
|
199 | else: | |
200 | display(*objs, include=['text/plain','application/json']) |
|
200 | display(*objs, include=['text/plain','application/json']) | |
201 |
|
201 | |||
202 |
|
202 | |||
203 | def display_javascript(*objs, **kwargs): |
|
203 | def display_javascript(*objs, **kwargs): | |
204 | """Display the Javascript representation of an object. |
|
204 | """Display the Javascript representation of an object. | |
205 |
|
205 | |||
206 | Parameters |
|
206 | Parameters | |
207 | ---------- |
|
207 | ---------- | |
208 | objs : tuple of objects |
|
208 | objs : tuple of objects | |
209 | The Python objects to display, or if raw=True raw javascript data to |
|
209 | The Python objects to display, or if raw=True raw javascript data to | |
210 | display. |
|
210 | display. | |
211 | raw : bool |
|
211 | raw : bool | |
212 | Are the data objects raw data or Python objects that need to be |
|
212 | Are the data objects raw data or Python objects that need to be | |
213 | formatted before display? [default: False] |
|
213 | formatted before display? [default: False] | |
214 | """ |
|
214 | """ | |
215 | raw = kwargs.pop('raw',False) |
|
215 | raw = kwargs.pop('raw',False) | |
216 | if raw: |
|
216 | if raw: | |
217 | for obj in objs: |
|
217 | for obj in objs: | |
218 | publish_javascript(obj) |
|
218 | publish_javascript(obj) | |
219 | else: |
|
219 | else: | |
220 | display(*objs, include=['text/plain','application/javascript']) |
|
220 | display(*objs, include=['text/plain','application/javascript']) | |
221 |
|
221 | |||
222 | #----------------------------------------------------------------------------- |
|
222 | #----------------------------------------------------------------------------- | |
223 | # Smart classes |
|
223 | # Smart classes | |
224 | #----------------------------------------------------------------------------- |
|
224 | #----------------------------------------------------------------------------- | |
225 |
|
225 | |||
226 |
|
226 | |||
227 | class DisplayObject(object): |
|
227 | class DisplayObject(object): | |
228 | """An object that wraps data to be displayed.""" |
|
228 | """An object that wraps data to be displayed.""" | |
229 |
|
229 | |||
230 | _read_flags = 'r' |
|
230 | _read_flags = 'r' | |
231 |
|
231 | |||
232 | def __init__(self, data=None, url=None, filename=None): |
|
232 | def __init__(self, data=None, url=None, filename=None): | |
233 | """Create a display object given raw data. |
|
233 | """Create a display object given raw data. | |
234 |
|
234 | |||
235 | When this object is returned by an expression or passed to the |
|
235 | When this object is returned by an expression or passed to the | |
236 | display function, it will result in the data being displayed |
|
236 | display function, it will result in the data being displayed | |
237 | in the frontend. The MIME type of the data should match the |
|
237 | in the frontend. The MIME type of the data should match the | |
238 | subclasses used, so the Png subclass should be used for 'image/png' |
|
238 | subclasses used, so the Png subclass should be used for 'image/png' | |
239 | data. If the data is a URL, the data will first be downloaded |
|
239 | data. If the data is a URL, the data will first be downloaded | |
240 | and then displayed. If |
|
240 | and then displayed. If | |
241 |
|
241 | |||
242 | Parameters |
|
242 | Parameters | |
243 | ---------- |
|
243 | ---------- | |
244 | data : unicode, str or bytes |
|
244 | data : unicode, str or bytes | |
245 | The raw data or a URL to download the data from. |
|
245 | The raw data or a URL to download the data from. | |
246 | url : unicode |
|
246 | url : unicode | |
247 | A URL to download the data from. |
|
247 | A URL to download the data from. | |
248 | filename : unicode |
|
248 | filename : unicode | |
249 | Path to a local file to load the data from. |
|
249 | Path to a local file to load the data from. | |
250 | """ |
|
250 | """ | |
251 | if data is not None and data.startswith('http'): |
|
251 | if data is not None and data.startswith('http'): | |
252 | self.url = data |
|
252 | self.url = data | |
253 | self.filename = None |
|
253 | self.filename = None | |
254 | self.data = None |
|
254 | self.data = None | |
255 | else: |
|
255 | else: | |
256 | self.data = data |
|
256 | self.data = data | |
257 | self.url = url |
|
257 | self.url = url | |
258 | self.filename = None if filename is None else unicode(filename) |
|
258 | self.filename = None if filename is None else unicode(filename) | |
259 | self.reload() |
|
259 | self.reload() | |
260 |
|
260 | |||
261 | def reload(self): |
|
261 | def reload(self): | |
262 | """Reload the raw data from file or URL.""" |
|
262 | """Reload the raw data from file or URL.""" | |
263 | if self.filename is not None: |
|
263 | if self.filename is not None: | |
264 | with open(self.filename, self._read_flags) as f: |
|
264 | with open(self.filename, self._read_flags) as f: | |
265 | self.data = f.read() |
|
265 | self.data = f.read() | |
266 | elif self.url is not None: |
|
266 | elif self.url is not None: | |
267 | try: |
|
267 | try: | |
268 | import urllib2 |
|
268 | import urllib2 | |
269 | response = urllib2.urlopen(self.url) |
|
269 | response = urllib2.urlopen(self.url) | |
270 | self.data = response.read() |
|
270 | self.data = response.read() | |
271 | # extract encoding from header, if there is one: |
|
271 | # extract encoding from header, if there is one: | |
272 | encoding = None |
|
272 | encoding = None | |
273 | for sub in response.headers['content-type'].split(';'): |
|
273 | for sub in response.headers['content-type'].split(';'): | |
274 | sub = sub.strip() |
|
274 | sub = sub.strip() | |
275 | if sub.startswith('charset'): |
|
275 | if sub.startswith('charset'): | |
276 | encoding = sub.split('=')[-1].strip() |
|
276 | encoding = sub.split('=')[-1].strip() | |
277 | break |
|
277 | break | |
278 | # decode data, if an encoding was specified |
|
278 | # decode data, if an encoding was specified | |
279 | if encoding: |
|
279 | if encoding: | |
280 | self.data = self.data.decode(encoding, 'replace') |
|
280 | self.data = self.data.decode(encoding, 'replace') | |
281 | except: |
|
281 | except: | |
282 | self.data = None |
|
282 | self.data = None | |
283 |
|
283 | |||
284 | class Pretty(DisplayObject): |
|
284 | class Pretty(DisplayObject): | |
285 |
|
285 | |||
286 | def _repr_pretty_(self): |
|
286 | def _repr_pretty_(self): | |
287 | return self.data |
|
287 | return self.data | |
288 |
|
288 | |||
289 |
|
289 | |||
290 | class HTML(DisplayObject): |
|
290 | class HTML(DisplayObject): | |
291 |
|
291 | |||
292 | def _repr_html_(self): |
|
292 | def _repr_html_(self): | |
293 | return self.data |
|
293 | return self.data | |
294 |
|
294 | |||
295 |
|
295 | |||
296 | class Math(DisplayObject): |
|
296 | class Math(DisplayObject): | |
297 |
|
297 | |||
298 | def _repr_latex_(self): |
|
298 | def _repr_latex_(self): | |
299 | return self.data |
|
299 | return self.data | |
300 |
|
300 | |||
301 |
|
301 | |||
302 | class SVG(DisplayObject): |
|
302 | class SVG(DisplayObject): | |
303 |
|
303 | |||
304 | def _repr_svg_(self): |
|
304 | def _repr_svg_(self): | |
305 | return self.data |
|
305 | return self.data | |
306 |
|
306 | |||
307 |
|
307 | |||
308 | class JSON(DisplayObject): |
|
308 | class JSON(DisplayObject): | |
309 |
|
309 | |||
310 | def _repr_json_(self): |
|
310 | def _repr_json_(self): | |
311 | return self.data |
|
311 | return self.data | |
312 |
|
312 | |||
313 |
|
313 | |||
314 | class Javascript(DisplayObject): |
|
314 | class Javascript(DisplayObject): | |
315 |
|
315 | |||
316 | def _repr_javascript_(self): |
|
316 | def _repr_javascript_(self): | |
317 | return self.data |
|
317 | return self.data | |
318 |
|
318 | |||
319 |
|
319 | |||
320 | class Image(DisplayObject): |
|
320 | class Image(DisplayObject): | |
321 |
|
321 | |||
322 | _read_flags = 'rb' |
|
322 | _read_flags = 'rb' | |
323 |
|
323 | |||
324 | def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False): |
|
324 | def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False): | |
325 | """Create a display an PNG/JPEG image given raw data. |
|
325 | """Create a display an PNG/JPEG image given raw data. | |
326 |
|
326 | |||
327 | When this object is returned by an expression or passed to the |
|
327 | When this object is returned by an expression or passed to the | |
328 | display function, it will result in the image being displayed |
|
328 | display function, it will result in the image being displayed | |
329 | in the frontend. |
|
329 | in the frontend. | |
330 |
|
330 | |||
331 | Parameters |
|
331 | Parameters | |
332 | ---------- |
|
332 | ---------- | |
333 | data : unicode, str or bytes |
|
333 | data : unicode, str or bytes | |
334 | The raw data or a URL to download the data from. |
|
334 | The raw data or a URL to download the data from. | |
335 | url : unicode |
|
335 | url : unicode | |
336 | A URL to download the data from. |
|
336 | A URL to download the data from. | |
337 | filename : unicode |
|
337 | filename : unicode | |
338 | Path to a local file to load the data from. |
|
338 | Path to a local file to load the data from. | |
339 | format : unicode |
|
339 | format : unicode | |
340 | The format of the image data (png/jpeg/jpg). If a filename or URL is given |
|
340 | The format of the image data (png/jpeg/jpg). If a filename or URL is given | |
341 | for format will be inferred from the filename extension. |
|
341 | for format will be inferred from the filename extension. | |
342 | embed : bool |
|
342 | embed : bool | |
343 | Should the image data be embedded in the notebook using a data URI (True) |
|
343 | Should the image data be embedded in the notebook using a data URI (True) | |
344 | or be loaded using an <img> tag. Set this to True if you want the image |
|
344 | or be loaded using an <img> tag. Set this to True if you want the image | |
345 | to be viewable later with no internet connection. If a filename is given |
|
345 | to be viewable later with no internet connection. If a filename is given | |
346 | embed is always set to True. |
|
346 | embed is always set to True. | |
347 | """ |
|
347 | """ | |
348 | if filename is not None: |
|
348 | if filename is not None: | |
349 | ext = self._find_ext(filename) |
|
349 | ext = self._find_ext(filename) | |
350 | elif url is not None: |
|
350 | elif url is not None: | |
351 | ext = self._find_ext(url) |
|
351 | ext = self._find_ext(url) | |
352 | elif data.startswith('http'): |
|
352 | elif data.startswith('http'): | |
353 | ext = self._find_ext(data) |
|
353 | ext = self._find_ext(data) | |
354 | else: |
|
354 | else: | |
355 | ext = None |
|
355 | ext = None | |
356 | if ext is not None: |
|
356 | if ext is not None: | |
357 | if ext == u'jpg' or ext == u'jpeg': |
|
357 | if ext == u'jpg' or ext == u'jpeg': | |
358 | format = u'jpeg' |
|
358 | format = u'jpeg' | |
359 | if ext == u'png': |
|
359 | if ext == u'png': | |
360 | format = u'png' |
|
360 | format = u'png' | |
361 | self.format = unicode(format).lower() |
|
361 | self.format = unicode(format).lower() | |
362 | self.embed = True if filename is not None else embed |
|
362 | self.embed = True if filename is not None else embed | |
363 | super(Image, self).__init__(data=data, url=url, filename=filename) |
|
363 | super(Image, self).__init__(data=data, url=url, filename=filename) | |
364 |
|
364 | |||
365 | def reload(self): |
|
365 | def reload(self): | |
366 | """Reload the raw data from file or URL.""" |
|
366 | """Reload the raw data from file or URL.""" | |
367 | if self.embed: |
|
367 | if self.embed: | |
368 | super(Image,self).reload() |
|
368 | super(Image,self).reload() | |
369 |
|
369 | |||
370 | def _repr_html_(self): |
|
370 | def _repr_html_(self): | |
371 | if not self.embed: |
|
371 | if not self.embed: | |
372 | return u'<img src="%s" />' % self.url |
|
372 | return u'<img src="%s" />' % self.url | |
373 |
|
373 | |||
374 | def _repr_png_(self): |
|
374 | def _repr_png_(self): | |
375 | if self.embed and self.format == u'png': |
|
375 | if self.embed and self.format == u'png': | |
376 | return self.data |
|
376 | return self.data | |
377 |
|
377 | |||
378 | def _repr_jpeg_(self): |
|
378 | def _repr_jpeg_(self): | |
379 | if self.embed and (self.format == u'jpeg' or self.format == u'jpg'): |
|
379 | if self.embed and (self.format == u'jpeg' or self.format == u'jpg'): | |
380 | return self.data |
|
380 | return self.data | |
381 |
|
381 | |||
382 | def _find_ext(self, s): |
|
382 | def _find_ext(self, s): | |
383 | return unicode(s.split('.')[-1].lower()) |
|
383 | return unicode(s.split('.')[-1].lower()) | |
|
384 | ||||
|
385 | ||||
|
386 | def clear_output(stdout=True, stderr=True, other=True): | |||
|
387 | """Clear the output of the current cell receiving output. | |||
|
388 | ||||
|
389 | Optionally, each of stdout/stderr or other non-stream data (e.g. anything | |||
|
390 | produced by display()) can be excluded from the clear event. | |||
|
391 | ||||
|
392 | By default, everything is cleared. | |||
|
393 | ||||
|
394 | Parameters | |||
|
395 | ---------- | |||
|
396 | stdout : bool [default: True] | |||
|
397 | Whether to clear stdout. | |||
|
398 | stderr : bool [default: True] | |||
|
399 | Whether to clear stderr. | |||
|
400 | other : bool [default: True] | |||
|
401 | Whether to clear everything else that is not stdout/stderr | |||
|
402 | (e.g. figures,images,HTML, any result of display()). | |||
|
403 | """ | |||
|
404 | from IPython.core.interactiveshell import InteractiveShell | |||
|
405 | InteractiveShell.instance().display_pub.clear_output( | |||
|
406 | stdout=stdout, stderr=stderr, other=other, | |||
|
407 | ) |
@@ -1,298 +1,302 b'' | |||||
1 | """An interface for publishing rich data to frontends. |
|
1 | """An interface for publishing rich data to frontends. | |
2 |
|
2 | |||
3 | There are two components of the display system: |
|
3 | There are two components of the display system: | |
4 |
|
4 | |||
5 | * Display formatters, which take a Python object and compute the |
|
5 | * Display formatters, which take a Python object and compute the | |
6 | representation of the object in various formats (text, HTML, SVg, etc.). |
|
6 | representation of the object in various formats (text, HTML, SVg, etc.). | |
7 | * The display publisher that is used to send the representation data to the |
|
7 | * The display publisher that is used to send the representation data to the | |
8 | various frontends. |
|
8 | various frontends. | |
9 |
|
9 | |||
10 | This module defines the logic display publishing. The display publisher uses |
|
10 | This module defines the logic display publishing. The display publisher uses | |
11 | the ``display_data`` message type that is defined in the IPython messaging |
|
11 | the ``display_data`` message type that is defined in the IPython messaging | |
12 | spec. |
|
12 | spec. | |
13 |
|
13 | |||
14 | Authors: |
|
14 | Authors: | |
15 |
|
15 | |||
16 | * Brian Granger |
|
16 | * Brian Granger | |
17 | """ |
|
17 | """ | |
18 |
|
18 | |||
19 | #----------------------------------------------------------------------------- |
|
19 | #----------------------------------------------------------------------------- | |
20 | # Copyright (C) 2008-2010 The IPython Development Team |
|
20 | # Copyright (C) 2008-2010 The IPython Development Team | |
21 | # |
|
21 | # | |
22 | # Distributed under the terms of the BSD License. The full license is in |
|
22 | # Distributed under the terms of the BSD License. The full license is in | |
23 | # the file COPYING, distributed as part of this software. |
|
23 | # the file COPYING, distributed as part of this software. | |
24 | #----------------------------------------------------------------------------- |
|
24 | #----------------------------------------------------------------------------- | |
25 |
|
25 | |||
26 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
27 | # Imports |
|
27 | # Imports | |
28 | #----------------------------------------------------------------------------- |
|
28 | #----------------------------------------------------------------------------- | |
29 |
|
29 | |||
30 | from __future__ import print_function |
|
30 | from __future__ import print_function | |
31 |
|
31 | |||
32 | from IPython.config.configurable import Configurable |
|
32 | from IPython.config.configurable import Configurable | |
33 |
|
33 | |||
34 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
35 | # Main payload class |
|
35 | # Main payload class | |
36 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
37 |
|
37 | |||
38 | class DisplayPublisher(Configurable): |
|
38 | class DisplayPublisher(Configurable): | |
39 | """A traited class that publishes display data to frontends. |
|
39 | """A traited class that publishes display data to frontends. | |
40 |
|
40 | |||
41 | Instances of this class are created by the main IPython object and should |
|
41 | Instances of this class are created by the main IPython object and should | |
42 | be accessed there. |
|
42 | be accessed there. | |
43 | """ |
|
43 | """ | |
44 |
|
44 | |||
45 | def _validate_data(self, source, data, metadata=None): |
|
45 | def _validate_data(self, source, data, metadata=None): | |
46 | """Validate the display data. |
|
46 | """Validate the display data. | |
47 |
|
47 | |||
48 | Parameters |
|
48 | Parameters | |
49 | ---------- |
|
49 | ---------- | |
50 | source : str |
|
50 | source : str | |
51 | The fully dotted name of the callable that created the data, like |
|
51 | The fully dotted name of the callable that created the data, like | |
52 | :func:`foo.bar.my_formatter`. |
|
52 | :func:`foo.bar.my_formatter`. | |
53 | data : dict |
|
53 | data : dict | |
54 | The formata data dictionary. |
|
54 | The formata data dictionary. | |
55 | metadata : dict |
|
55 | metadata : dict | |
56 | Any metadata for the data. |
|
56 | Any metadata for the data. | |
57 | """ |
|
57 | """ | |
58 |
|
58 | |||
59 | if not isinstance(source, basestring): |
|
59 | if not isinstance(source, basestring): | |
60 | raise TypeError('source must be a str, got: %r' % source) |
|
60 | raise TypeError('source must be a str, got: %r' % source) | |
61 | if not isinstance(data, dict): |
|
61 | if not isinstance(data, dict): | |
62 | raise TypeError('data must be a dict, got: %r' % data) |
|
62 | raise TypeError('data must be a dict, got: %r' % data) | |
63 | if metadata is not None: |
|
63 | if metadata is not None: | |
64 | if not isinstance(metadata, dict): |
|
64 | if not isinstance(metadata, dict): | |
65 | raise TypeError('metadata must be a dict, got: %r' % data) |
|
65 | raise TypeError('metadata must be a dict, got: %r' % data) | |
66 |
|
66 | |||
67 | def publish(self, source, data, metadata=None): |
|
67 | def publish(self, source, data, metadata=None): | |
68 | """Publish data and metadata to all frontends. |
|
68 | """Publish data and metadata to all frontends. | |
69 |
|
69 | |||
70 | See the ``display_data`` message in the messaging documentation for |
|
70 | See the ``display_data`` message in the messaging documentation for | |
71 | more details about this message type. |
|
71 | more details about this message type. | |
72 |
|
72 | |||
73 | The following MIME types are currently implemented: |
|
73 | The following MIME types are currently implemented: | |
74 |
|
74 | |||
75 | * text/plain |
|
75 | * text/plain | |
76 | * text/html |
|
76 | * text/html | |
77 | * text/latex |
|
77 | * text/latex | |
78 | * application/json |
|
78 | * application/json | |
79 | * application/javascript |
|
79 | * application/javascript | |
80 | * image/png |
|
80 | * image/png | |
81 | * image/jpeg |
|
81 | * image/jpeg | |
82 | * image/svg+xml |
|
82 | * image/svg+xml | |
83 |
|
83 | |||
84 | Parameters |
|
84 | Parameters | |
85 | ---------- |
|
85 | ---------- | |
86 | source : str |
|
86 | source : str | |
87 | A string that give the function or method that created the data, |
|
87 | A string that give the function or method that created the data, | |
88 | such as 'IPython.core.page'. |
|
88 | such as 'IPython.core.page'. | |
89 | data : dict |
|
89 | data : dict | |
90 | A dictionary having keys that are valid MIME types (like |
|
90 | A dictionary having keys that are valid MIME types (like | |
91 | 'text/plain' or 'image/svg+xml') and values that are the data for |
|
91 | 'text/plain' or 'image/svg+xml') and values that are the data for | |
92 | that MIME type. The data itself must be a JSON'able data |
|
92 | that MIME type. The data itself must be a JSON'able data | |
93 | structure. Minimally all data should have the 'text/plain' data, |
|
93 | structure. Minimally all data should have the 'text/plain' data, | |
94 | which can be displayed by all frontends. If more than the plain |
|
94 | which can be displayed by all frontends. If more than the plain | |
95 | text is given, it is up to the frontend to decide which |
|
95 | text is given, it is up to the frontend to decide which | |
96 | representation to use. |
|
96 | representation to use. | |
97 | metadata : dict |
|
97 | metadata : dict | |
98 | A dictionary for metadata related to the data. This can contain |
|
98 | A dictionary for metadata related to the data. This can contain | |
99 | arbitrary key, value pairs that frontends can use to interpret |
|
99 | arbitrary key, value pairs that frontends can use to interpret | |
100 | the data. |
|
100 | the data. | |
101 | """ |
|
101 | """ | |
102 | from IPython.utils import io |
|
102 | from IPython.utils import io | |
103 | # The default is to simply write the plain text data using io.stdout. |
|
103 | # The default is to simply write the plain text data using io.stdout. | |
104 | if data.has_key('text/plain'): |
|
104 | if data.has_key('text/plain'): | |
105 | print(data['text/plain'], file=io.stdout) |
|
105 | print(data['text/plain'], file=io.stdout) | |
106 |
|
106 | |||
|
107 | def clear_output(self, stdout=True, stderr=True, other=True): | |||
|
108 | """Clear the output of the cell receiving output.""" | |||
|
109 | pass | |||
|
110 | ||||
107 |
|
111 | |||
108 | def publish_display_data(source, data, metadata=None): |
|
112 | def publish_display_data(source, data, metadata=None): | |
109 | """Publish data and metadata to all frontends. |
|
113 | """Publish data and metadata to all frontends. | |
110 |
|
114 | |||
111 | See the ``display_data`` message in the messaging documentation for |
|
115 | See the ``display_data`` message in the messaging documentation for | |
112 | more details about this message type. |
|
116 | more details about this message type. | |
113 |
|
117 | |||
114 | The following MIME types are currently implemented: |
|
118 | The following MIME types are currently implemented: | |
115 |
|
119 | |||
116 | * text/plain |
|
120 | * text/plain | |
117 | * text/html |
|
121 | * text/html | |
118 | * text/latex |
|
122 | * text/latex | |
119 | * application/json |
|
123 | * application/json | |
120 | * application/javascript |
|
124 | * application/javascript | |
121 | * image/png |
|
125 | * image/png | |
122 | * image/jpeg |
|
126 | * image/jpeg | |
123 | * image/svg+xml |
|
127 | * image/svg+xml | |
124 |
|
128 | |||
125 | Parameters |
|
129 | Parameters | |
126 | ---------- |
|
130 | ---------- | |
127 | source : str |
|
131 | source : str | |
128 | A string that give the function or method that created the data, |
|
132 | A string that give the function or method that created the data, | |
129 | such as 'IPython.core.page'. |
|
133 | such as 'IPython.core.page'. | |
130 | data : dict |
|
134 | data : dict | |
131 | A dictionary having keys that are valid MIME types (like |
|
135 | A dictionary having keys that are valid MIME types (like | |
132 | 'text/plain' or 'image/svg+xml') and values that are the data for |
|
136 | 'text/plain' or 'image/svg+xml') and values that are the data for | |
133 | that MIME type. The data itself must be a JSON'able data |
|
137 | that MIME type. The data itself must be a JSON'able data | |
134 | structure. Minimally all data should have the 'text/plain' data, |
|
138 | structure. Minimally all data should have the 'text/plain' data, | |
135 | which can be displayed by all frontends. If more than the plain |
|
139 | which can be displayed by all frontends. If more than the plain | |
136 | text is given, it is up to the frontend to decide which |
|
140 | text is given, it is up to the frontend to decide which | |
137 | representation to use. |
|
141 | representation to use. | |
138 | metadata : dict |
|
142 | metadata : dict | |
139 | A dictionary for metadata related to the data. This can contain |
|
143 | A dictionary for metadata related to the data. This can contain | |
140 | arbitrary key, value pairs that frontends can use to interpret |
|
144 | arbitrary key, value pairs that frontends can use to interpret | |
141 | the data. |
|
145 | the data. | |
142 | """ |
|
146 | """ | |
143 | from IPython.core.interactiveshell import InteractiveShell |
|
147 | from IPython.core.interactiveshell import InteractiveShell | |
144 | InteractiveShell.instance().display_pub.publish( |
|
148 | InteractiveShell.instance().display_pub.publish( | |
145 | source, |
|
149 | source, | |
146 | data, |
|
150 | data, | |
147 | metadata |
|
151 | metadata | |
148 | ) |
|
152 | ) | |
149 |
|
153 | |||
150 |
|
154 | |||
151 | def publish_pretty(data, metadata=None): |
|
155 | def publish_pretty(data, metadata=None): | |
152 | """Publish raw text data to all frontends. |
|
156 | """Publish raw text data to all frontends. | |
153 |
|
157 | |||
154 | Parameters |
|
158 | Parameters | |
155 | ---------- |
|
159 | ---------- | |
156 | data : unicode |
|
160 | data : unicode | |
157 | The raw text data to publish. |
|
161 | The raw text data to publish. | |
158 | metadata : dict |
|
162 | metadata : dict | |
159 | A dictionary for metadata related to the data. This can contain |
|
163 | A dictionary for metadata related to the data. This can contain | |
160 | arbitrary key, value pairs that frontends can use to interpret |
|
164 | arbitrary key, value pairs that frontends can use to interpret | |
161 | the data. |
|
165 | the data. | |
162 | """ |
|
166 | """ | |
163 | publish_display_data( |
|
167 | publish_display_data( | |
164 | u'IPython.core.displaypub.publish_pretty', |
|
168 | u'IPython.core.displaypub.publish_pretty', | |
165 | {'text/plain':data}, |
|
169 | {'text/plain':data}, | |
166 | metadata=metadata |
|
170 | metadata=metadata | |
167 | ) |
|
171 | ) | |
168 |
|
172 | |||
169 |
|
173 | |||
170 | def publish_html(data, metadata=None): |
|
174 | def publish_html(data, metadata=None): | |
171 | """Publish raw HTML data to all frontends. |
|
175 | """Publish raw HTML data to all frontends. | |
172 |
|
176 | |||
173 | Parameters |
|
177 | Parameters | |
174 | ---------- |
|
178 | ---------- | |
175 | data : unicode |
|
179 | data : unicode | |
176 | The raw HTML data to publish. |
|
180 | The raw HTML data to publish. | |
177 | metadata : dict |
|
181 | metadata : dict | |
178 | A dictionary for metadata related to the data. This can contain |
|
182 | A dictionary for metadata related to the data. This can contain | |
179 | arbitrary key, value pairs that frontends can use to interpret |
|
183 | arbitrary key, value pairs that frontends can use to interpret | |
180 | the data. |
|
184 | the data. | |
181 | """ |
|
185 | """ | |
182 | publish_display_data( |
|
186 | publish_display_data( | |
183 | u'IPython.core.displaypub.publish_html', |
|
187 | u'IPython.core.displaypub.publish_html', | |
184 | {'text/html':data}, |
|
188 | {'text/html':data}, | |
185 | metadata=metadata |
|
189 | metadata=metadata | |
186 | ) |
|
190 | ) | |
187 |
|
191 | |||
188 |
|
192 | |||
189 | def publish_latex(data, metadata=None): |
|
193 | def publish_latex(data, metadata=None): | |
190 | """Publish raw LaTeX data to all frontends. |
|
194 | """Publish raw LaTeX data to all frontends. | |
191 |
|
195 | |||
192 | Parameters |
|
196 | Parameters | |
193 | ---------- |
|
197 | ---------- | |
194 | data : unicode |
|
198 | data : unicode | |
195 | The raw LaTeX data to publish. |
|
199 | The raw LaTeX data to publish. | |
196 | metadata : dict |
|
200 | metadata : dict | |
197 | A dictionary for metadata related to the data. This can contain |
|
201 | A dictionary for metadata related to the data. This can contain | |
198 | arbitrary key, value pairs that frontends can use to interpret |
|
202 | arbitrary key, value pairs that frontends can use to interpret | |
199 | the data. |
|
203 | the data. | |
200 | """ |
|
204 | """ | |
201 | publish_display_data( |
|
205 | publish_display_data( | |
202 | u'IPython.core.displaypub.publish_latex', |
|
206 | u'IPython.core.displaypub.publish_latex', | |
203 | {'text/latex':data}, |
|
207 | {'text/latex':data}, | |
204 | metadata=metadata |
|
208 | metadata=metadata | |
205 | ) |
|
209 | ) | |
206 |
|
210 | |||
207 | def publish_png(data, metadata=None): |
|
211 | def publish_png(data, metadata=None): | |
208 | """Publish raw binary PNG data to all frontends. |
|
212 | """Publish raw binary PNG data to all frontends. | |
209 |
|
213 | |||
210 | Parameters |
|
214 | Parameters | |
211 | ---------- |
|
215 | ---------- | |
212 | data : str/bytes |
|
216 | data : str/bytes | |
213 | The raw binary PNG data to publish. |
|
217 | The raw binary PNG data to publish. | |
214 | metadata : dict |
|
218 | metadata : dict | |
215 | A dictionary for metadata related to the data. This can contain |
|
219 | A dictionary for metadata related to the data. This can contain | |
216 | arbitrary key, value pairs that frontends can use to interpret |
|
220 | arbitrary key, value pairs that frontends can use to interpret | |
217 | the data. |
|
221 | the data. | |
218 | """ |
|
222 | """ | |
219 | publish_display_data( |
|
223 | publish_display_data( | |
220 | u'IPython.core.displaypub.publish_png', |
|
224 | u'IPython.core.displaypub.publish_png', | |
221 | {'image/png':data}, |
|
225 | {'image/png':data}, | |
222 | metadata=metadata |
|
226 | metadata=metadata | |
223 | ) |
|
227 | ) | |
224 |
|
228 | |||
225 |
|
229 | |||
226 | def publish_jpeg(data, metadata=None): |
|
230 | def publish_jpeg(data, metadata=None): | |
227 | """Publish raw binary JPEG data to all frontends. |
|
231 | """Publish raw binary JPEG data to all frontends. | |
228 |
|
232 | |||
229 | Parameters |
|
233 | Parameters | |
230 | ---------- |
|
234 | ---------- | |
231 | data : str/bytes |
|
235 | data : str/bytes | |
232 | The raw binary JPEG data to publish. |
|
236 | The raw binary JPEG data to publish. | |
233 | metadata : dict |
|
237 | metadata : dict | |
234 | A dictionary for metadata related to the data. This can contain |
|
238 | A dictionary for metadata related to the data. This can contain | |
235 | arbitrary key, value pairs that frontends can use to interpret |
|
239 | arbitrary key, value pairs that frontends can use to interpret | |
236 | the data. |
|
240 | the data. | |
237 | """ |
|
241 | """ | |
238 | publish_display_data( |
|
242 | publish_display_data( | |
239 | u'IPython.core.displaypub.publish_jpeg', |
|
243 | u'IPython.core.displaypub.publish_jpeg', | |
240 | {'image/jpeg':data}, |
|
244 | {'image/jpeg':data}, | |
241 | metadata=metadata |
|
245 | metadata=metadata | |
242 | ) |
|
246 | ) | |
243 |
|
247 | |||
244 |
|
248 | |||
245 | def publish_svg(data, metadata=None): |
|
249 | def publish_svg(data, metadata=None): | |
246 | """Publish raw SVG data to all frontends. |
|
250 | """Publish raw SVG data to all frontends. | |
247 |
|
251 | |||
248 | Parameters |
|
252 | Parameters | |
249 | ---------- |
|
253 | ---------- | |
250 | data : unicode |
|
254 | data : unicode | |
251 | The raw SVG data to publish. |
|
255 | The raw SVG data to publish. | |
252 | metadata : dict |
|
256 | metadata : dict | |
253 | A dictionary for metadata related to the data. This can contain |
|
257 | A dictionary for metadata related to the data. This can contain | |
254 | arbitrary key, value pairs that frontends can use to interpret |
|
258 | arbitrary key, value pairs that frontends can use to interpret | |
255 | the data. |
|
259 | the data. | |
256 | """ |
|
260 | """ | |
257 | publish_display_data( |
|
261 | publish_display_data( | |
258 | u'IPython.core.displaypub.publish_svg', |
|
262 | u'IPython.core.displaypub.publish_svg', | |
259 | {'image/svg+xml':data}, |
|
263 | {'image/svg+xml':data}, | |
260 | metadata=metadata |
|
264 | metadata=metadata | |
261 | ) |
|
265 | ) | |
262 |
|
266 | |||
263 | def publish_json(data, metadata=None): |
|
267 | def publish_json(data, metadata=None): | |
264 | """Publish raw JSON data to all frontends. |
|
268 | """Publish raw JSON data to all frontends. | |
265 |
|
269 | |||
266 | Parameters |
|
270 | Parameters | |
267 | ---------- |
|
271 | ---------- | |
268 | data : unicode |
|
272 | data : unicode | |
269 | The raw JSON data to publish. |
|
273 | The raw JSON data to publish. | |
270 | metadata : dict |
|
274 | metadata : dict | |
271 | A dictionary for metadata related to the data. This can contain |
|
275 | A dictionary for metadata related to the data. This can contain | |
272 | arbitrary key, value pairs that frontends can use to interpret |
|
276 | arbitrary key, value pairs that frontends can use to interpret | |
273 | the data. |
|
277 | the data. | |
274 | """ |
|
278 | """ | |
275 | publish_display_data( |
|
279 | publish_display_data( | |
276 | u'IPython.core.displaypub.publish_json', |
|
280 | u'IPython.core.displaypub.publish_json', | |
277 | {'application/json':data}, |
|
281 | {'application/json':data}, | |
278 | metadata=metadata |
|
282 | metadata=metadata | |
279 | ) |
|
283 | ) | |
280 |
|
284 | |||
281 | def publish_javascript(data, metadata=None): |
|
285 | def publish_javascript(data, metadata=None): | |
282 | """Publish raw Javascript data to all frontends. |
|
286 | """Publish raw Javascript data to all frontends. | |
283 |
|
287 | |||
284 | Parameters |
|
288 | Parameters | |
285 | ---------- |
|
289 | ---------- | |
286 | data : unicode |
|
290 | data : unicode | |
287 | The raw Javascript data to publish. |
|
291 | The raw Javascript data to publish. | |
288 | metadata : dict |
|
292 | metadata : dict | |
289 | A dictionary for metadata related to the data. This can contain |
|
293 | A dictionary for metadata related to the data. This can contain | |
290 | arbitrary key, value pairs that frontends can use to interpret |
|
294 | arbitrary key, value pairs that frontends can use to interpret | |
291 | the data. |
|
295 | the data. | |
292 | """ |
|
296 | """ | |
293 | publish_display_data( |
|
297 | publish_display_data( | |
294 | u'IPython.core.displaypub.publish_javascript', |
|
298 | u'IPython.core.displaypub.publish_javascript', | |
295 | {'application/javascript':data}, |
|
299 | {'application/javascript':data}, | |
296 | metadata=metadata |
|
300 | metadata=metadata | |
297 | ) |
|
301 | ) | |
298 |
|
302 |
@@ -1,486 +1,518 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2008-2011 The IPython Development Team |
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |
3 | // |
|
3 | // | |
4 | // Distributed under the terms of the BSD License. The full license is in |
|
4 | // Distributed under the terms of the BSD License. The full license is in | |
5 | // the file COPYING, distributed as part of this software. |
|
5 | // the file COPYING, distributed as part of this software. | |
6 | //---------------------------------------------------------------------------- |
|
6 | //---------------------------------------------------------------------------- | |
7 |
|
7 | |||
8 | //============================================================================ |
|
8 | //============================================================================ | |
9 | // CodeCell |
|
9 | // CodeCell | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
13 |
|
13 | |||
14 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
15 |
|
15 | |||
16 | var CodeCell = function (notebook) { |
|
16 | var CodeCell = function (notebook) { | |
17 | this.code_mirror = null; |
|
17 | this.code_mirror = null; | |
18 | this.input_prompt_number = ' '; |
|
18 | this.input_prompt_number = ' '; | |
19 | this.is_completing = false; |
|
19 | this.is_completing = false; | |
20 | this.completion_cursor = null; |
|
20 | this.completion_cursor = null; | |
21 | this.outputs = []; |
|
21 | this.outputs = []; | |
22 | this.collapsed = false; |
|
22 | this.collapsed = false; | |
23 | IPython.Cell.apply(this, arguments); |
|
23 | IPython.Cell.apply(this, arguments); | |
24 | }; |
|
24 | }; | |
25 |
|
25 | |||
26 |
|
26 | |||
27 | CodeCell.prototype = new IPython.Cell(); |
|
27 | CodeCell.prototype = new IPython.Cell(); | |
28 |
|
28 | |||
29 |
|
29 | |||
30 | CodeCell.prototype.create_element = function () { |
|
30 | CodeCell.prototype.create_element = function () { | |
31 | var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox'); |
|
31 | var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox'); | |
32 | cell.attr('tabindex','2'); |
|
32 | cell.attr('tabindex','2'); | |
33 | var input = $('<div></div>').addClass('input hbox'); |
|
33 | var input = $('<div></div>').addClass('input hbox'); | |
34 | input.append($('<div/>').addClass('prompt input_prompt')); |
|
34 | input.append($('<div/>').addClass('prompt input_prompt')); | |
35 | var input_area = $('<div/>').addClass('input_area box-flex1'); |
|
35 | var input_area = $('<div/>').addClass('input_area box-flex1'); | |
36 | this.code_mirror = CodeMirror(input_area.get(0), { |
|
36 | this.code_mirror = CodeMirror(input_area.get(0), { | |
37 | indentUnit : 4, |
|
37 | indentUnit : 4, | |
38 | mode: 'python', |
|
38 | mode: 'python', | |
39 | theme: 'ipython', |
|
39 | theme: 'ipython', | |
40 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) |
|
40 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) | |
41 | }); |
|
41 | }); | |
42 | input.append(input_area); |
|
42 | input.append(input_area); | |
43 | var output = $('<div></div>').addClass('output vbox'); |
|
43 | var output = $('<div></div>').addClass('output vbox'); | |
44 | cell.append(input).append(output); |
|
44 | cell.append(input).append(output); | |
45 | this.element = cell; |
|
45 | this.element = cell; | |
46 | this.collapse() |
|
46 | this.collapse() | |
47 | }; |
|
47 | }; | |
48 |
|
48 | |||
49 |
|
49 | |||
50 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
50 | CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { | |
51 | // This method gets called in CodeMirror's onKeyDown/onKeyPress |
|
51 | // This method gets called in CodeMirror's onKeyDown/onKeyPress | |
52 | // handlers and is used to provide custom key handling. Its return |
|
52 | // handlers and is used to provide custom key handling. Its return | |
53 | // value is used to determine if CodeMirror should ignore the event: |
|
53 | // value is used to determine if CodeMirror should ignore the event: | |
54 | // true = ignore, false = don't ignore. |
|
54 | // true = ignore, false = don't ignore. | |
55 | if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) { |
|
55 | if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) { | |
56 | // Always ignore shift-enter in CodeMirror as we handle it. |
|
56 | // Always ignore shift-enter in CodeMirror as we handle it. | |
57 | return true; |
|
57 | return true; | |
58 | } else if (event.keyCode === 9 && event.type == 'keydown') { |
|
58 | } else if (event.keyCode === 9 && event.type == 'keydown') { | |
59 | // Tab completion. |
|
59 | // Tab completion. | |
60 | var cur = editor.getCursor(); |
|
60 | var cur = editor.getCursor(); | |
61 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); |
|
61 | var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); | |
62 | if (pre_cursor === "") { |
|
62 | if (pre_cursor === "") { | |
63 | // Don't autocomplete if the part of the line before the cursor |
|
63 | // Don't autocomplete if the part of the line before the cursor | |
64 | // is empty. In this case, let CodeMirror handle indentation. |
|
64 | // is empty. In this case, let CodeMirror handle indentation. | |
65 | return false; |
|
65 | return false; | |
66 | } else { |
|
66 | } else { | |
67 | // Autocomplete the current line. |
|
67 | // Autocomplete the current line. | |
68 | event.stop(); |
|
68 | event.stop(); | |
69 | var line = editor.getLine(cur.line); |
|
69 | var line = editor.getLine(cur.line); | |
70 | this.is_completing = true; |
|
70 | this.is_completing = true; | |
71 | this.completion_cursor = cur; |
|
71 | this.completion_cursor = cur; | |
72 | IPython.notebook.complete_cell(this, line, cur.ch); |
|
72 | IPython.notebook.complete_cell(this, line, cur.ch); | |
73 | return true; |
|
73 | return true; | |
74 | } |
|
74 | } | |
75 | } else if (event.keyCode === 8 && event.type == 'keydown') { |
|
75 | } else if (event.keyCode === 8 && event.type == 'keydown') { | |
76 | // If backspace and the line ends with 4 spaces, remove them. |
|
76 | // If backspace and the line ends with 4 spaces, remove them. | |
77 | var cur = editor.getCursor(); |
|
77 | var cur = editor.getCursor(); | |
78 | var line = editor.getLine(cur.line); |
|
78 | var line = editor.getLine(cur.line); | |
79 | var ending = line.slice(-4); |
|
79 | var ending = line.slice(-4); | |
80 | if (ending === ' ') { |
|
80 | if (ending === ' ') { | |
81 | editor.replaceRange('', |
|
81 | editor.replaceRange('', | |
82 | {line: cur.line, ch: cur.ch-4}, |
|
82 | {line: cur.line, ch: cur.ch-4}, | |
83 | {line: cur.line, ch: cur.ch} |
|
83 | {line: cur.line, ch: cur.ch} | |
84 | ); |
|
84 | ); | |
85 | event.stop(); |
|
85 | event.stop(); | |
86 | return true; |
|
86 | return true; | |
87 | } else { |
|
87 | } else { | |
88 | return false; |
|
88 | return false; | |
89 | }; |
|
89 | }; | |
90 | } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey |
|
90 | } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey | |
91 | && event.type == 'keydown') { |
|
91 | && event.type == 'keydown') { | |
92 | // toggle line numbers with Ctrl-Shift-L |
|
92 | // toggle line numbers with Ctrl-Shift-L | |
93 | this.toggle_line_numbers(); |
|
93 | this.toggle_line_numbers(); | |
94 | } |
|
94 | } | |
95 | else { |
|
95 | else { | |
96 | // keypress/keyup also trigger on TAB press, and we don't want to |
|
96 | // keypress/keyup also trigger on TAB press, and we don't want to | |
97 | // use those to disable tab completion. |
|
97 | // use those to disable tab completion. | |
98 | if (this.is_completing && event.keyCode !== 9) { |
|
98 | if (this.is_completing && event.keyCode !== 9) { | |
99 | var ed_cur = editor.getCursor(); |
|
99 | var ed_cur = editor.getCursor(); | |
100 | var cc_cur = this.completion_cursor; |
|
100 | var cc_cur = this.completion_cursor; | |
101 | if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) { |
|
101 | if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) { | |
102 | this.is_completing = false; |
|
102 | this.is_completing = false; | |
103 | this.completion_cursor = null; |
|
103 | this.completion_cursor = null; | |
104 | }; |
|
104 | }; | |
105 | }; |
|
105 | }; | |
106 | return false; |
|
106 | return false; | |
107 | }; |
|
107 | }; | |
108 | }; |
|
108 | }; | |
109 |
|
109 | |||
110 |
|
110 | |||
111 | CodeCell.prototype.finish_completing = function (matched_text, matches) { |
|
111 | CodeCell.prototype.finish_completing = function (matched_text, matches) { | |
112 | // console.log("Got matches", matched_text, matches); |
|
112 | // console.log("Got matches", matched_text, matches); | |
113 | if (!this.is_completing || matches.length === 0) {return;} |
|
113 | if (!this.is_completing || matches.length === 0) {return;} | |
114 |
|
114 | |||
115 | var that = this; |
|
115 | var that = this; | |
116 | var cur = this.completion_cursor; |
|
116 | var cur = this.completion_cursor; | |
117 |
|
117 | |||
118 | var insert = function (selected_text) { |
|
118 | var insert = function (selected_text) { | |
119 | that.code_mirror.replaceRange( |
|
119 | that.code_mirror.replaceRange( | |
120 | selected_text, |
|
120 | selected_text, | |
121 | {line: cur.line, ch: (cur.ch-matched_text.length)}, |
|
121 | {line: cur.line, ch: (cur.ch-matched_text.length)}, | |
122 | {line: cur.line, ch: cur.ch} |
|
122 | {line: cur.line, ch: cur.ch} | |
123 | ); |
|
123 | ); | |
124 | }; |
|
124 | }; | |
125 |
|
125 | |||
126 | if (matches.length === 1) { |
|
126 | if (matches.length === 1) { | |
127 | insert(matches[0]); |
|
127 | insert(matches[0]); | |
128 | setTimeout(function(){that.code_mirror.focus();}, 50); |
|
128 | setTimeout(function(){that.code_mirror.focus();}, 50); | |
129 | return; |
|
129 | return; | |
130 | }; |
|
130 | }; | |
131 |
|
131 | |||
132 | var complete = $('<div/>').addClass('completions'); |
|
132 | var complete = $('<div/>').addClass('completions'); | |
133 | var select = $('<select/>').attr('multiple','true'); |
|
133 | var select = $('<select/>').attr('multiple','true'); | |
134 | for (var i=0; i<matches.length; ++i) { |
|
134 | for (var i=0; i<matches.length; ++i) { | |
135 | select.append($('<option/>').text(matches[i])); |
|
135 | select.append($('<option/>').text(matches[i])); | |
136 | } |
|
136 | } | |
137 | select.children().first().attr('selected','true'); |
|
137 | select.children().first().attr('selected','true'); | |
138 | select.attr('size',Math.min(10,matches.length)); |
|
138 | select.attr('size',Math.min(10,matches.length)); | |
139 | var pos = this.code_mirror.cursorCoords(); |
|
139 | var pos = this.code_mirror.cursorCoords(); | |
140 | complete.css('left',pos.x+'px'); |
|
140 | complete.css('left',pos.x+'px'); | |
141 | complete.css('top',pos.yBot+'px'); |
|
141 | complete.css('top',pos.yBot+'px'); | |
142 | complete.append(select); |
|
142 | complete.append(select); | |
143 |
|
143 | |||
144 | $('body').append(complete); |
|
144 | $('body').append(complete); | |
145 | var done = false; |
|
145 | var done = false; | |
146 |
|
146 | |||
147 | var close = function () { |
|
147 | var close = function () { | |
148 | if (done) return; |
|
148 | if (done) return; | |
149 | done = true; |
|
149 | done = true; | |
150 | complete.remove(); |
|
150 | complete.remove(); | |
151 | that.is_completing = false; |
|
151 | that.is_completing = false; | |
152 | that.completion_cursor = null; |
|
152 | that.completion_cursor = null; | |
153 | }; |
|
153 | }; | |
154 |
|
154 | |||
155 | var pick = function () { |
|
155 | var pick = function () { | |
156 | insert(select.val()[0]); |
|
156 | insert(select.val()[0]); | |
157 | close(); |
|
157 | close(); | |
158 | setTimeout(function(){that.code_mirror.focus();}, 50); |
|
158 | setTimeout(function(){that.code_mirror.focus();}, 50); | |
159 | }; |
|
159 | }; | |
160 |
|
160 | |||
161 | select.blur(close); |
|
161 | select.blur(close); | |
162 | select.keydown(function (event) { |
|
162 | select.keydown(function (event) { | |
163 | var code = event.which; |
|
163 | var code = event.which; | |
164 | if (code === 13 || code === 32) { |
|
164 | if (code === 13 || code === 32) { | |
165 | // Pressing SPACE or ENTER will cause a pick |
|
165 | // Pressing SPACE or ENTER will cause a pick | |
166 | event.stopPropagation(); |
|
166 | event.stopPropagation(); | |
167 | event.preventDefault(); |
|
167 | event.preventDefault(); | |
168 | pick(); |
|
168 | pick(); | |
169 | } else if (code === 38 || code === 40) { |
|
169 | } else if (code === 38 || code === 40) { | |
170 | // We don't want the document keydown handler to handle UP/DOWN, |
|
170 | // We don't want the document keydown handler to handle UP/DOWN, | |
171 | // but we want the default action. |
|
171 | // but we want the default action. | |
172 | event.stopPropagation(); |
|
172 | event.stopPropagation(); | |
173 | } else { |
|
173 | } else { | |
174 | // All other key presses exit completion. |
|
174 | // All other key presses exit completion. | |
175 | event.stopPropagation(); |
|
175 | event.stopPropagation(); | |
176 | event.preventDefault(); |
|
176 | event.preventDefault(); | |
177 | close(); |
|
177 | close(); | |
178 | that.code_mirror.focus(); |
|
178 | that.code_mirror.focus(); | |
179 | } |
|
179 | } | |
180 | }); |
|
180 | }); | |
181 | // Double click also causes a pick. |
|
181 | // Double click also causes a pick. | |
182 | select.dblclick(pick); |
|
182 | select.dblclick(pick); | |
183 | select.focus(); |
|
183 | select.focus(); | |
184 | }; |
|
184 | }; | |
185 |
|
185 | |||
186 | CodeCell.prototype.toggle_line_numbers = function () { |
|
186 | CodeCell.prototype.toggle_line_numbers = function () { | |
187 | if (this.code_mirror.getOption('lineNumbers') == false) { |
|
187 | if (this.code_mirror.getOption('lineNumbers') == false) { | |
188 | this.code_mirror.setOption('lineNumbers', true); |
|
188 | this.code_mirror.setOption('lineNumbers', true); | |
189 | } else { |
|
189 | } else { | |
190 | this.code_mirror.setOption('lineNumbers', false); |
|
190 | this.code_mirror.setOption('lineNumbers', false); | |
191 | } |
|
191 | } | |
192 | this.code_mirror.refresh() |
|
192 | this.code_mirror.refresh() | |
193 | }; |
|
193 | }; | |
194 |
|
194 | |||
195 | CodeCell.prototype.select = function () { |
|
195 | CodeCell.prototype.select = function () { | |
196 | IPython.Cell.prototype.select.apply(this); |
|
196 | IPython.Cell.prototype.select.apply(this); | |
197 | // Todo: this dance is needed because as of CodeMirror 2.12, focus is |
|
197 | // Todo: this dance is needed because as of CodeMirror 2.12, focus is | |
198 | // not causing the cursor to blink if the editor is empty initially. |
|
198 | // not causing the cursor to blink if the editor is empty initially. | |
199 | // While this seems to fix the issue, this should be fixed |
|
199 | // While this seems to fix the issue, this should be fixed | |
200 | // in CodeMirror proper. |
|
200 | // in CodeMirror proper. | |
201 | var s = this.code_mirror.getValue(); |
|
201 | var s = this.code_mirror.getValue(); | |
202 | this.code_mirror.focus(); |
|
202 | this.code_mirror.focus(); | |
203 | if (s === '') this.code_mirror.setValue(''); |
|
203 | if (s === '') this.code_mirror.setValue(''); | |
204 | }; |
|
204 | }; | |
205 |
|
205 | |||
206 |
|
206 | |||
207 | CodeCell.prototype.select_all = function () { |
|
207 | CodeCell.prototype.select_all = function () { | |
208 | var start = {line: 0, ch: 0}; |
|
208 | var start = {line: 0, ch: 0}; | |
209 | var nlines = this.code_mirror.lineCount(); |
|
209 | var nlines = this.code_mirror.lineCount(); | |
210 | var last_line = this.code_mirror.getLine(nlines-1); |
|
210 | var last_line = this.code_mirror.getLine(nlines-1); | |
211 | var end = {line: nlines-1, ch: last_line.length}; |
|
211 | var end = {line: nlines-1, ch: last_line.length}; | |
212 | this.code_mirror.setSelection(start, end); |
|
212 | this.code_mirror.setSelection(start, end); | |
213 | }; |
|
213 | }; | |
214 |
|
214 | |||
215 |
|
215 | |||
216 | CodeCell.prototype.append_output = function (json) { |
|
216 | CodeCell.prototype.append_output = function (json) { | |
217 | this.expand(); |
|
217 | this.expand(); | |
218 | if (json.output_type === 'pyout') { |
|
218 | if (json.output_type === 'pyout') { | |
219 | this.append_pyout(json); |
|
219 | this.append_pyout(json); | |
220 | } else if (json.output_type === 'pyerr') { |
|
220 | } else if (json.output_type === 'pyerr') { | |
221 | this.append_pyerr(json); |
|
221 | this.append_pyerr(json); | |
222 | } else if (json.output_type === 'display_data') { |
|
222 | } else if (json.output_type === 'display_data') { | |
223 | this.append_display_data(json); |
|
223 | this.append_display_data(json); | |
224 | } else if (json.output_type === 'stream') { |
|
224 | } else if (json.output_type === 'stream') { | |
225 | this.append_stream(json); |
|
225 | this.append_stream(json); | |
226 | }; |
|
226 | }; | |
227 | this.outputs.push(json); |
|
227 | this.outputs.push(json); | |
228 | }; |
|
228 | }; | |
229 |
|
229 | |||
230 |
|
230 | |||
231 | CodeCell.prototype.create_output_area = function () { |
|
231 | CodeCell.prototype.create_output_area = function () { | |
232 | var oa = $("<div/>").addClass("hbox output_area"); |
|
232 | var oa = $("<div/>").addClass("hbox output_area"); | |
233 | oa.append($('<div/>').addClass('prompt')); |
|
233 | oa.append($('<div/>').addClass('prompt')); | |
234 | return oa; |
|
234 | return oa; | |
235 | }; |
|
235 | }; | |
236 |
|
236 | |||
237 |
|
237 | |||
238 | CodeCell.prototype.append_pyout = function (json) { |
|
238 | CodeCell.prototype.append_pyout = function (json) { | |
239 | n = json.prompt_number || ' '; |
|
239 | n = json.prompt_number || ' '; | |
240 | var toinsert = this.create_output_area(); |
|
240 | var toinsert = this.create_output_area(); | |
241 | toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:'); |
|
241 | toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:'); | |
242 | this.append_mime_type(json, toinsert); |
|
242 | this.append_mime_type(json, toinsert); | |
243 | this.element.find('div.output').append(toinsert); |
|
243 | this.element.find('div.output').append(toinsert); | |
244 | // If we just output latex, typeset it. |
|
244 | // If we just output latex, typeset it. | |
245 | if (json.latex !== undefined) { |
|
245 | if (json.latex !== undefined) { | |
246 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
246 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
247 | }; |
|
247 | }; | |
248 | }; |
|
248 | }; | |
249 |
|
249 | |||
250 |
|
250 | |||
251 | CodeCell.prototype.append_pyerr = function (json) { |
|
251 | CodeCell.prototype.append_pyerr = function (json) { | |
252 | var tb = json.traceback; |
|
252 | var tb = json.traceback; | |
253 | if (tb !== undefined && tb.length > 0) { |
|
253 | if (tb !== undefined && tb.length > 0) { | |
254 | var s = ''; |
|
254 | var s = ''; | |
255 | var len = tb.length; |
|
255 | var len = tb.length; | |
256 | for (var i=0; i<len; i++) { |
|
256 | for (var i=0; i<len; i++) { | |
257 | s = s + tb[i] + '\n'; |
|
257 | s = s + tb[i] + '\n'; | |
258 | } |
|
258 | } | |
259 | s = s + '\n'; |
|
259 | s = s + '\n'; | |
260 | var toinsert = this.create_output_area(); |
|
260 | var toinsert = this.create_output_area(); | |
261 | this.append_text(s, toinsert); |
|
261 | this.append_text(s, toinsert); | |
262 | this.element.find('div.output').append(toinsert); |
|
262 | this.element.find('div.output').append(toinsert); | |
263 | }; |
|
263 | }; | |
264 | }; |
|
264 | }; | |
265 |
|
265 | |||
266 |
|
266 | |||
267 | CodeCell.prototype.append_stream = function (json) { |
|
267 | CodeCell.prototype.append_stream = function (json) { | |
268 | // temporary fix: if stream undefined (json file written prior to this patch), |
|
268 | // temporary fix: if stream undefined (json file written prior to this patch), | |
269 | // default to most likely stdout: |
|
269 | // default to most likely stdout: | |
270 | if (json.stream == undefined){ |
|
270 | if (json.stream == undefined){ | |
271 | json.stream = 'stdout'; |
|
271 | json.stream = 'stdout'; | |
272 | } |
|
272 | } | |
273 | var subclass = "output_"+json.stream; |
|
273 | var subclass = "output_"+json.stream; | |
274 | if (this.outputs.length > 0){ |
|
274 | if (this.outputs.length > 0){ | |
275 | // have at least one output to consider |
|
275 | // have at least one output to consider | |
276 | var last = this.outputs[this.outputs.length-1]; |
|
276 | var last = this.outputs[this.outputs.length-1]; | |
277 | if (last.output_type == 'stream' && json.stream == last.stream){ |
|
277 | if (last.output_type == 'stream' && json.stream == last.stream){ | |
278 | // latest output was in the same stream, |
|
278 | // latest output was in the same stream, | |
279 | // so append directly into its pre tag |
|
279 | // so append directly into its pre tag | |
280 | this.element.find('div.'+subclass).last().find('pre').append(json.text); |
|
280 | this.element.find('div.'+subclass).last().find('pre').append(json.text); | |
281 | return; |
|
281 | return; | |
282 | } |
|
282 | } | |
283 | } |
|
283 | } | |
284 |
|
284 | |||
285 | // If we got here, attach a new div |
|
285 | // If we got here, attach a new div | |
286 | var toinsert = this.create_output_area(); |
|
286 | var toinsert = this.create_output_area(); | |
287 | this.append_text(json.text, toinsert, "output_stream "+subclass); |
|
287 | this.append_text(json.text, toinsert, "output_stream "+subclass); | |
288 | this.element.find('div.output').append(toinsert); |
|
288 | this.element.find('div.output').append(toinsert); | |
289 | }; |
|
289 | }; | |
290 |
|
290 | |||
291 |
|
291 | |||
292 | CodeCell.prototype.append_display_data = function (json) { |
|
292 | CodeCell.prototype.append_display_data = function (json) { | |
293 | var toinsert = this.create_output_area(); |
|
293 | var toinsert = this.create_output_area(); | |
294 | this.append_mime_type(json, toinsert) |
|
294 | this.append_mime_type(json, toinsert) | |
295 | this.element.find('div.output').append(toinsert); |
|
295 | this.element.find('div.output').append(toinsert); | |
296 | // If we just output latex, typeset it. |
|
296 | // If we just output latex, typeset it. | |
297 | if (json.latex !== undefined) { |
|
297 | if (json.latex !== undefined) { | |
298 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
298 | MathJax.Hub.Queue(["Typeset",MathJax.Hub]); | |
299 | }; |
|
299 | }; | |
300 | }; |
|
300 | }; | |
301 |
|
301 | |||
302 |
|
302 | |||
303 | CodeCell.prototype.append_mime_type = function (json, element) { |
|
303 | CodeCell.prototype.append_mime_type = function (json, element) { | |
304 | if (json.html !== undefined) { |
|
304 | if (json.html !== undefined) { | |
305 | this.append_html(json.html, element); |
|
305 | this.append_html(json.html, element); | |
306 | } else if (json.latex !== undefined) { |
|
306 | } else if (json.latex !== undefined) { | |
307 | this.append_latex(json.latex, element); |
|
307 | this.append_latex(json.latex, element); | |
308 | } else if (json.svg !== undefined) { |
|
308 | } else if (json.svg !== undefined) { | |
309 | this.append_svg(json.svg, element); |
|
309 | this.append_svg(json.svg, element); | |
310 | } else if (json.png !== undefined) { |
|
310 | } else if (json.png !== undefined) { | |
311 | this.append_png(json.png, element); |
|
311 | this.append_png(json.png, element); | |
312 | } else if (json.jpeg !== undefined) { |
|
312 | } else if (json.jpeg !== undefined) { | |
313 | this.append_jpeg(json.jpeg, element); |
|
313 | this.append_jpeg(json.jpeg, element); | |
314 | } else if (json.text !== undefined) { |
|
314 | } else if (json.text !== undefined) { | |
315 | this.append_text(json.text, element); |
|
315 | this.append_text(json.text, element); | |
316 | }; |
|
316 | }; | |
317 | }; |
|
317 | }; | |
318 |
|
318 | |||
319 |
|
319 | |||
320 | CodeCell.prototype.append_html = function (html, element) { |
|
320 | CodeCell.prototype.append_html = function (html, element) { | |
321 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html"); |
|
321 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html"); | |
322 | toinsert.append(html); |
|
322 | toinsert.append(html); | |
323 | element.append(toinsert); |
|
323 | element.append(toinsert); | |
324 | } |
|
324 | } | |
325 |
|
325 | |||
326 |
|
326 | |||
327 | CodeCell.prototype.append_text = function (data, element, extra_class) { |
|
327 | CodeCell.prototype.append_text = function (data, element, extra_class) { | |
328 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text"); |
|
328 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text"); | |
329 | if (extra_class){ |
|
329 | if (extra_class){ | |
330 | toinsert.addClass(extra_class); |
|
330 | toinsert.addClass(extra_class); | |
331 | } |
|
331 | } | |
332 | toinsert.append($("<pre/>").html(data)); |
|
332 | toinsert.append($("<pre/>").html(data)); | |
333 | element.append(toinsert); |
|
333 | element.append(toinsert); | |
334 | }; |
|
334 | }; | |
335 |
|
335 | |||
336 |
|
336 | |||
337 | CodeCell.prototype.append_svg = function (svg, element) { |
|
337 | CodeCell.prototype.append_svg = function (svg, element) { | |
338 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg"); |
|
338 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg"); | |
339 | toinsert.append(svg); |
|
339 | toinsert.append(svg); | |
340 | element.append(toinsert); |
|
340 | element.append(toinsert); | |
341 | }; |
|
341 | }; | |
342 |
|
342 | |||
343 |
|
343 | |||
344 | CodeCell.prototype.append_png = function (png, element) { |
|
344 | CodeCell.prototype.append_png = function (png, element) { | |
345 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png"); |
|
345 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png"); | |
346 | toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png)); |
|
346 | toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png)); | |
347 | element.append(toinsert); |
|
347 | element.append(toinsert); | |
348 | }; |
|
348 | }; | |
349 |
|
349 | |||
350 |
|
350 | |||
351 | CodeCell.prototype.append_jpeg = function (jpeg, element) { |
|
351 | CodeCell.prototype.append_jpeg = function (jpeg, element) { | |
352 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg"); |
|
352 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg"); | |
353 | toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg)); |
|
353 | toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg)); | |
354 | element.append(toinsert); |
|
354 | element.append(toinsert); | |
355 | }; |
|
355 | }; | |
356 |
|
356 | |||
357 |
|
357 | |||
358 | CodeCell.prototype.append_latex = function (latex, element) { |
|
358 | CodeCell.prototype.append_latex = function (latex, element) { | |
359 | // This method cannot do the typesetting because the latex first has to |
|
359 | // This method cannot do the typesetting because the latex first has to | |
360 | // be on the page. |
|
360 | // be on the page. | |
361 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex"); |
|
361 | var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex"); | |
362 | toinsert.append(latex); |
|
362 | toinsert.append(latex); | |
363 | element.append(toinsert); |
|
363 | element.append(toinsert); | |
364 | } |
|
364 | } | |
365 |
|
365 | |||
366 |
|
366 | |||
367 | CodeCell.prototype.clear_output = function () { |
|
367 | CodeCell.prototype.clear_output = function (stdout, stderr, other) { | |
368 |
this.element.find("div.output") |
|
368 | var output_div = this.element.find("div.output"); | |
369 | this.outputs = []; |
|
369 | if (stdout && stderr && other){ | |
|
370 | // clear all, no need for logic | |||
|
371 | output_div.html(""); | |||
|
372 | this.outputs = []; | |||
|
373 | return; | |||
|
374 | } | |||
|
375 | // remove html output | |||
|
376 | // each output_subarea that has an identifying class is in an output_area | |||
|
377 | // which is the element to be removed. | |||
|
378 | if (stdout){ | |||
|
379 | output_div.find("div.output_stdout").parent().remove(); | |||
|
380 | } | |||
|
381 | if (stderr){ | |||
|
382 | output_div.find("div.output_stderr").parent().remove(); | |||
|
383 | } | |||
|
384 | if (other){ | |||
|
385 | output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove(); | |||
|
386 | } | |||
|
387 | ||||
|
388 | // remove cleared outputs from JSON list: | |||
|
389 | for (var i = this.outputs.length - 1; i >= 0; i--){ | |||
|
390 | var out = this.outputs[i]; | |||
|
391 | var output_type = out.output_type; | |||
|
392 | if (output_type == "display_data" && other){ | |||
|
393 | this.outputs.splice(i,1); | |||
|
394 | }else if (output_type == "stream"){ | |||
|
395 | if (stdout && out.stream == "stdout"){ | |||
|
396 | this.outputs.splice(i,1); | |||
|
397 | }else if (stderr && out.stream == "stderr"){ | |||
|
398 | this.outputs.splice(i,1); | |||
|
399 | } | |||
|
400 | } | |||
|
401 | } | |||
370 | }; |
|
402 | }; | |
371 |
|
403 | |||
372 |
|
404 | |||
373 | CodeCell.prototype.clear_input = function () { |
|
405 | CodeCell.prototype.clear_input = function () { | |
374 | this.code_mirror.setValue(''); |
|
406 | this.code_mirror.setValue(''); | |
375 | }; |
|
407 | }; | |
376 |
|
408 | |||
377 |
|
409 | |||
378 | CodeCell.prototype.collapse = function () { |
|
410 | CodeCell.prototype.collapse = function () { | |
379 | if (!this.collapsed) { |
|
411 | if (!this.collapsed) { | |
380 | this.element.find('div.output').hide(); |
|
412 | this.element.find('div.output').hide(); | |
381 | this.collapsed = true; |
|
413 | this.collapsed = true; | |
382 | }; |
|
414 | }; | |
383 | }; |
|
415 | }; | |
384 |
|
416 | |||
385 |
|
417 | |||
386 | CodeCell.prototype.expand = function () { |
|
418 | CodeCell.prototype.expand = function () { | |
387 | if (this.collapsed) { |
|
419 | if (this.collapsed) { | |
388 | this.element.find('div.output').show(); |
|
420 | this.element.find('div.output').show(); | |
389 | this.collapsed = false; |
|
421 | this.collapsed = false; | |
390 | }; |
|
422 | }; | |
391 | }; |
|
423 | }; | |
392 |
|
424 | |||
393 |
|
425 | |||
394 | CodeCell.prototype.toggle_output = function () { |
|
426 | CodeCell.prototype.toggle_output = function () { | |
395 | if (this.collapsed) { |
|
427 | if (this.collapsed) { | |
396 | this.expand(); |
|
428 | this.expand(); | |
397 | } else { |
|
429 | } else { | |
398 | this.collapse(); |
|
430 | this.collapse(); | |
399 | }; |
|
431 | }; | |
400 | }; |
|
432 | }; | |
401 |
|
433 | |||
402 | CodeCell.prototype.set_input_prompt = function (number) { |
|
434 | CodeCell.prototype.set_input_prompt = function (number) { | |
403 | var n = number || ' '; |
|
435 | var n = number || ' '; | |
404 | this.input_prompt_number = n |
|
436 | this.input_prompt_number = n | |
405 | this.element.find('div.input_prompt').html('In [' + n + ']:'); |
|
437 | this.element.find('div.input_prompt').html('In [' + n + ']:'); | |
406 | }; |
|
438 | }; | |
407 |
|
439 | |||
408 |
|
440 | |||
409 | CodeCell.prototype.get_code = function () { |
|
441 | CodeCell.prototype.get_code = function () { | |
410 | return this.code_mirror.getValue(); |
|
442 | return this.code_mirror.getValue(); | |
411 | }; |
|
443 | }; | |
412 |
|
444 | |||
413 |
|
445 | |||
414 | CodeCell.prototype.set_code = function (code) { |
|
446 | CodeCell.prototype.set_code = function (code) { | |
415 | return this.code_mirror.setValue(code); |
|
447 | return this.code_mirror.setValue(code); | |
416 | }; |
|
448 | }; | |
417 |
|
449 | |||
418 |
|
450 | |||
419 | CodeCell.prototype.at_top = function () { |
|
451 | CodeCell.prototype.at_top = function () { | |
420 | var cursor = this.code_mirror.getCursor(); |
|
452 | var cursor = this.code_mirror.getCursor(); | |
421 | if (cursor.line === 0) { |
|
453 | if (cursor.line === 0) { | |
422 | return true; |
|
454 | return true; | |
423 | } else { |
|
455 | } else { | |
424 | return false; |
|
456 | return false; | |
425 | } |
|
457 | } | |
426 | }; |
|
458 | }; | |
427 |
|
459 | |||
428 |
|
460 | |||
429 | CodeCell.prototype.at_bottom = function () { |
|
461 | CodeCell.prototype.at_bottom = function () { | |
430 | var cursor = this.code_mirror.getCursor(); |
|
462 | var cursor = this.code_mirror.getCursor(); | |
431 | if (cursor.line === (this.code_mirror.lineCount()-1)) { |
|
463 | if (cursor.line === (this.code_mirror.lineCount()-1)) { | |
432 | return true; |
|
464 | return true; | |
433 | } else { |
|
465 | } else { | |
434 | return false; |
|
466 | return false; | |
435 | } |
|
467 | } | |
436 | }; |
|
468 | }; | |
437 |
|
469 | |||
438 |
|
470 | |||
439 | CodeCell.prototype.fromJSON = function (data) { |
|
471 | CodeCell.prototype.fromJSON = function (data) { | |
440 | console.log('Import from JSON:', data); |
|
472 | console.log('Import from JSON:', data); | |
441 | if (data.cell_type === 'code') { |
|
473 | if (data.cell_type === 'code') { | |
442 | if (data.input !== undefined) { |
|
474 | if (data.input !== undefined) { | |
443 | this.set_code(data.input); |
|
475 | this.set_code(data.input); | |
444 | } |
|
476 | } | |
445 | if (data.prompt_number !== undefined) { |
|
477 | if (data.prompt_number !== undefined) { | |
446 | this.set_input_prompt(data.prompt_number); |
|
478 | this.set_input_prompt(data.prompt_number); | |
447 | } else { |
|
479 | } else { | |
448 | this.set_input_prompt(); |
|
480 | this.set_input_prompt(); | |
449 | }; |
|
481 | }; | |
450 | var len = data.outputs.length; |
|
482 | var len = data.outputs.length; | |
451 | for (var i=0; i<len; i++) { |
|
483 | for (var i=0; i<len; i++) { | |
452 | this.append_output(data.outputs[i]); |
|
484 | this.append_output(data.outputs[i]); | |
453 | }; |
|
485 | }; | |
454 | if (data.collapsed !== undefined) { |
|
486 | if (data.collapsed !== undefined) { | |
455 | if (data.collapsed) { |
|
487 | if (data.collapsed) { | |
456 | this.collapse(); |
|
488 | this.collapse(); | |
457 | }; |
|
489 | }; | |
458 | }; |
|
490 | }; | |
459 | }; |
|
491 | }; | |
460 | }; |
|
492 | }; | |
461 |
|
493 | |||
462 |
|
494 | |||
463 | CodeCell.prototype.toJSON = function () { |
|
495 | CodeCell.prototype.toJSON = function () { | |
464 | var data = {}; |
|
496 | var data = {}; | |
465 | data.input = this.get_code(); |
|
497 | data.input = this.get_code(); | |
466 | data.cell_type = 'code'; |
|
498 | data.cell_type = 'code'; | |
467 | if (this.input_prompt_number !== ' ') { |
|
499 | if (this.input_prompt_number !== ' ') { | |
468 | data.prompt_number = this.input_prompt_number |
|
500 | data.prompt_number = this.input_prompt_number | |
469 | }; |
|
501 | }; | |
470 | var outputs = []; |
|
502 | var outputs = []; | |
471 | var len = this.outputs.length; |
|
503 | var len = this.outputs.length; | |
472 | for (var i=0; i<len; i++) { |
|
504 | for (var i=0; i<len; i++) { | |
473 | outputs[i] = this.outputs[i]; |
|
505 | outputs[i] = this.outputs[i]; | |
474 | }; |
|
506 | }; | |
475 | data.outputs = outputs; |
|
507 | data.outputs = outputs; | |
476 | data.language = 'python'; |
|
508 | data.language = 'python'; | |
477 | data.collapsed = this.collapsed; |
|
509 | data.collapsed = this.collapsed; | |
478 | // console.log('Export to JSON:',data); |
|
510 | // console.log('Export to JSON:',data); | |
479 | return data; |
|
511 | return data; | |
480 | }; |
|
512 | }; | |
481 |
|
513 | |||
482 |
|
514 | |||
483 | IPython.CodeCell = CodeCell; |
|
515 | IPython.CodeCell = CodeCell; | |
484 |
|
516 | |||
485 | return IPython; |
|
517 | return IPython; | |
486 | }(IPython)); |
|
518 | }(IPython)); |
@@ -1,995 +1,997 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2008-2011 The IPython Development Team |
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |
3 | // |
|
3 | // | |
4 | // Distributed under the terms of the BSD License. The full license is in |
|
4 | // Distributed under the terms of the BSD License. The full license is in | |
5 | // the file COPYING, distributed as part of this software. |
|
5 | // the file COPYING, distributed as part of this software. | |
6 | //---------------------------------------------------------------------------- |
|
6 | //---------------------------------------------------------------------------- | |
7 |
|
7 | |||
8 | //============================================================================ |
|
8 | //============================================================================ | |
9 | // Notebook |
|
9 | // Notebook | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
13 |
|
13 | |||
14 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
15 |
|
15 | |||
16 | var Notebook = function (selector) { |
|
16 | var Notebook = function (selector) { | |
17 | this.element = $(selector); |
|
17 | this.element = $(selector); | |
18 | this.element.scroll(); |
|
18 | this.element.scroll(); | |
19 | this.element.data("notebook", this); |
|
19 | this.element.data("notebook", this); | |
20 | this.next_prompt_number = 1; |
|
20 | this.next_prompt_number = 1; | |
21 | this.kernel = null; |
|
21 | this.kernel = null; | |
22 | this.dirty = false; |
|
22 | this.dirty = false; | |
23 | this.msg_cell_map = {}; |
|
23 | this.msg_cell_map = {}; | |
24 | this.metadata = {}; |
|
24 | this.metadata = {}; | |
25 | this.control_key_active = false; |
|
25 | this.control_key_active = false; | |
26 | this.style(); |
|
26 | this.style(); | |
27 | this.create_elements(); |
|
27 | this.create_elements(); | |
28 | this.bind_events(); |
|
28 | this.bind_events(); | |
29 | }; |
|
29 | }; | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | Notebook.prototype.style = function () { |
|
32 | Notebook.prototype.style = function () { | |
33 | $('div#notebook').addClass('border-box-sizing'); |
|
33 | $('div#notebook').addClass('border-box-sizing'); | |
34 | }; |
|
34 | }; | |
35 |
|
35 | |||
36 |
|
36 | |||
37 | Notebook.prototype.create_elements = function () { |
|
37 | Notebook.prototype.create_elements = function () { | |
38 | // We add this end_space div to the end of the notebook div to: |
|
38 | // We add this end_space div to the end of the notebook div to: | |
39 | // i) provide a margin between the last cell and the end of the notebook |
|
39 | // i) provide a margin between the last cell and the end of the notebook | |
40 | // ii) to prevent the div from scrolling up when the last cell is being |
|
40 | // ii) to prevent the div from scrolling up when the last cell is being | |
41 | // edited, but is too low on the page, which browsers will do automatically. |
|
41 | // edited, but is too low on the page, which browsers will do automatically. | |
42 | var that = this; |
|
42 | var that = this; | |
43 | var end_space = $('<div class="end_space"></div>').height(150); |
|
43 | var end_space = $('<div class="end_space"></div>').height(150); | |
44 | end_space.dblclick(function (e) { |
|
44 | end_space.dblclick(function (e) { | |
45 | var ncells = that.ncells(); |
|
45 | var ncells = that.ncells(); | |
46 | that.insert_code_cell_below(ncells-1); |
|
46 | that.insert_code_cell_below(ncells-1); | |
47 | }); |
|
47 | }); | |
48 | this.element.append(end_space); |
|
48 | this.element.append(end_space); | |
49 | $('div#notebook').addClass('border-box-sizing'); |
|
49 | $('div#notebook').addClass('border-box-sizing'); | |
50 | }; |
|
50 | }; | |
51 |
|
51 | |||
52 |
|
52 | |||
53 | Notebook.prototype.bind_events = function () { |
|
53 | Notebook.prototype.bind_events = function () { | |
54 | var that = this; |
|
54 | var that = this; | |
55 | $(document).keydown(function (event) { |
|
55 | $(document).keydown(function (event) { | |
56 | // console.log(event); |
|
56 | // console.log(event); | |
57 | if (event.which === 38) { |
|
57 | if (event.which === 38) { | |
58 | var cell = that.selected_cell(); |
|
58 | var cell = that.selected_cell(); | |
59 | if (cell.at_top()) { |
|
59 | if (cell.at_top()) { | |
60 | event.preventDefault(); |
|
60 | event.preventDefault(); | |
61 | that.select_prev(); |
|
61 | that.select_prev(); | |
62 | }; |
|
62 | }; | |
63 | } else if (event.which === 40) { |
|
63 | } else if (event.which === 40) { | |
64 | var cell = that.selected_cell(); |
|
64 | var cell = that.selected_cell(); | |
65 | if (cell.at_bottom()) { |
|
65 | if (cell.at_bottom()) { | |
66 | event.preventDefault(); |
|
66 | event.preventDefault(); | |
67 | that.select_next(); |
|
67 | that.select_next(); | |
68 | }; |
|
68 | }; | |
69 | } else if (event.which === 13 && event.shiftKey) { |
|
69 | } else if (event.which === 13 && event.shiftKey) { | |
70 | that.execute_selected_cell(); |
|
70 | that.execute_selected_cell(); | |
71 | return false; |
|
71 | return false; | |
72 | } else if (event.which === 13 && event.ctrlKey) { |
|
72 | } else if (event.which === 13 && event.ctrlKey) { | |
73 | that.execute_selected_cell({terminal:true}); |
|
73 | that.execute_selected_cell({terminal:true}); | |
74 | return false; |
|
74 | return false; | |
75 | } else if (event.which === 77 && event.ctrlKey) { |
|
75 | } else if (event.which === 77 && event.ctrlKey) { | |
76 | that.control_key_active = true; |
|
76 | that.control_key_active = true; | |
77 | return false; |
|
77 | return false; | |
78 | } else if (event.which === 68 && that.control_key_active) { |
|
78 | } else if (event.which === 68 && that.control_key_active) { | |
79 | // Delete selected cell = d |
|
79 | // Delete selected cell = d | |
80 | that.delete_cell(); |
|
80 | that.delete_cell(); | |
81 | that.control_key_active = false; |
|
81 | that.control_key_active = false; | |
82 | return false; |
|
82 | return false; | |
83 | } else if (event.which === 65 && that.control_key_active) { |
|
83 | } else if (event.which === 65 && that.control_key_active) { | |
84 | // Insert code cell above selected = a |
|
84 | // Insert code cell above selected = a | |
85 | that.insert_code_cell_above(); |
|
85 | that.insert_code_cell_above(); | |
86 | that.control_key_active = false; |
|
86 | that.control_key_active = false; | |
87 | return false; |
|
87 | return false; | |
88 | } else if (event.which === 66 && that.control_key_active) { |
|
88 | } else if (event.which === 66 && that.control_key_active) { | |
89 | // Insert code cell below selected = b |
|
89 | // Insert code cell below selected = b | |
90 | that.insert_code_cell_below(); |
|
90 | that.insert_code_cell_below(); | |
91 | that.control_key_active = false; |
|
91 | that.control_key_active = false; | |
92 | return false; |
|
92 | return false; | |
93 | } else if (event.which === 67 && that.control_key_active) { |
|
93 | } else if (event.which === 67 && that.control_key_active) { | |
94 | // To code = c |
|
94 | // To code = c | |
95 | that.to_code(); |
|
95 | that.to_code(); | |
96 | that.control_key_active = false; |
|
96 | that.control_key_active = false; | |
97 | return false; |
|
97 | return false; | |
98 | } else if (event.which === 77 && that.control_key_active) { |
|
98 | } else if (event.which === 77 && that.control_key_active) { | |
99 | // To markdown = m |
|
99 | // To markdown = m | |
100 | that.to_markdown(); |
|
100 | that.to_markdown(); | |
101 | that.control_key_active = false; |
|
101 | that.control_key_active = false; | |
102 | return false; |
|
102 | return false; | |
103 | } else if (event.which === 84 && that.control_key_active) { |
|
103 | } else if (event.which === 84 && that.control_key_active) { | |
104 | // Toggle output = t |
|
104 | // Toggle output = t | |
105 | that.toggle_output(); |
|
105 | that.toggle_output(); | |
106 | that.control_key_active = false; |
|
106 | that.control_key_active = false; | |
107 | return false; |
|
107 | return false; | |
108 | } else if (event.which === 83 && that.control_key_active) { |
|
108 | } else if (event.which === 83 && that.control_key_active) { | |
109 | // Save notebook = s |
|
109 | // Save notebook = s | |
110 | IPython.save_widget.save_notebook(); |
|
110 | IPython.save_widget.save_notebook(); | |
111 | that.control_key_active = false; |
|
111 | that.control_key_active = false; | |
112 | return false; |
|
112 | return false; | |
113 | } else if (event.which === 74 && that.control_key_active) { |
|
113 | } else if (event.which === 74 && that.control_key_active) { | |
114 | // Move cell down = j |
|
114 | // Move cell down = j | |
115 | that.move_cell_down(); |
|
115 | that.move_cell_down(); | |
116 | that.control_key_active = false; |
|
116 | that.control_key_active = false; | |
117 | return false; |
|
117 | return false; | |
118 | } else if (event.which === 75 && that.control_key_active) { |
|
118 | } else if (event.which === 75 && that.control_key_active) { | |
119 | // Move cell up = k |
|
119 | // Move cell up = k | |
120 | that.move_cell_up(); |
|
120 | that.move_cell_up(); | |
121 | that.control_key_active = false; |
|
121 | that.control_key_active = false; | |
122 | return false; |
|
122 | return false; | |
123 | } else if (event.which === 80 && that.control_key_active) { |
|
123 | } else if (event.which === 80 && that.control_key_active) { | |
124 | // Select previous = p |
|
124 | // Select previous = p | |
125 | that.select_prev(); |
|
125 | that.select_prev(); | |
126 | that.control_key_active = false; |
|
126 | that.control_key_active = false; | |
127 | return false; |
|
127 | return false; | |
128 | } else if (event.which === 78 && that.control_key_active) { |
|
128 | } else if (event.which === 78 && that.control_key_active) { | |
129 | // Select next = n |
|
129 | // Select next = n | |
130 | that.select_next(); |
|
130 | that.select_next(); | |
131 | that.control_key_active = false; |
|
131 | that.control_key_active = false; | |
132 | return false; |
|
132 | return false; | |
133 | } else if (event.which === 76 && that.control_key_active) { |
|
133 | } else if (event.which === 76 && that.control_key_active) { | |
134 | // Toggle line numbers = l |
|
134 | // Toggle line numbers = l | |
135 | that.cell_toggle_line_numbers(); |
|
135 | that.cell_toggle_line_numbers(); | |
136 | that.control_key_active = false; |
|
136 | that.control_key_active = false; | |
137 | return false; |
|
137 | return false; | |
138 | } else if (event.which === 73 && that.control_key_active) { |
|
138 | } else if (event.which === 73 && that.control_key_active) { | |
139 | // Interrupt kernel = i |
|
139 | // Interrupt kernel = i | |
140 | IPython.notebook.kernel.interrupt(); |
|
140 | IPython.notebook.kernel.interrupt(); | |
141 | that.control_key_active = false; |
|
141 | that.control_key_active = false; | |
142 | return false; |
|
142 | return false; | |
143 | } else if (event.which === 190 && that.control_key_active) { |
|
143 | } else if (event.which === 190 && that.control_key_active) { | |
144 | // Restart kernel = . # matches qt console |
|
144 | // Restart kernel = . # matches qt console | |
145 | IPython.notebook.restart_kernel(); |
|
145 | IPython.notebook.restart_kernel(); | |
146 | that.control_key_active = false; |
|
146 | that.control_key_active = false; | |
147 | return false; |
|
147 | return false; | |
148 | } else if (event.which === 72 && that.control_key_active) { |
|
148 | } else if (event.which === 72 && that.control_key_active) { | |
149 | // Show keyboard shortcuts = h |
|
149 | // Show keyboard shortcuts = h | |
150 | that.toggle_keyboard_shortcuts(); |
|
150 | that.toggle_keyboard_shortcuts(); | |
151 | that.control_key_active = false; |
|
151 | that.control_key_active = false; | |
152 | return false; |
|
152 | return false; | |
153 | } else if (that.control_key_active) { |
|
153 | } else if (that.control_key_active) { | |
154 | that.control_key_active = false; |
|
154 | that.control_key_active = false; | |
155 | return true; |
|
155 | return true; | |
156 | }; |
|
156 | }; | |
157 | }); |
|
157 | }); | |
158 |
|
158 | |||
159 | this.element.bind('collapse_pager', function () { |
|
159 | this.element.bind('collapse_pager', function () { | |
160 | var app_height = $('div#main_app').height(); // content height |
|
160 | var app_height = $('div#main_app').height(); // content height | |
161 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
161 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
162 | var new_height = app_height - splitter_height; |
|
162 | var new_height = app_height - splitter_height; | |
163 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
163 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
164 | }); |
|
164 | }); | |
165 |
|
165 | |||
166 | this.element.bind('expand_pager', function () { |
|
166 | this.element.bind('expand_pager', function () { | |
167 | var app_height = $('div#main_app').height(); // content height |
|
167 | var app_height = $('div#main_app').height(); // content height | |
168 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
168 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
169 | var pager_height = $('div#pager').outerHeight(true); |
|
169 | var pager_height = $('div#pager').outerHeight(true); | |
170 | var new_height = app_height - pager_height - splitter_height; |
|
170 | var new_height = app_height - pager_height - splitter_height; | |
171 | that.element.animate({height : new_height + 'px'}, 'fast'); |
|
171 | that.element.animate({height : new_height + 'px'}, 'fast'); | |
172 | }); |
|
172 | }); | |
173 |
|
173 | |||
174 | this.element.bind('collapse_left_panel', function () { |
|
174 | this.element.bind('collapse_left_panel', function () { | |
175 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
175 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
176 | var new_margin = splitter_width; |
|
176 | var new_margin = splitter_width; | |
177 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
177 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
178 | }); |
|
178 | }); | |
179 |
|
179 | |||
180 | this.element.bind('expand_left_panel', function () { |
|
180 | this.element.bind('expand_left_panel', function () { | |
181 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); |
|
181 | var splitter_width = $('div#left_panel_splitter').outerWidth(true); | |
182 | var left_panel_width = IPython.left_panel.width; |
|
182 | var left_panel_width = IPython.left_panel.width; | |
183 | var new_margin = splitter_width + left_panel_width; |
|
183 | var new_margin = splitter_width + left_panel_width; | |
184 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); |
|
184 | $('div#notebook_panel').animate({marginLeft : new_margin + 'px'}, 'fast'); | |
185 | }); |
|
185 | }); | |
186 |
|
186 | |||
187 | $(window).bind('beforeunload', function () { |
|
187 | $(window).bind('beforeunload', function () { | |
188 | var kill_kernel = $('#kill_kernel').prop('checked'); |
|
188 | var kill_kernel = $('#kill_kernel').prop('checked'); | |
189 | if (kill_kernel) { |
|
189 | if (kill_kernel) { | |
190 | that.kernel.kill(); |
|
190 | that.kernel.kill(); | |
191 | } |
|
191 | } | |
192 | if (that.dirty) { |
|
192 | if (that.dirty) { | |
193 | return "You have unsaved changes that will be lost if you leave this page."; |
|
193 | return "You have unsaved changes that will be lost if you leave this page."; | |
194 | }; |
|
194 | }; | |
195 | }); |
|
195 | }); | |
196 | }; |
|
196 | }; | |
197 |
|
197 | |||
198 |
|
198 | |||
199 | Notebook.prototype.toggle_keyboard_shortcuts = function () { |
|
199 | Notebook.prototype.toggle_keyboard_shortcuts = function () { | |
200 | // toggles display of keyboard shortcut dialog |
|
200 | // toggles display of keyboard shortcut dialog | |
201 | var that = this; |
|
201 | var that = this; | |
202 | if ( this.shortcut_dialog ){ |
|
202 | if ( this.shortcut_dialog ){ | |
203 | // if dialog is already shown, close it |
|
203 | // if dialog is already shown, close it | |
204 | this.shortcut_dialog.dialog("close"); |
|
204 | this.shortcut_dialog.dialog("close"); | |
205 | this.shortcut_dialog = null; |
|
205 | this.shortcut_dialog = null; | |
206 | return; |
|
206 | return; | |
207 | } |
|
207 | } | |
208 | var dialog = $('<div/>'); |
|
208 | var dialog = $('<div/>'); | |
209 | this.shortcut_dialog = dialog; |
|
209 | this.shortcut_dialog = dialog; | |
210 | var shortcuts = [ |
|
210 | var shortcuts = [ | |
211 | {key: 'Shift-Enter', help: 'run cell'}, |
|
211 | {key: 'Shift-Enter', help: 'run cell'}, | |
212 | {key: 'Ctrl-Enter', help: 'run cell in-place'}, |
|
212 | {key: 'Ctrl-Enter', help: 'run cell in-place'}, | |
213 | {key: 'Ctrl-m d', help: 'delete cell'}, |
|
213 | {key: 'Ctrl-m d', help: 'delete cell'}, | |
214 | {key: 'Ctrl-m a', help: 'insert cell above'}, |
|
214 | {key: 'Ctrl-m a', help: 'insert cell above'}, | |
215 | {key: 'Ctrl-m b', help: 'insert cell below'}, |
|
215 | {key: 'Ctrl-m b', help: 'insert cell below'}, | |
216 | {key: 'Ctrl-m t', help: 'toggle output'}, |
|
216 | {key: 'Ctrl-m t', help: 'toggle output'}, | |
217 | {key: 'Ctrl-m l', help: 'toggle line numbers'}, |
|
217 | {key: 'Ctrl-m l', help: 'toggle line numbers'}, | |
218 | {key: 'Ctrl-m s', help: 'save notebook'}, |
|
218 | {key: 'Ctrl-m s', help: 'save notebook'}, | |
219 | {key: 'Ctrl-m j', help: 'move cell down'}, |
|
219 | {key: 'Ctrl-m j', help: 'move cell down'}, | |
220 | {key: 'Ctrl-m k', help: 'move cell up'}, |
|
220 | {key: 'Ctrl-m k', help: 'move cell up'}, | |
221 | {key: 'Ctrl-m c', help: 'code cell'}, |
|
221 | {key: 'Ctrl-m c', help: 'code cell'}, | |
222 | {key: 'Ctrl-m m', help: 'markdown cell'}, |
|
222 | {key: 'Ctrl-m m', help: 'markdown cell'}, | |
223 | {key: 'Ctrl-m p', help: 'select previous'}, |
|
223 | {key: 'Ctrl-m p', help: 'select previous'}, | |
224 | {key: 'Ctrl-m n', help: 'select next'}, |
|
224 | {key: 'Ctrl-m n', help: 'select next'}, | |
225 | {key: 'Ctrl-m i', help: 'interrupt kernel'}, |
|
225 | {key: 'Ctrl-m i', help: 'interrupt kernel'}, | |
226 | {key: 'Ctrl-m .', help: 'restart kernel'}, |
|
226 | {key: 'Ctrl-m .', help: 'restart kernel'}, | |
227 | {key: 'Ctrl-m h', help: 'show keyboard shortcuts'} |
|
227 | {key: 'Ctrl-m h', help: 'show keyboard shortcuts'} | |
228 | ]; |
|
228 | ]; | |
229 | for (var i=0; i<shortcuts.length; i++) { |
|
229 | for (var i=0; i<shortcuts.length; i++) { | |
230 | dialog.append($('<div>'). |
|
230 | dialog.append($('<div>'). | |
231 | append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)). |
|
231 | append($('<span/>').addClass('shortcut_key').html(shortcuts[i].key)). | |
232 | append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help)) |
|
232 | append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help)) | |
233 | ); |
|
233 | ); | |
234 | }; |
|
234 | }; | |
235 | dialog.bind('dialogclose', function(event) { |
|
235 | dialog.bind('dialogclose', function(event) { | |
236 | // dialog has been closed, allow it to be drawn again. |
|
236 | // dialog has been closed, allow it to be drawn again. | |
237 | that.shortcut_dialog = null; |
|
237 | that.shortcut_dialog = null; | |
238 | }); |
|
238 | }); | |
239 | dialog.dialog({title: 'Keyboard shortcuts'}); |
|
239 | dialog.dialog({title: 'Keyboard shortcuts'}); | |
240 | }; |
|
240 | }; | |
241 |
|
241 | |||
242 |
|
242 | |||
243 | Notebook.prototype.scroll_to_bottom = function () { |
|
243 | Notebook.prototype.scroll_to_bottom = function () { | |
244 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); |
|
244 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); | |
245 | }; |
|
245 | }; | |
246 |
|
246 | |||
247 |
|
247 | |||
248 | Notebook.prototype.scroll_to_top = function () { |
|
248 | Notebook.prototype.scroll_to_top = function () { | |
249 | this.element.animate({scrollTop:0}, 0); |
|
249 | this.element.animate({scrollTop:0}, 0); | |
250 | }; |
|
250 | }; | |
251 |
|
251 | |||
252 |
|
252 | |||
253 | // Cell indexing, retrieval, etc. |
|
253 | // Cell indexing, retrieval, etc. | |
254 |
|
254 | |||
255 |
|
255 | |||
256 | Notebook.prototype.cell_elements = function () { |
|
256 | Notebook.prototype.cell_elements = function () { | |
257 | return this.element.children("div.cell"); |
|
257 | return this.element.children("div.cell"); | |
258 | } |
|
258 | } | |
259 |
|
259 | |||
260 |
|
260 | |||
261 | Notebook.prototype.ncells = function (cell) { |
|
261 | Notebook.prototype.ncells = function (cell) { | |
262 | return this.cell_elements().length; |
|
262 | return this.cell_elements().length; | |
263 | } |
|
263 | } | |
264 |
|
264 | |||
265 |
|
265 | |||
266 | // TODO: we are often calling cells as cells()[i], which we should optimize |
|
266 | // TODO: we are often calling cells as cells()[i], which we should optimize | |
267 | // to cells(i) or a new method. |
|
267 | // to cells(i) or a new method. | |
268 | Notebook.prototype.cells = function () { |
|
268 | Notebook.prototype.cells = function () { | |
269 | return this.cell_elements().toArray().map(function (e) { |
|
269 | return this.cell_elements().toArray().map(function (e) { | |
270 | return $(e).data("cell"); |
|
270 | return $(e).data("cell"); | |
271 | }); |
|
271 | }); | |
272 | } |
|
272 | } | |
273 |
|
273 | |||
274 |
|
274 | |||
275 | Notebook.prototype.find_cell_index = function (cell) { |
|
275 | Notebook.prototype.find_cell_index = function (cell) { | |
276 | var result = null; |
|
276 | var result = null; | |
277 | this.cell_elements().filter(function (index) { |
|
277 | this.cell_elements().filter(function (index) { | |
278 | if ($(this).data("cell") === cell) { |
|
278 | if ($(this).data("cell") === cell) { | |
279 | result = index; |
|
279 | result = index; | |
280 | }; |
|
280 | }; | |
281 | }); |
|
281 | }); | |
282 | return result; |
|
282 | return result; | |
283 | }; |
|
283 | }; | |
284 |
|
284 | |||
285 |
|
285 | |||
286 | Notebook.prototype.index_or_selected = function (index) { |
|
286 | Notebook.prototype.index_or_selected = function (index) { | |
287 | return index || this.selected_index() || 0; |
|
287 | return index || this.selected_index() || 0; | |
288 | } |
|
288 | } | |
289 |
|
289 | |||
290 |
|
290 | |||
291 | Notebook.prototype.select = function (index) { |
|
291 | Notebook.prototype.select = function (index) { | |
292 | if (index !== undefined && index >= 0 && index < this.ncells()) { |
|
292 | if (index !== undefined && index >= 0 && index < this.ncells()) { | |
293 | if (this.selected_index() !== null) { |
|
293 | if (this.selected_index() !== null) { | |
294 | this.selected_cell().unselect(); |
|
294 | this.selected_cell().unselect(); | |
295 | }; |
|
295 | }; | |
296 | this.cells()[index].select(); |
|
296 | this.cells()[index].select(); | |
297 | }; |
|
297 | }; | |
298 | return this; |
|
298 | return this; | |
299 | }; |
|
299 | }; | |
300 |
|
300 | |||
301 |
|
301 | |||
302 | Notebook.prototype.select_next = function () { |
|
302 | Notebook.prototype.select_next = function () { | |
303 | var index = this.selected_index(); |
|
303 | var index = this.selected_index(); | |
304 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { |
|
304 | if (index !== null && index >= 0 && (index+1) < this.ncells()) { | |
305 | this.select(index+1); |
|
305 | this.select(index+1); | |
306 | }; |
|
306 | }; | |
307 | return this; |
|
307 | return this; | |
308 | }; |
|
308 | }; | |
309 |
|
309 | |||
310 |
|
310 | |||
311 | Notebook.prototype.select_prev = function () { |
|
311 | Notebook.prototype.select_prev = function () { | |
312 | var index = this.selected_index(); |
|
312 | var index = this.selected_index(); | |
313 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { |
|
313 | if (index !== null && index >= 0 && (index-1) < this.ncells()) { | |
314 | this.select(index-1); |
|
314 | this.select(index-1); | |
315 | }; |
|
315 | }; | |
316 | return this; |
|
316 | return this; | |
317 | }; |
|
317 | }; | |
318 |
|
318 | |||
319 |
|
319 | |||
320 | Notebook.prototype.selected_index = function () { |
|
320 | Notebook.prototype.selected_index = function () { | |
321 | var result = null; |
|
321 | var result = null; | |
322 | this.cell_elements().filter(function (index) { |
|
322 | this.cell_elements().filter(function (index) { | |
323 | if ($(this).data("cell").selected === true) { |
|
323 | if ($(this).data("cell").selected === true) { | |
324 | result = index; |
|
324 | result = index; | |
325 | }; |
|
325 | }; | |
326 | }); |
|
326 | }); | |
327 | return result; |
|
327 | return result; | |
328 | }; |
|
328 | }; | |
329 |
|
329 | |||
330 |
|
330 | |||
331 | Notebook.prototype.cell_for_msg = function (msg_id) { |
|
331 | Notebook.prototype.cell_for_msg = function (msg_id) { | |
332 | var cell_id = this.msg_cell_map[msg_id]; |
|
332 | var cell_id = this.msg_cell_map[msg_id]; | |
333 | var result = null; |
|
333 | var result = null; | |
334 | this.cell_elements().filter(function (index) { |
|
334 | this.cell_elements().filter(function (index) { | |
335 | cell = $(this).data("cell"); |
|
335 | cell = $(this).data("cell"); | |
336 | if (cell.cell_id === cell_id) { |
|
336 | if (cell.cell_id === cell_id) { | |
337 | result = cell; |
|
337 | result = cell; | |
338 | }; |
|
338 | }; | |
339 | }); |
|
339 | }); | |
340 | return result; |
|
340 | return result; | |
341 | }; |
|
341 | }; | |
342 |
|
342 | |||
343 |
|
343 | |||
344 | Notebook.prototype.selected_cell = function () { |
|
344 | Notebook.prototype.selected_cell = function () { | |
345 | return this.cell_elements().eq(this.selected_index()).data("cell"); |
|
345 | return this.cell_elements().eq(this.selected_index()).data("cell"); | |
346 | } |
|
346 | } | |
347 |
|
347 | |||
348 |
|
348 | |||
349 | // Cell insertion, deletion and moving. |
|
349 | // Cell insertion, deletion and moving. | |
350 |
|
350 | |||
351 |
|
351 | |||
352 | Notebook.prototype.delete_cell = function (index) { |
|
352 | Notebook.prototype.delete_cell = function (index) { | |
353 | var i = index || this.selected_index(); |
|
353 | var i = index || this.selected_index(); | |
354 | if (i !== null && i >= 0 && i < this.ncells()) { |
|
354 | if (i !== null && i >= 0 && i < this.ncells()) { | |
355 | this.cell_elements().eq(i).remove(); |
|
355 | this.cell_elements().eq(i).remove(); | |
356 | if (i === (this.ncells())) { |
|
356 | if (i === (this.ncells())) { | |
357 | this.select(i-1); |
|
357 | this.select(i-1); | |
358 | } else { |
|
358 | } else { | |
359 | this.select(i); |
|
359 | this.select(i); | |
360 | }; |
|
360 | }; | |
361 | }; |
|
361 | }; | |
362 | this.dirty = true; |
|
362 | this.dirty = true; | |
363 | return this; |
|
363 | return this; | |
364 | }; |
|
364 | }; | |
365 |
|
365 | |||
366 |
|
366 | |||
367 | Notebook.prototype.append_cell = function (cell) { |
|
367 | Notebook.prototype.append_cell = function (cell) { | |
368 | this.element.find('div.end_space').before(cell.element); |
|
368 | this.element.find('div.end_space').before(cell.element); | |
369 | this.dirty = true; |
|
369 | this.dirty = true; | |
370 | return this; |
|
370 | return this; | |
371 | }; |
|
371 | }; | |
372 |
|
372 | |||
373 |
|
373 | |||
374 | Notebook.prototype.insert_cell_below = function (cell, index) { |
|
374 | Notebook.prototype.insert_cell_below = function (cell, index) { | |
375 | var ncells = this.ncells(); |
|
375 | var ncells = this.ncells(); | |
376 | if (ncells === 0) { |
|
376 | if (ncells === 0) { | |
377 | this.append_cell(cell); |
|
377 | this.append_cell(cell); | |
378 | return this; |
|
378 | return this; | |
379 | }; |
|
379 | }; | |
380 | if (index >= 0 && index < ncells) { |
|
380 | if (index >= 0 && index < ncells) { | |
381 | this.cell_elements().eq(index).after(cell.element); |
|
381 | this.cell_elements().eq(index).after(cell.element); | |
382 | }; |
|
382 | }; | |
383 | this.dirty = true; |
|
383 | this.dirty = true; | |
384 | return this |
|
384 | return this | |
385 | }; |
|
385 | }; | |
386 |
|
386 | |||
387 |
|
387 | |||
388 | Notebook.prototype.insert_cell_above = function (cell, index) { |
|
388 | Notebook.prototype.insert_cell_above = function (cell, index) { | |
389 | var ncells = this.ncells(); |
|
389 | var ncells = this.ncells(); | |
390 | if (ncells === 0) { |
|
390 | if (ncells === 0) { | |
391 | this.append_cell(cell); |
|
391 | this.append_cell(cell); | |
392 | return this; |
|
392 | return this; | |
393 | }; |
|
393 | }; | |
394 | if (index >= 0 && index < ncells) { |
|
394 | if (index >= 0 && index < ncells) { | |
395 | this.cell_elements().eq(index).before(cell.element); |
|
395 | this.cell_elements().eq(index).before(cell.element); | |
396 | }; |
|
396 | }; | |
397 | this.dirty = true; |
|
397 | this.dirty = true; | |
398 | return this; |
|
398 | return this; | |
399 | }; |
|
399 | }; | |
400 |
|
400 | |||
401 |
|
401 | |||
402 | Notebook.prototype.move_cell_up = function (index) { |
|
402 | Notebook.prototype.move_cell_up = function (index) { | |
403 | var i = index || this.selected_index(); |
|
403 | var i = index || this.selected_index(); | |
404 | if (i !== null && i < this.ncells() && i > 0) { |
|
404 | if (i !== null && i < this.ncells() && i > 0) { | |
405 | var pivot = this.cell_elements().eq(i-1); |
|
405 | var pivot = this.cell_elements().eq(i-1); | |
406 | var tomove = this.cell_elements().eq(i); |
|
406 | var tomove = this.cell_elements().eq(i); | |
407 | if (pivot !== null && tomove !== null) { |
|
407 | if (pivot !== null && tomove !== null) { | |
408 | tomove.detach(); |
|
408 | tomove.detach(); | |
409 | pivot.before(tomove); |
|
409 | pivot.before(tomove); | |
410 | this.select(i-1); |
|
410 | this.select(i-1); | |
411 | }; |
|
411 | }; | |
412 | }; |
|
412 | }; | |
413 | this.dirty = true; |
|
413 | this.dirty = true; | |
414 | return this; |
|
414 | return this; | |
415 | } |
|
415 | } | |
416 |
|
416 | |||
417 |
|
417 | |||
418 | Notebook.prototype.move_cell_down = function (index) { |
|
418 | Notebook.prototype.move_cell_down = function (index) { | |
419 | var i = index || this.selected_index(); |
|
419 | var i = index || this.selected_index(); | |
420 | if (i !== null && i < (this.ncells()-1) && i >= 0) { |
|
420 | if (i !== null && i < (this.ncells()-1) && i >= 0) { | |
421 | var pivot = this.cell_elements().eq(i+1) |
|
421 | var pivot = this.cell_elements().eq(i+1) | |
422 | var tomove = this.cell_elements().eq(i) |
|
422 | var tomove = this.cell_elements().eq(i) | |
423 | if (pivot !== null && tomove !== null) { |
|
423 | if (pivot !== null && tomove !== null) { | |
424 | tomove.detach(); |
|
424 | tomove.detach(); | |
425 | pivot.after(tomove); |
|
425 | pivot.after(tomove); | |
426 | this.select(i+1); |
|
426 | this.select(i+1); | |
427 | }; |
|
427 | }; | |
428 | }; |
|
428 | }; | |
429 | this.dirty = true; |
|
429 | this.dirty = true; | |
430 | return this; |
|
430 | return this; | |
431 | } |
|
431 | } | |
432 |
|
432 | |||
433 |
|
433 | |||
434 | Notebook.prototype.sort_cells = function () { |
|
434 | Notebook.prototype.sort_cells = function () { | |
435 | var ncells = this.ncells(); |
|
435 | var ncells = this.ncells(); | |
436 | var sindex = this.selected_index(); |
|
436 | var sindex = this.selected_index(); | |
437 | var swapped; |
|
437 | var swapped; | |
438 | do { |
|
438 | do { | |
439 | swapped = false |
|
439 | swapped = false | |
440 | for (var i=1; i<ncells; i++) { |
|
440 | for (var i=1; i<ncells; i++) { | |
441 | current = this.cell_elements().eq(i).data("cell"); |
|
441 | current = this.cell_elements().eq(i).data("cell"); | |
442 | previous = this.cell_elements().eq(i-1).data("cell"); |
|
442 | previous = this.cell_elements().eq(i-1).data("cell"); | |
443 | if (previous.input_prompt_number > current.input_prompt_number) { |
|
443 | if (previous.input_prompt_number > current.input_prompt_number) { | |
444 | this.move_cell_up(i); |
|
444 | this.move_cell_up(i); | |
445 | swapped = true; |
|
445 | swapped = true; | |
446 | }; |
|
446 | }; | |
447 | }; |
|
447 | }; | |
448 | } while (swapped); |
|
448 | } while (swapped); | |
449 | this.select(sindex); |
|
449 | this.select(sindex); | |
450 | return this; |
|
450 | return this; | |
451 | }; |
|
451 | }; | |
452 |
|
452 | |||
453 |
|
453 | |||
454 | Notebook.prototype.insert_code_cell_above = function (index) { |
|
454 | Notebook.prototype.insert_code_cell_above = function (index) { | |
455 | // TODO: Bounds check for i |
|
455 | // TODO: Bounds check for i | |
456 | var i = this.index_or_selected(index); |
|
456 | var i = this.index_or_selected(index); | |
457 | var cell = new IPython.CodeCell(this); |
|
457 | var cell = new IPython.CodeCell(this); | |
458 | cell.set_input_prompt(); |
|
458 | cell.set_input_prompt(); | |
459 | this.insert_cell_above(cell, i); |
|
459 | this.insert_cell_above(cell, i); | |
460 | this.select(this.find_cell_index(cell)); |
|
460 | this.select(this.find_cell_index(cell)); | |
461 | return cell; |
|
461 | return cell; | |
462 | } |
|
462 | } | |
463 |
|
463 | |||
464 |
|
464 | |||
465 | Notebook.prototype.insert_code_cell_below = function (index) { |
|
465 | Notebook.prototype.insert_code_cell_below = function (index) { | |
466 | // TODO: Bounds check for i |
|
466 | // TODO: Bounds check for i | |
467 | var i = this.index_or_selected(index); |
|
467 | var i = this.index_or_selected(index); | |
468 | var cell = new IPython.CodeCell(this); |
|
468 | var cell = new IPython.CodeCell(this); | |
469 | cell.set_input_prompt(); |
|
469 | cell.set_input_prompt(); | |
470 | this.insert_cell_below(cell, i); |
|
470 | this.insert_cell_below(cell, i); | |
471 | this.select(this.find_cell_index(cell)); |
|
471 | this.select(this.find_cell_index(cell)); | |
472 | return cell; |
|
472 | return cell; | |
473 | } |
|
473 | } | |
474 |
|
474 | |||
475 |
|
475 | |||
476 | Notebook.prototype.insert_html_cell_above = function (index) { |
|
476 | Notebook.prototype.insert_html_cell_above = function (index) { | |
477 | // TODO: Bounds check for i |
|
477 | // TODO: Bounds check for i | |
478 | var i = this.index_or_selected(index); |
|
478 | var i = this.index_or_selected(index); | |
479 | var cell = new IPython.HTMLCell(this); |
|
479 | var cell = new IPython.HTMLCell(this); | |
480 | cell.config_mathjax(); |
|
480 | cell.config_mathjax(); | |
481 | this.insert_cell_above(cell, i); |
|
481 | this.insert_cell_above(cell, i); | |
482 | this.select(this.find_cell_index(cell)); |
|
482 | this.select(this.find_cell_index(cell)); | |
483 | return cell; |
|
483 | return cell; | |
484 | } |
|
484 | } | |
485 |
|
485 | |||
486 |
|
486 | |||
487 | Notebook.prototype.insert_html_cell_below = function (index) { |
|
487 | Notebook.prototype.insert_html_cell_below = function (index) { | |
488 | // TODO: Bounds check for i |
|
488 | // TODO: Bounds check for i | |
489 | var i = this.index_or_selected(index); |
|
489 | var i = this.index_or_selected(index); | |
490 | var cell = new IPython.HTMLCell(this); |
|
490 | var cell = new IPython.HTMLCell(this); | |
491 | cell.config_mathjax(); |
|
491 | cell.config_mathjax(); | |
492 | this.insert_cell_below(cell, i); |
|
492 | this.insert_cell_below(cell, i); | |
493 | this.select(this.find_cell_index(cell)); |
|
493 | this.select(this.find_cell_index(cell)); | |
494 | return cell; |
|
494 | return cell; | |
495 | } |
|
495 | } | |
496 |
|
496 | |||
497 |
|
497 | |||
498 | Notebook.prototype.insert_markdown_cell_above = function (index) { |
|
498 | Notebook.prototype.insert_markdown_cell_above = function (index) { | |
499 | // TODO: Bounds check for i |
|
499 | // TODO: Bounds check for i | |
500 | var i = this.index_or_selected(index); |
|
500 | var i = this.index_or_selected(index); | |
501 | var cell = new IPython.MarkdownCell(this); |
|
501 | var cell = new IPython.MarkdownCell(this); | |
502 | cell.config_mathjax(); |
|
502 | cell.config_mathjax(); | |
503 | this.insert_cell_above(cell, i); |
|
503 | this.insert_cell_above(cell, i); | |
504 | this.select(this.find_cell_index(cell)); |
|
504 | this.select(this.find_cell_index(cell)); | |
505 | return cell; |
|
505 | return cell; | |
506 | } |
|
506 | } | |
507 |
|
507 | |||
508 |
|
508 | |||
509 | Notebook.prototype.insert_markdown_cell_below = function (index) { |
|
509 | Notebook.prototype.insert_markdown_cell_below = function (index) { | |
510 | // TODO: Bounds check for i |
|
510 | // TODO: Bounds check for i | |
511 | var i = this.index_or_selected(index); |
|
511 | var i = this.index_or_selected(index); | |
512 | var cell = new IPython.MarkdownCell(this); |
|
512 | var cell = new IPython.MarkdownCell(this); | |
513 | cell.config_mathjax(); |
|
513 | cell.config_mathjax(); | |
514 | this.insert_cell_below(cell, i); |
|
514 | this.insert_cell_below(cell, i); | |
515 | this.select(this.find_cell_index(cell)); |
|
515 | this.select(this.find_cell_index(cell)); | |
516 | return cell; |
|
516 | return cell; | |
517 | } |
|
517 | } | |
518 |
|
518 | |||
519 |
|
519 | |||
520 | Notebook.prototype.to_code = function (index) { |
|
520 | Notebook.prototype.to_code = function (index) { | |
521 | // TODO: Bounds check for i |
|
521 | // TODO: Bounds check for i | |
522 | var i = this.index_or_selected(index); |
|
522 | var i = this.index_or_selected(index); | |
523 | var source_element = this.cell_elements().eq(i); |
|
523 | var source_element = this.cell_elements().eq(i); | |
524 | var source_cell = source_element.data("cell"); |
|
524 | var source_cell = source_element.data("cell"); | |
525 | if (source_cell instanceof IPython.HTMLCell || |
|
525 | if (source_cell instanceof IPython.HTMLCell || | |
526 | source_cell instanceof IPython.MarkdownCell) { |
|
526 | source_cell instanceof IPython.MarkdownCell) { | |
527 | this.insert_code_cell_below(i); |
|
527 | this.insert_code_cell_below(i); | |
528 | var target_cell = this.cells()[i+1]; |
|
528 | var target_cell = this.cells()[i+1]; | |
529 | target_cell.set_code(source_cell.get_source()); |
|
529 | target_cell.set_code(source_cell.get_source()); | |
530 | source_element.remove(); |
|
530 | source_element.remove(); | |
531 | target_cell.select(); |
|
531 | target_cell.select(); | |
532 | }; |
|
532 | }; | |
533 | this.dirty = true; |
|
533 | this.dirty = true; | |
534 | }; |
|
534 | }; | |
535 |
|
535 | |||
536 |
|
536 | |||
537 | Notebook.prototype.to_markdown = function (index) { |
|
537 | Notebook.prototype.to_markdown = function (index) { | |
538 | // TODO: Bounds check for i |
|
538 | // TODO: Bounds check for i | |
539 | var i = this.index_or_selected(index); |
|
539 | var i = this.index_or_selected(index); | |
540 | var source_element = this.cell_elements().eq(i); |
|
540 | var source_element = this.cell_elements().eq(i); | |
541 | var source_cell = source_element.data("cell"); |
|
541 | var source_cell = source_element.data("cell"); | |
542 | var target_cell = null; |
|
542 | var target_cell = null; | |
543 | if (source_cell instanceof IPython.CodeCell) { |
|
543 | if (source_cell instanceof IPython.CodeCell) { | |
544 | this.insert_markdown_cell_below(i); |
|
544 | this.insert_markdown_cell_below(i); | |
545 | var target_cell = this.cells()[i+1]; |
|
545 | var target_cell = this.cells()[i+1]; | |
546 | var text = source_cell.get_code(); |
|
546 | var text = source_cell.get_code(); | |
547 | } else if (source_cell instanceof IPython.HTMLCell) { |
|
547 | } else if (source_cell instanceof IPython.HTMLCell) { | |
548 | this.insert_markdown_cell_below(i); |
|
548 | this.insert_markdown_cell_below(i); | |
549 | var target_cell = this.cells()[i+1]; |
|
549 | var target_cell = this.cells()[i+1]; | |
550 | var text = source_cell.get_source(); |
|
550 | var text = source_cell.get_source(); | |
551 | if (text === source_cell.placeholder) { |
|
551 | if (text === source_cell.placeholder) { | |
552 | text = target_cell.placeholder; |
|
552 | text = target_cell.placeholder; | |
553 | } |
|
553 | } | |
554 | } |
|
554 | } | |
555 | if (target_cell !== null) { |
|
555 | if (target_cell !== null) { | |
556 | if (text === "") {text = target_cell.placeholder;}; |
|
556 | if (text === "") {text = target_cell.placeholder;}; | |
557 | target_cell.set_source(text); |
|
557 | target_cell.set_source(text); | |
558 | source_element.remove(); |
|
558 | source_element.remove(); | |
559 | target_cell.edit(); |
|
559 | target_cell.edit(); | |
560 | } |
|
560 | } | |
561 | this.dirty = true; |
|
561 | this.dirty = true; | |
562 | }; |
|
562 | }; | |
563 |
|
563 | |||
564 |
|
564 | |||
565 | Notebook.prototype.to_html = function (index) { |
|
565 | Notebook.prototype.to_html = function (index) { | |
566 | // TODO: Bounds check for i |
|
566 | // TODO: Bounds check for i | |
567 | var i = this.index_or_selected(index); |
|
567 | var i = this.index_or_selected(index); | |
568 | var source_element = this.cell_elements().eq(i); |
|
568 | var source_element = this.cell_elements().eq(i); | |
569 | var source_cell = source_element.data("cell"); |
|
569 | var source_cell = source_element.data("cell"); | |
570 | var target_cell = null; |
|
570 | var target_cell = null; | |
571 | if (source_cell instanceof IPython.CodeCell) { |
|
571 | if (source_cell instanceof IPython.CodeCell) { | |
572 | this.insert_html_cell_below(i); |
|
572 | this.insert_html_cell_below(i); | |
573 | var target_cell = this.cells()[i+1]; |
|
573 | var target_cell = this.cells()[i+1]; | |
574 | var text = source_cell.get_code(); |
|
574 | var text = source_cell.get_code(); | |
575 | } else if (source_cell instanceof IPython.MarkdownCell) { |
|
575 | } else if (source_cell instanceof IPython.MarkdownCell) { | |
576 | this.insert_html_cell_below(i); |
|
576 | this.insert_html_cell_below(i); | |
577 | var target_cell = this.cells()[i+1]; |
|
577 | var target_cell = this.cells()[i+1]; | |
578 | var text = source_cell.get_source(); |
|
578 | var text = source_cell.get_source(); | |
579 | if (text === source_cell.placeholder) { |
|
579 | if (text === source_cell.placeholder) { | |
580 | text = target_cell.placeholder; |
|
580 | text = target_cell.placeholder; | |
581 | } |
|
581 | } | |
582 | } |
|
582 | } | |
583 | if (target_cell !== null) { |
|
583 | if (target_cell !== null) { | |
584 | if (text === "") {text = target_cell.placeholder;}; |
|
584 | if (text === "") {text = target_cell.placeholder;}; | |
585 | target_cell.set_source(text); |
|
585 | target_cell.set_source(text); | |
586 | source_element.remove(); |
|
586 | source_element.remove(); | |
587 | target_cell.edit(); |
|
587 | target_cell.edit(); | |
588 | } |
|
588 | } | |
589 | this.dirty = true; |
|
589 | this.dirty = true; | |
590 | }; |
|
590 | }; | |
591 |
|
591 | |||
592 |
|
592 | |||
593 | // Cell collapsing and output clearing |
|
593 | // Cell collapsing and output clearing | |
594 |
|
594 | |||
595 | Notebook.prototype.collapse = function (index) { |
|
595 | Notebook.prototype.collapse = function (index) { | |
596 | var i = this.index_or_selected(index); |
|
596 | var i = this.index_or_selected(index); | |
597 | this.cells()[i].collapse(); |
|
597 | this.cells()[i].collapse(); | |
598 | this.dirty = true; |
|
598 | this.dirty = true; | |
599 | }; |
|
599 | }; | |
600 |
|
600 | |||
601 |
|
601 | |||
602 | Notebook.prototype.expand = function (index) { |
|
602 | Notebook.prototype.expand = function (index) { | |
603 | var i = this.index_or_selected(index); |
|
603 | var i = this.index_or_selected(index); | |
604 | this.cells()[i].expand(); |
|
604 | this.cells()[i].expand(); | |
605 | this.dirty = true; |
|
605 | this.dirty = true; | |
606 | }; |
|
606 | }; | |
607 |
|
607 | |||
608 |
|
608 | |||
609 | Notebook.prototype.toggle_output = function (index) { |
|
609 | Notebook.prototype.toggle_output = function (index) { | |
610 | var i = this.index_or_selected(index); |
|
610 | var i = this.index_or_selected(index); | |
611 | this.cells()[i].toggle_output(); |
|
611 | this.cells()[i].toggle_output(); | |
612 | this.dirty = true; |
|
612 | this.dirty = true; | |
613 | }; |
|
613 | }; | |
614 |
|
614 | |||
615 |
|
615 | |||
616 | Notebook.prototype.set_autoindent = function (state) { |
|
616 | Notebook.prototype.set_autoindent = function (state) { | |
617 | var cells = this.cells(); |
|
617 | var cells = this.cells(); | |
618 | len = cells.length; |
|
618 | len = cells.length; | |
619 | for (var i=0; i<len; i++) { |
|
619 | for (var i=0; i<len; i++) { | |
620 | cells[i].set_autoindent(state) |
|
620 | cells[i].set_autoindent(state) | |
621 | }; |
|
621 | }; | |
622 | }; |
|
622 | }; | |
623 |
|
623 | |||
624 |
|
624 | |||
625 | Notebook.prototype.clear_all_output = function () { |
|
625 | Notebook.prototype.clear_all_output = function () { | |
626 | var ncells = this.ncells(); |
|
626 | var ncells = this.ncells(); | |
627 | var cells = this.cells(); |
|
627 | var cells = this.cells(); | |
628 | for (var i=0; i<ncells; i++) { |
|
628 | for (var i=0; i<ncells; i++) { | |
629 | if (cells[i] instanceof IPython.CodeCell) { |
|
629 | if (cells[i] instanceof IPython.CodeCell) { | |
630 | cells[i].clear_output(); |
|
630 | cells[i].clear_output(true,true,true); | |
631 | } |
|
631 | } | |
632 | }; |
|
632 | }; | |
633 | this.dirty = true; |
|
633 | this.dirty = true; | |
634 | }; |
|
634 | }; | |
635 |
|
635 | |||
636 | // Other cell functions: line numbers, ... |
|
636 | // Other cell functions: line numbers, ... | |
637 |
|
637 | |||
638 | Notebook.prototype.cell_toggle_line_numbers = function() { |
|
638 | Notebook.prototype.cell_toggle_line_numbers = function() { | |
639 | this.selected_cell().toggle_line_numbers() |
|
639 | this.selected_cell().toggle_line_numbers() | |
640 | }; |
|
640 | }; | |
641 |
|
641 | |||
642 | // Kernel related things |
|
642 | // Kernel related things | |
643 |
|
643 | |||
644 | Notebook.prototype.start_kernel = function () { |
|
644 | Notebook.prototype.start_kernel = function () { | |
645 | this.kernel = new IPython.Kernel(); |
|
645 | this.kernel = new IPython.Kernel(); | |
646 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
646 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
647 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); |
|
647 | this.kernel.start(notebook_id, $.proxy(this.kernel_started, this)); | |
648 | }; |
|
648 | }; | |
649 |
|
649 | |||
650 |
|
650 | |||
651 | Notebook.prototype.restart_kernel = function () { |
|
651 | Notebook.prototype.restart_kernel = function () { | |
652 | var that = this; |
|
652 | var that = this; | |
653 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
653 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
654 |
|
654 | |||
655 | var dialog = $('<div/>'); |
|
655 | var dialog = $('<div/>'); | |
656 | dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.'); |
|
656 | dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.'); | |
657 | $(document).append(dialog); |
|
657 | $(document).append(dialog); | |
658 | dialog.dialog({ |
|
658 | dialog.dialog({ | |
659 | resizable: false, |
|
659 | resizable: false, | |
660 | modal: true, |
|
660 | modal: true, | |
661 | title: "Restart kernel or continue running?", |
|
661 | title: "Restart kernel or continue running?", | |
662 | buttons : { |
|
662 | buttons : { | |
663 | "Restart": function () { |
|
663 | "Restart": function () { | |
664 | that.kernel.restart($.proxy(that.kernel_started, that)); |
|
664 | that.kernel.restart($.proxy(that.kernel_started, that)); | |
665 | $(this).dialog('close'); |
|
665 | $(this).dialog('close'); | |
666 | }, |
|
666 | }, | |
667 | "Continue running": function () { |
|
667 | "Continue running": function () { | |
668 | $(this).dialog('close'); |
|
668 | $(this).dialog('close'); | |
669 | } |
|
669 | } | |
670 | } |
|
670 | } | |
671 | }); |
|
671 | }); | |
672 | }; |
|
672 | }; | |
673 |
|
673 | |||
674 |
|
674 | |||
675 | Notebook.prototype.kernel_started = function () { |
|
675 | Notebook.prototype.kernel_started = function () { | |
676 | console.log("Kernel started: ", this.kernel.kernel_id); |
|
676 | console.log("Kernel started: ", this.kernel.kernel_id); | |
677 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); |
|
677 | this.kernel.shell_channel.onmessage = $.proxy(this.handle_shell_reply,this); | |
678 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); |
|
678 | this.kernel.iopub_channel.onmessage = $.proxy(this.handle_iopub_reply,this); | |
679 | }; |
|
679 | }; | |
680 |
|
680 | |||
681 |
|
681 | |||
682 | Notebook.prototype.handle_shell_reply = function (e) { |
|
682 | Notebook.prototype.handle_shell_reply = function (e) { | |
683 | reply = $.parseJSON(e.data); |
|
683 | reply = $.parseJSON(e.data); | |
684 | var header = reply.header; |
|
684 | var header = reply.header; | |
685 | var content = reply.content; |
|
685 | var content = reply.content; | |
686 | var msg_type = header.msg_type; |
|
686 | var msg_type = header.msg_type; | |
687 | // console.log(reply); |
|
687 | // console.log(reply); | |
688 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
688 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
689 | if (msg_type === "execute_reply") { |
|
689 | if (msg_type === "execute_reply") { | |
690 | cell.set_input_prompt(content.execution_count); |
|
690 | cell.set_input_prompt(content.execution_count); | |
691 | this.dirty = true; |
|
691 | this.dirty = true; | |
692 | } else if (msg_type === "complete_reply") { |
|
692 | } else if (msg_type === "complete_reply") { | |
693 | cell.finish_completing(content.matched_text, content.matches); |
|
693 | cell.finish_completing(content.matched_text, content.matches); | |
694 | }; |
|
694 | }; | |
695 | var payload = content.payload || []; |
|
695 | var payload = content.payload || []; | |
696 | this.handle_payload(cell, payload); |
|
696 | this.handle_payload(cell, payload); | |
697 | }; |
|
697 | }; | |
698 |
|
698 | |||
699 |
|
699 | |||
700 | Notebook.prototype.handle_payload = function (cell, payload) { |
|
700 | Notebook.prototype.handle_payload = function (cell, payload) { | |
701 | var l = payload.length; |
|
701 | var l = payload.length; | |
702 | for (var i=0; i<l; i++) { |
|
702 | for (var i=0; i<l; i++) { | |
703 | if (payload[i].source === 'IPython.zmq.page.page') { |
|
703 | if (payload[i].source === 'IPython.zmq.page.page') { | |
704 | if (payload[i].text.trim() !== '') { |
|
704 | if (payload[i].text.trim() !== '') { | |
705 | IPython.pager.clear(); |
|
705 | IPython.pager.clear(); | |
706 | IPython.pager.expand(); |
|
706 | IPython.pager.expand(); | |
707 | IPython.pager.append_text(payload[i].text); |
|
707 | IPython.pager.append_text(payload[i].text); | |
708 | } |
|
708 | } | |
709 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { |
|
709 | } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') { | |
710 | var index = this.find_cell_index(cell); |
|
710 | var index = this.find_cell_index(cell); | |
711 | var new_cell = this.insert_code_cell_below(index); |
|
711 | var new_cell = this.insert_code_cell_below(index); | |
712 | new_cell.set_code(payload[i].text); |
|
712 | new_cell.set_code(payload[i].text); | |
713 | this.dirty = true; |
|
713 | this.dirty = true; | |
714 | } |
|
714 | } | |
715 | }; |
|
715 | }; | |
716 | }; |
|
716 | }; | |
717 |
|
717 | |||
718 |
|
718 | |||
719 | Notebook.prototype.handle_iopub_reply = function (e) { |
|
719 | Notebook.prototype.handle_iopub_reply = function (e) { | |
720 | reply = $.parseJSON(e.data); |
|
720 | reply = $.parseJSON(e.data); | |
721 | var content = reply.content; |
|
721 | var content = reply.content; | |
722 | // console.log(reply); |
|
722 | // console.log(reply); | |
723 | var msg_type = reply.header.msg_type; |
|
723 | var msg_type = reply.header.msg_type; | |
724 | var cell = this.cell_for_msg(reply.parent_header.msg_id); |
|
724 | var cell = this.cell_for_msg(reply.parent_header.msg_id); | |
725 | var output_types = ['stream','display_data','pyout','pyerr']; |
|
725 | var output_types = ['stream','display_data','pyout','pyerr']; | |
726 | if (output_types.indexOf(msg_type) >= 0) { |
|
726 | if (output_types.indexOf(msg_type) >= 0) { | |
727 | this.handle_output(cell, msg_type, content); |
|
727 | this.handle_output(cell, msg_type, content); | |
728 | } else if (msg_type === 'status') { |
|
728 | } else if (msg_type === 'status') { | |
729 | if (content.execution_state === 'busy') { |
|
729 | if (content.execution_state === 'busy') { | |
730 | IPython.kernel_status_widget.status_busy(); |
|
730 | IPython.kernel_status_widget.status_busy(); | |
731 | } else if (content.execution_state === 'idle') { |
|
731 | } else if (content.execution_state === 'idle') { | |
732 | IPython.kernel_status_widget.status_idle(); |
|
732 | IPython.kernel_status_widget.status_idle(); | |
733 | } else if (content.execution_state === 'dead') { |
|
733 | } else if (content.execution_state === 'dead') { | |
734 | this.handle_status_dead(); |
|
734 | this.handle_status_dead(); | |
735 | }; |
|
735 | }; | |
736 | } |
|
736 | } else if (msg_type === 'clear_output') { | |
|
737 | cell.clear_output(content.stdout, content.stderr, content.other); | |||
|
738 | }; | |||
737 | }; |
|
739 | }; | |
738 |
|
740 | |||
739 |
|
741 | |||
740 | Notebook.prototype.handle_status_dead = function () { |
|
742 | Notebook.prototype.handle_status_dead = function () { | |
741 | var that = this; |
|
743 | var that = this; | |
742 | this.kernel.stop_channels(); |
|
744 | this.kernel.stop_channels(); | |
743 | var dialog = $('<div/>'); |
|
745 | var dialog = $('<div/>'); | |
744 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); |
|
746 | dialog.html('The kernel has died, would you like to restart it? If you do not restart the kernel, you will be able to save the notebook, but running code will not work until the notebook is reopened.'); | |
745 | $(document).append(dialog); |
|
747 | $(document).append(dialog); | |
746 | dialog.dialog({ |
|
748 | dialog.dialog({ | |
747 | resizable: false, |
|
749 | resizable: false, | |
748 | modal: true, |
|
750 | modal: true, | |
749 | title: "Dead kernel", |
|
751 | title: "Dead kernel", | |
750 | buttons : { |
|
752 | buttons : { | |
751 | "Restart": function () { |
|
753 | "Restart": function () { | |
752 | that.start_kernel(); |
|
754 | that.start_kernel(); | |
753 | $(this).dialog('close'); |
|
755 | $(this).dialog('close'); | |
754 | }, |
|
756 | }, | |
755 | "Continue running": function () { |
|
757 | "Continue running": function () { | |
756 | $(this).dialog('close'); |
|
758 | $(this).dialog('close'); | |
757 | } |
|
759 | } | |
758 | } |
|
760 | } | |
759 | }); |
|
761 | }); | |
760 | }; |
|
762 | }; | |
761 |
|
763 | |||
762 |
|
764 | |||
763 | Notebook.prototype.handle_output = function (cell, msg_type, content) { |
|
765 | Notebook.prototype.handle_output = function (cell, msg_type, content) { | |
764 | var json = {}; |
|
766 | var json = {}; | |
765 | json.output_type = msg_type; |
|
767 | json.output_type = msg_type; | |
766 | if (msg_type === "stream") { |
|
768 | if (msg_type === "stream") { | |
767 | json.text = utils.fixConsole(content.data); |
|
769 | json.text = utils.fixConsole(content.data); | |
768 | json.stream = content.name; |
|
770 | json.stream = content.name; | |
769 | } else if (msg_type === "display_data") { |
|
771 | } else if (msg_type === "display_data") { | |
770 | json = this.convert_mime_types(json, content.data); |
|
772 | json = this.convert_mime_types(json, content.data); | |
771 | } else if (msg_type === "pyout") { |
|
773 | } else if (msg_type === "pyout") { | |
772 | json.prompt_number = content.execution_count; |
|
774 | json.prompt_number = content.execution_count; | |
773 | json = this.convert_mime_types(json, content.data); |
|
775 | json = this.convert_mime_types(json, content.data); | |
774 | } else if (msg_type === "pyerr") { |
|
776 | } else if (msg_type === "pyerr") { | |
775 | json.ename = content.ename; |
|
777 | json.ename = content.ename; | |
776 | json.evalue = content.evalue; |
|
778 | json.evalue = content.evalue; | |
777 | var traceback = []; |
|
779 | var traceback = []; | |
778 | for (var i=0; i<content.traceback.length; i++) { |
|
780 | for (var i=0; i<content.traceback.length; i++) { | |
779 | traceback.push(utils.fixConsole(content.traceback[i])); |
|
781 | traceback.push(utils.fixConsole(content.traceback[i])); | |
780 | } |
|
782 | } | |
781 | json.traceback = traceback; |
|
783 | json.traceback = traceback; | |
782 | }; |
|
784 | }; | |
783 | cell.append_output(json); |
|
785 | cell.append_output(json); | |
784 | this.dirty = true; |
|
786 | this.dirty = true; | |
785 | }; |
|
787 | }; | |
786 |
|
788 | |||
787 |
|
789 | |||
788 | Notebook.prototype.convert_mime_types = function (json, data) { |
|
790 | Notebook.prototype.convert_mime_types = function (json, data) { | |
789 | if (data['text/plain'] !== undefined) { |
|
791 | if (data['text/plain'] !== undefined) { | |
790 | json.text = utils.fixConsole(data['text/plain']); |
|
792 | json.text = utils.fixConsole(data['text/plain']); | |
791 | }; |
|
793 | }; | |
792 | if (data['text/html'] !== undefined) { |
|
794 | if (data['text/html'] !== undefined) { | |
793 | json.html = data['text/html']; |
|
795 | json.html = data['text/html']; | |
794 | }; |
|
796 | }; | |
795 | if (data['image/svg+xml'] !== undefined) { |
|
797 | if (data['image/svg+xml'] !== undefined) { | |
796 | json.svg = data['image/svg+xml']; |
|
798 | json.svg = data['image/svg+xml']; | |
797 | }; |
|
799 | }; | |
798 | if (data['image/png'] !== undefined) { |
|
800 | if (data['image/png'] !== undefined) { | |
799 | json.png = data['image/png']; |
|
801 | json.png = data['image/png']; | |
800 | }; |
|
802 | }; | |
801 | if (data['image/jpeg'] !== undefined) { |
|
803 | if (data['image/jpeg'] !== undefined) { | |
802 | json.jpeg = data['image/jpeg']; |
|
804 | json.jpeg = data['image/jpeg']; | |
803 | }; |
|
805 | }; | |
804 | if (data['text/latex'] !== undefined) { |
|
806 | if (data['text/latex'] !== undefined) { | |
805 | json.latex = data['text/latex']; |
|
807 | json.latex = data['text/latex']; | |
806 | }; |
|
808 | }; | |
807 | if (data['application/json'] !== undefined) { |
|
809 | if (data['application/json'] !== undefined) { | |
808 | json.json = data['application/json']; |
|
810 | json.json = data['application/json']; | |
809 | }; |
|
811 | }; | |
810 | if (data['application/javascript'] !== undefined) { |
|
812 | if (data['application/javascript'] !== undefined) { | |
811 | json.javascript = data['application/javascript']; |
|
813 | json.javascript = data['application/javascript']; | |
812 | } |
|
814 | } | |
813 | return json; |
|
815 | return json; | |
814 | }; |
|
816 | }; | |
815 |
|
817 | |||
816 |
|
818 | |||
817 | Notebook.prototype.execute_selected_cell = function (options) { |
|
819 | Notebook.prototype.execute_selected_cell = function (options) { | |
818 | // add_new: should a new cell be added if we are at the end of the nb |
|
820 | // add_new: should a new cell be added if we are at the end of the nb | |
819 | // terminal: execute in terminal mode, which stays in the current cell |
|
821 | // terminal: execute in terminal mode, which stays in the current cell | |
820 | default_options = {terminal: false, add_new: true} |
|
822 | default_options = {terminal: false, add_new: true} | |
821 | $.extend(default_options, options) |
|
823 | $.extend(default_options, options) | |
822 | var that = this; |
|
824 | var that = this; | |
823 | var cell = that.selected_cell(); |
|
825 | var cell = that.selected_cell(); | |
824 | var cell_index = that.find_cell_index(cell); |
|
826 | var cell_index = that.find_cell_index(cell); | |
825 | if (cell instanceof IPython.CodeCell) { |
|
827 | if (cell instanceof IPython.CodeCell) { | |
826 | cell.clear_output(); |
|
828 | cell.clear_output(true, true, true); | |
827 | var code = cell.get_code(); |
|
829 | var code = cell.get_code(); | |
828 | var msg_id = that.kernel.execute(cell.get_code()); |
|
830 | var msg_id = that.kernel.execute(cell.get_code()); | |
829 | that.msg_cell_map[msg_id] = cell.cell_id; |
|
831 | that.msg_cell_map[msg_id] = cell.cell_id; | |
830 | } else if (cell instanceof IPython.HTMLCell) { |
|
832 | } else if (cell instanceof IPython.HTMLCell) { | |
831 | cell.render(); |
|
833 | cell.render(); | |
832 | } |
|
834 | } | |
833 | if (default_options.terminal) { |
|
835 | if (default_options.terminal) { | |
834 | cell.select_all(); |
|
836 | cell.select_all(); | |
835 | } else { |
|
837 | } else { | |
836 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { |
|
838 | if ((cell_index === (that.ncells()-1)) && default_options.add_new) { | |
837 | that.insert_code_cell_below(); |
|
839 | that.insert_code_cell_below(); | |
838 | // If we are adding a new cell at the end, scroll down to show it. |
|
840 | // If we are adding a new cell at the end, scroll down to show it. | |
839 | that.scroll_to_bottom(); |
|
841 | that.scroll_to_bottom(); | |
840 | } else { |
|
842 | } else { | |
841 | that.select(cell_index+1); |
|
843 | that.select(cell_index+1); | |
842 | }; |
|
844 | }; | |
843 | }; |
|
845 | }; | |
844 | this.dirty = true; |
|
846 | this.dirty = true; | |
845 | }; |
|
847 | }; | |
846 |
|
848 | |||
847 |
|
849 | |||
848 | Notebook.prototype.execute_all_cells = function () { |
|
850 | Notebook.prototype.execute_all_cells = function () { | |
849 | var ncells = this.ncells(); |
|
851 | var ncells = this.ncells(); | |
850 | for (var i=0; i<ncells; i++) { |
|
852 | for (var i=0; i<ncells; i++) { | |
851 | this.select(i); |
|
853 | this.select(i); | |
852 | this.execute_selected_cell({add_new:false}); |
|
854 | this.execute_selected_cell({add_new:false}); | |
853 | }; |
|
855 | }; | |
854 | this.scroll_to_bottom(); |
|
856 | this.scroll_to_bottom(); | |
855 | }; |
|
857 | }; | |
856 |
|
858 | |||
857 |
|
859 | |||
858 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { |
|
860 | Notebook.prototype.complete_cell = function (cell, line, cursor_pos) { | |
859 | var msg_id = this.kernel.complete(line, cursor_pos); |
|
861 | var msg_id = this.kernel.complete(line, cursor_pos); | |
860 | this.msg_cell_map[msg_id] = cell.cell_id; |
|
862 | this.msg_cell_map[msg_id] = cell.cell_id; | |
861 | }; |
|
863 | }; | |
862 |
|
864 | |||
863 | // Persistance and loading |
|
865 | // Persistance and loading | |
864 |
|
866 | |||
865 |
|
867 | |||
866 | Notebook.prototype.fromJSON = function (data) { |
|
868 | Notebook.prototype.fromJSON = function (data) { | |
867 | var ncells = this.ncells(); |
|
869 | var ncells = this.ncells(); | |
868 | for (var i=0; i<ncells; i++) { |
|
870 | for (var i=0; i<ncells; i++) { | |
869 | // Always delete cell 0 as they get renumbered as they are deleted. |
|
871 | // Always delete cell 0 as they get renumbered as they are deleted. | |
870 | this.delete_cell(0); |
|
872 | this.delete_cell(0); | |
871 | }; |
|
873 | }; | |
872 | // Save the metadata |
|
874 | // Save the metadata | |
873 | this.metadata = data.metadata; |
|
875 | this.metadata = data.metadata; | |
874 | // Only handle 1 worksheet for now. |
|
876 | // Only handle 1 worksheet for now. | |
875 | var worksheet = data.worksheets[0]; |
|
877 | var worksheet = data.worksheets[0]; | |
876 | if (worksheet !== undefined) { |
|
878 | if (worksheet !== undefined) { | |
877 | var new_cells = worksheet.cells; |
|
879 | var new_cells = worksheet.cells; | |
878 | ncells = new_cells.length; |
|
880 | ncells = new_cells.length; | |
879 | var cell_data = null; |
|
881 | var cell_data = null; | |
880 | var new_cell = null; |
|
882 | var new_cell = null; | |
881 | for (var i=0; i<ncells; i++) { |
|
883 | for (var i=0; i<ncells; i++) { | |
882 | cell_data = new_cells[i]; |
|
884 | cell_data = new_cells[i]; | |
883 | if (cell_data.cell_type == 'code') { |
|
885 | if (cell_data.cell_type == 'code') { | |
884 | new_cell = this.insert_code_cell_below(); |
|
886 | new_cell = this.insert_code_cell_below(); | |
885 | new_cell.fromJSON(cell_data); |
|
887 | new_cell.fromJSON(cell_data); | |
886 | } else if (cell_data.cell_type === 'html') { |
|
888 | } else if (cell_data.cell_type === 'html') { | |
887 | new_cell = this.insert_html_cell_below(); |
|
889 | new_cell = this.insert_html_cell_below(); | |
888 | new_cell.fromJSON(cell_data); |
|
890 | new_cell.fromJSON(cell_data); | |
889 | } else if (cell_data.cell_type === 'markdown') { |
|
891 | } else if (cell_data.cell_type === 'markdown') { | |
890 | new_cell = this.insert_markdown_cell_below(); |
|
892 | new_cell = this.insert_markdown_cell_below(); | |
891 | new_cell.fromJSON(cell_data); |
|
893 | new_cell.fromJSON(cell_data); | |
892 | }; |
|
894 | }; | |
893 | }; |
|
895 | }; | |
894 | }; |
|
896 | }; | |
895 | }; |
|
897 | }; | |
896 |
|
898 | |||
897 |
|
899 | |||
898 | Notebook.prototype.toJSON = function () { |
|
900 | Notebook.prototype.toJSON = function () { | |
899 | var cells = this.cells(); |
|
901 | var cells = this.cells(); | |
900 | var ncells = cells.length; |
|
902 | var ncells = cells.length; | |
901 | cell_array = new Array(ncells); |
|
903 | cell_array = new Array(ncells); | |
902 | for (var i=0; i<ncells; i++) { |
|
904 | for (var i=0; i<ncells; i++) { | |
903 | cell_array[i] = cells[i].toJSON(); |
|
905 | cell_array[i] = cells[i].toJSON(); | |
904 | }; |
|
906 | }; | |
905 | data = { |
|
907 | data = { | |
906 | // Only handle 1 worksheet for now. |
|
908 | // Only handle 1 worksheet for now. | |
907 | worksheets : [{cells:cell_array}], |
|
909 | worksheets : [{cells:cell_array}], | |
908 | metadata : this.metadata |
|
910 | metadata : this.metadata | |
909 | } |
|
911 | } | |
910 | return data |
|
912 | return data | |
911 | }; |
|
913 | }; | |
912 |
|
914 | |||
913 | Notebook.prototype.save_notebook = function () { |
|
915 | Notebook.prototype.save_notebook = function () { | |
914 | if (IPython.save_widget.test_notebook_name()) { |
|
916 | if (IPython.save_widget.test_notebook_name()) { | |
915 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
917 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
916 | var nbname = IPython.save_widget.get_notebook_name(); |
|
918 | var nbname = IPython.save_widget.get_notebook_name(); | |
917 | // We may want to move the name/id/nbformat logic inside toJSON? |
|
919 | // We may want to move the name/id/nbformat logic inside toJSON? | |
918 | var data = this.toJSON(); |
|
920 | var data = this.toJSON(); | |
919 | data.metadata.name = nbname; |
|
921 | data.metadata.name = nbname; | |
920 | data.nbformat = 2; |
|
922 | data.nbformat = 2; | |
921 | // We do the call with settings so we can set cache to false. |
|
923 | // We do the call with settings so we can set cache to false. | |
922 | var settings = { |
|
924 | var settings = { | |
923 | processData : false, |
|
925 | processData : false, | |
924 | cache : false, |
|
926 | cache : false, | |
925 | type : "PUT", |
|
927 | type : "PUT", | |
926 | data : JSON.stringify(data), |
|
928 | data : JSON.stringify(data), | |
927 | headers : {'Content-Type': 'application/json'}, |
|
929 | headers : {'Content-Type': 'application/json'}, | |
928 | success : $.proxy(this.notebook_saved,this), |
|
930 | success : $.proxy(this.notebook_saved,this), | |
929 | error : $.proxy(this.notebook_save_failed,this) |
|
931 | error : $.proxy(this.notebook_save_failed,this) | |
930 | }; |
|
932 | }; | |
931 | IPython.save_widget.status_saving(); |
|
933 | IPython.save_widget.status_saving(); | |
932 | $.ajax("/notebooks/" + notebook_id, settings); |
|
934 | $.ajax("/notebooks/" + notebook_id, settings); | |
933 | }; |
|
935 | }; | |
934 | }; |
|
936 | }; | |
935 |
|
937 | |||
936 |
|
938 | |||
937 | Notebook.prototype.notebook_saved = function (data, status, xhr) { |
|
939 | Notebook.prototype.notebook_saved = function (data, status, xhr) { | |
938 | this.dirty = false; |
|
940 | this.dirty = false; | |
939 | IPython.save_widget.notebook_saved(); |
|
941 | IPython.save_widget.notebook_saved(); | |
940 | setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500); |
|
942 | setTimeout($.proxy(IPython.save_widget.status_save,IPython.save_widget),500); | |
941 | } |
|
943 | } | |
942 |
|
944 | |||
943 |
|
945 | |||
944 | Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) { |
|
946 | Notebook.prototype.notebook_save_failed = function (xhr, status, error_msg) { | |
945 | // Notify the user and reset the save button |
|
947 | // Notify the user and reset the save button | |
946 | // TODO: Handle different types of errors (timeout etc.) |
|
948 | // TODO: Handle different types of errors (timeout etc.) | |
947 | alert('An unexpected error occured while saving the notebook.'); |
|
949 | alert('An unexpected error occured while saving the notebook.'); | |
948 | setTimeout($.proxy(IPython.save_widget.reset_status,IPython.save_widget),500); |
|
950 | setTimeout($.proxy(IPython.save_widget.reset_status,IPython.save_widget),500); | |
949 | } |
|
951 | } | |
950 |
|
952 | |||
951 |
|
953 | |||
952 | Notebook.prototype.load_notebook = function (callback) { |
|
954 | Notebook.prototype.load_notebook = function (callback) { | |
953 | var that = this; |
|
955 | var that = this; | |
954 | var notebook_id = IPython.save_widget.get_notebook_id(); |
|
956 | var notebook_id = IPython.save_widget.get_notebook_id(); | |
955 | // We do the call with settings so we can set cache to false. |
|
957 | // We do the call with settings so we can set cache to false. | |
956 | var settings = { |
|
958 | var settings = { | |
957 | processData : false, |
|
959 | processData : false, | |
958 | cache : false, |
|
960 | cache : false, | |
959 | type : "GET", |
|
961 | type : "GET", | |
960 | dataType : "json", |
|
962 | dataType : "json", | |
961 | success : function (data, status, xhr) { |
|
963 | success : function (data, status, xhr) { | |
962 | that.notebook_loaded(data, status, xhr); |
|
964 | that.notebook_loaded(data, status, xhr); | |
963 | if (callback !== undefined) { |
|
965 | if (callback !== undefined) { | |
964 | callback(); |
|
966 | callback(); | |
965 | }; |
|
967 | }; | |
966 | } |
|
968 | } | |
967 | }; |
|
969 | }; | |
968 | IPython.save_widget.status_loading(); |
|
970 | IPython.save_widget.status_loading(); | |
969 | $.ajax("/notebooks/" + notebook_id, settings); |
|
971 | $.ajax("/notebooks/" + notebook_id, settings); | |
970 | } |
|
972 | } | |
971 |
|
973 | |||
972 |
|
974 | |||
973 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { |
|
975 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { | |
974 | this.fromJSON(data); |
|
976 | this.fromJSON(data); | |
975 | if (this.ncells() === 0) { |
|
977 | if (this.ncells() === 0) { | |
976 | this.insert_code_cell_below(); |
|
978 | this.insert_code_cell_below(); | |
977 | }; |
|
979 | }; | |
978 | IPython.save_widget.status_save(); |
|
980 | IPython.save_widget.status_save(); | |
979 | IPython.save_widget.set_notebook_name(data.metadata.name); |
|
981 | IPython.save_widget.set_notebook_name(data.metadata.name); | |
980 | this.start_kernel(); |
|
982 | this.start_kernel(); | |
981 | this.dirty = false; |
|
983 | this.dirty = false; | |
982 | // fromJSON always selects the last cell inserted. We need to wait |
|
984 | // fromJSON always selects the last cell inserted. We need to wait | |
983 | // until that is done before scrolling to the top. |
|
985 | // until that is done before scrolling to the top. | |
984 | setTimeout(function () { |
|
986 | setTimeout(function () { | |
985 | IPython.notebook.select(0); |
|
987 | IPython.notebook.select(0); | |
986 | IPython.notebook.scroll_to_top(); |
|
988 | IPython.notebook.scroll_to_top(); | |
987 | }, 50); |
|
989 | }, 50); | |
988 | }; |
|
990 | }; | |
989 |
|
991 | |||
990 | IPython.Notebook = Notebook; |
|
992 | IPython.Notebook = Notebook; | |
991 |
|
993 | |||
992 | return IPython; |
|
994 | return IPython; | |
993 |
|
995 | |||
994 | }(IPython)); |
|
996 | }(IPython)); | |
995 |
|
997 |
@@ -1,489 +1,495 b'' | |||||
1 | """A ZMQ-based subclass of InteractiveShell. |
|
1 | """A ZMQ-based subclass of InteractiveShell. | |
2 |
|
2 | |||
3 | This code is meant to ease the refactoring of the base InteractiveShell into |
|
3 | This code is meant to ease the refactoring of the base InteractiveShell into | |
4 | something with a cleaner architecture for 2-process use, without actually |
|
4 | something with a cleaner architecture for 2-process use, without actually | |
5 | breaking InteractiveShell itself. So we're doing something a bit ugly, where |
|
5 | breaking InteractiveShell itself. So we're doing something a bit ugly, where | |
6 | we subclass and override what we want to fix. Once this is working well, we |
|
6 | we subclass and override what we want to fix. Once this is working well, we | |
7 | can go back to the base class and refactor the code for a cleaner inheritance |
|
7 | can go back to the base class and refactor the code for a cleaner inheritance | |
8 | implementation that doesn't rely on so much monkeypatching. |
|
8 | implementation that doesn't rely on so much monkeypatching. | |
9 |
|
9 | |||
10 | But this lets us maintain a fully working IPython as we develop the new |
|
10 | But this lets us maintain a fully working IPython as we develop the new | |
11 | machinery. This should thus be thought of as scaffolding. |
|
11 | machinery. This should thus be thought of as scaffolding. | |
12 | """ |
|
12 | """ | |
13 | #----------------------------------------------------------------------------- |
|
13 | #----------------------------------------------------------------------------- | |
14 | # Imports |
|
14 | # Imports | |
15 | #----------------------------------------------------------------------------- |
|
15 | #----------------------------------------------------------------------------- | |
16 | from __future__ import print_function |
|
16 | from __future__ import print_function | |
17 |
|
17 | |||
18 | # Stdlib |
|
18 | # Stdlib | |
19 | import inspect |
|
19 | import inspect | |
20 | import os |
|
20 | import os | |
21 | import sys |
|
21 | import sys | |
22 | from subprocess import Popen, PIPE |
|
22 | from subprocess import Popen, PIPE | |
23 |
|
23 | |||
24 | # Our own |
|
24 | # Our own | |
25 | from IPython.core.interactiveshell import ( |
|
25 | from IPython.core.interactiveshell import ( | |
26 | InteractiveShell, InteractiveShellABC |
|
26 | InteractiveShell, InteractiveShellABC | |
27 | ) |
|
27 | ) | |
28 | from IPython.core import page |
|
28 | from IPython.core import page | |
29 | from IPython.core.autocall import ZMQExitAutocall |
|
29 | from IPython.core.autocall import ZMQExitAutocall | |
30 | from IPython.core.displaypub import DisplayPublisher |
|
30 | from IPython.core.displaypub import DisplayPublisher | |
31 | from IPython.core.macro import Macro |
|
31 | from IPython.core.macro import Macro | |
32 | from IPython.core.magic import MacroToEdit |
|
32 | from IPython.core.magic import MacroToEdit | |
33 | from IPython.core.payloadpage import install_payload_page |
|
33 | from IPython.core.payloadpage import install_payload_page | |
34 | from IPython.lib.kernel import ( |
|
34 | from IPython.lib.kernel import ( | |
35 | get_connection_file, get_connection_info, connect_qtconsole |
|
35 | get_connection_file, get_connection_info, connect_qtconsole | |
36 | ) |
|
36 | ) | |
37 | from IPython.utils import io |
|
37 | from IPython.utils import io | |
38 | from IPython.utils.jsonutil import json_clean |
|
38 | from IPython.utils.jsonutil import json_clean | |
39 | from IPython.utils.path import get_py_filename |
|
39 | from IPython.utils.path import get_py_filename | |
40 | from IPython.utils.process import arg_split |
|
40 | from IPython.utils.process import arg_split | |
41 | from IPython.utils.traitlets import Instance, Type, Dict, CBool |
|
41 | from IPython.utils.traitlets import Instance, Type, Dict, CBool | |
42 | from IPython.utils.warn import warn, error |
|
42 | from IPython.utils.warn import warn, error | |
43 | from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary |
|
43 | from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary | |
44 | from IPython.zmq.session import extract_header |
|
44 | from IPython.zmq.session import extract_header | |
45 | from session import Session |
|
45 | from session import Session | |
46 |
|
46 | |||
47 | #----------------------------------------------------------------------------- |
|
47 | #----------------------------------------------------------------------------- | |
48 | # Globals and side-effects |
|
48 | # Globals and side-effects | |
49 | #----------------------------------------------------------------------------- |
|
49 | #----------------------------------------------------------------------------- | |
50 |
|
50 | |||
51 | # Install the payload version of page. |
|
51 | # Install the payload version of page. | |
52 | install_payload_page() |
|
52 | install_payload_page() | |
53 |
|
53 | |||
54 | #----------------------------------------------------------------------------- |
|
54 | #----------------------------------------------------------------------------- | |
55 | # Functions and classes |
|
55 | # Functions and classes | |
56 | #----------------------------------------------------------------------------- |
|
56 | #----------------------------------------------------------------------------- | |
57 |
|
57 | |||
58 | class ZMQDisplayPublisher(DisplayPublisher): |
|
58 | class ZMQDisplayPublisher(DisplayPublisher): | |
59 | """A display publisher that publishes data using a ZeroMQ PUB socket.""" |
|
59 | """A display publisher that publishes data using a ZeroMQ PUB socket.""" | |
60 |
|
60 | |||
61 | session = Instance(Session) |
|
61 | session = Instance(Session) | |
62 | pub_socket = Instance('zmq.Socket') |
|
62 | pub_socket = Instance('zmq.Socket') | |
63 | parent_header = Dict({}) |
|
63 | parent_header = Dict({}) | |
64 |
|
64 | |||
65 | def set_parent(self, parent): |
|
65 | def set_parent(self, parent): | |
66 | """Set the parent for outbound messages.""" |
|
66 | """Set the parent for outbound messages.""" | |
67 | self.parent_header = extract_header(parent) |
|
67 | self.parent_header = extract_header(parent) | |
68 |
|
68 | |||
69 | def publish(self, source, data, metadata=None): |
|
69 | def publish(self, source, data, metadata=None): | |
70 | if metadata is None: |
|
70 | if metadata is None: | |
71 | metadata = {} |
|
71 | metadata = {} | |
72 | self._validate_data(source, data, metadata) |
|
72 | self._validate_data(source, data, metadata) | |
73 | content = {} |
|
73 | content = {} | |
74 | content['source'] = source |
|
74 | content['source'] = source | |
75 | _encode_binary(data) |
|
75 | _encode_binary(data) | |
76 | content['data'] = data |
|
76 | content['data'] = data | |
77 | content['metadata'] = metadata |
|
77 | content['metadata'] = metadata | |
78 | self.session.send( |
|
78 | self.session.send( | |
79 | self.pub_socket, u'display_data', json_clean(content), |
|
79 | self.pub_socket, u'display_data', json_clean(content), | |
80 | parent=self.parent_header |
|
80 | parent=self.parent_header | |
81 | ) |
|
81 | ) | |
82 |
|
82 | |||
|
83 | def clear_output(self, stdout=True, stderr=True, other=True): | |||
|
84 | content = dict(stdout=stdout, stderr=stderr, other=other) | |||
|
85 | self.session.send( | |||
|
86 | self.pub_socket, u'clear_output', content, | |||
|
87 | parent=self.parent_header | |||
|
88 | ) | |||
83 |
|
89 | |||
84 | class ZMQInteractiveShell(InteractiveShell): |
|
90 | class ZMQInteractiveShell(InteractiveShell): | |
85 | """A subclass of InteractiveShell for ZMQ.""" |
|
91 | """A subclass of InteractiveShell for ZMQ.""" | |
86 |
|
92 | |||
87 | displayhook_class = Type(ZMQShellDisplayHook) |
|
93 | displayhook_class = Type(ZMQShellDisplayHook) | |
88 | display_pub_class = Type(ZMQDisplayPublisher) |
|
94 | display_pub_class = Type(ZMQDisplayPublisher) | |
89 |
|
95 | |||
90 | # Override the traitlet in the parent class, because there's no point using |
|
96 | # Override the traitlet in the parent class, because there's no point using | |
91 | # readline for the kernel. Can be removed when the readline code is moved |
|
97 | # readline for the kernel. Can be removed when the readline code is moved | |
92 | # to the terminal frontend. |
|
98 | # to the terminal frontend. | |
93 | colors_force = CBool(True) |
|
99 | colors_force = CBool(True) | |
94 | readline_use = CBool(False) |
|
100 | readline_use = CBool(False) | |
95 | # autoindent has no meaning in a zmqshell, and attempting to enable it |
|
101 | # autoindent has no meaning in a zmqshell, and attempting to enable it | |
96 | # will print a warning in the absence of readline. |
|
102 | # will print a warning in the absence of readline. | |
97 | autoindent = CBool(False) |
|
103 | autoindent = CBool(False) | |
98 |
|
104 | |||
99 | exiter = Instance(ZMQExitAutocall) |
|
105 | exiter = Instance(ZMQExitAutocall) | |
100 | def _exiter_default(self): |
|
106 | def _exiter_default(self): | |
101 | return ZMQExitAutocall(self) |
|
107 | return ZMQExitAutocall(self) | |
102 |
|
108 | |||
103 | keepkernel_on_exit = None |
|
109 | keepkernel_on_exit = None | |
104 |
|
110 | |||
105 | def init_environment(self): |
|
111 | def init_environment(self): | |
106 | """Configure the user's environment. |
|
112 | """Configure the user's environment. | |
107 |
|
113 | |||
108 | """ |
|
114 | """ | |
109 | env = os.environ |
|
115 | env = os.environ | |
110 | # These two ensure 'ls' produces nice coloring on BSD-derived systems |
|
116 | # These two ensure 'ls' produces nice coloring on BSD-derived systems | |
111 | env['TERM'] = 'xterm-color' |
|
117 | env['TERM'] = 'xterm-color' | |
112 | env['CLICOLOR'] = '1' |
|
118 | env['CLICOLOR'] = '1' | |
113 | # Since normal pagers don't work at all (over pexpect we don't have |
|
119 | # Since normal pagers don't work at all (over pexpect we don't have | |
114 | # single-key control of the subprocess), try to disable paging in |
|
120 | # single-key control of the subprocess), try to disable paging in | |
115 | # subprocesses as much as possible. |
|
121 | # subprocesses as much as possible. | |
116 | env['PAGER'] = 'cat' |
|
122 | env['PAGER'] = 'cat' | |
117 | env['GIT_PAGER'] = 'cat' |
|
123 | env['GIT_PAGER'] = 'cat' | |
118 |
|
124 | |||
119 | def auto_rewrite_input(self, cmd): |
|
125 | def auto_rewrite_input(self, cmd): | |
120 | """Called to show the auto-rewritten input for autocall and friends. |
|
126 | """Called to show the auto-rewritten input for autocall and friends. | |
121 |
|
127 | |||
122 | FIXME: this payload is currently not correctly processed by the |
|
128 | FIXME: this payload is currently not correctly processed by the | |
123 | frontend. |
|
129 | frontend. | |
124 | """ |
|
130 | """ | |
125 | new = self.displayhook.prompt1.auto_rewrite() + cmd |
|
131 | new = self.displayhook.prompt1.auto_rewrite() + cmd | |
126 | payload = dict( |
|
132 | payload = dict( | |
127 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input', |
|
133 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input', | |
128 | transformed_input=new, |
|
134 | transformed_input=new, | |
129 | ) |
|
135 | ) | |
130 | self.payload_manager.write_payload(payload) |
|
136 | self.payload_manager.write_payload(payload) | |
131 |
|
137 | |||
132 | def ask_exit(self): |
|
138 | def ask_exit(self): | |
133 | """Engage the exit actions.""" |
|
139 | """Engage the exit actions.""" | |
134 | payload = dict( |
|
140 | payload = dict( | |
135 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit', |
|
141 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit', | |
136 | exit=True, |
|
142 | exit=True, | |
137 | keepkernel=self.keepkernel_on_exit, |
|
143 | keepkernel=self.keepkernel_on_exit, | |
138 | ) |
|
144 | ) | |
139 | self.payload_manager.write_payload(payload) |
|
145 | self.payload_manager.write_payload(payload) | |
140 |
|
146 | |||
141 | def _showtraceback(self, etype, evalue, stb): |
|
147 | def _showtraceback(self, etype, evalue, stb): | |
142 |
|
148 | |||
143 | exc_content = { |
|
149 | exc_content = { | |
144 | u'traceback' : stb, |
|
150 | u'traceback' : stb, | |
145 | u'ename' : unicode(etype.__name__), |
|
151 | u'ename' : unicode(etype.__name__), | |
146 | u'evalue' : unicode(evalue) |
|
152 | u'evalue' : unicode(evalue) | |
147 | } |
|
153 | } | |
148 |
|
154 | |||
149 | dh = self.displayhook |
|
155 | dh = self.displayhook | |
150 | # Send exception info over pub socket for other clients than the caller |
|
156 | # Send exception info over pub socket for other clients than the caller | |
151 | # to pick up |
|
157 | # to pick up | |
152 | exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header) |
|
158 | exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header) | |
153 |
|
159 | |||
154 | # FIXME - Hack: store exception info in shell object. Right now, the |
|
160 | # FIXME - Hack: store exception info in shell object. Right now, the | |
155 | # caller is reading this info after the fact, we need to fix this logic |
|
161 | # caller is reading this info after the fact, we need to fix this logic | |
156 | # to remove this hack. Even uglier, we need to store the error status |
|
162 | # to remove this hack. Even uglier, we need to store the error status | |
157 | # here, because in the main loop, the logic that sets it is being |
|
163 | # here, because in the main loop, the logic that sets it is being | |
158 | # skipped because runlines swallows the exceptions. |
|
164 | # skipped because runlines swallows the exceptions. | |
159 | exc_content[u'status'] = u'error' |
|
165 | exc_content[u'status'] = u'error' | |
160 | self._reply_content = exc_content |
|
166 | self._reply_content = exc_content | |
161 | # /FIXME |
|
167 | # /FIXME | |
162 |
|
168 | |||
163 | return exc_content |
|
169 | return exc_content | |
164 |
|
170 | |||
165 | #------------------------------------------------------------------------ |
|
171 | #------------------------------------------------------------------------ | |
166 | # Magic overrides |
|
172 | # Magic overrides | |
167 | #------------------------------------------------------------------------ |
|
173 | #------------------------------------------------------------------------ | |
168 | # Once the base class stops inheriting from magic, this code needs to be |
|
174 | # Once the base class stops inheriting from magic, this code needs to be | |
169 | # moved into a separate machinery as well. For now, at least isolate here |
|
175 | # moved into a separate machinery as well. For now, at least isolate here | |
170 | # the magics which this class needs to implement differently from the base |
|
176 | # the magics which this class needs to implement differently from the base | |
171 | # class, or that are unique to it. |
|
177 | # class, or that are unique to it. | |
172 |
|
178 | |||
173 | def magic_doctest_mode(self,parameter_s=''): |
|
179 | def magic_doctest_mode(self,parameter_s=''): | |
174 | """Toggle doctest mode on and off. |
|
180 | """Toggle doctest mode on and off. | |
175 |
|
181 | |||
176 | This mode is intended to make IPython behave as much as possible like a |
|
182 | This mode is intended to make IPython behave as much as possible like a | |
177 | plain Python shell, from the perspective of how its prompts, exceptions |
|
183 | plain Python shell, from the perspective of how its prompts, exceptions | |
178 | and output look. This makes it easy to copy and paste parts of a |
|
184 | and output look. This makes it easy to copy and paste parts of a | |
179 | session into doctests. It does so by: |
|
185 | session into doctests. It does so by: | |
180 |
|
186 | |||
181 | - Changing the prompts to the classic ``>>>`` ones. |
|
187 | - Changing the prompts to the classic ``>>>`` ones. | |
182 | - Changing the exception reporting mode to 'Plain'. |
|
188 | - Changing the exception reporting mode to 'Plain'. | |
183 | - Disabling pretty-printing of output. |
|
189 | - Disabling pretty-printing of output. | |
184 |
|
190 | |||
185 | Note that IPython also supports the pasting of code snippets that have |
|
191 | Note that IPython also supports the pasting of code snippets that have | |
186 | leading '>>>' and '...' prompts in them. This means that you can paste |
|
192 | leading '>>>' and '...' prompts in them. This means that you can paste | |
187 | doctests from files or docstrings (even if they have leading |
|
193 | doctests from files or docstrings (even if they have leading | |
188 | whitespace), and the code will execute correctly. You can then use |
|
194 | whitespace), and the code will execute correctly. You can then use | |
189 | '%history -t' to see the translated history; this will give you the |
|
195 | '%history -t' to see the translated history; this will give you the | |
190 | input after removal of all the leading prompts and whitespace, which |
|
196 | input after removal of all the leading prompts and whitespace, which | |
191 | can be pasted back into an editor. |
|
197 | can be pasted back into an editor. | |
192 |
|
198 | |||
193 | With these features, you can switch into this mode easily whenever you |
|
199 | With these features, you can switch into this mode easily whenever you | |
194 | need to do testing and changes to doctests, without having to leave |
|
200 | need to do testing and changes to doctests, without having to leave | |
195 | your existing IPython session. |
|
201 | your existing IPython session. | |
196 | """ |
|
202 | """ | |
197 |
|
203 | |||
198 | from IPython.utils.ipstruct import Struct |
|
204 | from IPython.utils.ipstruct import Struct | |
199 |
|
205 | |||
200 | # Shorthands |
|
206 | # Shorthands | |
201 | shell = self.shell |
|
207 | shell = self.shell | |
202 | disp_formatter = self.shell.display_formatter |
|
208 | disp_formatter = self.shell.display_formatter | |
203 | ptformatter = disp_formatter.formatters['text/plain'] |
|
209 | ptformatter = disp_formatter.formatters['text/plain'] | |
204 | # dstore is a data store kept in the instance metadata bag to track any |
|
210 | # dstore is a data store kept in the instance metadata bag to track any | |
205 | # changes we make, so we can undo them later. |
|
211 | # changes we make, so we can undo them later. | |
206 | dstore = shell.meta.setdefault('doctest_mode', Struct()) |
|
212 | dstore = shell.meta.setdefault('doctest_mode', Struct()) | |
207 | save_dstore = dstore.setdefault |
|
213 | save_dstore = dstore.setdefault | |
208 |
|
214 | |||
209 | # save a few values we'll need to recover later |
|
215 | # save a few values we'll need to recover later | |
210 | mode = save_dstore('mode', False) |
|
216 | mode = save_dstore('mode', False) | |
211 | save_dstore('rc_pprint', ptformatter.pprint) |
|
217 | save_dstore('rc_pprint', ptformatter.pprint) | |
212 | save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) |
|
218 | save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) | |
213 | save_dstore('xmode', shell.InteractiveTB.mode) |
|
219 | save_dstore('xmode', shell.InteractiveTB.mode) | |
214 |
|
220 | |||
215 | if mode == False: |
|
221 | if mode == False: | |
216 | # turn on |
|
222 | # turn on | |
217 | ptformatter.pprint = False |
|
223 | ptformatter.pprint = False | |
218 | disp_formatter.plain_text_only = True |
|
224 | disp_formatter.plain_text_only = True | |
219 | shell.magic_xmode('Plain') |
|
225 | shell.magic_xmode('Plain') | |
220 | else: |
|
226 | else: | |
221 | # turn off |
|
227 | # turn off | |
222 | ptformatter.pprint = dstore.rc_pprint |
|
228 | ptformatter.pprint = dstore.rc_pprint | |
223 | disp_formatter.plain_text_only = dstore.rc_plain_text_only |
|
229 | disp_formatter.plain_text_only = dstore.rc_plain_text_only | |
224 | shell.magic_xmode(dstore.xmode) |
|
230 | shell.magic_xmode(dstore.xmode) | |
225 |
|
231 | |||
226 | # Store new mode and inform on console |
|
232 | # Store new mode and inform on console | |
227 | dstore.mode = bool(1-int(mode)) |
|
233 | dstore.mode = bool(1-int(mode)) | |
228 | mode_label = ['OFF','ON'][dstore.mode] |
|
234 | mode_label = ['OFF','ON'][dstore.mode] | |
229 | print('Doctest mode is:', mode_label) |
|
235 | print('Doctest mode is:', mode_label) | |
230 |
|
236 | |||
231 | # Send the payload back so that clients can modify their prompt display |
|
237 | # Send the payload back so that clients can modify their prompt display | |
232 | payload = dict( |
|
238 | payload = dict( | |
233 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode', |
|
239 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode', | |
234 | mode=dstore.mode) |
|
240 | mode=dstore.mode) | |
235 | self.payload_manager.write_payload(payload) |
|
241 | self.payload_manager.write_payload(payload) | |
236 |
|
242 | |||
237 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
243 | def magic_edit(self,parameter_s='',last_call=['','']): | |
238 | """Bring up an editor and execute the resulting code. |
|
244 | """Bring up an editor and execute the resulting code. | |
239 |
|
245 | |||
240 | Usage: |
|
246 | Usage: | |
241 | %edit [options] [args] |
|
247 | %edit [options] [args] | |
242 |
|
248 | |||
243 | %edit runs an external text editor. You will need to set the command for |
|
249 | %edit runs an external text editor. You will need to set the command for | |
244 | this editor via the ``TerminalInteractiveShell.editor`` option in your |
|
250 | this editor via the ``TerminalInteractiveShell.editor`` option in your | |
245 | configuration file before it will work. |
|
251 | configuration file before it will work. | |
246 |
|
252 | |||
247 | This command allows you to conveniently edit multi-line code right in |
|
253 | This command allows you to conveniently edit multi-line code right in | |
248 | your IPython session. |
|
254 | your IPython session. | |
249 |
|
255 | |||
250 | If called without arguments, %edit opens up an empty editor with a |
|
256 | If called without arguments, %edit opens up an empty editor with a | |
251 | temporary file and will execute the contents of this file when you |
|
257 | temporary file and will execute the contents of this file when you | |
252 | close it (don't forget to save it!). |
|
258 | close it (don't forget to save it!). | |
253 |
|
259 | |||
254 |
|
260 | |||
255 | Options: |
|
261 | Options: | |
256 |
|
262 | |||
257 | -n <number>: open the editor at a specified line number. By default, |
|
263 | -n <number>: open the editor at a specified line number. By default, | |
258 | the IPython editor hook uses the unix syntax 'editor +N filename', but |
|
264 | the IPython editor hook uses the unix syntax 'editor +N filename', but | |
259 | you can configure this by providing your own modified hook if your |
|
265 | you can configure this by providing your own modified hook if your | |
260 | favorite editor supports line-number specifications with a different |
|
266 | favorite editor supports line-number specifications with a different | |
261 | syntax. |
|
267 | syntax. | |
262 |
|
268 | |||
263 | -p: this will call the editor with the same data as the previous time |
|
269 | -p: this will call the editor with the same data as the previous time | |
264 | it was used, regardless of how long ago (in your current session) it |
|
270 | it was used, regardless of how long ago (in your current session) it | |
265 | was. |
|
271 | was. | |
266 |
|
272 | |||
267 | -r: use 'raw' input. This option only applies to input taken from the |
|
273 | -r: use 'raw' input. This option only applies to input taken from the | |
268 | user's history. By default, the 'processed' history is used, so that |
|
274 | user's history. By default, the 'processed' history is used, so that | |
269 | magics are loaded in their transformed version to valid Python. If |
|
275 | magics are loaded in their transformed version to valid Python. If | |
270 | this option is given, the raw input as typed as the command line is |
|
276 | this option is given, the raw input as typed as the command line is | |
271 | used instead. When you exit the editor, it will be executed by |
|
277 | used instead. When you exit the editor, it will be executed by | |
272 | IPython's own processor. |
|
278 | IPython's own processor. | |
273 |
|
279 | |||
274 | -x: do not execute the edited code immediately upon exit. This is |
|
280 | -x: do not execute the edited code immediately upon exit. This is | |
275 | mainly useful if you are editing programs which need to be called with |
|
281 | mainly useful if you are editing programs which need to be called with | |
276 | command line arguments, which you can then do using %run. |
|
282 | command line arguments, which you can then do using %run. | |
277 |
|
283 | |||
278 |
|
284 | |||
279 | Arguments: |
|
285 | Arguments: | |
280 |
|
286 | |||
281 | If arguments are given, the following possibilites exist: |
|
287 | If arguments are given, the following possibilites exist: | |
282 |
|
288 | |||
283 | - The arguments are numbers or pairs of colon-separated numbers (like |
|
289 | - The arguments are numbers or pairs of colon-separated numbers (like | |
284 | 1 4:8 9). These are interpreted as lines of previous input to be |
|
290 | 1 4:8 9). These are interpreted as lines of previous input to be | |
285 | loaded into the editor. The syntax is the same of the %macro command. |
|
291 | loaded into the editor. The syntax is the same of the %macro command. | |
286 |
|
292 | |||
287 | - If the argument doesn't start with a number, it is evaluated as a |
|
293 | - If the argument doesn't start with a number, it is evaluated as a | |
288 | variable and its contents loaded into the editor. You can thus edit |
|
294 | variable and its contents loaded into the editor. You can thus edit | |
289 | any string which contains python code (including the result of |
|
295 | any string which contains python code (including the result of | |
290 | previous edits). |
|
296 | previous edits). | |
291 |
|
297 | |||
292 | - If the argument is the name of an object (other than a string), |
|
298 | - If the argument is the name of an object (other than a string), | |
293 | IPython will try to locate the file where it was defined and open the |
|
299 | IPython will try to locate the file where it was defined and open the | |
294 | editor at the point where it is defined. You can use `%edit function` |
|
300 | editor at the point where it is defined. You can use `%edit function` | |
295 | to load an editor exactly at the point where 'function' is defined, |
|
301 | to load an editor exactly at the point where 'function' is defined, | |
296 | edit it and have the file be executed automatically. |
|
302 | edit it and have the file be executed automatically. | |
297 |
|
303 | |||
298 | If the object is a macro (see %macro for details), this opens up your |
|
304 | If the object is a macro (see %macro for details), this opens up your | |
299 | specified editor with a temporary file containing the macro's data. |
|
305 | specified editor with a temporary file containing the macro's data. | |
300 | Upon exit, the macro is reloaded with the contents of the file. |
|
306 | Upon exit, the macro is reloaded with the contents of the file. | |
301 |
|
307 | |||
302 | Note: opening at an exact line is only supported under Unix, and some |
|
308 | Note: opening at an exact line is only supported under Unix, and some | |
303 | editors (like kedit and gedit up to Gnome 2.8) do not understand the |
|
309 | editors (like kedit and gedit up to Gnome 2.8) do not understand the | |
304 | '+NUMBER' parameter necessary for this feature. Good editors like |
|
310 | '+NUMBER' parameter necessary for this feature. Good editors like | |
305 | (X)Emacs, vi, jed, pico and joe all do. |
|
311 | (X)Emacs, vi, jed, pico and joe all do. | |
306 |
|
312 | |||
307 | - If the argument is not found as a variable, IPython will look for a |
|
313 | - If the argument is not found as a variable, IPython will look for a | |
308 | file with that name (adding .py if necessary) and load it into the |
|
314 | file with that name (adding .py if necessary) and load it into the | |
309 | editor. It will execute its contents with execfile() when you exit, |
|
315 | editor. It will execute its contents with execfile() when you exit, | |
310 | loading any code in the file into your interactive namespace. |
|
316 | loading any code in the file into your interactive namespace. | |
311 |
|
317 | |||
312 | After executing your code, %edit will return as output the code you |
|
318 | After executing your code, %edit will return as output the code you | |
313 | typed in the editor (except when it was an existing file). This way |
|
319 | typed in the editor (except when it was an existing file). This way | |
314 | you can reload the code in further invocations of %edit as a variable, |
|
320 | you can reload the code in further invocations of %edit as a variable, | |
315 | via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of |
|
321 | via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of | |
316 | the output. |
|
322 | the output. | |
317 |
|
323 | |||
318 | Note that %edit is also available through the alias %ed. |
|
324 | Note that %edit is also available through the alias %ed. | |
319 |
|
325 | |||
320 | This is an example of creating a simple function inside the editor and |
|
326 | This is an example of creating a simple function inside the editor and | |
321 | then modifying it. First, start up the editor: |
|
327 | then modifying it. First, start up the editor: | |
322 |
|
328 | |||
323 | In [1]: ed |
|
329 | In [1]: ed | |
324 | Editing... done. Executing edited code... |
|
330 | Editing... done. Executing edited code... | |
325 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' |
|
331 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' | |
326 |
|
332 | |||
327 | We can then call the function foo(): |
|
333 | We can then call the function foo(): | |
328 |
|
334 | |||
329 | In [2]: foo() |
|
335 | In [2]: foo() | |
330 | foo() was defined in an editing session |
|
336 | foo() was defined in an editing session | |
331 |
|
337 | |||
332 | Now we edit foo. IPython automatically loads the editor with the |
|
338 | Now we edit foo. IPython automatically loads the editor with the | |
333 | (temporary) file where foo() was previously defined: |
|
339 | (temporary) file where foo() was previously defined: | |
334 |
|
340 | |||
335 | In [3]: ed foo |
|
341 | In [3]: ed foo | |
336 | Editing... done. Executing edited code... |
|
342 | Editing... done. Executing edited code... | |
337 |
|
343 | |||
338 | And if we call foo() again we get the modified version: |
|
344 | And if we call foo() again we get the modified version: | |
339 |
|
345 | |||
340 | In [4]: foo() |
|
346 | In [4]: foo() | |
341 | foo() has now been changed! |
|
347 | foo() has now been changed! | |
342 |
|
348 | |||
343 | Here is an example of how to edit a code snippet successive |
|
349 | Here is an example of how to edit a code snippet successive | |
344 | times. First we call the editor: |
|
350 | times. First we call the editor: | |
345 |
|
351 | |||
346 | In [5]: ed |
|
352 | In [5]: ed | |
347 | Editing... done. Executing edited code... |
|
353 | Editing... done. Executing edited code... | |
348 | hello |
|
354 | hello | |
349 | Out[5]: "print 'hello'n" |
|
355 | Out[5]: "print 'hello'n" | |
350 |
|
356 | |||
351 | Now we call it again with the previous output (stored in _): |
|
357 | Now we call it again with the previous output (stored in _): | |
352 |
|
358 | |||
353 | In [6]: ed _ |
|
359 | In [6]: ed _ | |
354 | Editing... done. Executing edited code... |
|
360 | Editing... done. Executing edited code... | |
355 | hello world |
|
361 | hello world | |
356 | Out[6]: "print 'hello world'n" |
|
362 | Out[6]: "print 'hello world'n" | |
357 |
|
363 | |||
358 | Now we call it with the output #8 (stored in _8, also as Out[8]): |
|
364 | Now we call it with the output #8 (stored in _8, also as Out[8]): | |
359 |
|
365 | |||
360 | In [7]: ed _8 |
|
366 | In [7]: ed _8 | |
361 | Editing... done. Executing edited code... |
|
367 | Editing... done. Executing edited code... | |
362 | hello again |
|
368 | hello again | |
363 | Out[7]: "print 'hello again'n" |
|
369 | Out[7]: "print 'hello again'n" | |
364 | """ |
|
370 | """ | |
365 |
|
371 | |||
366 | opts,args = self.parse_options(parameter_s,'prn:') |
|
372 | opts,args = self.parse_options(parameter_s,'prn:') | |
367 |
|
373 | |||
368 | try: |
|
374 | try: | |
369 | filename, lineno, _ = self._find_edit_target(args, opts, last_call) |
|
375 | filename, lineno, _ = self._find_edit_target(args, opts, last_call) | |
370 | except MacroToEdit as e: |
|
376 | except MacroToEdit as e: | |
371 | # TODO: Implement macro editing over 2 processes. |
|
377 | # TODO: Implement macro editing over 2 processes. | |
372 | print("Macro editing not yet implemented in 2-process model.") |
|
378 | print("Macro editing not yet implemented in 2-process model.") | |
373 | return |
|
379 | return | |
374 |
|
380 | |||
375 | # Make sure we send to the client an absolute path, in case the working |
|
381 | # Make sure we send to the client an absolute path, in case the working | |
376 | # directory of client and kernel don't match |
|
382 | # directory of client and kernel don't match | |
377 | filename = os.path.abspath(filename) |
|
383 | filename = os.path.abspath(filename) | |
378 |
|
384 | |||
379 | payload = { |
|
385 | payload = { | |
380 | 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic', |
|
386 | 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic', | |
381 | 'filename' : filename, |
|
387 | 'filename' : filename, | |
382 | 'line_number' : lineno |
|
388 | 'line_number' : lineno | |
383 | } |
|
389 | } | |
384 | self.payload_manager.write_payload(payload) |
|
390 | self.payload_manager.write_payload(payload) | |
385 |
|
391 | |||
386 | def magic_gui(self, *args, **kwargs): |
|
392 | def magic_gui(self, *args, **kwargs): | |
387 | raise NotImplementedError( |
|
393 | raise NotImplementedError( | |
388 | 'Kernel GUI support is not implemented yet, except for --pylab.') |
|
394 | 'Kernel GUI support is not implemented yet, except for --pylab.') | |
389 |
|
395 | |||
390 | def magic_pylab(self, *args, **kwargs): |
|
396 | def magic_pylab(self, *args, **kwargs): | |
391 | raise NotImplementedError( |
|
397 | raise NotImplementedError( | |
392 | 'pylab support must be enabled in command line options.') |
|
398 | 'pylab support must be enabled in command line options.') | |
393 |
|
399 | |||
394 | # A few magics that are adapted to the specifics of using pexpect and a |
|
400 | # A few magics that are adapted to the specifics of using pexpect and a | |
395 | # remote terminal |
|
401 | # remote terminal | |
396 |
|
402 | |||
397 | def magic_clear(self, arg_s): |
|
403 | def magic_clear(self, arg_s): | |
398 | """Clear the terminal.""" |
|
404 | """Clear the terminal.""" | |
399 | if os.name == 'posix': |
|
405 | if os.name == 'posix': | |
400 | self.shell.system("clear") |
|
406 | self.shell.system("clear") | |
401 | else: |
|
407 | else: | |
402 | self.shell.system("cls") |
|
408 | self.shell.system("cls") | |
403 |
|
409 | |||
404 | if os.name == 'nt': |
|
410 | if os.name == 'nt': | |
405 | # This is the usual name in windows |
|
411 | # This is the usual name in windows | |
406 | magic_cls = magic_clear |
|
412 | magic_cls = magic_clear | |
407 |
|
413 | |||
408 | # Terminal pagers won't work over pexpect, but we do have our own pager |
|
414 | # Terminal pagers won't work over pexpect, but we do have our own pager | |
409 |
|
415 | |||
410 | def magic_less(self, arg_s): |
|
416 | def magic_less(self, arg_s): | |
411 | """Show a file through the pager. |
|
417 | """Show a file through the pager. | |
412 |
|
418 | |||
413 | Files ending in .py are syntax-highlighted.""" |
|
419 | Files ending in .py are syntax-highlighted.""" | |
414 | cont = open(arg_s).read() |
|
420 | cont = open(arg_s).read() | |
415 | if arg_s.endswith('.py'): |
|
421 | if arg_s.endswith('.py'): | |
416 | cont = self.shell.pycolorize(cont) |
|
422 | cont = self.shell.pycolorize(cont) | |
417 | page.page(cont) |
|
423 | page.page(cont) | |
418 |
|
424 | |||
419 | magic_more = magic_less |
|
425 | magic_more = magic_less | |
420 |
|
426 | |||
421 | # Man calls a pager, so we also need to redefine it |
|
427 | # Man calls a pager, so we also need to redefine it | |
422 | if os.name == 'posix': |
|
428 | if os.name == 'posix': | |
423 | def magic_man(self, arg_s): |
|
429 | def magic_man(self, arg_s): | |
424 | """Find the man page for the given command and display in pager.""" |
|
430 | """Find the man page for the given command and display in pager.""" | |
425 | page.page(self.shell.getoutput('man %s | col -b' % arg_s, |
|
431 | page.page(self.shell.getoutput('man %s | col -b' % arg_s, | |
426 | split=False)) |
|
432 | split=False)) | |
427 |
|
433 | |||
428 | # FIXME: this is specific to the GUI, so we should let the gui app load |
|
434 | # FIXME: this is specific to the GUI, so we should let the gui app load | |
429 | # magics at startup that are only for the gui. Once the gui app has proper |
|
435 | # magics at startup that are only for the gui. Once the gui app has proper | |
430 | # profile and configuration management, we can have it initialize a kernel |
|
436 | # profile and configuration management, we can have it initialize a kernel | |
431 | # with a special config file that provides these. |
|
437 | # with a special config file that provides these. | |
432 | def magic_guiref(self, arg_s): |
|
438 | def magic_guiref(self, arg_s): | |
433 | """Show a basic reference about the GUI console.""" |
|
439 | """Show a basic reference about the GUI console.""" | |
434 | from IPython.core.usage import gui_reference |
|
440 | from IPython.core.usage import gui_reference | |
435 | page.page(gui_reference, auto_html=True) |
|
441 | page.page(gui_reference, auto_html=True) | |
436 |
|
442 | |||
437 | def magic_connect_info(self, arg_s): |
|
443 | def magic_connect_info(self, arg_s): | |
438 | """Print information for connecting other clients to this kernel |
|
444 | """Print information for connecting other clients to this kernel | |
439 |
|
445 | |||
440 | It will print the contents of this session's connection file, as well as |
|
446 | It will print the contents of this session's connection file, as well as | |
441 | shortcuts for local clients. |
|
447 | shortcuts for local clients. | |
442 |
|
448 | |||
443 | In the simplest case, when called from the most recently launched kernel, |
|
449 | In the simplest case, when called from the most recently launched kernel, | |
444 | secondary clients can be connected, simply with: |
|
450 | secondary clients can be connected, simply with: | |
445 |
|
451 | |||
446 | $> ipython <app> --existing |
|
452 | $> ipython <app> --existing | |
447 |
|
453 | |||
448 | """ |
|
454 | """ | |
449 | try: |
|
455 | try: | |
450 | connection_file = get_connection_file() |
|
456 | connection_file = get_connection_file() | |
451 | info = get_connection_info(unpack=False) |
|
457 | info = get_connection_info(unpack=False) | |
452 | except Exception as e: |
|
458 | except Exception as e: | |
453 | error("Could not get connection info: %r" % e) |
|
459 | error("Could not get connection info: %r" % e) | |
454 | return |
|
460 | return | |
455 |
|
461 | |||
456 | print (info + '\n') |
|
462 | print (info + '\n') | |
457 | print ("Paste the above JSON into a file, and connect with:\n" |
|
463 | print ("Paste the above JSON into a file, and connect with:\n" | |
458 | " $> ipython <app> --existing <file>\n" |
|
464 | " $> ipython <app> --existing <file>\n" | |
459 | "or, if you are local, you can connect with just:\n" |
|
465 | "or, if you are local, you can connect with just:\n" | |
460 | " $> ipython <app> --existing %s\n" |
|
466 | " $> ipython <app> --existing %s\n" | |
461 | "or even just:\n" |
|
467 | "or even just:\n" | |
462 | " $> ipython <app> --existing\n" |
|
468 | " $> ipython <app> --existing\n" | |
463 | "if this is the most recent IPython session you have started." |
|
469 | "if this is the most recent IPython session you have started." | |
464 | % os.path.basename(connection_file) |
|
470 | % os.path.basename(connection_file) | |
465 | ) |
|
471 | ) | |
466 |
|
472 | |||
467 | def magic_qtconsole(self, arg_s): |
|
473 | def magic_qtconsole(self, arg_s): | |
468 | """Open a qtconsole connected to this kernel. |
|
474 | """Open a qtconsole connected to this kernel. | |
469 |
|
475 | |||
470 | Useful for connecting a qtconsole to running notebooks, for better |
|
476 | Useful for connecting a qtconsole to running notebooks, for better | |
471 | debugging. |
|
477 | debugging. | |
472 | """ |
|
478 | """ | |
473 | try: |
|
479 | try: | |
474 | p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix')) |
|
480 | p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix')) | |
475 | except Exception as e: |
|
481 | except Exception as e: | |
476 | error("Could not start qtconsole: %r" % e) |
|
482 | error("Could not start qtconsole: %r" % e) | |
477 | return |
|
483 | return | |
478 |
|
484 | |||
479 |
|
485 | |||
480 | def set_next_input(self, text): |
|
486 | def set_next_input(self, text): | |
481 | """Send the specified text to the frontend to be presented at the next |
|
487 | """Send the specified text to the frontend to be presented at the next | |
482 | input cell.""" |
|
488 | input cell.""" | |
483 | payload = dict( |
|
489 | payload = dict( | |
484 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input', |
|
490 | source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input', | |
485 | text=text |
|
491 | text=text | |
486 | ) |
|
492 | ) | |
487 | self.payload_manager.write_payload(payload) |
|
493 | self.payload_manager.write_payload(payload) | |
488 |
|
494 | |||
489 | InteractiveShellABC.register(ZMQInteractiveShell) |
|
495 | InteractiveShellABC.register(ZMQInteractiveShell) |
General Comments 0
You need to be logged in to leave comments.
Login now