Google Colab에서 코드 편집이 완료되는 Chrome 확장 프로그램을 개발했습니다.
결과
이렇게 되었다
배경
최근, 기계 학습 주위의 공부를 Google Colab 상에서 실시하게 되었다. 다만, 코드 편집 기능에 조금 불만을 느끼고 있었다. 그래서 최근에 학습한 Javascript와 Chrome 확장의 지식을 조합하여 코드 편집이 끝나는 Chrome 확장을 개발해보기로 했다.
출처
구현 방법
Google Colab(Jupyter Notebook에서도 OK)을 연 상태에서 Chrome Dev Tool의 Console에 다음 코드를 입력하면 각 셀에 CodeMirror라는 개체가 연결되어 있는지 확인할 수 있습니다.
const div = document.querySelector('div.CodeMirror')
div.CodeMirror
셀상에서 일어나는 이벤트는, 이 CodeMirror 객체에 의해 관리되고 있다. 즉, 이 객체의 프로퍼티를 재기록하는 것으로, 새로운 기능을 추가할 수 있다(기존의 기능을 오염하지 않도록 주의가 필요). 개발시는 공식 문서와 GitHub 상의 소스 코드를 참고로 했다.
여담이지만 Jupyter Notebook이나 Kaggle의 Kernel에서도 CodeMirror가 사용되고 있다.
구현한 기능
스니펫
CodeMirror 객체가 프리미티브한 조작(커서 이동, 셀내 캐릭터 라인의 취득·치환·삭제 등)을 실시하는 함수를 가지고 있으므로, 이것들을 조합해 스니펫 기능을 실현하고 있다.
const snippets = {
'inp' : 'import numpy as np\n',
'iplt' : 'import matplotlib.pyplot as plt\n',
'ipd' : 'import pandas as pd\n',
'isb' : 'import seaborn as sns\n',
'itf' : 'import tensorflow as tf\n',
'pdrc' : 'pd.read_csv()'
};
const expandSnippetOrIndent = cm => {
// cm: CodeMirror object
const cursor = cm.getCursor(); // cursor position
const cursorLeft = cm.getRange({line: cursor.line, ch: 0}, cursor); // カーソルより左側の文字列
const match = cursorLeft.match(/[^a-zA-Z0-9_]?([a-zA-Z0-9_]+)$/);
if (!match) {
tabDefaultFunc(cm);
return
}
const prefix = match[1];
const head = {line: cursor.line, ch: cursor.ch - prefix.length};
// マッチあり
if (prefix in snippets) {
const body = snippets[prefix];
cm.replaceRange(body, head, cursor);
const match = body.match(/\)+$/);
if (match) cm.moveH(-match[0].length, 'char');
} else {
tabDefaultFunc(cm);
}
// TODO:展開候補が複数個があった場合には、ヒントを表示する機能を実装
}
// Tab にスニペット展開機能を割り当て
cell.CodeMirror.options.extraKeys['Tab'] = expandSnippetOrIndent;
스니펫 팁
하고 있는 것은 스니펫 기능과 거의 같다. 힌트 표시중에, 유저로부터 입력이 있으면, 힌트가 자동 갱신되도록 하고 있다.
const showSnippetHint = cm => {
// TODO: expandSnippetOrIndent と被っている処理は関数化
const cursor = cm.getCursor();
const cursorLeft = cm.getRange({line: cursor.line, ch: 0}, cursor);
const match = cursorLeft.match(/[^a-zA-Z0-9_]?([a-zA-Z0-9_]+)$/);
const prefix = match ? match[1] : '';
const head = {line: cursor.line, ch: cursor.ch - prefix.length};
const matchedPrefixes = Object.keys(snippets).filter(k => k.indexOf(prefix) > -1);
matchedPrefixes.sort();
const hintList = matchedPrefixes.map(key => {
const displayText = snippets[key].replace('\n', '; ');
const displayTextTrunc = displayText.length > 40 ? displayText.slice(0, 40) + '...' : displayText
return {
text: snippets[key], // 挿入される文字列
displayText: `${key.padEnd(7, ' ')}: ${displayTextTrunc}` // ヒントに表示される文字列
}
});
const hintFunc = () => {
return {
list: hintList,
from: head,
to: cursor
}
}
// ヒントを表示
cm.showHint({
hint: hintFunc,
});
}
// ヒント表示中に、ユーザーから入力があったら、ヒントを更新する
const conCursorActivity = cm => {
if (cm.state.completionActive) {
showSnippetHint(cm);
}
}
// Ctrl-h にヒント表示機能を割り当て
cell.CodeMirror.options.extraKeys['Ctrl-H'] = showSnippetHint;
cell.CodeMirror.on('cursorActivity', conCursorActivity);
Vim
선구자가 있었기 때문에 그것을 참고했다. Chrome 확장 파일 구성도이 리포지토리와 유사합니다.
const enableVim = cell => {
cell.CodeMirror.setOption('vimMode', true);
cell.CodeMirror.options.keyMap = 'vim';
cell.CodeMirror.options.showCursorWhenSelecting = 'vim';
};
요약
개발한 Chrome 확장 덕분에 Google Colab에서 작업 효율이 크게 향상되었습니다. 본 기사에서 소개하고 있는 방법을 이용하여 Jupyter Notebook도 해킹해 볼 예정. 끝까지 읽어 주셔서 감사합니다!
Reference
이 문제에 관하여(Google Colab에서 코드 편집이 완료되는 Chrome 확장 프로그램을 개발했습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/harupy/items/f309c18b351c565661b7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)