Created
May 10, 2014 16:58
-
-
Save asford/89d49168923d5dd343b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"name": "", | |
"signature": "sha256:aa80de3b5274221258ac3d45888e886c7895584b0774b2d985661159674e9f99" | |
}, | |
"nbformat": 3, | |
"nbformat_minor": 0, | |
"worksheets": [ | |
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"more vim!\n", | |
"=========" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"This is a markdown cell which contains script tags and the bits of code which will be reused in the cells which follow.\n", | |
"\n", | |
"```javascript\n", | |
"var cmd = IPython.keyboard_manager.command_shortcuts;\n", | |
"var edit = IPython.keyboard_manager.edit_shortcuts;\n", | |
"var def_cmd = IPython.default_command_shortcuts;\n", | |
"var def_edit = IPython.default_edit_shortcuts;\n", | |
"```\n", | |
"<script>\n", | |
"var cmd = IPython.keyboard_manager.command_shortcuts;\n", | |
"var edit = IPython.keyboard_manager.edit_shortcuts;\n", | |
"var def_cmd = IPython.default_command_shortcuts;\n", | |
"var def_edit = IPython.default_edit_shortcuts;\n", | |
"\n", | |
"// get the code mirror editor of a curently selected cell\n", | |
"function C() { return IPython.notebook.get_selected_cell().code_mirror; };\n", | |
"\n", | |
"// change the mode of all current and future CodeMirror instances\n", | |
"function to(mode) {\n", | |
" var mode = mode || 'vim'\n", | |
" // first let's apply vim mode to all current cells\n", | |
" function to_mode(c) { return c.code_mirror.setOption('keyMap', mode);};\n", | |
" IPython.notebook.get_cells().map(to_mode);\n", | |
" // apply the mode to future cells created\n", | |
" IPython.Cell.options_default.cm_config.keyMap = mode;\n", | |
"}\n", | |
"\n", | |
"// Grab the CodeMirror vim keymap\n", | |
"$.getScript(\"/static/components/codemirror/keymap/vim.js\")\n", | |
"\n", | |
"// also make search work\n", | |
"$.getScript(\"/static/components/codemirror/addon/search/search.js\");\n", | |
"$.getScript(\"/static/components/codemirror/addon/search/searchcursor.js\");\n", | |
"// WARNING\n", | |
"//$.getScript(\"/static/components/codemirror/addon/dialog/dialog.js\");\n", | |
"//$.getScript(\"/static/components/codemirror/addon/dialog/dialog.css\");\n", | |
"\n", | |
"\n", | |
"// on all code mirror instances on this page, apply the function f\n", | |
"function all_cm(f) {\n", | |
" // apply f to every code mirror instance. f takes one parameter\n", | |
" IPython.notebook.get_cells().map(function (c) { f(c.code_mirror); } );\n", | |
"}\n", | |
"</script>" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"to('vim')" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"to('vim')" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f91250>" | |
] | |
} | |
], | |
"prompt_number": 8 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"*You* probably will never need this, but for completeness, here how you can reset CodeMirror mode to the default." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// you can call this to restore the edit mode for mere mortals\n", | |
"//to('default')" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"// you can call this to restore the edit mode for mere mortals\n", | |
"//to('default')" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x36f7cd0>" | |
] | |
} | |
], | |
"prompt_number": 41 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Most important - entering command mode\n", | |
"---\n", | |
"\n", | |
"One of the most important keys is how you get to command mode. Indeed, it's not\n", | |
"so much how you get into command mode, as it is how you **escape** from other\n", | |
"modes ;) \n", | |
"\n", | |
"By default, `Esc` will enter command mode, but the more seasoned vim users have some tricks up their sleeves to not have to move our hands all the way to the corner of the keyboard. As far as *I'm* concerned, the **right** way is to rebind your `Caps` key to be another `Ctrl`, and then type `Ctrl-[`, which is the equivalent of `Esc` in the terminal.\n", | |
"\n", | |
"you'll note that `Ctrl-[` works in codemirror ( [you're welcome ;)](https://github.com/marijnh/CodeMirror/commit/95520892742eacd9d560084f00ef5ec0376b0bba) )\n", | |
"\n", | |
"Note, there's current a bug where `Ctrl-[` doesn't leave visual mode, I've submitted a [tiny patch upstream](https://github.com/marijnh/CodeMirror/pull/2206)\n", | |
"\n", | |
"That works in CodeMirror, but it doesn't work in the notebook. Let's fix that:\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// N.B. This code looks fairly simple, but it took me forever to \n", | |
"// figure out how to do this, \n", | |
"// \n", | |
"// there's a problem here, Ctrl-[ is already handled by CodeMirror by the time we \n", | |
"// (IPython.keyboard_manager) get it CodeMirror issues signals on mode change, \n", | |
"// so we have to hook into that to get Ctrl-[\n", | |
"edit.remove_shortcut('Ctrl+[');\n", | |
"\n", | |
"CodeMirror.commands.leaveInsertOrEdit = function (cm) {\n", | |
" if ( cm.state.vim.insertMode ) {\n", | |
" // do magic here to get out of insert mode\n", | |
" CodeMirror.keyMap['vim-insert']['Esc'](cm);\n", | |
" } else {\n", | |
" IPython.notebook.command_mode();\n", | |
" IPython.notebook.focus_cell();\n", | |
" }\n", | |
"};\n", | |
" \n", | |
"//C().options.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
"all_cm( function (cm) {\n", | |
" cm.options.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
" if ( CodeMirror.defaults.extraKeys === null ) { \n", | |
" CodeMirror.defaults.extraKeys = {};\n", | |
" }\n", | |
" // TODO: make this change permanent\n", | |
" // this part seems to be ignore when adding a new cell\n", | |
" // - alternative solution would be to listen for NewCell events and rerun the CM function on it\n", | |
" // - it could also be the case that when we instatiate CodeMirror, we somehow leave out CM.defaults.extraKeys\n", | |
" CodeMirror.defaults.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
"})" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"// N.B. This code looks fairly simple, but it took me forever to \n", | |
"// figure out how to do this, \n", | |
"// \n", | |
"// there's a problem here, Ctrl-[ is already handled by CodeMirror by the time we \n", | |
"// (IPython.keyboard_manager) get it CodeMirror issues signals on mode change, \n", | |
"// so we have to hook into that to get Ctrl-[\n", | |
"edit.remove_shortcut('Ctrl+[');\n", | |
"\n", | |
"CodeMirror.commands.leaveInsertOrEdit = function (cm) {\n", | |
" if ( cm.state.vim.insertMode ) {\n", | |
" // do magic here to get out of insert mode\n", | |
" CodeMirror.keyMap['vim-insert']['Esc'](cm);\n", | |
" } else {\n", | |
" IPython.notebook.command_mode();\n", | |
" IPython.notebook.focus_cell();\n", | |
" }\n", | |
"};\n", | |
" \n", | |
"//C().options.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
"all_cm( function (cm) {\n", | |
" cm.options.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
" if ( CodeMirror.defaults.extraKeys === null ) { \n", | |
" CodeMirror.defaults.extraKeys = {};\n", | |
" }\n", | |
" // TODO: make this change permanent\n", | |
" // this part seems to be ignore when adding a new cell\n", | |
" // - alternative solution would be to listen for NewCell events and rerun the CM function on it\n", | |
" // - it could also be the case that when we instatiate CodeMirror, we somehow leave out CM.defaults.extraKeys\n", | |
" CodeMirror.defaults.extraKeys['Ctrl-['] = 'leaveInsertOrEdit';\n", | |
"})" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f911d0>" | |
] | |
} | |
], | |
"prompt_number": 9 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"\n", | |
"// not quite what we want - 'i' requires a double-tap\n", | |
"cmd.add_shortcut('Ctrl+C', def_cmd['i']);" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"cmd.add_shortcut('Ctrl+C', def_cmd['i']);" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f911d0>" | |
] | |
} | |
], | |
"prompt_number": 11 | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"To alleviate the inconsistency of what mode a CodeMirror editor is left in, we will register a function that will reset that state to vim command mode on blur events. Any time you click outside of the cell, click back inside will put you in vim command mode." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// On blur, make sure we go back to command mode for CodeMirror (in case user clicked away)\n", | |
"// TODO: Make this permanent - how to get CodeMirror to do this for new cells created after\n", | |
"all_cm( function (cm) {\n", | |
" cm.on('blur', function(cm) {\n", | |
" // TODO: I wish I understood a better way to do this, but fake pressing Escape work\n", | |
" CodeMirror.keyMap['vim-insert']['Esc'](cm);\n", | |
" CodeMirror.keyMap['vim']['Esc'](cm);\n", | |
" });\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"// On blur, make sure we go back to command mode for CodeMirror (in case user clicked away)\n", | |
"// TODO: Make this permanent - how to get CodeMirror to do this for new cells created after\n", | |
"all_cm( function (cm) {\n", | |
" cm.on('blur', function(cm) {\n", | |
" // TODO: I wish I understood a better way to do this, but fake pressing Escape work\n", | |
" CodeMirror.keyMap['vim-insert']['Esc'](cm);\n", | |
" CodeMirror.keyMap['vim']['Esc'](cm);\n", | |
" });\n", | |
"});" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f91150>" | |
] | |
} | |
], | |
"prompt_number": 12 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// 'i' by default interrupts the kernel (what Ctrl-C does at the terminal)\n", | |
"cmd.remove_shortcut('i');\n", | |
"cmd.add_shortcut('i', def_cmd.enter);\n", | |
"\n", | |
"// not quite what we want - 'i' requires a double-tap\n", | |
"// add documentation for this.\n", | |
"cmd.add_shortcut('ctrl+c', function(e) { IPython.notebook.kernel.interrupt(); return false});\n", | |
"\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"// 'i' by default interrupts the kernel (what Ctrl-C does at the terminal)\n", | |
"cmd.remove_shortcut('i');\n", | |
"cmd.add_shortcut('i', def_cmd.enter);\n", | |
"\n", | |
"// not quite what we want - 'i' requires a double-tap\n", | |
"cmd.add_shortcut('ctrl+c', function(e) { IPython.notebook.kernel.interrupt(); return false});\n" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f911d0>" | |
] | |
} | |
], | |
"prompt_number": 24 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"function focus_last(e) {\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[cells.length-1].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function focus_first(e) {\n", | |
" console.log('focus first called');\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[0].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function combo_tap(combo, action) {\n", | |
" var that = this;\n", | |
" function f() {\n", | |
" console.log('f called once');\n", | |
" \n", | |
" // redo this so that when an action is performed, we restore the original combo\n", | |
" cmd.add_shortcut(combo[1], action);\n", | |
" setTimeout(function () {\n", | |
" console.log('resetting f');\n", | |
" reset();\n", | |
" //cmd.add_shortcut(combo[0], reset)\n", | |
" }, 800);\n", | |
" }\n", | |
" function reset(e) {\n", | |
" console.log('reset called');\n", | |
" //that(combo, action); \n", | |
" cmd.add_shortcut(combo[0], f);\n", | |
" }\n", | |
" \n", | |
" reset();\n", | |
"};\n", | |
"cmd.add_shortcut('shift+g', focus_last);\n", | |
"combo_tap('gg', focus_first);\n", | |
"\n", | |
"// cut\n", | |
"combo_tap('dd', def_cmd['x']);\n", | |
"\n", | |
"// copy\n", | |
"combo_tap('yy', def_cmd['c']);\n", | |
"\n", | |
"// paste\n", | |
"cmd.add_shortcut('p', def_cmd['v']);\n", | |
"\n", | |
"// undo\n", | |
"cmd.add_shortcut('u', def_cmd['z']);\n", | |
"\n", | |
"// Join (merge down with cell below)\n", | |
"cmd.add_shortcut('shift+j', def_cmd['shift+m'])" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"function focus_last(e) {\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[cells.length-1].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function focus_first(e) {\n", | |
" console.log('focus first called');\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[0].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function combo_tap(combo, action) {\n", | |
" var that = this;\n", | |
" function f() {\n", | |
" console.log('f called once');\n", | |
" cmd.add_shortcut(combo[1], action);\n", | |
" setTimeout(function () {\n", | |
" console.log('resetting f');\n", | |
" reset();\n", | |
" //cmd.add_shortcut(combo[0], reset)\n", | |
" }, 800);\n", | |
" }\n", | |
" function reset(e) {\n", | |
" console.log('reset called');\n", | |
" //that(combo, action); \n", | |
" cmd.add_shortcut(combo[0], f);\n", | |
" }\n", | |
" \n", | |
" reset();\n", | |
"};\n", | |
"cmd.add_shortcut('shift+g', focus_last);\n", | |
"combo_tap('gg', focus_first);\n", | |
"\n", | |
"// cut\n", | |
"combo_tap('dd', def_cmd['x']);\n", | |
"\n", | |
"// copy\n", | |
"combo_tap('yy', def_cmd['c']);\n", | |
"\n", | |
"// paste\n", | |
"cmd.add_shortcut('p', def_cmd['v']);\n", | |
"\n", | |
"// undo\n", | |
"cmd.add_shortcut('u', def_cmd['z']);\n", | |
"\n", | |
"// Join (merge down with cell below)\n", | |
"cmd.add_shortcut('shift+j', def_cmd['shift+m'])" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f91310>" | |
] | |
} | |
], | |
"prompt_number": 33 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// if you want to keep track of mode changes in codemirror, you can register an even here\n", | |
"// for example, here I just print the current mode, but you can imagine using this to change to an -- INSERT -- \n", | |
"all_cm( function (cm) {\n", | |
" cm.on('vim-mode-change', function() {\n", | |
" console.log(cm.options.keyMap);\n", | |
" });\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"C().on('vim-mode-change', function(e) {\n", | |
" if (e.mode == 'insert') {\n", | |
" console.log(e);\n", | |
" console.log('helo');\n", | |
" }\n", | |
" console.log(e.mode);\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"edit.remove_shortcut('ctrl+[');" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"edit.remove_shortcut('ctrl+[');" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f91250>" | |
] | |
} | |
], | |
"prompt_number": 4 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"nested vi-like interfaces\n", | |
"-----------\n", | |
"\n", | |
"With the modal UI merged in IPython, we now have the ability to make the notebook experience more vi-like.\n", | |
"\n", | |
"Now, let's put CodeMirror into vim mode, for an experience [sjobeek](https://github.com/sjobeek) has coined as [\"vimception\"](https://github.com/ipython/ipython/issues/4798)\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
" \n", | |
"function to(mode) {\n", | |
" var mode = mode || 'vim'\n", | |
" // first let's apply vim mode to all current cells\n", | |
" function to_mode(c) { return c.code_mirror.setOption('keyMap', mode);};\n", | |
" IPython.notebook.get_cells().map(to_mode);\n", | |
" // apply the mode to future cells created\n", | |
" IPython.Cell.options_default.cm_config.keyMap = mode;\n", | |
"}\n", | |
"\n", | |
"//vim mode requires an extra little bit of javascript, so let's fetch that\n", | |
"$.getScript(\"/static/components/codemirror/keymap/vim.js\", function() {to('vim');} );\n", | |
"\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"If we decide we don't like this, or if we've got a colleague who's a mere mortal, we can switch the mode back for them with:\n", | |
"```javascript\n", | |
" %%javascript\n", | |
" to('default');\n", | |
" \n", | |
"```\n", | |
"<sub>\n", | |
"(see my earlier caveat about %%javascript cells if you see \"Javascript error adding output! ReferenceError: to is not defined See your browser Javascript console for more details.\")\n", | |
"\n", | |
"Here's a little helper function that will print into your browser's javascript \n", | |
"console you the current modes of all cells in this notebook." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"console.log(\n", | |
" IPython.notebook.get_cells().map(\n", | |
" function(x) { \n", | |
" return x.code_mirror.options.keyMap; \n", | |
" }\n", | |
" )\n", | |
");\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### CodeMirror vim mode warts\n", | |
"#### None of the following goodies work\n", | |
"\n", | |
"- searching via `/` and `?` \n", | |
" - (though there's a [search addon](http://codemirror.net/demo/search.html)), that just doesn't play nicely with dialogs, since dialogs blur our cells, so the notebook enters command mode.\n", | |
"- autowrapping or formatting via `gq`\n", | |
"- ctrl-w for deleting a word (CM)\n", | |
"- ctrl-n and ctrl-p for in-buffer completion (there's an IPython workaround for this)\n", | |
"- ctrl-v visual-block mode is not implemented\n", | |
"- middle-click paste doesn't work in X11, though yanking text does place it in the clipboard\n", | |
"- ctrl-y and ctrl-e for copying character from line above and below\n", | |
"http://codemirror.net/doc/manual.html" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"\n", | |
"- ctrl-n and ctrl-p for in-buffer completion (there's an IPython workaround for this)\n", | |
"- ctrl-v visual-block mode is not implemented\n", | |
"\n", | |
"- ctrl-n and ctrl-p for in-buffer completion (there's an IPython workaround for this)\n", | |
"- ctrl-v visual-block mode is not implemented\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"\n", | |
"- ctrl-n and ctrl-p for in-buffer completion (there's an IPython workaround for this)\n", | |
"- ctrl-v visual-block mode is not implemented\n", | |
"$" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"I wish I could **:q** you!\n", | |
"---\n", | |
"Yes, muscle memory can be a tough mistress.\n", | |
"\n", | |
"Luckily, we're control freaks, and we can change the world to suit our muscle memory.\n", | |
"\n", | |
"CodeMirror vim mode already supports calling the 'save' method on a CodeMirror object when you type `:w`, so let's just add a sensible method to all CodeMirror instance." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"\n", | |
"CodeMirror.prototype.save = function() { \n", | |
" IPython.notebook.save_checkpoint()\n", | |
"}" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"\n", | |
"CodeMirror.prototype.save = function() { \n", | |
" IPython.notebook.save_checkpoint()\n", | |
"}" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f911d0>" | |
] | |
} | |
], | |
"prompt_number": 5 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"\n", | |
"// we'll add shortcuts here as we go along\n", | |
"var vi_keys = {};\n", | |
"var edit = IPython.keyboard_manager.edit_shortcuts;\n", | |
"var def_edit = IPython.default_edit_shortcuts['esc'];\n", | |
"var cmd = IPython.keyboard_manager.command_shortcuts;\n", | |
"\n", | |
"vi_keys[':+w'] = IPython.default_edit_shortcuts['s'];\n", | |
"edit.add_shortcuts(vi_keys);\n", | |
"// 'i' by default interrupts the kernel (what Ctrl-C does at the terminal)\n", | |
"cmd.remove_shortcut('i');\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"from IPython.display import Javascript, display, HTML\n", | |
"\n", | |
"t = \"\"\"var help = IPython.quick_help.build_{0}_help();\n", | |
"help.children().first().remove();\n", | |
"this.append_output({{output_type: 'display_data', html: help.html()}});\"\"\"\n", | |
"\n", | |
"def display_command_shortcuts():\n", | |
" display(Javascript(t.format('command')))\n", | |
"\n", | |
"def display_edit_shortcuts():\n", | |
" display(Javascript(t.format('edit')))\n", | |
"\n", | |
"display(HTML(\"\"\"\n", | |
"<style>\n", | |
".shortcut_key {display: inline-block; width: 15ex; text-align: right; font-family: monospace;}\n", | |
".shortcut_descr {display: inline-block;}\n", | |
"div.quickhelp {float: none; width: 100%;}\n", | |
"</style>\n", | |
"\"\"\"))\n", | |
"\n" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"dogfooding\n", | |
"-----------\n", | |
"\n", | |
"this post was written in the notebook, and I addressed the things I found problemetic as I went along \n", | |
"```\n", | |
"TODO:\n", | |
"[x] ctrl-[ to enter escape mode\n", | |
" [ ] check if we're in code-mirror insert mode, then no-op, and let CM handle the transition.\n", | |
"[x] G in command mode to go to the last cell\n", | |
"[x] gg in command mode to go to the first cell\n", | |
"[ ] cw in a vim command mode broken in notebook only (i think)\n", | |
"[ ] j and k and bottom and top lines to transition to next cell?\n", | |
"[ ] swap 'a' with 'b' and make 'b' be 'i'\n", | |
"[ ] 'y' at the command level to copy a cell\n", | |
"[ ] 'p' to paste a cell\n", | |
"[ ] 'J' for what 'M' currently does (to merge)\n", | |
"\n", | |
"[ ] on 'blur' of CM, leave insert mode as per suggestion?\n", | |
"[ ] <enter> should execute? \n", | |
"[ ] 'i' should do <enter>'s behavior\n", | |
"[ ] get rid of default 'i' binding, and enter edit mode and insert mode in the notebook\n", | |
"[ ] :e functionality\n", | |
"[ ] u for undo (caveat! only one level of undo)\n", | |
"[ ] ':' has dialog pop-up in codemirror that doesn't quite work anymore in the notebook\n", | |
" Object has no method save\n", | |
" - ':' does have implementation [here](http://codemirror.net/demo/vim.html) (via inclusion of dialog?)\n", | |
" \n", | |
"[ ] move the notification area for the whole notebook to bottom right\n", | |
"``` " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"function focus_last(e) {\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[cells.length-1].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function focus_first(e) {\n", | |
" console.log('focus first called');\n", | |
" var cells = IPython.notebook.get_cells();\n", | |
" cells[0].focus_cell();\n", | |
"};\n", | |
"\n", | |
"function combo_tap(combo, action) {\n", | |
" var that = this;\n", | |
" function f() {\n", | |
" console.log('f called once');\n", | |
" cmd.add_shortcut(combo[1], action);\n", | |
" setTimeout(function () {\n", | |
" console.log('resetting f');\n", | |
" reset();\n", | |
" //cmd.add_shortcut(combo[0], reset)\n", | |
" }, 800);\n", | |
" }\n", | |
" function reset(e) {\n", | |
" console.log('reset called');\n", | |
" //that(combo, action); \n", | |
" cmd.add_shortcut(combo[0], f);\n", | |
" }\n", | |
" \n", | |
" reset();\n", | |
"};\n", | |
"cmd.add_shortcut('shift+g', focus_last);\n", | |
"combo_tap('gg', focus_first);" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Misc" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"%%javascript\n", | |
"// get rid of the default Ctrl-W binding\n", | |
"// this only works for Firefox\n", | |
"$(document).ready(function() {\n", | |
"\t$(this).bind('keypress', function(e) {\n", | |
"\t\tvar key = (e.keyCode ? e.keyCode : e.charCode);\n", | |
"\t\tif (key == '119' && e.ctrlKey) {\n", | |
"\t\t\treturn false;\n", | |
"\t\t}\n", | |
"\t});\n", | |
"});\n", | |
"%%javascript\n", | |
"window.addEventListener(\"beforeunload\", function( event ) {\n", | |
" var press = jQuery.Event(\"keypress\");\n", | |
" press.ctrlKey = false;\n", | |
" press.which = 27; // escape\n", | |
" $(document).trigger(press);\n", | |
" event.returnValue = \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
" event.returnValue +=\"\\nX Chrome sucks at captruring Ctrl-W, sorry X\";\n", | |
" event.returnValue += \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"javascript": [ | |
"// get rid of the default Ctrl-W binding\n", | |
"// this only works for Firefox\n", | |
"$(document).ready(function() {\n", | |
"\t$(this).bind('keypress', function(e) {\n", | |
"\t\tvar key = (e.keyCode ? e.keyCode : e.charCode);\n", | |
"\t\tif (key == '119' && e.ctrlKey) {\n", | |
"\t\t\treturn false;\n", | |
"\t\t}\n", | |
"\t});\n", | |
"});" | |
], | |
"metadata": {}, | |
"output_type": "display_data", | |
"text": [ | |
"<IPython.core.display.Javascript at 0x2f91290>" | |
] | |
} | |
], | |
"prompt_number": 6 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"1%%javascript\n", | |
"// get rid of the default Ctrl-W binding\n", | |
"// this only works for Firefox\n", | |
"$(document).ready(function() {\n", | |
"\t$(this).bind('keypress', function(e) {\n", | |
"\t\tvar key = (e.keyCode ? e.keyCode : e.charCode);\n", | |
"\t\tif (key == '119' && e.ctrlKey) {\n", | |
"\t\t\treturn false;\n", | |
"\t\t}\n", | |
"\t});\n", | |
"});\n", | |
"%%javascript\n", | |
"window.addEventListener(\"beforeunload\", function( event ) {\n", | |
" var press = jQuery.Event(\"keypress\");\n", | |
" press.ctrlKey = false;\n", | |
" press.which = 27; // escape\n", | |
" $(document).trigger(press);\n", | |
" event.returnValue = \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
" event.returnValue +=\"\\nX Chrome sucks at captruring Ctrl-W, sorry X\";\n", | |
" event.returnValue += \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "SyntaxError", | |
"evalue": "invalid syntax (<ipython-input-27-7132ad196d2a>, line 1)", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[1;36m File \u001b[1;32m\"<ipython-input-27-7132ad196d2a>\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m 1%%javascript\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" | |
] | |
} | |
], | |
"prompt_number": 27 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"1%%javascript\n", | |
"// get rid of the default Ctrl-W binding\n", | |
"// this only works for Firefox\n", | |
"$(document).ready(function() {\n", | |
"\t$(this).bind('keypress', function(e) {\n", | |
"\t\tvar key = (e.keyCode ? e.keyCode : e.charCode);\n", | |
"\t\tif (key == '119' && e.ctrlKey) {\n", | |
"\t\t\treturn false;\n", | |
"\t\t}\n", | |
"\t});\n", | |
"});\n", | |
"%%javascript\n", | |
"window.addEventListener(\"beforeunload\", function( event ) {\n", | |
" var press = jQuery.Event(\"keypress\");\n", | |
" press.ctrlKey = false;\n", | |
" press.which = 27; // escape\n", | |
" $(document).trigger(press);\n", | |
" event.returnValue = \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
" event.returnValue +=\"\\nX Chrome sucks at captruring Ctrl-W, sorry X\";\n", | |
" event.returnValue += \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "SyntaxError", | |
"evalue": "invalid syntax (<ipython-input-28-7132ad196d2a>, line 1)", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[1;36m File \u001b[1;32m\"<ipython-input-28-7132ad196d2a>\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m 1%%javascript\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" | |
] | |
} | |
], | |
"prompt_number": 28 | |
}, | |
{ | |
"cell_type": "code", | |
"collapsed": false, | |
"input": [ | |
"1%%javascript\n", | |
"// get rid of the default Ctrl-W binding\n", | |
"// this only works for Firefox\n", | |
"$(document).ready(function() {\n", | |
"\t$(this).bind('keypress', function(e) {\n", | |
"\t\tvar key = (e.keyCode ? e.keyCode : e.charCode);\n", | |
"\t\tif (key == '119' && e.ctrlKey) {\n", | |
"\t\t\treturn false;\n", | |
"\t\t}\n", | |
"\t});\n", | |
"});\n", | |
"%%javascript\n", | |
"window.addEventListener(\"beforeunload\", function( event ) {\n", | |
" var press = jQuery.Event(\"keypress\");\n", | |
" press.ctrlKey = false;\n", | |
" press.which = 27; // escape\n", | |
" $(document).trigger(press);\n", | |
" event.returnValue = \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
" event.returnValue +=\"\\nX Chrome sucks at captruring Ctrl-W, sorry X\";\n", | |
" event.returnValue += \"\\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\"\n", | |
"});" | |
], | |
"language": "python", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"ename": "SyntaxError", | |
"evalue": "invalid syntax (<ipython-input-29-7132ad196d2a>, line 1)", | |
"output_type": "pyerr", | |
"traceback": [ | |
"\u001b[1;36m File \u001b[1;32m\"<ipython-input-29-7132ad196d2a>\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m 1%%javascript\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" | |
] | |
} | |
], | |
"prompt_number": 29 | |
} | |
], | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment