Skip to content
This repository

ReST support in notebook frontend #873

Closed
wants to merge 1 commit into from

4 participants

Julien Jehannet Min RK Fernando Perez Brian E. Granger
Julien Jehannet

Hello,

I'm working on the integration of the notebook app into the Logilab's framework named CubicWeb.

http://www.cubicweb.org

Here a first patch about minor changes to enable ReST format in frontend.

Cheers from Logilab !

Min RK
Owner

Thanks! This is a good start.

We do have plans for rst support, but I think it will have be rendered whole document at a time. The reason rst cells have been disabled is that if cells are rendered on their own, they do not behave as expected. For instance, section levels will not be respected across cells, cross-cell links will not resolve, etc.

Julien Jehannet

Ok, I see. @minrk: could you put your requirements in a new ticket, please ? So, I could maybe provide useful code then.

In a second time, I hope to provide some changes to make the ajax call configurable to connect to a different rendering server (instead of tornado by default)

Min RK
Owner

Sure thing, I'll try to describe what we need.

Min RK
Owner

My recollections of our ReST discussions are now in #888.

Fernando Perez
Owner

@jjehannet, I've also added a number of further points on this to #888 from a recent discussion we had on email... Thanks again for pitching in, this is a hugely important feature so we will get to it; it's just that it's also non-trivial so it will deserve (and require) a bit of design/thought up front.

Fernando Perez
Owner

@jjehannet, I've played with the code and it's indeed a great start, but as @minrk pointed out, we'll need to back off from rendering reST for now, because it's simply too easy to trigger a docutils error. For example, right now if you have one cell with:

.. _example:

An example
========

blah...

and another with:

as we see in the example_ above, blah...

the second one produces a "Docutils System Messages" result with an "unknown target name" for the "example" target.

So I think that in the long run, we'll probably want a solution that does:

  • per-cell rendering with manually controlled docutils errors, so that unresolved references are just left alone. This would render basic things, in-cell references and simple markup, but leave the rest as-is.

  • have a button/option that forces a render of the whole document and updates all the cells. This may not be completely trivial to write, as the default html writer in docutils just returns a whole blob, and we'll need a way to get per-cell output to put it back in place.

  • export to reST on-disk for production of full-quality sphinx-based html and pdf.

Now, it seems there's already useful code in this PR, so we could start merging things piece by piece, as the full effort will be a big job that will take some time. But in its current form we can't merge it quite yet. I see when I run the notebook it's dumping the html out to the terminal, but I don't know where that's coming from, since your code doesn't have printing. Perhaps those were in the old reST code that @ellisonbg was prototyping? In any case, they should be silenced and turned into logging calls at best, so they aren't seen in normal usage.

So question to everyone participating: what do we do with this specific PR? Do we try to polish it and merge it in as a first step on the road towards reST support, or do you think we need to start over with a different approach? I just want to reach a conclusion with this one before it starts having merge conflicts...

Brian E. Granger
Owner

As we add reST cells we need to move to a model where the cell type is selected by a select menu/box rather than clicking on a button. This will require substantial refactoring but will more easily open the door to adding other cells types, such as the heading cells @fperez discusses. I guess I am 50/50 on simply aborting this PR. But, if we do allow it to live on, we need to remove the reST rendering that is there now.

Fernando Perez
Owner

@jjehannet, would you wan to rebase and refactor it to remove the rendering part, so we merge this bit only as an incremental first step towards the model @ellisonbg describes? Or do you prefer to close this PR and work from scratch on the whole problem as discussed above and in more detail in #888?

Fernando Perez
Owner

I should have said more explicitly that in any event, a rebase is needed right now, because it currently doesn't apply cleanly anymore.

Julien Jehannet

@fperez: Sorry, I'm afraid I will only refresh the patch for now. I hope to work on it tomorrow.
I will rebase the whole thing (and try to fix the console output as well).

IMO, there is another approach: instead of using just one cell content, we could try to rendering the whole document every time and redispatch cell output afterwards. Not very elegant (!) but we could test a prototype before rejecting.

Brian E. Granger
Owner
Fernando Perez
Owner
Brian E. Granger
Owner
Brian E. Granger
Owner

RST support is being added in PR #1331.

Brian E. Granger ellisonbg closed this January 27, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Oct 14, 2011
ReST support in notebook frontend ed90329
This page is out of date. Refresh to see the latest.
78  IPython/frontend/html/notebook/static/js/notebook.js
@@ -100,6 +100,11 @@ var IPython = (function (IPython) {
100 100
                 that.to_markdown();
101 101
                 that.control_key_active = false;
102 102
                 return false;
  103
+            } else if (event.which === 82 && that.control_key_active) {
  104
+                // To reStructuredText = r
  105
+                that.to_rst();
  106
+                that.control_key_active = false;
  107
+                return false;
103 108
             } else if (event.which === 84 && that.control_key_active) {
104 109
                 // Toggle output = t
105 110
                 that.toggle_output();
@@ -195,6 +200,7 @@ var IPython = (function (IPython) {
195 200
             {key: 'Ctrl-m k', help: 'move cell up'},
196 201
             {key: 'Ctrl-m c', help: 'code cell'},
197 202
             {key: 'Ctrl-m m', help: 'markdown cell'},
  203
+            {key: 'Ctrl-m r', help: 'reStructuredText cell'},
198 204
             {key: 'Ctrl-m p', help: 'select previous'},
199 205
             {key: 'Ctrl-m n', help: 'select next'},
200 206
             {key: 'Ctrl-m h', help: 'display keyboard shortcuts'}
@@ -463,6 +469,15 @@ var IPython = (function (IPython) {
463 469
         return cell;
464 470
     }
465 471
 
  472
+    Notebook.prototype.insert_rst_cell_above = function (index) {
  473
+        // TODO: Bounds check for i
  474
+        var i = this.index_or_selected(index);
  475
+        var cell = new IPython.RSTCell(this);
  476
+        cell.config_mathjax();
  477
+        this.insert_cell_above(cell, i);
  478
+        this.select(this.find_cell_index(cell));
  479
+        return cell;
  480
+    }
466 481
 
467 482
     Notebook.prototype.insert_markdown_cell_above = function (index) {
468 483
         // TODO: Bounds check for i
@@ -474,6 +489,15 @@ var IPython = (function (IPython) {
474 489
         return cell;
475 490
     }
476 491
 
  492
+    Notebook.prototype.insert_rst_cell_below = function (index) {
  493
+        // TODO: Bounds check for i
  494
+        var i = this.index_or_selected(index);
  495
+        var cell = new IPython.RSTCell(this);
  496
+        cell.config_mathjax();
  497
+        this.insert_cell_below(cell, i);
  498
+        this.select(this.find_cell_index(cell));
  499
+        return cell;
  500
+    }
477 501
 
478 502
     Notebook.prototype.insert_markdown_cell_below = function (index) {
479 503
         // TODO: Bounds check for i
@@ -492,6 +516,7 @@ var IPython = (function (IPython) {
492 516
         var source_element = this.cell_elements().eq(i);
493 517
         var source_cell = source_element.data("cell");
494 518
         if (source_cell instanceof IPython.HTMLCell || 
  519
+            source_cell instanceof IPython.RSTCell || 
495 520
             source_cell instanceof IPython.MarkdownCell) {
496 521
             this.insert_code_cell_below(i);
497 522
             var target_cell = this.cells()[i+1];
@@ -502,6 +527,40 @@ var IPython = (function (IPython) {
502 527
         this.dirty = true;
503 528
     };
504 529
 
  530
+    Notebook.prototype.to_rst = function (index) {
  531
+        // TODO: Bounds check for i
  532
+        var i = this.index_or_selected(index);
  533
+        var source_element = this.cell_elements().eq(i);
  534
+        var source_cell = source_element.data("cell");
  535
+        var target_cell = null;
  536
+        if (source_cell instanceof IPython.CodeCell) {
  537
+            this.insert_rst_cell_below(i);
  538
+            var target_cell = this.cells()[i+1];
  539
+            var text = source_cell.get_code();
  540
+        } else if (source_cell instanceof IPython.MarkdownCell) {
  541
+            this.insert_rst_cell_below(i);
  542
+            var target_cell = this.cells()[i+1];
  543
+            var text = source_cell.get_source();
  544
+            if (text === source_cell.placeholder) {
  545
+                text = target_cell.placeholder;
  546
+            }
  547
+        } else if (source_cell instanceof IPython.HTMLCell) {
  548
+            this.insert_rst_cell_below(i);
  549
+            var target_cell = this.cells()[i+1];
  550
+            var text = source_cell.get_source();
  551
+            if (text === source_cell.placeholder) {
  552
+                text = target_cell.placeholder;
  553
+            }
  554
+        }
  555
+        if (target_cell !== null) {
  556
+            if (text === "") {text = target_cell.placeholder;};
  557
+            target_cell.set_source(text);
  558
+            target_cell.render();
  559
+            source_element.remove();
  560
+            target_cell.edit();
  561
+        }
  562
+        this.dirty = true;
  563
+    };
505 564
 
506 565
     Notebook.prototype.to_markdown = function (index) {
507 566
         // TODO: Bounds check for i
@@ -520,6 +579,13 @@ var IPython = (function (IPython) {
520 579
             if (text === source_cell.placeholder) {
521 580
                 text = target_cell.placeholder;
522 581
             }
  582
+        } else if (source_cell instanceof IPython.RSTCell) {
  583
+            this.insert_html_cell_below(i);
  584
+            var target_cell = this.cells()[i+1];
  585
+            var text = source_cell.get_source();
  586
+            if (text === source_cell.placeholder) {
  587
+                text = target_cell.placeholder;
  588
+            }
523 589
         }
524 590
         if (target_cell !== null) {
525 591
             if (text === "") {text = target_cell.placeholder;};
@@ -548,6 +614,13 @@ var IPython = (function (IPython) {
548 614
             if (text === source_cell.placeholder) {
549 615
                 text = target_cell.placeholder;
550 616
             }
  617
+        } else if (source_cell instanceof IPython.RSTCell) {
  618
+            this.insert_html_cell_below(i);
  619
+            var target_cell = this.cells()[i+1];
  620
+            var text = source_cell.get_source();
  621
+            if (text === source_cell.placeholder) {
  622
+                text = target_cell.placeholder;
  623
+            }
551 624
         }
552 625
         if (target_cell !== null) {
553 626
             if (text === "") {text = target_cell.placeholder;};
@@ -835,8 +908,11 @@ var IPython = (function (IPython) {
835 908
                 } else if (cell_data.cell_type === 'markdown') {
836 909
                     new_cell = this.insert_markdown_cell_below();
837 910
                     new_cell.fromJSON(cell_data);
  911
+                } else if (cell_data.cell_type === 'rst') {
  912
+                    new_cell = this.insert_rst_cell_below();
  913
+                    new_cell.fromJSON(cell_data);
838 914
                 };
839  
-            };          
  915
+            };
840 916
         };
841 917
     };
842 918
 
3  IPython/frontend/html/notebook/static/js/panelsection.js
@@ -164,6 +164,9 @@ var IPython = (function (IPython) {
164 164
         this.content.find('#to_markdown').click(function () {
165 165
             IPython.notebook.to_markdown();
166 166
         });
  167
+        this.content.find('#to_rst').click(function () {
  168
+            IPython.notebook.to_rst();
  169
+        });
167 170
         this.content.find('#run_selected_cell').click(function () {
168 171
             IPython.notebook.execute_selected_cell();
169 172
         });
10  IPython/frontend/html/notebook/static/js/textcell.js
@@ -223,8 +223,9 @@ var IPython = (function (IPython) {
223 223
 
224 224
     var RSTCell = function (notebook) {
225 225
         this.placeholder = "\u0000Type *ReStructured Text* and LaTeX: $\\alpha^2$";
226  
-        IPython.TextCell.apply(this, arguments);
  226
+        this.rendered = false;
227 227
         this.cell_type = 'rst';
  228
+        IPython.TextCell.apply(this, arguments);
228 229
     };
229 230
 
230 231
 
@@ -232,21 +233,22 @@ var IPython = (function (IPython) {
232 233
 
233 234
 
234 235
     RSTCell.prototype.render = function () {
235  
-        if (this.rendered === false) {  
  236
+        if (this.rendered === false) {
236 237
             var text = this.get_source();
237 238
             if (text === "") {text = this.placeholder;};
238 239
             var settings = {
239 240
                 processData : false,
  241
+                dataType: 'html',
240 242
                 cache : false,
241 243
                 type : "POST",
242 244
                 data : text,
243 245
                 headers : {'Content-Type': 'application/x-rst'},
244  
-                success : $.proxy(this.handle_render,this)
  246
+                success : $.proxy(this.handle_render, this)
245 247
             };
246 248
             $.ajax("/rstservice/render", settings);
247 249
             this.element.find('div.text_cell_input').hide();
248  
-            this.element.find("div.text_cell_render").show();
249 250
             this.set_rendered("Rendering...");
  251
+            this.element.find("div.text_cell_render").show();
250 252
         };
251 253
     };
252 254
 
1  IPython/frontend/html/notebook/templates/notebook.html
@@ -98,6 +98,7 @@ <h3 class="section_header">Cell</h3>
98 98
                         <button id="to_code"><u>C</u>ode</button>
99 99
 <!--                        <button id="to_html">HTML</button>-->
100 100
                         <button id="to_markdown"><u>M</u>arkdown</button>
  101
+                        <button id="to_rst"><u>R</u>eST</button>
101 102
                     </span>
102 103
                      <span class="button_label">Format</span> 
103 104
                 </div>
16  IPython/nbformat/v2/nbpy.py
@@ -58,6 +58,12 @@ def to_notebook(self, s, **kwargs):
58 58
                     cells.append(cell)
59 59
                 state = u'markdowncell'
60 60
                 cell_lines = []
  61
+            elif line.startswith(u'# <rstdowncell>'):
  62
+                cell = self.new_cell(state, cell_lines)
  63
+                if cell is not None:
  64
+                    cells.append(cell)
  65
+                state = u'rst'
  66
+                cell_lines = []
61 67
             else:
62 68
                 cell_lines.append(line)
63 69
         if cell_lines and state == u'codecell':
@@ -82,6 +88,10 @@ def new_cell(self, state, lines):
82 88
             text = self._remove_comments(lines)
83 89
             if text:
84 90
                 return new_text_cell(u'markdown',source=text)
  91
+        elif state == u'rstcell':
  92
+            text = self._remove_comments(lines)
  93
+            if text:
  94
+                return new_text_cell(u'rst',source=text)
85 95
 
86 96
     def _remove_comments(self, lines):
87 97
         new_lines = []
@@ -132,6 +142,12 @@ def writes(self, nb, **kwargs):
132 142
                         lines.extend([u'# <markdowncell>',u''])
133 143
                         lines.extend([u'# ' + line for line in input.splitlines()])
134 144
                         lines.append(u'')
  145
+                elif cell.cell_type == u'rst':
  146
+                    input = cell.get(u'source')
  147
+                    if input is not None:
  148
+                        lines.extend([u'# <rstcell>',u''])
  149
+                        lines.extend([u'# ' + line for line in input.splitlines()])
  150
+                        lines.append(u'')
135 151
         lines.append('')
136 152
         return unicode('\n'.join(lines))
137 153
 
4  IPython/nbformat/v2/nbxml.py
@@ -172,6 +172,10 @@ def to_notebook(self, root, **kwargs):
172 172
                     source = _get_text(cell_e,u'source')
173 173
                     rendered = _get_text(cell_e,u'rendered')
174 174
                     cells.append(new_text_cell(u'markdown', source=source, rendered=rendered))
  175
+                if cell_e.tag == u'rstcell':
  176
+                    source = _get_text(cell_e,u'source')
  177
+                    rendered = _get_text(cell_e,u'rendered')
  178
+                    cells.append(new_text_cell(u'rst', source=source, rendered=rendered))
175 179
             ws = new_worksheet(name=wsname,cells=cells)
176 180
             worksheets.append(ws)
177 181
 
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.