極楽とんぼのロボット製作記

情報工学系大学院生がロボットとその周辺技術や身の回りの出来事について紹介するブログ

最強のJupyterNotebook環境(vim-bind)を構築する

この記事で行うこと

  • 「jupyter-vim-binding」を使って、jupyter notebookにvim-bindのキー設定をする
  • 「xkeysnail」を使ってctrl+nなどのvim-bindで操作した際に邪魔になるブラウザのデフォルトのショートカットキーを別の設定に割り当てる

f:id:gokuraku104robot:20180810180518p:plain:w500

jupyter notebookのinstall

以下のコマンドからjupyter notebookをインストールします。

$ pip install jupyter

jupyter notebookを

$ jupyter notebook

で起動します。

vim bindの設定をする

jupyter-vim-bindingのインストール

以下のコマンドからjupyter-vim-bindingをインストールします。

$ pip install jupyter_contrib_nbextensions
$ jupyter contrib nbextension install --user
$ mkdir -p $(jupyter --data-dir)/nbextensions
$ cd $(jupyter --data-dir)/nbextensions
$ git clone https://github.com/lambdalisue/jupyter-vim-binding vim_binding
$ jupyter nbextension enable vim_binding/vim_binding

これによりj,kなどを使ってセルを移動したり、iでインサートモードに入って編集したりできます。

vim-bindの編集

<ESC>がデフォルトのままで使いづらければ、custom.js<ESC>jjなどにremapすることができます。 まず~/.jupyter/custom/custom.jsファイルを作成します。

$ mkdir -p ~/.jupyter/custom/
$ cd ~/.jupyter/custom
$ vim custom.js

custom.jsには以下のようにキーバインドを設定します。
custom.js

// Configure CodeMirror Keymap
require([
  'nbextensions/vim_binding/vim_binding',   // depends your installation
], function() {
  // Map jj to <Esc>
  CodeMirror.Vim.map("jj", "<Esc>", "insert");
  // Swap j/k and gj/gk (Note that <Plug> mappings)
  CodeMirror.Vim.map("j", "<Plug>(vim-binding-gj)", "normal");
  CodeMirror.Vim.map("k", "<Plug>(vim-binding-gk)", "normal");
  CodeMirror.Vim.map("gj", "<Plug>(vim-binding-j)", "normal");
  CodeMirror.Vim.map("gk", "<Plug>(vim-binding-k)", "normal");
});

// Configure Jupyter Keymap
require([
  'nbextensions/vim_binding/vim_binding',
  'base/js/namespace',
], function(vim_binding, ns) {
  // Add post callback
  vim_binding.on_ready_callbacks.push(function(){
    var km = ns.keyboard_manager;
    // Allow Ctrl-2 to change the cell mode into Markdown in Vim normal mode
    km.edit_shortcuts.add_shortcut('ctrl-2', 'vim-binding:change-cell-to-markdown', true);
    // Update Help
    km.edit_shortcuts.events.trigger('rebuild.QuickHelp');
  });
});

ブラウザのデフォルトのショートカットキーを無効化

jupyter notebookをvim-bindするとctrl+nctrl+pなどブラウザのデフォルトのショートカットキーが邪魔になってきます。これらを別のショートカットキーとして設定し直します。

アドオンを使う方法

shortkeys,hotkeysなどのアドオンを使ってショートカットキーを編集する方法ですが、ブラウザのバージョンアップの影響のためか、まともに動作するものはありませんでした。いつかブラウザがデフォルトのキーマッピングを編集できる仕様になってくれたらいいと思います。

OS側のショートカットキーを変更する方法

ブラウザの進化を待っている時間はないので、OS側からショートカットキーを変更することでブラウザのショートカットキーを上書きします。 MACの場合、OS側でアプリケーションのショートカットキーを編集できるらしいです。 fabrec.jp Ubuntuの場合はxkeysnailを使ってこれを実現します。

xkeysnailのインストール

$ sudo pip3 install xkeysnail

xkeysnailを使ってみる

以下のようにpythonでconfigファイルを作成します。
xkeysnail_config.py

import re
from xkeysnail.transform import *
define_keymap(re.compile("Firefox|Google"), {
    K("C-p"): with_mark(K("up")),
    K("C-n"): with_mark(K("down")),
}, "Firefox and Chrome")

作成したPythonプログラムをxkeysnailから実行します。

$ xhost +SI:localuser:root
$ sudo xkeysnail xkeysnail_config.py

FirefoxやChrome上でctrl+nやctrl+pをしても新しいウィンドウや印刷画面がでなければ成功です。

自動起動の設定

xkeysnailを自動で起動する設定を行います。先程はrootで実行しましたが、ここではxkeysnail用にsudoが可能なユーザーxkeysnailを作成することにします。

自動起動用のユーザを作成

以下のコマンドからユーザーグループとユーザーを作成します。

$ sudo groupadd uinput
$ sudo useradd -G input,uinput -s /sbin/nologin xkeysnail

以下のファイルを作成して、保存します。
/etc/udev/rules.d/40-udev-xkeysnail.rules

KERNEL=="uinput", GROUP="uinput"


/etc/modules-load.d/uinput.conf

uinput


/etc/sudoers.d/10-installer

username ALL=(ALL) ALL, (xkeysnail) NOPASSWD: /opt/xkeysnail/bin/xkeysnail

usernameには自分のユーザー名を入力してください。sudoersの設定は間違えると修正が面倒なので慎重に行ってください。

自動起動用のスクリプトの作成

xkeysnailをubuntuで自動起動するための設定を行います。 先ほど作ったPythonのconfigファイルを/etc/opt/xkeysnail/にコピーします。

$ sudo mkdir -p /etc/opt/xkeysnail/
$ cp xkeysnail_config.py /etc/opt/xkeysnail/

同じく/etc/opt/xkeysnail/にxkeysnailを起動するシェルスクリプトを作成します。 /etc/opt/xkeysnail/start_xkeysnail.sh

#!/usr/bin/env bash
if [ -x /usr/local/bin/xkeysnail ]; then
    xhost +SI:localuser:xkeysnail
    sudo -u xkeysnail DISPLAY=:1 /usr/local/bin/xkeysnail /etc/opt/xkeysnail/xkeysnail_config.py &
fi

さらにUbuntuが起動時に自動でシェルスクリプトを実行するための設定を~/.config/autostart/に作成します。
~/.config/autostart/xkeysnail.desktop

[Desktop Entry]
Type=Application
Version=1.0
Name=xkeysnail
GenericName=Keymapper
Exec=/etc/opt/xkeysnail/start_xkeysnail.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

コンピュータを再起動後、FirefoxやChrome上でctrl+nやctrl+pをしても新しいウィンドウや印刷画面がでなければ成功です。

参考サイト
jupyter上でvimを使う
GitHub - lambdalisue/jupyter-vim-binding: Jupyter meets Vim. Vimmer will fall in love.
Vimの手癖が出ても安心!Firefoxのアドオン「Shortkeys」 | atominux
xkeysnail - もうひとつの Linux 向けキーリマッパ
GitHub - mooz/xkeysnail: Yet another keyboard remapping tool for X environment
xremap の代わりに xkeysnail を使ってみる - @tmtms のメモ
xmodmapとxcapeで消耗するのはもうやめよう - ぽよメモ
xkeysnailでキーリマップする