$30 off During Our Annual Pro Sale. View Details »

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

arakawa
October 17, 2020

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

arakawa

October 17, 2020
Tweet

More Decks by arakawa

Other Decks in Programming

Transcript

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


    View Slide

  2. 荒川聖悟

    Sansan事業部

    プロダクト開発部

    iOSエンジニア

    自己紹介

    2
    @adsholoko


    View Slide

  3. 車輪の再発明が好きです

    3
    NESエミュレータ『goones』 

    https://github.com/ad-sho-loko/goones 

    DB『bogoDB』

    https://github.com/ad-sho-loko/bogoDB 

    他にもコンパイラなど... 


    View Slide

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


    View Slide

  5. milleの特徴

    - ターミナルで動作する自作テキストエディタ

    - ソースコードは1000行以内(テストコードは除く)

    - Goで実装

    - 外部ライブラリを利用していない


    View Slide

  6. milleの機能

    - ASCII対応

    - キーボードショートカット

    - ファイルの読み込み/保存

    - Goのキーワードハイライト機能


    View Slide

  7. 参考実装


    View Slide

  8. どうやって作るのか3つほど紹介

    - キーボード入力を受け付ける仕組み

    - ターミナルをテキストエディタに変える仕組み

    - 文字入力を効率化するためのデータ構造 


    View Slide

  9. キーボードからの入力受け付け

    - 当然、標準入力から受け付ける

    - ただし処理中にキー入力があった場
    合にも取りこぼさないように実装する
    必要がある

    goroutineにて別スレッドとして実行させ、排
    他制御のためにchannelを利用


    View Slide

  10. ターミナルをテキストエディタに変える仕組み

    通常、プロセスは標準入力のデータをバッファし、改行が行われたときにプロセスに渡
    されるようになっている(Cookedモード)

    しかしテキストエディタでは1文字入力するごとにプロセスに渡したい場合はrawモード
    にする必要がある。


    View Slide

  11. Rawモードへ移行する方法

    https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
    https://en.wikipedia.org/wiki/Terminal_mode
    参考


    View Slide

  12. テキストエディタに適したデータ構造選び

    - 当然ながらテキストエディタは文字を入力し、それを格納する必要がある

    - 文字の参照・入力・挿入・削除はなるべく早く実行したい!

    - しかしすべてがO(1)なデータ構造はない...

    GapBufferというデータ構造を採用することに


    View Slide

  13. “Hello, World”を入力することを考えてみる 

    文字入力の動き

    View Slide

  14. 文字入力の動き

    ‘H’を挿入

    H


    View Slide

  15. H
 e

    ‘e’を挿入

    文字入力の動き

    View Slide

  16. H
 e
 l

    文字入力の動き

    View Slide

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

    ‘!’を挿入

    文字入力の動き

    View Slide

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

    ’lo’を入力し忘れた!

    もし入力ミスが起きたときに...

    View Slide

  19. 配列の場合

    H
 e
 l
 ,
 W
 o
 r
 l
 d
 !

    ‘l’を挿入


    View Slide

  20. 配列の場合

    H
 e
 l
 ,
 ,
 W
 o
 r
 l
 d
 !

    O(n)操作が発生!

    挿入処理のためにずらす必要がある 


    View Slide

  21. 配列の場合

    H
 e
 l
 l
 ,
 W
 o
 r
 l
 d
 !

    ‘o’を挿入


    View Slide

  22. 配列の場合

    H
 e
 l
 l
 ,
 W
 o
 r
 l
 d
 !

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


    View Slide

  23. 配列の場合

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

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


    View Slide

  24. GapBuffer

    H
 e
 l
 ,
 W
 o
 r
 l
 d
 !

    ’lo’を入力し忘れた!


    View Slide

  25. GapBuffer

    H
 e
 l
 ,
 W
 o
 r
 l
 d
 !

    ‘l’を挿入


    View Slide

  26. GapBuffer

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

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


    View Slide

  27. GapBuffer

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

    O(n)操作が発生!

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


    View Slide

  28. GapBuffer

    H
 e
 l
 l
 ,
 W
 o
 r
 l
 d
 !

    ‘o’を挿入


    View Slide

  29. GapBuffer

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

    ‘o’を挿入

    O(1)で挿入可能!


    View Slide

  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 


    View Slide

  31. GapBuffer

    メリット

    挿入をする箇所から連続で入力する人間の動きに適したデータ構造である

    - 実装コードがシンプル

    - 参照はO(1)で可能

    - 一定の条件下では挿入O(1)、削除O(1)

    デメリット

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


    View Slide

  32. まとめ

    - テキストエディタに適したデータ構造やアルゴリズムが存在する

    - Goが低レイヤな箇所は抽象化しており、本質的な箇所の実装だけで良い

    - 1000行未満のコードなのでぜひ詳細はコードリーディングしてみてください

    - 車輪の再発明は楽しい!!


    View Slide

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


    View Slide

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

    @adsholoko

    34

    View Slide