SlideShare a Scribd company logo
1 of 31
Download to read offline
Common Lisp製のテキストエディタ
Lemにフレーム多重化機能をつくった
t-sin (@sin_clav)
2020-08-27, lispmeetup #89
もくじ
●
Lemについて
●
フレーム多重化機能について
●
Lemの描画関連用語について
●
フレーム多重化機能対応でやったこと
Lemってなんだ?
●
Common Lisp製テキストエディタ
Lemってなんだ?
●
Common Lisp製テキストエディタ
●
https://github.com/cxxxr/lem
●
GNU Emacsのような操作感
●
vi-modeもある
●
Common Lispとの統合がよい
フレーム多重化機能って?
●
tmux
●
あるいはGNU Emacsのelscreen
●
画面中のバッファ配置を複数記憶しそれらを
切り替えられる機能
●
つまりtmux
フレーム多重化機能って?
frame-multiplexerの
ヘッダウィンドウ
#付きが現在のフレーム
Lemの描画関係用語
(ユーザが操作するもの)
ウィンドウ
モードライン
バッファ
ミニバッファ/エコーエリア
floatingウィンドウ
Lemの描画関係用語
(ユーザが操作するもの)
●
ウィンドウ
– 編集領域。C-x oで切り替えているアレ
– window-tree構造体により2分木で分割を表現
●
スクリーン
– 各バッファの表示を抽象的に担当する構造体
●
裏に具体的な描画を担当する「ビュー」がある(後述)
– バッファとは1対他の関係(同じバッファを複数表示)
●
バッファ
– 編集内容を保持している構造体
– キー入力するとバッファの中身が書き換えられる
Lemの描画関係用語
(実際に描画するためのもの)
●
ディスプレイ
– 描画している画面
– たとえば端末エミュレータなど
●
ビュー
– スクリーンを実際の画面に表示するためのもの
– スクリーンとは1対1の関係
●
フロントエンド
– ディスプレイやビューの定義と描画を担当する
– ncursesやelectronなど
Lemの描画関係用語
(実際に描画するためのもの)
Lem上のデータ構造 フロントエンド
ビュー
ビュー
ビュー
ビュー
ディスプレイ
ウィンドウ
とスクリーン
ウィンドウツリー
フレーム多重化機能対応でやったこと
●
「フレーム」の概念をLemに追加
– ウィンドウ(つまり画面構成)を保持するもの
●
Lemの描画処理をフレームに対して働くよう変更
– 起動時に1個のフレームを作成しておく
●
フレームを複数持てるように拡張
– 仮想フレームって呼ぶことにした
●
切り替えコマンドを追加
– 大事
フレーム多重化機能対応でやったこと
●
「フレーム」の概念をLemに追加
– ウィンドウ(つまり画面構成)を保持するもの
●
Lemの描画処理をフレームに対して働くよう変更
– 起動時に1個のフレームを作成しておく
●
フレームを複数持てるように拡張
– 仮想フレームって呼ぶことにした
●
切り替えコマンドを追加
– 大事
フレームの概念を追加
●
画面表示関係のグローバル変数を集約
●
frame構造体を作成
●
以下のものを持つ
– 現在操作しているウィンドウ
– ウィンドウ構成(分割状態)
– ミニバッファのウィンドウ
– ミニバッファのバッファ
– 補完時に出てくるウィンドウ
など…
フレームの概念を追加
Lem上のデータ構造 フロントエンド
ディスプレイ
フレーム
フレームの概念を追加
●
frame構造体
– 現在の「ウィンドウ」
– ウィンドウ構成(window-tree)
– ミニバッファ関連
–
補完時のfloatingウィンドウ
– ヘッダウィンドウ
– ウィンドウまわりのフラグ
(defstruct frame
;; window
current-window
(window-tree nil)
(floating-windows '())
(header-windows '())
(modified-floating-windows nil)
(modified-header-windows nil)
;; minibuffer
minibuffer-buffer
echoarea-buffer
(minibuffer-window nil)
(minibuffer-calls-window nil)
(minibuffer-start-charpos nil))
フレーム多重化機能対応でやったこと
●
「フレーム」の概念をLemに追加
– ウィンドウ(つまり画面構成)を保持するもの
●
Lemの描画処理をフレームに対して働くよう変更
– 起動時に1個のフレームを作成しておく
●
フレームを複数持てるように拡張
– 仮想フレームって呼ぶことにした
●
切り替えコマンドを追加
– 大事
フレームに対する描画処理
●
Lemの起動時に1個のフレームを作成
●
グローバル変数を使う処理が現在のフレームに
対して働くようにぜんぶ変更
●
動作確認
– 大事
フレームに対する描画処理(変更例)
●
floating-windowに対する削除処理
– 前: グローバルな変数に対してsetf
– 後: グローバルなフレームのスロットにsetf
(defmethod %delete-window ((window floating-window))
(when (eq window (current-window))
(editor-error "Can not delete this window"))
- (setf *modified-floating-windows* t)
- (setf *floating-windows*
- (delete window *floating-windows*)))
+ (setf (frame-modified-floating-windows (current-frame)) t)
+ (setf (frame-floating-windows (current-frame))
+ (delete window (frame-floating-windows (current-frame)))))
ここまでのPR
●
https://github.com/cxxxr/lem/pull/500
フレーム多重化機能対応でやったこと
●
「フレーム」の概念をLemに追加
– ウィンドウ(つまり画面構成)を保持するもの
●
Lemの描画処理をフレームに対して働くよう変更
– 起動時に1個のフレームを作成しておく
●
フレームを複数持てるように拡張
– 仮想フレームって呼ぶことにした
●
切り替えコマンドを追加
– 大事
フレームを複数持てるよう拡張
●
やること
– 「仮想フレーム」の用意
●
フレームを複数保持するスロット
●
現在表示中のフレームを置くスロット
– 仮想フレームの描画処理の実装
フレームを複数持てるよう拡張
●
仮想フレームの用意
– フレームの配列
– 現在のフレーム
– ディスプレイ幅・高さ
– 仮想フレームが変更されたかフラグ
– 仮想フレームのヘッダ用バッファ
●
(いまvfはvirtual-frameにリネームされてます)
●
ディスプレイ-仮想フレームの対応表も追加
– ただのハッシュテーブル
– キーはディスプレイ (現在は1つしかない)
– Lemが複数の表示画面を持つときのため
(defclass vf (header-window)
((frames)
(current)
(display-width)
(display-height)
(changed)
(buffer)))
フレームを複数持てるよう拡張
これが仮想フレーム
兼
ヘッダウィンドウ
フレームを複数持てるよう拡張
●
vfはLemのヘッダウィンドウなので
●
Lemのウィンドウ再描画メソッドを実装する必要あり
●
仮想フレームの描画処理
– ヘッダを描画
– 現在のフレームのウィンドウをぜんぶ描画
– 仮想フレームの描画フラグをnilに設定
(defmethod window-redraw ((window vf) force)
;; draw button for frames
...
;; redraw windows in current frame
...
;; clear all vf-changed to nil because of applying redraw
...
(call-next-method))
フレーム多重化機能対応でやったこと
●
「フレーム」の概念をLemに追加
– ウィンドウ(つまり画面構成)を保持するもの
●
Lemの描画処理をフレームに対して働くよう変更
– 起動時に1個のフレームを作成しておく
●
フレームを複数持てるように拡張
– 仮想フレームって呼ぶことにした
●
切り替えコマンドを追加
– 大事
操作の実装とコマンドの定義
●
基本的なフレーム操作
– フレーム多重化機能の起動・終了処理
– フレームの追加・削除
– フレームの切り替え
●
どの操作でも最後にvf-changedをtにする
– 現在のフレームを変更した後に再描画させるため
●
操作用コマンド
– toggle-frame-multiplexer
– frame-multiplexer-create (C-z c)
– frame-multiplexer-delete (C-z d)
– frame-multiplexer-prev (C-z p)
– frame-multiplexer-next (C-z n)
操作の実装とコマンドの定義 (例)
●
仮想フレーム上のフレーム切り替え(前へ)
– 仮想フレーム上の1つ前のフレームを探し、
– そのフレームを現在のLemのフレームに設定し、
– 再描画フラグをtに設定する。
(define-command frame-multiplexer-prev () ()
(check-frame-multiplexer-enabled)
(let* ((vf (gethash (implementation) *virtual-frame-map*))
(frame (search-previous-frame vf (virtual-frame-current vf))))
(when frame
(setf (virtual-frame-current vf) frame)
(lem:map-frame (implementation) frame))
(lem::change-display-size-hook)
(setf (virtual-frame-changed vf) t)))
ここまでのPR
●
https://github.com/cxxxr/lem/pull/501
このPRのときはfm-mode
という名前でした。
(いまはframe-multiplexer)
こぼれ話
●
実装にあたってLemのコードを調査した
– よくできててかなり勉強になった
– 描画の用語の整理結果はWikiに記載した
https://github.com/cxxxr/lem/wiki/Lem's-displaying-concepts
– 起動時の流れも調べた
https://gist.github.com/t-sin/cc0d036e40669395fd41cfd48bb9c997
●
最初はfm-modeという名前で作っていたが
Lemのdefine-modeを使っておらず実はモードではなかった
– frame-multiplexerに名称変更
– lem/modes/fm-mode/ から lem/lib/core/frame-multiplexer.lisp に
– 地味にcoreに取り込まれた🎊
こぼれ話
●
現在はバッファリスト(C-x bの対象)が共有されている
– elscreenの動き
– cxxxr氏より「作業を分けるためバッファリスト非共有がいい」
– ノリノリで雑ハックし、激しいバグを生む
●
PR: https://github.com/cxxxr/lem/pull/504
●
Lemの非公開関数でグローバル変数をもりもり変更するマナーの悪いコードだっ
たのでいったんクローズ
●
事前に設計をちゃんとしましょう
●
ちなみにGNU Emacsで仮想フレームに対応するものは
window-configurationというのだそう
– https://www.gnu.org/software/emacs/manual/html_node/elisp/Window-Configurations.html
– @conao_3 さんに教えてもらいました
●
https://twitter.com/conao_3/status/1291710740294901760
まとめ
●
Lemにフレーム多重化機能を実装した
●
Lemは読むとCommon Lispの勉強になる
– clrhash関数など
– http://www.lispworks.com/documentation/HyperSpec/Body/f_clrhas.htm
●
Lemは大きなソフトウェアなのでPRを投げると
Common Lispチョットデキル…という気持ちになれる
●
事前の設計は大事

More Related Content

What's hot

Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについてmametter
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと信之 岩永
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門Eita Sugimoto
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナドYoshihiro Mizoguchi
 
数学プログラムを Haskell で書くべき 6 の理由
数学プログラムを Haskell で書くべき 6 の理由数学プログラムを Haskell で書くべき 6 の理由
数学プログラムを Haskell で書くべき 6 の理由Hiromi Ishii
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Etsuji Nakai
 
20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdf20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdfKazuaki Ishizaki
 
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜Ryoma Sin'ya
 
GPUをJavaで使う話(Java Casual Talks #1)
GPUをJavaで使う話(Java Casual Talks #1)GPUをJavaで使う話(Java Casual Talks #1)
GPUをJavaで使う話(Java Casual Talks #1)なおき きしだ
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みMasahiro Sakai
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介MITSUNARI Shigeo
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxpsMITSUNARI Shigeo
 
C++でCプリプロセッサを作ったり速くしたりしたお話
C++でCプリプロセッサを作ったり速くしたりしたお話C++でCプリプロセッサを作ったり速くしたりしたお話
C++でCプリプロセッサを作ったり速くしたりしたお話Kinuko Yasuda
 

What's hot (20)

Quine・難解プログラミングについて
Quine・難解プログラミングについてQuine・難解プログラミングについて
Quine・難解プログラミングについて
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
C#とILとネイティブと
C#とILとネイティブとC#とILとネイティブと
C#とILとネイティブと
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
ラムダ計算入門
ラムダ計算入門ラムダ計算入門
ラムダ計算入門
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
Go入門
Go入門Go入門
Go入門
 
圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド圏論のモナドとHaskellのモナド
圏論のモナドとHaskellのモナド
 
暗認本読書会7
暗認本読書会7暗認本読書会7
暗認本読書会7
 
数学プログラムを Haskell で書くべき 6 の理由
数学プログラムを Haskell で書くべき 6 の理由数学プログラムを Haskell で書くべき 6 の理由
数学プログラムを Haskell で書くべき 6 の理由
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
 
20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdf20221226_TITECH_lecture_ishizaki_public.pdf
20221226_TITECH_lecture_ishizaki_public.pdf
 
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
AVX2時代の正規表現マッチング 〜半群でぐんぐん!〜
 
GPUをJavaで使う話(Java Casual Talks #1)
GPUをJavaで使う話(Java Casual Talks #1)GPUをJavaで使う話(Java Casual Talks #1)
GPUをJavaで使う話(Java Casual Talks #1)
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
C++でCプリプロセッサを作ったり速くしたりしたお話
C++でCプリプロセッサを作ったり速くしたりしたお話C++でCプリプロセッサを作ったり速くしたりしたお話
C++でCプリプロセッサを作ったり速くしたりしたお話
 

Similar to Common Lisp製のテキストエディタLemにフレーム多重化機能をつくった

Vimから見たemacs
Vimから見たemacsVimから見たemacs
Vimから見たemacsShougo
 
Common Lispっぽいものをつくっています
Common LispっぽいものをつくっていますCommon Lispっぽいものをつくっています
Common Lispっぽいものをつくっていますt-sin
 
Eclipse modeling 勉強会 dslについて
Eclipse modeling 勉強会 dslについてEclipse modeling 勉強会 dslについて
Eclipse modeling 勉強会 dslについてAkira Tanaka
 
Emacs上のターミナルを最強に
Emacs上のターミナルを最強にEmacs上のターミナルを最強に
Emacs上のターミナルを最強にLintaro Ina
 
うわ…私のEmacs力、低すぎ...?
うわ…私のEmacs力、低すぎ...?うわ…私のEmacs力、低すぎ...?
うわ…私のEmacs力、低すぎ...?Masahiro Sano
 
KLab Social Game Platform ~Symfony1.4活用事例~
KLab Social Game Platform ~Symfony1.4活用事例~KLab Social Game Platform ~Symfony1.4活用事例~
KLab Social Game Platform ~Symfony1.4活用事例~KLab株式会社
 

Similar to Common Lisp製のテキストエディタLemにフレーム多重化機能をつくった (6)

Vimから見たemacs
Vimから見たemacsVimから見たemacs
Vimから見たemacs
 
Common Lispっぽいものをつくっています
Common LispっぽいものをつくっていますCommon Lispっぽいものをつくっています
Common Lispっぽいものをつくっています
 
Eclipse modeling 勉強会 dslについて
Eclipse modeling 勉強会 dslについてEclipse modeling 勉強会 dslについて
Eclipse modeling 勉強会 dslについて
 
Emacs上のターミナルを最強に
Emacs上のターミナルを最強にEmacs上のターミナルを最強に
Emacs上のターミナルを最強に
 
うわ…私のEmacs力、低すぎ...?
うわ…私のEmacs力、低すぎ...?うわ…私のEmacs力、低すぎ...?
うわ…私のEmacs力、低すぎ...?
 
KLab Social Game Platform ~Symfony1.4活用事例~
KLab Social Game Platform ~Symfony1.4活用事例~KLab Social Game Platform ~Symfony1.4活用事例~
KLab Social Game Platform ~Symfony1.4活用事例~
 

More from t-sin

続・SECDマシン
続・SECDマシン続・SECDマシン
続・SECDマシンt-sin
 
SECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてSECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてt-sin
 
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミング
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミングSounds Like Common Lisp - ゼロからはじめるサウンドプログラミング
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミングt-sin
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装したt-sin
 
PythonでLispを実装した (evalつき)
PythonでLispを実装した (evalつき)PythonでLispを実装した (evalつき)
PythonでLispを実装した (evalつき)t-sin
 
バッテリー強奪! PythonをCommon Lispから使う
バッテリー強奪! PythonをCommon Lispから使うバッテリー強奪! PythonをCommon Lispから使う
バッテリー強奪! PythonをCommon Lispから使うt-sin
 
Common lispでグラフィックアート
Common lispでグラフィックアートCommon lispでグラフィックアート
Common lispでグラフィックアートt-sin
 
One - Common Lispでもワンライナーしたい
One - Common LispでもワンライナーしたいOne - Common Lispでもワンライナーしたい
One - Common Lispでもワンライナーしたいt-sin
 
Inquisitor -Common Lispに文字コード判定を-
Inquisitor -Common Lispに文字コード判定を-Inquisitor -Common Lispに文字コード判定を-
Inquisitor -Common Lispに文字コード判定を-t-sin
 

More from t-sin (9)

続・SECDマシン
続・SECDマシン続・SECDマシン
続・SECDマシン
 
SECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについてSECDマシン 実装と動きとその他もろもろについて
SECDマシン 実装と動きとその他もろもろについて
 
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミング
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミングSounds Like Common Lisp - ゼロからはじめるサウンドプログラミング
Sounds Like Common Lisp - ゼロからはじめるサウンドプログラミング
 
謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した謎の言語Forthが謎なので実装した
謎の言語Forthが謎なので実装した
 
PythonでLispを実装した (evalつき)
PythonでLispを実装した (evalつき)PythonでLispを実装した (evalつき)
PythonでLispを実装した (evalつき)
 
バッテリー強奪! PythonをCommon Lispから使う
バッテリー強奪! PythonをCommon Lispから使うバッテリー強奪! PythonをCommon Lispから使う
バッテリー強奪! PythonをCommon Lispから使う
 
Common lispでグラフィックアート
Common lispでグラフィックアートCommon lispでグラフィックアート
Common lispでグラフィックアート
 
One - Common Lispでもワンライナーしたい
One - Common LispでもワンライナーしたいOne - Common Lispでもワンライナーしたい
One - Common Lispでもワンライナーしたい
 
Inquisitor -Common Lispに文字コード判定を-
Inquisitor -Common Lispに文字コード判定を-Inquisitor -Common Lispに文字コード判定を-
Inquisitor -Common Lispに文字コード判定を-
 

Common Lisp製のテキストエディタLemにフレーム多重化機能をつくった