Goでテキストエディタを作った話@GDG Devfest2020

Dd54ef589676aa4bf9e09d72c61bb80e?s=47 arakawa
October 17, 2020

Goでテキストエディタを作った話@GDG Devfest2020

Dd54ef589676aa4bf9e09d72c61bb80e?s=128

arakawa

October 17, 2020
Tweet

Transcript

  1. Goでテキストエディタを作った話


  2. 荒川聖悟
 Sansan事業部
 プロダクト開発部
 iOSエンジニア
 自己紹介
 2 @adsholoko


  3. 車輪の再発明が好きです
 3 NESエミュレータ『goones』 
 https://github.com/ad-sho-loko/goones 
 DB『bogoDB』
 https://github.com/ad-sho-loko/bogoDB 
 他にもコンパイラなど...

  4. ターミナル上で動作するテキストエディタmille


  5. milleの特徴
 - ターミナルで動作する自作テキストエディタ
 - ソースコードは1000行以内(テストコードは除く)
 - Goで実装
 - 外部ライブラリを利用していない


  6. milleの機能
 - ASCII対応
 - キーボードショートカット
 - ファイルの読み込み/保存
 - Goのキーワードハイライト機能


  7. 参考実装


  8. どうやって作るのか3つほど紹介
 - キーボード入力を受け付ける仕組み
 - ターミナルをテキストエディタに変える仕組み
 - 文字入力を効率化するためのデータ構造 


  9. キーボードからの入力受け付け
 - 当然、標準入力から受け付ける
 - ただし処理中にキー入力があった場 合にも取りこぼさないように実装する 必要がある
 goroutineにて別スレッドとして実行させ、排 他制御のためにchannelを利用


  10. ターミナルをテキストエディタに変える仕組み
 通常、プロセスは標準入力のデータをバッファし、改行が行われたときにプロセスに渡 されるようになっている(Cookedモード)
 しかしテキストエディタでは1文字入力するごとにプロセスに渡したい場合はrawモード にする必要がある。


  11. Rawモードへ移行する方法
 https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html https://en.wikipedia.org/wiki/Terminal_mode 参考


  12. テキストエディタに適したデータ構造選び
 - 当然ながらテキストエディタは文字を入力し、それを格納する必要がある
 - 文字の参照・入力・挿入・削除はなるべく早く実行したい!
 - しかしすべてがO(1)なデータ構造はない...
 GapBufferというデータ構造を採用することに


  13. “Hello, World”を入力することを考えてみる 
 文字入力の動き 


  14. 文字入力の動き 
 ‘H’を挿入
 H


  15. H
 e
 ‘e’を挿入
 文字入力の動き 


  16. H
 e
 l
 文字入力の動き 


  17. H
 e
 l
 l
 o
 ,
 W
 o
 r
 l


    d
 !
 ‘!’を挿入
 文字入力の動き 

  18. H
 e
 l
 ,
 W
 o
 r
 l
 d
 !


    ’lo’を入力し忘れた!
 もし入力ミスが起きたときに... 

  19. 配列の場合
 H
 e
 l
 ,
 W
 o
 r
 l
 d


    !
 ‘l’を挿入

  20. 配列の場合
 H
 e
 l
 ,
 ,
 W
 o
 r
 l


    d
 !
 O(n)操作が発生!
 挿入処理のためにずらす必要がある 

  21. 配列の場合
 H
 e
 l
 l
 ,
 W
 o
 r
 l


    d
 !
 ‘o’を挿入

  22. 配列の場合
 H
 e
 l
 l
 ,
 W
 o
 r
 l


    d
 !
 O(n)操作が発生!(二回目)

  23. 配列の場合
 H
 e
 l
 l
 o
 ,
 W
 o
 r


    l
 d
 !
 挿入操作が走るたびにO(n)発生する

  24. GapBuffer
 H
 e
 l
 ,
 W
 o
 r
 l
 d


    !
 ’lo’を入力し忘れた!

  25. GapBuffer
 H
 e
 l
 ,
 W
 o
 r
 l
 d


    !
 ‘l’を挿入

  26. GapBuffer
 H
 e
 l
 ,
 W
 ,
 W
 o
 r


    l
 d
 !
 挿入位置以降の文字列を後方に移す 

  27. GapBuffer
 H
 e
 l
 ,
 W
 ,
 W
 o
 r


    l
 d
 !
 O(n)操作が発生!
 挿入位置以降の文字列を後方に移す 

  28. GapBuffer
 H
 e
 l
 l
 ,
 W
 o
 r
 l


    d
 !
 ‘o’を挿入

  29. GapBuffer
 H
 e
 l
 l
 o
 ,
 W
 o
 r


    l
 d
 !
 ‘o’を挿入
 O(1)で挿入可能!

  30. GapBuffer - データ構造
 H
 e
 l
 l
 o
 ,
 W


    o
 r
 l
 d
 !
 array
 startPieceIndex
 endPieceIndex
 https://github.com/ad-sho-loko/mille/blob/master/gap_table.go 

  31. GapBuffer
 メリット
 挿入をする箇所から連続で入力する人間の動きに適したデータ構造である
 - 実装コードがシンプル
 - 参照はO(1)で可能
 - 一定の条件下では挿入O(1)、削除O(1)
 デメリット


    - 要素をランダムに挿入・削除すると、配列と同様にO(n) 分のコストがかかる

  32. まとめ
 - テキストエディタに適したデータ構造やアルゴリズムが存在する
 - Goが低レイヤな箇所は抽象化しており、本質的な箇所の実装だけで良い
 - 1000行未満のコードなのでぜひ詳細はコードリーディングしてみてください
 - 車輪の再発明は楽しい!!


  33. テキストエディタ作りましょう


  34. 質問はTwitterにてどうぞ!
 @adsholoko
 34