IRB Reline Changes
2023/11/06
今日になってCIがこけるようになったことに対する修正として、Gemfileにraccを追記しています
今日RDocの新しいバージョンが出た・RDocがraccを必要としている・raccがbundled gemに変わった あたりが原因でした
なお、新しいRDocを入れると、IRBの補完速度が改善します。
ドキュメントが無いメソッド補完するとき、RDoc::RI::Driver::NotFoundErrorが発生する(ドキュメントがあるか探す・なかった場合は例外が出てrescueしている)んですが、
このエラーメッセージにDidYouMeanを使っていて、時々すごく遅くなる問題あったのが直っています(長いクラス名を使うと特に。error.messageを呼ぶまで遅延させるようになった)
Reline::Face APIが追加されたことにより、IRBの補完ダイアログなどの色をカスタマイズできるようになります :tada: 詳しくはPull Requestを見てね
2023/11/07
2023/11/08
IRBに型情報を使った補完が追加されました :katakatakata:
デフォルトは今までの正規表現を使った補完のままなので、有効化するには .irbrcに
IRB.conf[:COMPLETOR] = :type
を追記する必要があります。ぜひ試してみてね (コマンドラインオプションか環境変数でも有効化できるようにしたい)
RubyのCIが通るように一部のテストをスキップ
型使った補完のドキュメント追加
Pryとの比較(IRB側の実装進捗状況)の表を追加(と修正)
2023/11/09
型補完を使うか正規表現補完を使うか、コマンドラインオプションで切り替えれるようになりました
$ irb --type-completor
$ irb --regexp-completor (デフォルト)
2023/11/10
1.9.0 released :tada:
gem installすると
irb --type-completorで型情報を使った補完が使えます(別途gem prismも必要。足りない時は何が必要かのwarnメッセージが出る)
2023/11/13
Reline::Faceで "#abcdef" の形式で色を指定した時、truecolor(16777216色)未対応の端末(例えばMac標準のTerminal.app)では256色にfallbackするようになりました。
対応しているかどうかの判定には ENV['COLORTERM'] を見ているので、環境変数が設定されていなければ対応端末でも256色になってしまいます(例えばWindows Terminal)。
そんな時はReline::Face.force_truecolor をirbrcに書けば環境変数によらず常にtruecolorを使うようになります。(変わるかも)
2023/11/14
WorkaroundとしてGemfileに足したracc (rdocが使ってたっぽい?)が不要になったので消しています。
(rdocのgemspecにraccが足されたわけではなく、どう解消したのかよくわかっていない)
TypeCompletionのテストをruby/rubyのciで動かすようにした(一時期動いてなかったのでskipさせてた)んですが、
skipをやめたらIRB::VERSIONがあること前提の定数の補完テストだけが落ちてました。(IRB::VERSIONが未定義だった)
対処として、require 'irb/version' を足しています
2023/11/21
IRBのeaster-eggをautocompleteでも動くようにした時に入れてしまったバグの修正です
デフォルトの正規表現を使った補完で {}. に対してProcかHashのメソッド補完とドキュメント表示をしようとしてるんですが、この時に限り name = doc_namespace.call(result[pointer]) nameが配列になっていて、
nameがStringかnil前提のコードがエラーを出してました。
IRBの新しい型補完を環境変数を使って有効化できるようになりました
IRB 1.9.1 released :tada:
2023/11/24
補完でドキュメントを出す時、どのドキュメントを出すのか計算する処理をrescue Exceptionで囲ったりVERBOSE=nilにしてwarningが出ないようにしています。
具体的に問題があったのはSortedSetの補完で、SortedSet定数が存在しているからといってconst_get(:SortedSet)が成功するとは限らない(SortedSetに限らず、railsとかのautoloadされるconstだとエラーもwarnも何でも起きうる)
型補完に使っているPrismの必要バージョンを上げました。 case match と /(?<lvar>)/=~s のASTに非互換な変更が入ったので。(ruby3.3リリースまでにあと1つか2つくらい非互換な変更が入るかもしれない)
IRBに入力したコードをevalする時にexceptionが出て、かつそのexceptionをprintしようとした時に別のexceptionが出た場合にIRBが落ちる問題を修正しています。
exceptionが何かおかしい場合・時間がかかっていてCTRL+Cを押した場合などにIRBが落ちます。
code:ruby
# 例
irb(main):001> raise Exception.new.tap{def _1.message;puts'press CTRL+C';loop{};end}
Pagerで何かを表示する際、pagerがlessかmoreだった時は-Rオプションをつけていたところ、moreには-Rオプションはないのでlessにだけつけるように変えています。
これ、Macだとmore -Rで何も問題なくて、moreのバージョン問題かと思いきや
code:shell
$ more --version
less 581.2 (POSIX regular expressions)
lessがmoreになりきってるだけだった...
2023/11/25
backtrace=nilなexceptionが発生してもIRBが何も表示しない問題が直りました。
backtrace=nilなエラーが起きたとき(そんな例外を出すライブラリ側のバグ)IRBが死んでしまう問題が10年前にあって、その対策で if exc.backtrace みたいな分岐が足されていました。
(backtraceがない場合もexception.inspectが正しく表示されることを確認したそうなテストはあったがうまく機能していなかった)
pull/780 でexceptionの処理中に起きた例外はrescueするようになったこと、通常起きないbacktrace=nilだけ特別の分岐をする意味もないので不要な分岐を単に消して、ほぼ起きないであろうバグも直った、という感じ
Regexpを使った補完で {}. が失敗する問題の修正のために追加したテストがランダムにこけるのが修正されました。
ドキュメントのdialogが表示されるかされないかギリギリのタイミングなので、表示されていても表示されていなくてもテストが通るようにテストを変えて直しています。
補完dialogが表示されるまで待てればいいんですが、それをするには(hackはあるものの) ターミナル上でのテストフレームワーク yamatanooroti の機能不足でうまくいかない
2023/11/27
pagerを使うかどうかon/off指定するオプション(--no-pager と IRB.conf[:USE_PAGER])が追加されました。
inspectをpager出力できるようにするpullreqが出ていて、それをoffにしたい人もいるかもしれない、とかの意図かな、 --no-pager はpryやgitにもあるオプションです
debugモードでdebug用のコマンド(例えば info )を入力した時、 info # debug command と後ろにヒントが表示されるようになりました。
debug gemでもやっていることで、rubyのコードとして評価されるのか、debug用のコマンドなのか区別しやすくなります。(debug用のコマンドにはiとかnとかのローカル変数名と被りそうな短いエイリアスもあるので)
pull/789 では、入力中にのみヒントを表示して、入力完了後にはヒントが消えるようにしています。(それをする方法(output_modifier_procのcomplete:オプション)がRelineにあることが788の後に判明した)
2023/11/28
context.main (IRBの中のself)のto_sメソッド (promptのirb(この部分):001> に表示される) がエラーになる時にIRBが落ちる不具合が治りました。
IRBはそういうobjectがselfの時に落ちるべきではないし、def initializeの中にbinding.irbを仕込むと簡単にそういう状況になるとのこと。確かに。
show_sourceコマンドで show_source Foo#bar -s show_source Foo#bar -ssss と -sをつけた回数だけsuperを遡ってメソッド定義を見れるようになりました
Reline 0.4.1 リリースしました:rocket:
環境変数COLORTERMを見て256colorとtruecolorを分岐するようになりました。COLORTERMが設定されていないけどtruecolor対応の端末の場合、 .irbrc で Reline::Face.force_truecolor を呼ぶことでtruecolorとなります
新しくこんなリポジトリとgemができました
最初のバージョン0.1.0からはこれからapiが変わるかもしれない(0.1.0が入ってて>0.1.0が入ってない状態だとまずそう)
2023/11/29
両方ともテスト関連の修正です
show_source -ss のテストでclass Barを定義してしまうと、ruby/rubyのmodule自体のテストがこけてしまうようでした。(未定義のBarをconst_getできないことを確かめるテスト)
対策として、show_sourceのテストをIntegration test(別プロセスでirbを立ち上げるテスト)に変えています。(そもそもその方が適切だろう、と)
rake testで実行する対象のファイル指定方法を変えています。
FileList["test/irb/test_*.rb", その他] → FileList["test/irb/**/test_*.rb"]
TypeCompletorの実装がIRBから消えて、gem repl_type_completor を使うようになりました。
追加でgem installが必要な代わりに、IRBとは独立してreleaseできる・IRBとはテストも独立するので、rbs prism のいろんなバージョンでテストを回せる(そうした時にIRBのテストが遅くならない)とかのメリットがあります。(ruby 3.4 くらいでbundled gemになるといいな)
2023/11/30
irbで入力式を評価した結果の出力がpagerで表示されるようになりました :tada:
irb(main):001> 1000.times.to_a
でpagerが立ち上がります。特にremoteで(sshにみたいな環境で)irbを使ってる時、うっかり巨大なinspectを出力してももう大丈夫です
2023/12/01
Reline 0.5.0.pre.1 をリリースしました。 gem install reline -v 0.5.0.pre.1でインストールできます。
Relineの一番のコア部分 line_editor.rb のレンダリング処理を刷新しています。(line_editor.rb 3297行に 604 insertions(+), 1285 deletions(-))
多くのバグ(特に行数がターミナルの行数より長い時)が直ってるはず。ぜひ入れて使い勝手やバグ報告などフィードバックをください
Relineで単一行入力する場合 Reline.readline('>') 自動補完をoffにしてTab補完を使った場合 irb --noautocomplete の挙動も少し変わった
IRBの型補完で使うPrism RBSのバージョン範囲をちゃんと指定するようになりました(抜けてた上限の方を指定)
違うencoding(ENVLANGを変えて)でIRBを起動するとIRB終了時にhistoryファイルに複数のencodingのhistoryが混ざ...らずにhistoryファイルを消し飛ばしてしまう不具合を直しています String#scrubで(現在のencodingで)不正な文字を置換文字に置き換えて変えてhistoryに保存するようになりました。
history コマンドが追加されました。history -g 正規表現 で絞り込めます
history、色がついても良いし、index指定してshowできてもいいな (3行以上はtrancateされちゃうので) 正規表現がマッチした箇所のハイライトがあっても良さそう
2023/12/03
1.10.0 released :tada:
2023/12/06
IRB 1.10.1 released :tada:
CIでIRBを使うテスト(例えばrailsの、rails consoleのテスト)向けの修正が入っただけなので、普通に使う分には特に差は無いです
CI上でpagerが立ち上がると既存のテストがうまくできないのでpagerが無効になるようにしてます
2023/12/07
repl_type_completor でirb 0.10.0以上を使うようにしました。
型補完ライブラリなのに bin/console で型補完が効かない残念な状態が解消します。
(型補完が有効になってないだけなのに型補完壊れたのか思って調べたりと色々と不便だった)
2023/12/11
型補完でも、IRBの正規表現を使うデフォルトのメソッド補完と同様に、+ - * / などの記号のメソッドを補完候補から除外するようにしています
binding.irbではなくirbコマンドでIRBを立ち上げたときはdebug系のコマンドが使えないんですが、その旨を表示するメッセージを改善しています
show_source コマンドのリファクタリングです。
show_source foo.bar -sss などの-sオプションを指定しなかった場合、super_level=nilとしていたのを0にすることで条件分岐を減らしています
2023/12/13
Encoding.default_external を設定し、ensureで元に戻しているテストがあるんですが、warningが出るようでsuppressしています
IRBのドキュメントがたくさん追加されました。 +1069 -197
ドキュメントのうち、deprecatedにしたい機能についての項目などを消しています
2023/12/14
IRBのmeasureコマンドには実はdo endでブロックを渡せました。(ドキュメントされてない・渡しても想定したような挙動はしないので使わないでね)
渡してもwarningメッセージが出るだけで何も起きないようにしました。
813のテストコードの修正(未使用変数を紛れ込ませてしまったのを削除)
2023/12/17
特定の条件で gem readline が readline.so をrequire出来ないことがある問題の対処です。(rubygemsが上書きしたrequireメソッドの方に問題があって、そのworkaroundかな?)
ex() に対して ex()it などが補完されてしまう問題を修正しました。
prism 0.19.0 (ruby 3.3にbundleされる予定)への対応をしました。
新しく追加されたNode typeに対する処理の追加、バグ修正などで不要になったworkaroundを消したり、など
2023/12/18
CIのdaily build (ruby 2.7)がこけてたことに対する修正です。12/15にリリースされた最新のbundlerが ruby >= 3.0.0 になったからかな
Prism 0.19.0 に対応した ReplTypeCompletor v0.1.1をリリースしました
2023/12/20
irbrcで起きたエラー(LoadErrorとか)が何もエラーメッセージを出さない問題が解消しました。
begin; load irbrc_file; rescue LoadError irbrc_fileの存在確認をせずにLoadErrorを握りつぶしてるせいで、irbrcの中での例えば require 'hogehoge' が失敗したエラーまで握り潰していました。ファイルの存在確認をしたあとでloadするように変えています
IRB v1.11.0 released:クラッカー:
Ruby 3.3にbundleされるバージョンです
2023/12/22
pull/8の実装の不備(typoに近い)の修正です。
補完でエラーが出てIRBごと落ちたら大事だし、warnなどを出すと補完ダイアログが崩れるので起きた例外を握り潰してるせいで気づかなかった。(今後同じことが起きないようにテストコード側も修正)
:stoppdoc: で囲われた意味のないドキュメントを削除してるようです
2023/12/23
IRBのREADME 型補完の説明などの修正です
2023/12/25
require "path の補完時に、同じ候補の重複・同じファイルを指す複数の重複したパスを除去するようにしました。
同じ候補の重複の例: bundleされたirbとgem installされたirbの2つが候補に出る
重複パスの例: 3.2.0/arm64-darwin22/readline arm64-darwin22/readline readline はどれも同じファイルreadline.bundleをさしていてどれもrequire可能(LOAD_PATH次第) でも補完候補に出すのは最短のものだけで十分
classやmoduleの中のメソッド補完でclassのprivate_methodが出てこない問題を修正しました。
repl_type_completor v0.1.2 released :クラッカー:
2024/01/01
テストで使ってない環境変数を削除しようとしてたコード(relineからのコピペ?)を消してます
SIGINT関連のテストが特定環境でこける対策と、それに関連する足りてなさそうなテストケースの追加です
IRBの型補完を自動補完offで使い、TABキーでドキュメント表示する時にドキュメントが出ないことがある問題の修正です
(配列に入ってる値の順序間違えてた)
2024/01/02
show_sourceで::始まりのトップレベル定数のsourceを表示できない不具合が直ります
普段はあまり使うことはないと思うんですが、moduleの中でbinding.irbしていて、かつトップレベル定数と同名の定数があるときに役立ちます。
2024/01/03
IRBの正規表現補完で、空文字列・空白のみの時にタブを押した時に補完候補を出さないようになりました。
単にあまり意味のない補完をやめたというだけじゃなく、インデントに空白文字の代わりにタブを使っているコードをペーストした時に補完される ! とか != とかがタブの位置に挿入されるのを防ぎたいという意図もあります。
(が、Reline側のバグによりタブ混じりのコードを貼り付けるとRelineがエラーを吐いて落ちることがある)
2024/01/05
↑のタブ混じりのコードを貼り付けると落ちる問題の修正です
split("\n").last と split("\n", -1).last の違いみたいなバグでした。
カーソル位置の@byte_pointerに今編集中の行のbytesizeより大きい値が入ってしまっていた
2024/01/07
タブ混じりで落ちる問題が修正された reline-0.4.2 がreleaseされました
IRBでreline-0.4.2以上を使うようにしています。IRB側のタブでの補完の修正により、reline-0.4.2以上でないとirbが落ちるようになったため
(型補完使っていてタブ混じりのコード(rubyだとほぼないと思うけど)を貼り付けた場合は以前のirbでも落ちる...)
irbのexit(irbを抜ける)をコマンドとしてちゃんと実装しました。これにより、exitの説明がshow_cmdsにちゃんと表示されるようになります。
2024/01/08
バイナリファイル(.bundle .soなど)で定義されたものをshow_sourceしようとするエラーを吐く不具合の修正です。
バイナリファイルから該当行を探そうとして、invalid byte sequence in UTF-8エラーなどが出ます。
source_locaitonが filename, 0 のように行番号が通常1以上になるところ、0になってる場合はファイルを開かないようにしています。 ちなみにファイル名で判別しようとすると、例外ケース(bin/console bin/rails は拡張子がないけどrubyのスクリプト)がある
2024/01/09
v1.11.1 released :tada:
2024/01/23
ドキュメントのtypo修正 +niL+ → +nil+
2024/01/24
require 'libraryname の補完で、require 'fooが require 'foo/barより上に表示されることをテストしている箇所で、ライブラリ名の例として csv を使っていたところ、csvがruby 3.4でdefault gemからbundled gemに変わる(で合ってるかな?)ので、代わりに rubygemsを使うように変更されました。
2024/01/25
documentのtypo修正と、ついでに文章をいい感じに修正しています
こちらもtypo修正です。一括でtypoを全部直してくれたっぽい :arigata:
2024/01/30
alias if while undef end とかのインデントの不具合を直しています。
こんな感じになっていた
code:ruby
class A
alias if while
def foo
end
undef end
end
alias end:end alias**** alias:"#{}"=== とか、undef aliasは割と自由に書けるし、もちろん間に改行・コメント・#{}の埋め込みの中にヒアドキュメントも書ける。非常に読みにくくて良い
2024/02/01
trufflerubyでテストを一部スキップしています。
trufflerubyのsyntax errorの挙動が変わって、どうやらparserをprismに変えたっぽい雰囲気のテストのこけ方をしていました。
落ちてるテストは
1. IRBに .;a+ と入力した時のテスト(unexpected '.' ではなく cannot parse the expression が出る)
2. IRBに :"\xAE" と入力した時のテスト(parse時点でEncoding系のエラーを出す・prismはエラー出さない)
Prismに変わったことで、truffleruby(3.2相当と言いつつendless method definitionに対応してなかった)がもう対応してるかもしれない。(truffleのテストskipを減らせるようになってると思う。今回はskip増やしたけど)
IRBがSyntaxErrorのエラーメッセージに依存してるのがよくないのはそれはそう
IRBの初期化を一度しか行わないように修正されました。
- irbrcファイルを何度も読み込んでしまう
- irb -f (irbrcを読み込まないコマンドラインオプション)で起動しても binding.irbに到達すると結局irbrcを読み込んでしまう
などの不具合が直りました
2024/02/02
irbからdebugを使った時のHISTORY保存のバグ(HISTORYの行数が爆発的に増える)が直りました。
Reline::HISTORY Readline::HISTORY (配列)のうち、どこまでをhistoryファイルに保存したか、のカウンターに値をセットしないケースがあったところを修正しています
rubocop入りました
2024/02/03
新しくprism0.20.0がリリースされたので、gemspecのprismのバージョンをあげてciでもテスト回すようにしました。
irbrcで指定されたhistoryファイルのパスが、そもそもディレクトリすら存在しない時、history保存しようとした時にエラーが出ていたんですが、エラーが出ないように修正され、warningメッセージを出すようになりました。
ちなみに、mkdirpで無いディレクトリを作成するツールもあるんですが、ディレクトリ作成しないツールも割とある(作成するのがスタンダードではない)・typoだった時に変なディレクトリ作られるのは嫌だろう、ということで、IRBではwarningだけにすることにしました
↑のプルリクでciで問題が起きたことに対する対応2件
require 'pathname' が抜けていてruby/rubyのciがこけてしまうのを修正
ruby/rubyのciでwarningが出てしまうのを修正(とassertionをより厳密に)
2024/02/08
tracer gemがバージョンアップしてから irb --tracer (IRB.conf[:USE_TRACER] = true) が壊れていたのを直しています。テストもなかったようで追加されました
2024/02/11
IRBにexit! コマンドが追加されました。
exit!でプログラムを終了するとhistoryを保存してくれない(それはそう)というissueがあって、また、ループの中にbinding.irbを書いた時にIRBからプログラムを正常に終了する方法が分かりにくい(Kernel.exitを呼べばいいけど)という問題もあって、それらが解決します。
IRBの中では irb_exit Kernel.exit Kernel.exit! の役割が一つずれるという仕様になった。(exitでirb_exit、exit!でKernel.exit)、一貫してて良いんじゃないかなと思う
at_exitやensureをすべてスキップして終了したいときは irb(main):001> Kernel.exit! って打てばいいけどそう言うケースはあまりないんじゃないかなぁ
viモード(inputrcで設定できる)の大文字のCキー(カーソル位置から行末まで消してinsertモードに切り替える)が実装されました。
(viモードについてあまり知らずに遅くなってしまった。1年半前にopen)
もし今のタイミングで入れずにこの後控えてるリファクタの後にしてしまうと色々conflictしそうだった
2024/02/12
追加されたexit!コマンドの微修正です。
- binding.receiverがfrozenだった場合に出てしまうwarningが出ないように
- exit!コマンドをirb外で使った時の挙動を微修正
(IRBではコマンド=メソッドなので、binding.irbに入るとself.exit!コマンドが上書きされてしまい、irbを抜けた後で通常のexit!メソッドを実行しようとしてもコマンドのexit!が実行されてしまったりする)
2024/02/13
IRBで RubyVM.keep_script_lines を有効にして、IRB内で定義したメソッドもshow_sourceできるようにしました。
あと細かいリファクタとかもしたり、show_sourceの出力を良い感じにしたり。
code:ruby
irb(main):001> show_source IO::ConsoleMode
Defined in binary file: ~/.rbenv/versions/3.3.0/lib/ruby/3.3.0/arm64-darwin22/io/console.bundle
irb(main):001> show_source Object#tap
From: <internal:kernel>:89
Source not available
2024/02/14
ShowSourceのリファクタと、evalの第三(か第三?)引数に渡すfilename(irb_pathとeval_pathというのがある)関連のリファクタです
(Fileが実在するときは末尾に"(irb)" をつけ、irb内で定義したメソッドのsource_locationが実在するファイルと同一にならないようにする)
定数のshow_sourceを改善しました。例:
code:ruby
W=1
module M
X=2
end
class A
Y=3
class B
include M
Z=4
binding.irb
end
end
このコードのbinding.irbの位置では定数W X Y Z が参照できるのですが、今までのshow_sourceではYのみshowできませんでした。
複数の箇所で同じ名前の定数が定義されていた時(上のコードでW,X,Y,Zを全部同じ名前にした場合など)にも正しくshow_sourceできるよう、Rubyと(多分)同じ定数探索順序で調べるようにしました。
IRBのhelpコマンドが歴史的経緯で使う人の期待と違う機能を提供していたのが、ちゃんとhelpになりました。
show_doc(Rubyのドキュメントの検索機能) → show_cmds(IRBのコマンドの一覧・使い方)
(breaking changeになるだろうと、helpコマンドを実行した際、以前からhelpを変えるという予告メッセージを出していたのでそろそろいいだろう、と)
2024/02/16
テストコードの修正です。Ruby本体のNoMethodErrorなどのエラーメッセージが改善されたので、正しいエラーメッセージが出るかどうかのテスト(正規表現でマッチするか調べてる)がこけるようになっていました。
IRBの型補完 repl_type_completor の要求するprismのバージョンを更新してv0.1.3をリリースしました。
Ruby 3.3はprism-0.19.0をbundleしてるんですが、今は0.23.0まで出てるので要求バージョンを < 0.24.0 に引き上げました。
Prism 0.19.0まではbreaking changeがかなり多かったのでバージョンの上限も縛ってます。それ以降は今のところNodeの名前が変わるような変更は入ってない
2024/02/17
Rubyのエラーメッセージなどのquoteが ` ' から ' ' に変わったことに関連して
Relineが出すエラーメッセージのquoteも ' ' に変更
IRBのエラーハンドリングをquoteの種類変更に対応
debugコマンド: callerを見てirb内で実行されているかどうかを判定する正規表現を修正
debugモードの時はenterで直前のdebugコマンド再実行する機能を追加(debuggerにはもともとあった機能。IRB連携でも有効になった)
IRBのコマンド関連のファイル名・module名・class名を変更しています。
単語の省略をやめる: cmd → command
コマンドのsuperclass (RailsのモデルにおけるActiveRecord::Baseに相当するやつ: Nop → Base
互換性のために以前のものはaliasとして引き続き使えるようになってます
2024/02/19
test/irb/helper.rb に require 'rubygems' を追記しています。
rubygemsに依存したテストがいろいろあるんですが、requireし忘れている箇所があるせいでファイル指定でテスト実行すると動かなかったりしたんだと思う
Ruby 3.4で :"\xAE" をparseするとSyntaxErrorが出るように変わった(Bug #20280 )ことでテストが落ちていたのでskipしています(3.3まではparse時点でEncodingErrorが出る) helpコマンドにコマンド名を引数で渡すと、詳細表示するようになりました。
Pryのコマンド定義のAPIでは description(短い説明文) banner(詳細...のようなもの) を使ってるんですが、IRBでは description(短い説明文) help_message(詳細) を採用しました。
おそらくPryは、git blameで見た限りではgem slop(option parser) の用語を適してない用途に名前を変えずに流用してしまったっぽいので、その間違いをIRBが踏襲することもないだろうと思う
2024/02/22
IRB::NotImplementedErrorとIRB::OutputMethod::NotImplementedError を削除しています。
そんなのがあるとは知らずに raise NotImplementedError と書いていた箇所全てで、(IRB::NotImplementedError#initializeが引数1つ要求してるのに渡していないので) ArgumentErrorが出るということになっていました。(紛らわしい名前をつけてはいけない)
2024/02/23
IRBのlib/以下全てfrozen_string_literal: falseがtrueになりました
2箇所 +'' でunfreezeしてる箇所があります
(frozenコメントが何も書かれてないファイルがいくつかある)
IRB::Contextにメタプロっぽい方法でeval_history=とuse_tracer=メソッドが定義されていたのが、普通の方法で定義するようになりました。昔はもっと使ってたのかな、今となってはメタプロでたった2つの短いメソッドを定義するのは大袈裟っぽくなったので綺麗さっぱり
lines << '' if lines.empty? 不要なガード句を消しました。
RelineのAPIによりprocの引数に渡された配列を破壊するのは行儀良くないので直そうと調べたらそもそも消せそうだと判明した
昔からあった中身が空のifを消してます(882 merge後にnobuさんが見つけてコメントで指摘してくれた)
2024/02/26
show_sourceコマンドとshow_docコマンドに詳細な説明(help show_source などで見れる)が追加されました
promptを表示するかどうかの判定ロジックをInputMethod(stdin, reline, readlineなどがある)のメソッドに移動するリファクタです
Relineの補完ダイアログのデフォルトの色(cyan-whiteは環境によってかなり見難い)がついにgrayとbright_whiteに変更されました :tada:
pullreqのコメントを見るとなかなか難産だった様子が見れるのでぜひ
2024/03/04
workspaceのリファクタです。chws pushws popws でworkspace(IRBの中でselfになるもの)のスタックを操作できるんですが、
内部の構造が @workspace (現在のworkspace) @workspaces (workspaceのスタックから現在のworkspaceを取り除いたもの) となぜかスタックをバラした作りになっているの直しつつうまいこと整理しています。
promptを出すかどうかの判定ロジックを各InputMethodクラスのメソッドに移し替えています。
リファクタ以前は (kind_of?(A) && condA) || (kind_of?(B) && condB) || ... みたいになっていた
テストの修正です。正規表現のescape漏れのwarningが出ていたっぽい
2024/03/15
テスト中に~/.irb_history が作られる問題の対処のためにsetup teardownをリファクタしています。894はそのfollowup
IRB 1.12.0 released :tada:
RDocの最低バージョンを指定しています。(何か問題があって指定をやめてたっぽいけどその問題も起きないよう)
IRBに新しいコマンドdisable_irbが追加されました。binding.irbを空のメソッドに置き換えるコマンドで、loop{binding.irb}みたいなのから抜けるのに使えます。(次リリースまでに名前は変わるかもしれない)
Class#name メソッドが例外を吐く場合に補完が動かない(IRBごと落ちる)問題の対処で rescue nil を追加しています。
ActiveSupport::TimeWithZone.name がdeprecation warningやerrorを出すらしい(設定次第ではstderrにputsする副作用まである)
本来なら Class.instance_method(:name).bind_call をするべきだけど、直すべき箇所がたくさんあるので応急処置として rescue nil でいいかなと...
Class#name が上書きされるのはよくあること(gem faker gem gimei とかもやってる)
Relineが --enable-frozen-string-literal でも動くように修正しています。
2024/03/17
irbrc と irb_history の探索ロジックを分離しつつ、irbrcの重複読み込みの不具合などを修正・irb_historyはプロジェクトのディレクトリに作られないように変更しました
IRB.rc_file(ext) というメソッドでirbrcとirb_historyを探していたんですが、
・そもそも ext='rc' と ext='_history' しか使ってない。あまりgenericなメソッドじゃない
・ファイルがなかったときにどうするか、irbrcとirb_historyで異なる
・irbrcは複数個読み込むように変わったので、以前よりもさらに異なるロジックが1メソッドに無理やり詰め込まれた状態になってしまっていた
という問題があって、メソッドを分離したかった。
IRBのソースコードコメントに書かれているドキュメントのフォーマットをmarkdownに変えています。
ruby/rubyリポジトリ内にrdocとmarkdownが混ざることの影響がどんなものか懸念されていたみたいですが、devmeetingで議論に上がってmarkdown入れて問題なさそうということになったようです。
2024/03/19
irb --help の日本語版ヘルプメッセージ(IRBのコマンドラインオプションの説明文)に7箇所抜けてる項目があったのを追加しています。
2024/03/20
Relineのline_editor.rb (一番でかいファイル)に対する大きめのリファクタリングがmergeされました💪
line_editor.rbに対するdiffは +592 -1295
主な変更はレンダリングの全書き換えと不要なインスタンス変数の削減・内部で持つ状態の整理などです。
コードを沢山消しつつ、バグも沢山修正されているはず
pull 614でRelineのレンダリングが刷新されて差分レンダリングするようになったんですが、差分レンダリングのための、今画面に何が描画されているとRelineは思っているのか、という情報を持たせている @rendered_screen.lines の初期値を nil から [] に変えています。
not nullにして良い値はnot nullにしたら無駄なnilチェックも消えてシンプルになる。
2024/03/24
irbrcファイルの探索場所について、ドキュメントの間違いを修正しています。 IRBは ./.config/irb/irbrc は見ないけどドキュメントに書かれてた
Relineで、vi-modeかつmode-string(insert or command)をpromptに表示する時のバグ(変更が反映されない)を修正しています。
promptのキャッシュ・再計算のためのdependencyの配列にmode_stringが含め忘れていたのが原因
今日は他にも色々テスト関連の修正がありました。Ruby 3.4.0のfrozen string literal warningやRelineの最近の変更でテストがこけてる件などの対処です
テストコードの一部、3.4.0で入る frozen string literalのwarning が出ないように修正しています
Relineテストのassertionをシンプルにしています。
いくつかのassertionは意味がなくなったのでその整理(テスト対象のインスタンス変数がリファクタで消えた)
同じような複数個のassertionの組み合わせを何度も使うので、それをまとめて1つのassertionにした
Relineのテストモード(TERM=dumbの時)に、端末の色リセットのエスケープシーケンス "\e[0m" を出力しないようにしました。
Reline 0.4.2まではテストモードにはそういうのを出していなかったので、念の為挙動を合わせるためです。
Relineのテストモードで補完ダイアログ表示に使うエスケープシーケンスなどが出力されないようにしました。
Reline 0.4.2までと挙動を揃えるためなんですが、0.4.2までなぜ出てたのかが割と謎でした。原因調べたところ、テストモードでは端末のサイズを[1,1]と認識させるようにしてたのが色々と噛み合って意図せず偶然無効化されてたっぽい
yamatanooroti (vtermを使った端末でのE2Eテストツール)の、frozen string literal warning対応です。
warningが端末上に出るので、端末上に実際に表示される文字列によるE2EテストがIRB/Relineで軒並み全部落ちていたのが直ります。
(E2EというよりVisual Regression Testかな)
yamatanoorotiのCIで実行するrubyのバージョンの更新・schedule実行の設定など
IRBのテストをReline masterを使って実行した時のfailureを修正しています。
複数行のインデントがおかしいコードを貼り付けた時の挙動が微妙に変わった(直った?)ので、変わる前後どちらでも通るようなテスト内容に変更しています。
2024/03/25
RDocを表示するとき、RDoc::RI::Driver.newをキャッシュするようにしました。
通常は0.03秒程度しかかからないので目に見えての効果はないんですが、
armでamd版のrubyをdockerで動かした時とかに効いてきます。
あと、最新のRDocではnewが2倍ほど遅くなっていて、テストがこけやすくなる原因になっていたっぽいのも多少解消します。(Marshal.loadにfilterを追加したからっぽい。多分CVE関連)
Relineのペースト中の処理に関するテストを一部消しています。あまり意味のないテストだった
Reline 0.5.0 released :tada:
レンダリングが刷新されています。主にターミナルの高さ以上の行数を入力した時のバグなどが色々直ってます。いますぐインストール!
2024/03/30
ソースコードコメントのtypo修正です
2024/04/02
Relineのタブ補完(irb --noautocomplete)の補完リストの表示を変更しました。Readlineと合わせるため。
Before
code:ruby
irb(main):001> 1.a
1.abs
1.abs2
1.allbits?
1.angle
1.anybits?
1.arg
After
code:ruby
irb(main):001> 1.a
1.abs 1.allbits? 1.anybits?
1.abs2 1.angle 1.arg
補完ロジックのリファクタリング
タブ補完と自動補完のロジックが絡み合ってるのをほどいた
自動補完でcompletion_procが不必要に何度も呼ばれるを直した
補完ダイアログが消える不具合(無駄に何度もダイアログの表示条件を再計算してるせい)が直った
2024/04/04
オートインデントの処理で、lstripで取り除かれるのが"\x20"の空白文字だけだと決めつけたことで起きていたバグが修正されました。(例えば \C-v\C-k で垂直タブ \v を入力できる)
また、そうやって入力された\vなどをescape表示するようにしました。(でないと表示崩れする)
\C-v\C-kは無理やり見つけたレアケースなんですが、この先実装したbracketed-paste-modeでタブインデントされたコードをペーストした場合も見越して直しておく必要があった
Signal.trap(:INT) の使い方が悪くて以下の問題を起こしていたところを修正しました。
Signal.trap(:INT){puts 'hello'};loop{print 'a'} ←実はこれだけでdeadlockが発生してしまう
CTRL+Cで止めた時、違うスレッドで raise Interrupt をしてしまう
割込処理では変数に値をセットする程度に留めておいて、割込じゃないところでその変数の変化をチェックする、みたいなのが(多分)セオリーで、
Reline自身、 trap(:WINCH) ではそういう実装になっていたので、 trap(:INT) もそういう実装に変えました。また、CTRL+lの入力 (画面クリアして再描画)がsignalじゃないのに何故かsignalかのように扱われていたのをやめました。
2024/04/05
Relineのreadlineメソッドの終了時の後処理がスキップされてしまうことがある不具合の修正です。
rescueを追ってみた限りだと必ず line_editor.finalize io_gate.deprep が呼ばれそうなんですが、
throwなどで抜けるとensure節に書かなかった処理は実行されないことがあります。(実際起きてそうな不具合報告があった)
ついでに、ensure追加したことで不要になったrescueも消してます。
二つのスレッドで同時に Reline.readline を実行した時に、片方ずつ動くようにMutex#synchronizeを使うようにしました。
今までは入力を2つのReline.readlineが食い合う(そして同じ1つのReline::LineEditorインスタンスを共有しているので謎挙動する)のが直ります。
元々は2つのスレッドでReline.readlineを呼んだ状態でC-cで止めた時に、Signal.trapのprocが古いprocを呼ぶ無限ループが発生するのを防ぐ目的でこの修正を入れたんですが、https://github.com/ruby/reline/pull/646 でSignal.trapを修正していたおかげで無限ループ自体はすでに起きなくなっていたっぽいです(でも変な挙動はするのでやってよかったと思う) 2024/04/06
IRBに入力したコードを実行してエラーが出た時、 Workspace#filter_backtrace でどのbacktraceを隠すか指定できて、Railsがこのfilter_backtraceを上書きして使っているんですが、
filter_backtraceにbacktraceではなく " from: /foo/bar.rb:5 in baz" という文字列を渡してるせいでうまく動いていなかった(Railsのbacktrace_cleanerが全てのbacktraceを消してしまう)不具合を修正しています
exception.full_messageを文字列で切り出してfilterするのをやめて、exceptionをcloneしてset_backtraceでfilter済みのbacktraceに上書きするようになった
ENV['TERM']に未知のターミナルエミュレータ名が入ってる時・ENV['TERM']が空の時にRelineが落ちる不具合を直しています。
(例えば、TERM=tmux-256colorとかの情報は、新しいterminfoには入ってるけどちょっと古いと入っていない)
2024/04/09
型補完の、prismのバージョン上限の更新・ciの更新・テスト落ちてた修正です
Prismは0.25.0で括弧で囲われたパターンが正しくParenthesesNodeで囲われるように変わって(括弧の位置をASTから取れるようになった)
repl_type_completorがそれに対応してなくて foo in ((String)|((Integer))) => x; x. の補完が動かなくなってしまっていた。
ReplTypeCompletor v0.1.4 release 🎉
Reline v0.5.1 release 🎉 いろいろバグ修正されました
2024/04/11
IRBのコマンドがメソッドではなくなりました。
コマンドがメソッドだと 10.times{help 'show_source'} みたいなことができる利点があるし、ある意味Rubyらしいと思うんですが、
10.times{help 'show_source'} に需要はない
selfに勝手にメソッドを定義してしまう・selfをある意味壊してる
selfがfrozenだとdelegatorを使う必要がある
Rubyの構文として正しくないコマンド($ obj.method)を実装するために無理がでている
などの問題がありました。(この無理がでてる状態のままカスタムコマンドを定義するpublic APIを作るのはあまり良くない)
一方で、context コマンドがなどメソッドではなくなったことで irb(main):001> context.return_format = "#=> %s\n" みたいなことができなくなっています。
でも以下のようにソースコードに書かれていたので、むしろ context.foobar= を使えたことの方が間違ってたと思う
code:ruby
# Displays current configuration.
# Modifying the configuration is achieved by sending a message to IRB.conf.
def irb_context
IRB.CurrentContext
end
一方でメソッドが欲しいこともあるので、Commandとは別の、HelperMethodというものを導入するかもしれないです。例えばRails consoleで使える helper app reload! new_session controller メソッドなど。
HelperMethodがある場合はselfにメソッド定義せざるを得ないけど、Commandと分けることでそれを必要最小限にしたい。
コマンドをメソッドではなくする変更に対するfollowupとして、デバッグ系のコマンドの引数のrstripを一箇所に集約しています
コマンドの実行方式の変更でdebugのテストが落ちるようになったので暫定の対処をしています。
debugがIRBにpatchを当ててテスト動かしていたので、それがうまく動かなくなっただけでdebugとirbの連携が壊れたわけではなさそう
2024/04/13
Statement (IRBへの入力。コード or コマンド or 空入力(enterのみ)) の評価を全部 context.evaluate(statement) の中でやるように変更されました。
2024/04/14
Relineがinputrcの設定項目menu-complete-backwardを使えるようになりました 🎉
(元々 :completion_journey_up というReline独自の設定項目があった。readlineに対応する設定項目があるとは気づかなかったんだと思う)
forward(menu-complete) や TAB(complete) などもreadlineでは設定可能らしいということも判明したので、そのうち対応したいところ。
Relineのcompletionの実装は、自動補完の発火条件が複雑だったり "\C-p" "\C-n" "\C-i" などをハードコードしてるので、今後そういう特別な処理を減らすリファクタができると良いな
IRBのカスタムコマンド登録APIが追加されました
今までは、Railsがコマンドとして使えるメソッドを追加してはいるもののhelpによるコマンド一覧に表示されなかったり、別のツールはIRBが内部で使ってるAPIを呼び出してたり
2024/04/15
Relineのリファクタです。
Readlineのvi modeでは 3d4fx (カーソル位置から(3*4=)12個先の「x」の位置までの文字を消す)みたいな入力ができます。
Relineではそれを実現するために、waiting_proc と waiting_operator_proc というprocを設定して使っていたんですが、コールバック地獄のような状態になっていました。(実際のReadlineで必要なこと以上に複雑なことを実現できる実装で、バグもある)
というかなんで動いていたのかわからない。
ちょっと解きほぐすリファクタをしました。行数は増えてますが、callbackが別のcallbackを呼ぶみたいなことは無くなった
Relineのkey_actor (どのkeyを押したらどのメソッドが呼ばれるか対応表)のリファクタです。
メソッドの実装重複を消したり、メソッドが存在しないものを消したり、対応表に足りてなかったものを追加したり、など
LineEditorのレンダリングリファクタで壊してしまった vi_to_column (vi commandモードで 数字と | を入力して、数値で指定した位置にカーソル移動) が直りました。
2024/04/16
Relineで emacs-editing-mode と vi-editing-mode が設定可能になりました。vi modeとemacs modeの切り替えを .inputrc で書けます。
0.5.2 released :tada:
Historyの移動(historyのincremental search含む)のリファクタです。
history移動・キャンセルして戻る、あたり、いろんなところに重複して存在する処理をmove_historyメソッドに一元化してコードを減らしてます。
(別々の処理だった上移動と下移動はdir(+1 | -1)を渡すようにする、など)
2024/04/18
historyのリファクタで入ってしまった(消し忘れた)未使用ローカル変数を消しています
Relineのreadline(singlelineモード)とreadmultilineの条件分岐をかなり減らました。
singlelineとmultilineでは、改行キーを入力した時以外の挙動はほぼ同じになります。
背景
ほとんどの if @is_multiline の分岐は実は要らなくて消しても問題なかった
GNU Readlineは複数行入力が可能なので、合わせるなら複数行入力可能であるべき
Reline.readlineでも実は裏技的方法で複数行入力が可能だけど(やらなくていい分岐のせいで)バグってた
bracketed paste modeを実装するためには必須(複数行の文字列のペーストを受け入れる必要がある)
IRBのデフォルトのコマンドで、互換性のために使ってるメソッドをCommand::Baseから別のところに移しました。
コマンドはもうメソッドではないんですが、メソッドのように引数を渡しても動くようにするhackがあって、それをカスタムコマンド作成者に使わせたくなかった
IRBのプロンプトをカスタマイズする方法のドキュメントを修正しています。%NNi のNは数値だというのがドキュメント見ただけだとわからない状態でした。
(なお日本語のドキュメントにはその説明が書かれてた)
IRB::Color.colorize_code で "\t" が " " になってもテストがpassするように変更しました。
colorize_code の目的はRelineがレンダリングできる形式の文字列を作ることなんですが、 \t は可変幅なので困る。
そして、Reline側でターミナル上での正式なペースト(bracketed_paste)を実装するとタブが入力可能になる。
Reline側で Reline::Unicode.escape_for_prompt("\t") が " " を返すように変えるプルリクがあり、そのプルリクのCIが通ること・その変更後もIRBのCIが通るようにすることが目的です
IRBのカスタムpromptのフォーマット文字列、%をエスケープできない不具合を直してます
2024/04/20
RelineのCI(reline masterをインストールした状態でIRBのテストを走らせる)で、 rake build rake install の両方を実行していたところ、rake install だけにしています。中でrake buildも実行されるのでbuildの方は要らなかったらしい
自動補完無効(タブ補完)の時、補完候補が複数ある場合、通常はタブキーを2回入力しないと補完が出ないところ、タブキー1回で即座に補完候補が出るようになる機能で、inputrcで有効化できるようになりました。
IRBのmulti-irb系コマンドにテストを追加しています。これで、テストのないコマンドが多分残り1つになりました 🎉 :arigata:
exitコマンド・exit!コマンドにあったworkaroundが不要になったため削除されました。
最近のコマンド実装変更の前は、IRBのexit・exit!コマンドをIRB外で使ってしまうことがありました。(self.exit self.exit!がコマンドで置き換えられるため。 binding.irb; exit はコマンドの方のexitを実行してしまう) その時のためのworkaroundは今はもう不要。
また、rdbgモードが実装漏れにより、このworkaroundがあることに依存してしまっていたのを修正しています。
2024/04/24
IRBのリファクタリングです。
以前、IRB::ExtendCommand をrenameしてIRB::Commandを作ったんですが(compatibilityのためにExtendCommandも残している)
それに関連するmodule IRB::ExtendCommandBundleを内部で使うのをやめています。メソッドなどはIRB::Commandに移し替えたり
Relineのレンダリングの最適化です。
IRBなどでコードを入力するとき、
promptは変わらずにコードだけ変わる場合
コードは変わらずpromptが変わる場合( 1.\nitself の1行めのピリオドの後ろに ( を追加すると、2行めはpromptだけが irb(main):002> から irb(main):002* に変わる)
などと、promptと入力文字のうち片方だけが変わるケースが結構あります。
この時、片方だけを再描画できるように、promtと入力文字列をレンダリングの際に別々のものとして扱うように変更しています。
Reline v0.5.3をリリースしました。 show-all-if-ambiguous が設定可能になりました。レンダリング最適化のリファクタリングと、singleline/multilineの差分を減らすリファクタリングが含まれています。
IRBにコマンドとは別にHelperMethodというものが新しく導入されました 🎉
コマンドと違い、返り値を使う・返り値にメソッドチェーンするような用途のメソッドを定義するAPIです
Rails consoleで使える reload! app controller new_session などのメソッドのうち、reload!はコマンド、 app controller new_session はHelperMethodになる、という想定で、
RailsがこのAPIを使うようになれば、IRBのhelpコマンドでこれらのコマンド及びメソッドが一覧できるようになります。
2024/04/25
Relineへの1行の入力が長い時(jsonを貼り付ける、など)ペースト・編集・レンダリングなどが遅い問題があります。
そのうち、レンダリングの一部と、カーソル移動の一部(C-eが劇的に重い C-aは遅くないのに)のパフォーマンスを改善しています。
IRBのHelperMethodで、HelperMethodClassのinstanceをキャッシュ・使い回す(singletonにする)ようにしました。
Rails consoleのappメソッドをHelperMethodに変えようとしているんですが、appメソッドは内部で返り値をキャッシュしたり、引数によってキャッシュを破棄して作り直しす仕様になっていて、そのキャッシュの置き場所が必要だった。
2024/04/26
Relineが読む設定ファイルinputrcの条件分岐 $if $else $endif のバグ修正です。
$endif以降に書いた設定が全て無視される不具合の修正です。
Readlineでは本来入れ子にできるんですが、入れ子対応のendifを抜ける終了処理のちょっとしたバグを直しつつ、入れ子になったifの状態管理用stackをインスタンス変数2個からローカル変数1個に変えるリファクタも入れました。
IRBのコマンド登録APIでSymbolではなくStringでコマンド名を登録すると、コマンド一覧には表示されるのにコマンドが使えない、という問題を修正しています。
ArgumentErrorを出してSymbolしか受け付けないようにするのももちろんありなんですが、HelperMethod(define_methodしてる)は文字列も受け取ること、コマンドはメソッド名にならないもの(例えば "show-source")も使えるようになったことを考えると、文字列で指定したくなるはず。
2024/04/27
Command・HelperMethod追加方法に関するドキュメント追加
コマンド追加ドキュメントのサンプルコードで、登録するコマンド名を文字列表記からSymbol表記に変更しています。
コマンドは値を返さない(executeの返り値が何であれ、行の実行結果をnilにする)ようにしています。
今後、コマンドの返り値(大体の場合nil)を表示しないように変更した時、返り値がinspectされることに依存したカスタムコマンドが期待通りに動かなくなるので、あらかじめ無効化しておいた
2024/04/29
型補完ライブラリでPrismのバージョンの上限指定をやめました。
Prismは以前は結構バージョン間でAPIがガラッと変わったりしたので上限を指定していたんですが、Ruby3.3に入っている0.19.0以降は後方互換性を保つ変更しかないこと、
Prismの更新頻度の方が高く、Prismのバージョンが上がるたびにバージョン指定の上限を上げたReplTypeCompletorをリリースすることが現状できていないので、上限指定をやめてみました。
Reline Readlineの設定ファイルinputrcで $if mode=vi $if mode=emacs が使えるようになりました
補完ダイアログの両端の丁度境界部分の真下の、境界を跨ぐ位置に幅2の文字があるときに表示が崩れてしまう不具合が修正されました
一二三四五六 の 二 の真ん中から 五 の真ん中にかけて補完ダイアログが表示されるとき、 一 DIALOG 六 のように表示必要があり、さらにDIALOGが消える時はDIALOGの位置だけじゃなく両隣まで含めた 二三四五 を描画し直す必要があります。
ダイアログの配置によって描画し直し方が4パターンある(左隣だけ、右隣だけ、両隣、どちらもなし)、幅2文字が半分になった時に表示する空白文字には背景色が設定されていることがある、など、結構エッジケースが多くて大変でした
型補完ライブラリ ReplTypeCompletor 0.1.5 がリリースされました
0.1.4との差分はprismのバージョン上限を撤廃したこと
Relineへの入力が改行で終わらずEOFで終わった場合、空文字が入力された扱いになってしまうバグの修正です。
例えば printf "hello" | ruby -rreline -e 'p Reline.readline' など。 "hello" が読めるはずが "" になってしまっていた。
Reline 0.5.4をリリースしました 🚀
2024/05/01
IRBの中で2段階目のbinding.irbを実行して、exitで1段階目に戻ってきた時、IRB.CurrentContextが元に戻らない不具合を修正しました。
2024/05/02
ドキュメントをGitHub Pagesで公開するようになりました
IRBでエラーのbacktraceを表示する際に邪魔なbacktraceを除外するためのAPIが追加されました。
code:ruby
これがなかったため、Railsでは IRB::WorkSpace.prepend(BacktraceCleaner) みたいな感じでパッチしていた
IRB::Color.colorable? が必ず true|false を返すことが明白になるようなリファクタです。
背景: BACKTRACE_FILTERのAPI追加の変更で使うようになった exception.full_message(highlight: colorable) に渡す値は単にtruthyではだめで true|false|nil でないといけない
IRB 1.13.0 Released 🎉
目玉はコマンドの変更かな、実装の変更・Command追加API・HelperMethod追加API など
1行が長くて折り返されている時、補完ダイアログの表示位置が邪魔な問題を修正しました。
折り返されている時、状況によってはカーソルの一つ下の行からではなくカーソルと同じ行から補完ダイアログを表示すると割といい感じの見た目になるんですが、
同じ位置にすると困るケースでもカーソルと同じ行から表示してしまっていたので、条件を調整した
環境変数TERM=dumbの時はStdioInputMethod(Reline/Readlineを使わず、getsで入力を受け付けるモード)を使うようになりました。
EmacsのshellでIRBが使いにくい問題が直ります。
この問題は、TERM=dumbの時にRelineがテスト専用の使い物にならないモードに入ってしまうのが原因で、TERM=dumbがテスト用途以外でも使われている以上Reline側も直したいのですが
Reline側を直したところでdumbなterminalですごく使いやすくなるわけでもないので、IRB側でもちゃんと対応すべきだろうな、と思った。
なお、この変更が入るとRails consoleのテストがこけるはずなので、mergeは1.13.0リリースの後にした。
2024/05/03
TERM=dumbの修正の結果、rubyのCI(Debug gem)が落ちるようになってしまい、それのworkaroundとしてprompt表示前にputsを挟むようにしました。(debugのテストが1行入力直後の行を読み飛ばしてることが判明したため。このCIはリリース済みのgemをダウンロードしてるらしく、debug側を直してもリリースされるまでは落ち続けるらしい)
なおこのputsにより、ruby/ruby本体のCIが通らなくなってしまいました。(そちらは空行が紛れててもテストが通るよう修正)
流石にputs回避は安直だった。せめて puts if STDOUT.tty? にしておけばよかった
Relineがinputrcを何度も読んでしまう問題を修正しています。GNU Readlineも初回のみ読み込んでそう。
inputrcを初回一回だけ読み込むようにした結果、矢印キーやinputrcで設定したキーバインドがReline.readlineの直後に無効化されてしまう問題を修正しました。
inputrcファイルが存在するときだけ発生するバグで、今までは毎回inputrcを読み込んでキーバインドを再設定していたため問題なかった
Reline 0.5.5 released 🎉
2024/05/05
テストコード内のtypo修正
カスタムコマンドを登録する際、descriptionとhelp_message両方とも設定しなかった時に irb> help custom-command-name でエラーが出る問題の修正です
help_message || description || '' と空文字にfallbackしています
空文字だと不親切なので、 No description provided と表示するようにしつつ、コマンドのカテゴリ未指定のケースの表示改善もしています
irbをrequireした状態だとdebugコマンドでdebugモードに入れない不具合の修正です。irbコマンドではなくbinding.irbの時にしか使えない、というメッセージが誤って出てしまっていた。
IRBがカスタムコマンドAPIを作れるようにした際、ファイルのrequire順序が変わったのが原因だったんですが、
binding.irb経由でirbを立ち上げているかの判定を、ファイルの読み込み順序に依存しないような判定法に変更しています。
型補完ライブラリのprism 0.28.0対応です。ConstantPathNode#child がdeprecatedになったので、新しく追加されたメソッドnameを使うか、古いchild.nameを使うか分岐するようになりました。
タブ補完の\C-i vi-modeの時の補完\C-p \C-n がハードコードされていたのをやめて、Relineのkeyが押された時用のメソッドとして定義するようになりました。
これにより、分岐が減ってシンプルになったのと、inputrcからこれらのキーを変更することもできるようになりました。
ReadlineにありRelineでも設定可能な設定値...のように見えてどこからも使われていないものを削除しています。
IRBのHelperMethodであるconfのHelpでの説明文 Returns the current context. を current IRB context に変更しています。
Rails consoleとかでhelpでコマンド一覧を表示したとき、単にcontextだと何のcontextを返すのかわかりにくいからかな
IRB 1.13.1 released 🎉
型補完 rescue => ここ でconstの補完が正しく出ない不具合を直しています。
begin; rescue => Foo::Ba[r] begin; rescue => (a=1)::B; a.tim[es] などが補完できるようになります
コードもちょっと短くなった
ReplTypeCompletor 0.1.6 released 🎉
2024/05/26
irbrcでIRB.confにvalidationを追加し、誤った値を設定したときにわかりやすいエラーを出すようになりました(intであるべき設定値にboolを入れるなど)
PrismのだすSyntaxErrorに対応するよう正規表現を修正しています(ruby --parser=prismを指定してirbを起動した時かな)
テストコードでのtmpdir消し忘れ対応
SyntaxErrorのメッセージによるエラーの分類(unrecoverable/recoverable)のチェック順序を変更しています。
unrecoverable: def ) など。即座にエラー。
recoverable: def f など。SyntaxErrorだが後ろが足りないだけ。次の行に続く。
本来unrecoverableかどうかを先に調べるべきところ、今までたまたまうまく行っていたのが、Prismが同時に見つかった複数種類のエラーメッセージを出すので動かなくなっていた模様
require 'reline' をしただけでSTDIN.winsizeが呼ばれてしまう(そしてそれがエラーを返すことがある)問題を修正しています。
winsizeを呼ぶのは必要になってからで良い
ドキュメントのリンク切れ修正
STDIN.winsizeがENODEVを返すことがあるのでrescueするようにしています。
EBADFやIOErrorを投げることがあるが、rescueすべきはreadできるのにwinsizeがエラーを投げるケースのみ
inputrcで set vi-ins-mode-string (vi ins) と空白入りの文字列の値を設定できない不具合が修正されました。
Readlineでは、いくつかの設定値は空白以降を無視し、いくつかの設定値は空白も値に含めるような仕様になっていて、その挙動に合わせています。
(この空白以降を無視する挙動があるので、set colored-stats on # comment のようにコメントっぽい書き方ができるし結構みんな書いてる。が空白以降が無視されているだけでコメント記法ではない)
2024/05/28
Redoが実装されました🎉 C-_ がundoで C-M-_ がredoです めっちゃ便利
2024/05/29
Reline 0.5.8 リリースしました! redo コマンドが使えるようになりました
2024/06/02
Reline::IOGate (Reline::ANSI か Reline::GeneralIO もしくは Reline::Windows) がそれぞれ Reline::IO を継承したclassになりました。
今までは、一応classではあるもののinstanceが作られることはなく、module_functionが定義されているだけのものでした。
また、Reline::GeneralIOはReline::Dumbに改名されました。名前と違ってGeneralなIOではなく、環境変数TERMがdumbに設定されている時専用(テスト用途)なので名前と役割を一致させた。
classになったことで、テスト時にインスタンスを作り直すことで簡単にリセットすることが可能になりました。
2024/06/03
Relineへのキー入力(上矢印が "\e[A" 下矢印が "\e[B" option+deleteが "\e\x7F" など)の判定ロジックを変更しました。
入力があるキーと一致するか、または先頭一致(つまり続きの入力を待つ必要があるか) を判定するために、以前は 登録済みのものとstart_with?のような方法で判定していたのが、Hashで高速に判定できるようになりました。
今後 \C-a などの1byteの入力も同様の仕組みで扱うようにしたい(コードがシンプルになる)、そうするとキーの登録数が増えるので高速に判定できる必要があります。
入力バイト列があるキーと完全一致しつつ、さらに別のキーと先頭一致する、という今対応できていないケースに対応するための布石でもあります。
ed_search_(prev|next)_history 機能で検索文字列が空の状態で過去に遡るとき、カーソルの位置が先頭ではなく末尾になりました🎉
これはあまり簡単ではなく、カーソルが末尾にある時は、カーソルより前が検索文字列のこともあれば空文字で検索していることもある、つまり新しい状態を内部で持つ必要があります。
あるキー入力を処理した時、何かしらの状態を次のキー入力処理に引き継ぐための仕組みを導入して実現しています。
この仕組みは今後他のキー入力でも使う予定です。(そうでなければこの機能のためだけに新しい概念を入れない方が良い)
例えば、incremental_searchや、タブ補完もこの仕組みを使うようにしてみても良いかもしれない。特定の操作を連続して実行した時に状態を引き継ぐのはReadlineの他の機能でも必要になるはず。
標準出力が端末デバイスではない場合にテストモードに入ってしまう不具合を修正しています。
例: ruby -rreline -e "p Reline.readline" | cat
Readlineと挙動が違う・テストモードではpromptや入力が重複して沢山表示される、などの問題がありました。
また、これにより、 Reline.update_iogate というSTDIN/STDOUTがreopenされて制御端末に変わった時(railsでspringを使っている場合など)にテストモードから通常モードに切り替える処理が不要になり消えました。
2024/06/05
IRBでドキュメントダイアログ表示中にalt/option+dを押すとドキュメント詳細を表示する機能について
詳細を表示するキーのリストに Reline::Key.new(nil, 0xE4, true) が指定されているんですが、これが何の効果もないのと、今後のRelineのリファクタの邪魔になるので消しました。
(厳密には特殊な条件下で何らかの意味はあるんですが、その特殊な条件下ではIRBがまともに使えないので関係ない)
標準入出力が端末デバイスではない場合にも端末のbracketed-paste機能を有効化するエスケープシーケンスを出力していたので、bundler側でのRelineの出力文字列が期待する正規表現にマッチしなくなった。
Readlineと同様に、標準入出力が両方とも端末デバイスかどうかチェックするようにしています。
Relineのキー入力判定ロジックをシンプルにしました。
ESCが入力された時、単にESCを入力したいのか、 ESC b (option+b) ESC [ A (上矢印) の入力途中なのかが曖昧なので、
Readline/Relineは0.5秒待機して、その間に何も入力がなければESCとして扱うようになっています。
これは別にESCに限ったことではなく、2バイト目特有でもなく、曖昧なら待つ、というシンプルな仕組みなんですが、
Reline側の実装には read_2nd_character_of_key_sequence read_escaped_key というメソッドがあり、2バイト目・esc特有と決め打ちの実装をしていました。(Readlineより複雑な仕様を作り上げている)
リファクタリングというか作り直してシンプルになりました。
2024/06/06
コマンドのリファクタリングの時(多分)にうっかりdisable_irbコマンドが消えてしまった不具合を直しています。また、今後起きないよう、disable_irbコマンドのテストを足しています。
@first_char という謎のインスタンス変数を消しました。
何も入力がこない状態でEOFが来たら Reline.readline は nil を返すようになっていて、そのチェックのために @first_char ってのを使っていたんですが、
そんなものはいらなくて、現在の入力が空文字かどうかさえチェックすれば良いので消しました。
実際Readlineの挙動も空かどうかチェックしてるだけ。 文字入力 delete EOF の場合もnilを返す。
2024/06/11
カスタムコマンドとHelper Methodの使い分けについてのドキュメントを追加しています。
どちらにするか迷ったらとりあえずコマンドにしましょう。
Helper Methodはselfにメソッドを追加するという副作用があるのでなるべく少ない方がよいと個人的には思っています。
デフォルトで定義されているものは1つを除いて全てコマンドとして実装されています。(HelperMethodはconfメソッドだけ)
Ruby 3.4でwarningが出ることでテストがこけていたので、warningをsuppressしています。
Relineがfiddleをrequireするところで出ているwarning (Ruby3.5からfiddleがdefault gem → bundled gemに変わるのでgemspecに追加しましょう、という内容)
ドキュメントのtypo修正
fiddleのwarningのReline側対応です。
Relineではfiddleを terminfoを使う(必須ではない) windows対応(多分必須) の2箇所で使っています。
terminfoを使う箇所では、必須ではないfiddleのためにwarningが出ていても邪魔なのでsuppressしています。
windows対応はどうするか悩みどころです。fiddleはよくインストールに失敗する・default gemなのになぜか入ってないことがあるらしいので、単にgemspecのdependenciesに追加すると困る人が多く出そう。
terminfoがない場合のfallbackを追加しています。これにより、環境変数TERMがxtermに設定されているようなxterm互換の端末ではterminfoとfiddleがあってもなくても動作に違いが出ないようになりました。
通常の環境では、よりfiddleへの依存が減ったことなるかな?
2024/06/16
IRB v1.13.2 released 🎉
間違って消えてしまったdisable_irbコマンドが復活しています
2024/06/20
IRB コマンドの返り値(常にnil)をprintしないように、また コマンド実行が _(直前の入力をevalした結果)をnilに更新しないようになりました。
viモードで、yank delete_meta を使い、何もコピーしない場合にnilをコピーしてしまう不具合を修正しました。
pで貼り付けようとすると、(常に文字列のはずのvi_clipboardがnilで)エラーが出てしまっていた。
このあたり、空文字をコピーするか、何も起こらないか、Readlineのviモードとviとで挙動が微妙に違ったりします。(そういうエッジケースは無理にReadlineに合わせず、無難な感じに実装するのが良さそう)
2024/06/26
型補完 Prism0.29から出ていたdeprecation warningを直すついでに、Ruby3.3にbundleされているPrism0.19.0でも動くようにしていたコードを消して要求バージョンを prism >= 0.29.0 に上げました
IRBを、ctrl-zで中断してfgで戻った時に画面再描画したりするようになりました。
ただ再描画するだけじゃなく、標準入力がrawモードからcookedに変わってしまうのをrawに戻す必要があるし、中断中に画面サイズが変わっていることもある
2024/07/01
help = 1 help += 1 などはhelpコマンド(コマンドの引数が "= 1" "+= 1")として解釈されていましたが、変数代入として解釈されるようになりました。
一方でshow_source =~ --super などはコマンドとして解釈されて欲しいので、= による代入と += *= ||= などの形の代入のみ、Rubyのコードとして解釈されるようにしています。実装は単純なstart_with?(regexp)によるものです。
また、コマンド名と同名のローカル変数helpが定義されている場合はコマンドではなくrubyのコードとして解釈されるようになります。
この判定ロジックだと help ,=1 などが分割代入ではなくコマンドとして解釈されるんですが、普通はしない書き方なので許容範囲だと思う。
2024/07/04
Pryにあるようなcdコマンドが入りました。
pushws popws chws などが元々あったんですが、覚えにくいし分かりにくかった。
cd 1 + 2 はpushwsと同じ、 cd .. はpopwsと同じ、 cd はmainまで戻る、 cd - の実装は保留
2024/07/06
helpコマンド(引数にはコマンド名を渡す)の引数入力中にコマンド名の補完が出るようになりました。
今はメソッド補完のところにhelpコマンド専用の補完ロジックを書いていますが、他のコマンドにも補完を実装する時はコマンドクラスに補完ロジックを移すことになると思います。
2024/07/12
print 'aaaa'; Reline.readline('prompt>') をした時(それも2回目以降)にのみ起きる表示崩れを修正しています。
この場合、まず一瞬 aaaaprompt> が画面に表示されます(Readline互換のため・エスケープシーケンス無しでpromptを出力することを仮定してるテストコードが世の中に割とある)
その直後に行をクリアして promtp> をレンダリングし直しています。
このレンダリングし直しが、すでに prompt> が表示されている(とは限らなかったが)ので無駄だと思いスキップできるような最適化を入れていたのがバグの原因でした。
2024/07/19
rubocopのcop追加とスタイルの修正です。singleton methodの書き方・定数の定義位置などを統一しています
テストがIRBRC関連の環境変数に依存しないようにしています。
ユーザー定義のirbrcファイルをテストで参照してエラーや警告、内容次第ではテストがうまく動かないことがありえた。
2024/07/30
Relineでfiddleを使う箇所のメモリリーク修正のようです
2024/08/05
IRBは "ruby >= 2.7" なんですが、testで2.7以下の時のpendが2箇所残っていたようで、意味のなくなったpendを消しています
pryとの比較.md にcdコマンドの情報が追記されました
2024/08/06
テストの修正です。assertionで "{:key=>value}" との比較をしているところ、 Hash#inspect を使うようにしました。
code:diff
- assert_include(actual, "{:key=>value}")
+ assert_include(actual, { key: value }.inspect)
これなら RubyのHash#inspect のフォーマットが将来変わってもテストが通ります。
2024/08/14
IRBのeaster_eggで表示されるruby logoのアスキーアートを更新しました。
線が途切れてるのが直り、unicodeの点字を使ってるので解像度もかなり上がっています。
IRBが入力の評価結果などをpagerで表示した後、CTRL+Cでpager表示を中断した場合は外部コマンドとして起動したpagerをkillして止めるんですが、killする直前にプロセスがすでに終了していた場合のエラー処理を追加しました。
lessコマンドで72KB以上の文字列を表示させた時にCTRL+CでlessもIRBも中断しなくて、その後qを押した瞬間にlessが終了しつつIRBにCTRL+Cが飛んできて、killしようとしたプロセスがすでに終了している、といったことが起きてた
2024/08/20
ソースコードコメントのtypo修正(hight → high)
2024/08/29
Readlineの設定ファイルinputrcで設定可能な設定値のうち、Relineで未実装だが変数だけがあるもの bell-style comment-begin completion-query-items を消しています。
入力がcommandかどうか判定するメソッドをContextに移動しています。コマンドと同名のローカル変数が定義されてる場合のコマンド判定にはlocal_variablesの情報が必要で、それを持っているcontext一覧が必要で、それを持っているのはContextだからです
IRBのコマンドに色が付くようになりました。コマンドが太字になる・コマンドの引数はrubyとして色をつけてます。
show_sourceのaliasである $ obj.method などは、Rubyのコードとして見るとSyntax Errorになるせいで警告色がついてしまっていたのもこれで直ります。(これを直したかった)
pull/983のテストコードに不備があったので修正。環境変数NO_COLORが設定されているとテストがこける問題があった。
もう一つテストの不備修正
echo | rake test TEST=test/irb/test_input_method.rb が Switch to inspect mode. という文字列を出してしまっていた
2024/09/03
RDocがbundled gemになる予定らしく、RDocがrequireできない場合も考慮するようにしています
Windowsのコマンドプロンプトでの謎のエラーを修正しています。外部コマンドを叩くとconsole_handlerが閉じられてしまってRelineの表示が狂ってしまっていました。
IRBでbackquoteを使ったコードを実行する・RDocのドキュメントを表示する・別スレッドで外部コマンドを叩くなど、任意のタイミングで急にconsole_handlerが無効化されうるらしい。
console_handlerを使ってみて失敗したら1回だけconsole_handlerを取得し直してリトライするようにしています。
検証環境がないまま手探りで修正したんですが、github上で検証してくれた人が二人ほどいて助かりました :arigato:
最新のRDocを使うとテストが一部こけていたのでテストを修正しています
Relineのconfig周り及びそのテストのリファクタリングと、config再読み込みのテストを追加しています。
テストを追加した箇所、GNU Readlineの方はなんかバグっぽい挙動をしているのでRelineの方が良いです。
bugs.ruby-langの方に報告されていた、pre_input_hookとinsert_textとredisplay 周りの不具合を直しました。
pre_input_hookの中でredisplayを呼ぶと表示が狂う
Relineではそもそもredisplayを呼ぶ必要はないが呼ぶと表示が狂うのは直したい
promptのprintとpre_input_hookを呼ぶ順序の修正
promptをprintする必要はないが互換性のためにprintしている。が、順序がまずくて、初回描画(hookの中でredisplayを呼ぶと実行される)の後に標準出力に何かを出してはいけなかった
Readline互換のinsert_textメソッドに複数行のテキストを渡すと表示が狂う
今はReadlineも複数行をサポートしてるのでinsert_textも当然複数行を受け付けるべき
RDocが必要なテストのみ、RDocが使えない時はスキップするようにしました。
RDocはbundled gemになる予定らしいんですが、RDocが使えない時にtest_input_method.rbが丸ごと全部スキップされていたのをスキップが必要な箇所のみスキップするように変更しています。
また、EasterEggがRDocのpagerに依存するのをやめています。
2024/09/04
IRBの型補完で prism ~> 1.0 を使うようにしました。他、deprecation warning対応など
Relineの描画メソッドのリファクタリングです
描画処理(旧render_differential) を render(何をどこに描画するか決定)とrender_differential(renderが決めた描画内容と前回の差分を検出描画するアルゴリズムパート)に分割しました。
まぁ元のメソッド名はあまり良くなかった
2024/09/05
テストコードのRuby 3.4.0devでのwarning修正です。
frozen_string_literal: true を書かなくてもfrozenに将来なるらしく、それに向けて出ていたwarningの対策で、テストのとあるメソッドがfrozenな文字列を受け付けるように修正してます
Relne 0.5.10 released 🎉
2024/09/11
端末上のE2Eテストフレームワークであるyamatanoorotiのcommit hashを固定しています。
yamatanoorotiには色々問題があります。すごく遅い(何かするたびに0.2秒sleepする)・実行環境によって異なる時間sleepを挟まないとテストが通らないことがある・通常のE2EテストフレームワークにあるAPIが足りてない、など
その問題を解決して高速化すると、sleep 0.2 に依存している今のテストが軒並み通らなくなるので、そうならないようあらかじめcommit hashを固定しました。
型補完機能は読み込みに時間がかかることがあるので、別threadでrequireとrbsファイルの読み込みを行っています。
が、requireを実行しているThreadが止められると(debug gemが止める)、main threadでのrequireが始まらずdeadlockしてしまいます。(requireは同時に実行できないため、他のrequireが終わるまで待つ。が他のrequireがthreadごと止められていて進まない)
それを回避するために require 'rbs' (0.07秒ほどかかる)をmain threadで実行するようにしました。
これによりIRBの起動時間が数十%伸びてしまいますが仕方がない。
2024/09/13
IRBのDebug機能のコマンドのうち、breakとnextは、IRBがコマンドをメソッドとして実装していた時は特別扱いが必要でした。今はそうじゃないので、その特別扱いをやめています。
2024/09/14
端末のE2Eテスト yamatanooroti のwindows版のバグ修正です。
実行するコマンド名文字列がNULL終端でないといけなかった(たまたま動くこともある)
端末上の指定した矩形領域に表示されているの文字列を取得するAPIがバグってるらしく、行ごとに文字列を取得するように変更
なおCI上でwin版yamatanoorotiを動かすには他に色々とやることがあるらしく、まだ設定できてない。CI欲しい
2024/09/17
Yamatanooroti(端末のE2Eテスト)の改善です
高速化・assert_screenの自動リトライ・assert_screenを何度でも呼べるようになった
これでIRBとRelineの rake test_yamatanooroti を高速化できます(テストの書き換えは必要)
Yamatanoorotiのコマンド起動方法を変更しています。bash経由かつsttyも使っていたのを、指定されたコマンドそのまま使うように変更しました。
YamatanoorotiのCIの手入れです。actions/checkout@v4 に変更しました。というかdependabotが有効になりました。
YamatanoorotiのREADMEの内容が実際と異なった(変えた)ので文章微修正しました。
Yamatanooroti Gemfile.lockをgitignoreに追加
IRBに入力したコード内で定義したメソッドをshow_sourceコマンドで表示するとき、
RubyVM::AbstractSyntaxTree.ofを使っていたのをRubyVM::InstructionSequence.ofに変更しました。
parser=parse.yだけでなくparser=prismでも動くようになる
2024/09/19
Yamatanoorotiのtypo2箇所修正です
2024/09/28
HISTORYのencodingに関するテストで、localeの設定を微修正しました。
RelineのHISTORY関連のバグを直そうとしたらIRBのテストがこけるようになることがわかったのでその対処です。
Yamatanooroti(端末のE2Eテスト)のvtermを使う版を最近高速化・APIの使い方変更したんですが、それのwindows版対応です。
vterm版と同様に、assert_screenを複数回実行できるようになった・assert失敗しても何度か時間をおいてリトライするようになりました。
2024/10/02
型補完 0.1.7リリースしました。IRBでのdebugモードでのdeadlockが直る・Prism~>1.0 を使うようになる
Reline::HISTORYに様々なencodingの文字列・encodingとしてinvalidなバイト列などを追加したときに起きる不具合を修正
IRBのdebug modeで、debug gemが実際に使うbindingとIRBがシンタックスハイライト・コマンド実行に使うbindingが異なっていたのを修正しています
2024/10/03
Relineのカーソル位置取得で、端末がカーソル位置の返答を返さない場合無限に待ち続けてしまう問題があったので、0.5秒のタイムアウトを設けました。
一度タイムアウトした場合はそれ以降はカーソル位置を問い合わせない方がいいかもしれないがどうするか未定
RelineでCTRL-r で履歴検索を行った際に、正しく動かなかったりRelineが落ちたりするバグを修正しました。
カーソル位置取得のタイムアウトのテストでPTY.spawnのio閉じ忘れの修正
Reline::Windows::KeyEventRecord#matches? が match? にrenameされました。
IRBの型補完gem repl_type_completor が bundled gem になります! わいわい
最近更新したYamatanoorotiを使うことでRelineのE2Eテストを高速化しています。
CI上での rake test_yamatanooroti にかかった時間が 3:17 → 0:47 と約1/4に短縮されました 🎉
2024/10/06
E2Eテストのうち、setupが同じで一度にできるテストをまとめて実行するようにしました。
こんな感じ
code:text
before
文字を入力 undo assert_screen
文字を入力 undo redo assert_screen
↓
after
文字を入力 undo assert_screen redo assert_screen
Ruby 3.4でHashのinspectが変わることで落ちるようになったテストを直しています。
そういうテストはあらかじめ直してたつもりだったんですが、PTYを使うIntegration testはruby-coreのciで実行されなくて気づかなかったのかな
同じくRuby 3.4のHash inspect対応。こちらはE2Eテストです。これもruby-coreのciでは実行されない
最近追加したテストでのtempfileの消し忘れ対応
IRBのデフォルトの補完が型補完になります🎉 (ReplTypeCompletorがbundled gemとして入っているRuby 3.4以上の時のみ)
bundlerとかで使う時はGemfileに書かないと使えずに正規表現補完になるので注意
2024/10/07
Terminfo (端末ごとにどのエスケープシーケンスが使えるか定義したもの) が使えない場合、Relineはいくつかの端末向けのキーバインディングを登録していました。
それらのうち、typoか勘違いによる誤登録っぽいものを削除し、特定の端末用ではなく汎用のANSI escape sequenceなものは別途汎用のものを登録する処理に移し替えました。
inputrcファイルでMetaキーとの組み合わせのキーバインディングを設定ができるようになりました。
Meta-やM-から始まる設定の読み込みのバグ修正と、キーバインディングに登録するバイト列のバグ修正
2024/10/09
Emacs内でdumb terminal(リッチではない最低限のshell)内でIRBを動かした時、無駄なputsが表示されるようになっていました。(debug gemのテストの都合で入れたworkaround)
debug gemのテスト実行時に使ってる環境変数を見て、それが設定されていない時はworkaroundを入れないようにしました。
これ、単に空行が一つ余計に出るだけで特に困らないと思ってたけどissueコメントでの要望が強かった
2024/10/20
Readlineではできるはずのタブ補完が連続してできるようになりました。
IRBで補完候補が一つしかない場合、もう一度タブを押すとドキュメントが出る機能(とそれを実装するためのRelineのhook)があるんですが、
その機能のためにReadlineでできていたことができなくなっていました。hookを設定していない場合はReadlineと同じ挙動になるように修正
IRBのHistory保存件数を-1に設定すると無制限になることをドキュメントに追記
IRBのHistory保存関連の重複したコードをまとめるリファクタと、save_historyがoffでもhistoryのloadはするような変更が入っています。
名前からするとsave_history=offでもload_historyまでoffになるのは不自然なので、新機能というよりはバグ修正と言えそう
Reline同様、IRBもvtermを使ったE2Eテストを高速化と、mergeタイミングの都合でconflictしてしまったテストの修正
README に Debugging with IRB > Getting Started section を追加しています。
Debugするにはまずどうすればいいんだっけ、というのがわかりやすくなります。
止まってしまっていたCIのgh-pages関連のjobの修正
Historyのリファクタリングで入った、履歴の保存件数がbignumかどうかの判定を消しています。
Array#lastにbignumを渡すと動かないんですが、その閾値は環境によって違うし、array.last(n) if n < array.size の判定をすれば良いだけなので。
自動補完でAlt+Dを押すとドキュメントが表示されるんですが、この時、使っているpagerによっては元の画面に戻ろうとすると画面が崩れることがありました。
画面を復元できるようなescape sequenceを多くのpagerは使っているんですが、そうでないpagerのためにIRBが強制的にそれらのescape sequenceを使うように変更
build_statementメソッドが引数を破壊的に変更するのをやめているリファクタリングです。
元々はliteral string will be frozenというwarningを直すというpull requestでした。
それ自体は実際にはliteral stringを渡すことはないはずで問題ないと思うものの、破壊的変更をする(つまり呼び出し側に注意が要る)のはあまり良くなかったのが改善しました。
型補完がRuby 3.4から入るit構文に対応しました。
テストコードにも追加しましtが、itってこんな挙動するらしいです
code:ruby
# itはローカル変数ではない
:it_param.tap{p it; p local_variables}
# itを定義するまではitはパラメータのit
:it_param.tap{p it; it = :lvar; p it; p local_variables}
IRBのencoding関連のテスト修正です。Reline側のとあるencodingの問題を直すとテストが通らなくなることへの対処
Relineのencodingとして、Encoding.default_externalではなくSTDIN.encoding(特に設定していない場合はEncoding.default_externalと同じ)を使うようになりました。
TCP Socketとかを使う都合でdefault_externalをasciiにしている場合にutf8が使えず困るという報告があった・STDIN.getsとかKernel.readlineと挙動が揃うのは良いこと
2024/10/27
タブ補完した時にcompletion_append_character(区切りの空白文字)を自動で挿入する機能のバグ修正です。
唯一の候補が補完された時にだけ挿入されるはずですが、複数の補完候補の共通のprefixを補完したときにも挿入されてしまう不具合がありました。
completion_append_characterのテスト追加
promptなどの文字列に \1 \2 で囲まれた部分があった場合、標準出力にprintはするものの幅計算からは除外する、という機能があります。
Readlineでは\1 \2自体は出力しないのですがRelineは\1 \2も出力していました。
\1 \2 が出力されてしまうとWindowsのコンソールで問題があるらしい、というのを、CIのwin対応を試してくれている方が見つけて報告してくれました。
Thread.new{} proc{}.call などがあると補完が動かなくなっていた問題の修正です。
RBS 3.6からこれらの型に (?) -> void が使われるようになっていて、それを表現している RBS::Types::UntypedFunction に対応するようにしました
2024/11/10
pagerを止めるProcess.kill(:TERM)がWindowsでは使えないらしく、その場合はkill(:KILL)を代わりに使うようになりました。
IRBのコマンドライン引数のドキュメント(日本語)修正
RelineのWindowsのバグ修正などです。
ANSIエスケープシーケンスがターミナルの表示領域に対して文字表示などの操作をするのに対して、
コマンドプロンプトのWinAPIはスクリーンバッファ(画面外にスクロールされて隠れてる部分含む)に対する操作をするAPIのようです。
カーソルの位置も画面内じゃなくスクリーンバッファ基準で指定する必要があるらしく、主に座標に関連するバグ修正とリファクタリングが行われました。
Reline 0.5.1リリースされました🎉 pull requestの番号に注目 :777:
2024/11/12
Relineの文字列関連折り返し・文字列の操作範囲の計算(option+deleteで何文字消すか)関連メソッドの返り値のリファクタです。
文字列折り返しの返り値は [["1行目", nil, "2行目", nil, "3行目"], 3] から ["1行目", "2行目", "3行目"] に変更(昔は偶数indexにnil以外も含まれてたらしい)
option+deleteでの削除範囲の計算では、バイト数と文字の幅をセットで返していた(LineEditorの昔の実装都合)のを、バイトサイズだけ返すように変更しました。
タブ補完処理のスパゲッティコードをほどきました。
complete_internal_procが別々の複数の役割を無理やり一つにまとめたものになっていたのを分離、perform_completionが必要ないのに再帰関数になっていたのを解消
5種類あったCompletionStateのうち一つが、再帰関数呼び出しを跨いで状態を渡すために一時的に使われていただけの架空の状態だったことが判明したので消しました。
必要以上に複雑なフローは大抵バグも含んでいるもので、未知だったバグが意図せず直ってます。
2024/11/18
Terminfoを使わないようになりました。
ここ1年くらいの変更でRelineのTerminfoへの依存が減っていて、通常の端末では使う意味が全くない
今時xterm互換ではない端末が使われているとは思えないし、影響もおそらくHOMEキーENDキーが効かないといった程度
いくつかの特殊な端末にはそもそもRelineが現時点で対応していない(そういう端末が解釈できなさそうなエスケープシーケンスを使っている)
Terminfoはfiddleとlibncursesが両方使える環境でしか使えないしfiddleがdefault gemから外れる予定ので、fiddle依存を外したい
2024/11/19
IRBが使う環境変数についてドキュメントに追記しています
selfがfrozenの時(cd frozen_objectを実行したときなど)にSimpleDelegatorを使っていたのをやめています。
昔コマンドがメソッドとして実装されていた時、frozen objectにコマンドをメソッドとして定義していると見せかけるために使われていたんですが、今はもうコマンドはメソッドではないため、HelperMethodのためだけに使われています。
Delegatorを使うことに複雑さおよび奇妙な挙動をするデメリットがあること、frozen objectにHelperMethodが定義されないことには納得感があって使えなくても問題ないのでは、ということでDelegatorやめました。
2024/11/22
::Kernel.instance_method(:methods).bind(eval("self")).call
などを、method objectをCONSTANTに入れた上で KERNEL_METHODS.bind_call(receiver) に変えています。
binding.eval('self') の代わりに binding.receiver が使えるのはIRB関連のメタプロする上で便利ですね
pull 1031のfollowupとして、main object(現在のbindingのself)に対して、それがBasicObjectでも安全にメソッドを呼ぶための処理の定義場所をより適切なところに移動しています。
2024/11/26
現在Trufflerubyのciのsetupでio-consoleのinstallに失敗するためにIRB RelineのCIがこけ続けていました。(こういうことが今までも何回か起きてる)
Trufflerubyのciを別のgithub workflowに分けることで、trufflerubyのworkflowだけ設定でoffにできるようになりました。(IRBはgreenに戻った。Relineはまだ)
Truffleruby側で問題は解決したようなのですが、直ったバージョンがリリースされるまでもうちょっとかかるそう
タブ補完および自動処理をするとき、入力をカーソル位置によってpreposing target postposingに分離しているんですが、quoteがある時に分離がおかしい(concatしたら元の文字列に戻るはずが戻らない)問題を修正しています。
763のbranchで新しく追加したテストコードに、master branchでは引数の数が変わったメソッドを使っていてテストがこけていたことの修正です。gitのconflictに引っかからないタイプのconflict
"rub のタブ補完が "ruby" になってほしいケースで、補完されずに単に閉じquoteが追加され "rub" になってしまっていた不具合の修正です。
補完したのちに閉じquoteを追加する必要があるんですが、閉じquoteを追加する処理があってはいけない箇所(副作用がなさそうに見えるメソッド)にあったのを直した、など。
シンボルの補完をするとき、補完候補数を100個に制限しています。
補完候補が多いとRelineのダイアログ表示が遅くなるため。
backtickのインデントのバグ修正です。
同じbacktickでも Kernel.` みたいなメソッド呼び出しと `ls` みたいなxstring_literalを区別する必要があって、その方法を改善しています。
でも実は区別が難しいケースがあって、p p `ls` などを書くと依然としてインデントうまくいかない。
こういうのはやっぱりtoken列じゃなく構文木を使って判定しないと難しいんだろうな
標準入力から入力されるバイト列は
標準入力 → バイト列 → KeyStroke → 意味のあるキー → LineEditor
という変換を経てLineEditorに渡されるんですが、マルチバイト文字の入力はバイト列のままLineEditorに到達します。
LineEditorでは、asciiではない範囲の入力はバッファ貯めて、valid encodingになるまで待つ、みたいな処理をしています。
要は責務がうまく分かれていないので、LineEditorが無理をしているわけです。
これを、KeyStrokeレイヤーでマルチバイト文字列をちゃんと解釈して、文字入力をLineEditorに渡するようにリファクタリングしています。
また、KeyStrokeレイヤーでは、どのキーにも割り当てられていなくて解釈できないエスケープシーケンスを無視する機能があるので、これを流用して無効なマルチバイト入力も同様に無視できるようになりました。今までは無効なバイト列入力があると以降CTRL-Cを押すまで文字入力が不可能になってしまっていた。
2024/11/30
IRB同様、RelineもtrufflerubyでCIが落ちていたので、trufflerubyのテストだけ別のworkflowに分離しています。
LANG環境変数などによりdefault encodingがUS_ASCIIになった状態でテストを実行すると失敗するテストを微修正・一部omitするようにしています。
Reline 0.5.12 release 🎉
Relineが使うencodingを STDIN.external_encoding || Encoding.default_external に最近変えたんですが、Ruby 3.0以下ではcloseされたSTDINのexternal_encodingメソッドが呼べない(IOErrorが出る)問題があったのでrescueを追加しました。
Relineのテストは複数のencodingで実行している...はずだったのが実はうまくいっていなくてUTF-8しか試せていませんでした。
(ENV['RELINE_TEST_ENCODING'] をセットしてるのに ::RELINE_TEST_ENCODING をチェックしていた)
この問題を修正しつつ、ちゃんと複数のencodingでテストを実行すると通らないテストがいくつかあったのを修正しています。
743のfollowup...というかレビューで変な指摘をしてしまった部分の修正
環境変数INPUTRCを設定してる環境でテストが通らない問題の修正
Reline.readlineを呼び出している間、ユーザー定義のSIGWINCH SIGCONT handlerが呼ばれない問題を修正しています。
SIGINTなども同様に呼ばれないんですが(こちらは多分問題ない)、SIGWINCH SIGCONTはhandlerが呼ばれないとWINCHやCONTが起きたことが検知できず困るケースが想定されるし実際issueに報告されていました。
Rubyのeaster_egg(dancing ruby)で、カーソルがチラつくのを防ぐためにカーソルを非表示にする・easter_egg終了時にカーソルを再度表示するようにしています。
2024/12/03
binding.irbを実行する前にrequire済みのライブラリの型情報を(gemの中にrbs型定義があった場合)読み込むようにしています。
プロジェクトでrbs collectionの設定をしなくても型情報が使えて便利...ですが、irb起動後にrequireしたgemの型情報はまだ読み込めません。
RelineのSTDOUT.write出力をバッファリングするようになりました。
IRBに Thread.new{loop{}} を入力すると描画が非常に遅くなる問題が多少改善します。(操作不能になることがあるので試すときは注意)
2024/12/10
lsで存在しないローカル変数のメソッドを調べようとした時に長いbacktraceとともに Maybe IRB bug! と表示されるバグを直しています。
raise(Exception).fooをlsやshow_sourceした場合など、任意のエラーが起こり得るのでExceptionをrescueするようにした
lsコマンドがメソッドだった頃の古い記法 ls obj, grep: pattern からobjとpattern部分を取り出す処理をevalではなく正規表現で行うよう変更
key_bindings(2バイト以上のバイト列の組み合わせとLineEditorのメソッドとの紐付け)とMAPPING(1バイトのキー入力とメソッド)が別々に存在しており、
Reline::Keyはcharがsymbol(key_bindings由来)とnumber(MAPPING)が混在しているという複雑さがありました。
LineEditorが数値をMAPPINGに変換していたが、それも責務が違っていそう。key_bindingsとmappingsの統合し、Reline::Keyの構造もシンプルになりました。
RBSを読み込む処理(CPU bound)はスレッドを立てているのですが、CPU boundなスレッドがあるとIO boundなスレッドの実行が後回しにされていつまで経っても終了しないという問題があります。
(IO boundなものはすぐにGVLを解放するがCPU boundなものは一定時間GVLを持ち続けるからかな)
IRBでタブ補完すると、ドキュメントダイアログに表示するためのRDocの読み込みがいつまでも終わらず長時間待たされてしまう。
これを改善するため、RBS読み込み中に頻繁にThread.passを呼んで実行スレッドを切り替えるようにしています。
このほかに、時間計測しつつsleepを挟んでthrottlingする・TracePointのhookを使う方法なども考えられる。後で再検討するかも
string.encode. Thread.new{}. の補完が効かなかった原因を修正しています。
StringやThreadではなくinstanceを返す型定義になっていて、それに対応していなかったからでした。
"\u0001" や "\e[1m" といった制御文字・エスケープシーケンスをIRBに入力した時(入力方法は C-v C-a や C-v ESC [ 1 m など)
カーソルの位置計算がおかしくなる問題を修正しました。
色付きの文字列(制御文字は ^A などの2文字のアスキー文字に変換済みかつ、色を指定するエスケープシーケンスが別で追加されている)の改行計算を、スタイルなしの文字列にそのまま使ってしまったのが原因
2024/12/12
IRBがdebugモードに入った時のdebuggerの長い出力もpagerで表示するようになりました。
IRB 1.14.2 released🎉
IRBからdebugモードに入った時ではなく、debuggerからIRBを立ち上げた時(環境変数RUBY_DEBUG_IRB_CONSOLEで有効化できる) HISTORYファイルがロードされていなかった問題を修正しています。
rbs_collection.yamlが存在する場合、gemの中にsigディレクトリを強制的に読み込む処理をしないようにしています。
rbs_collection設定済みならそちらの設定を優先する、gemの中のsigを読み込むのは未設定の場合のfallback という扱いに。
RBSの読み込みがIRBのメインスレッドをブロックしてしまう問題の対処として、TracePointのhookでThread.passを呼び出すようにしました。
Thread.passを呼ぶ回数を制限することでオーバーヘッドも許容範囲になったと思うし、何よりIRBのドキュメント表示のためにRDocを読み込む処理を全く邪魔しなくて快適に動くようになった。
ReplTypeCompletor 0.1.8 released🎉
Undo Redo処理でオートインデントを無効化しました。
仮にインデントが崩れていたとしても、操作前の状態にそのまま戻すのがあるべきUndo Redoのはずなので。
ついでにUndoとRedoの処理の共通部分をリファクタリングしました。
undoとredoはそれぞれ move_undoredo(-1) move_undoredo(+1) を呼ぶだけ。
2024/12/16
IRBのドキュメントのうち、内部APIのものを生成しないようにしています。
IRBはライブラリとしてだけでなくツールとしての性質もあるので、コマンドの拡張・コンテクストなどいくつかのpublicにしているAPI以外はほとんどが内部用のものになっています。
それら、IRBをカスタマイズしたい人からするとノイズになるものを生成されるドキュメントから除外しました。
例えばEasterEggの内部で使うCanvas RubyModel とかまでドキュメントが生成されていた。
ドキュメント内のrdoc-refのtypoによるリンク切れ修正
カーソルを前の単語まで・後ろの単語まで移動するキーバインドの、カーソル移動距離計算の実装をリファクタしました。
emacs/vi modeそれぞれに forward/backward word と big-forward/big-backword word へ移動するキーバインドがあります。
実装がwhileを使った複雑なものになっていたので、grapheme_clusterに分割したあとtake_whileを使う実装に書き直したら240行くらい減りました。
減ったコードにたまたま含まれてた実装の不備のバグもいくつか直った。
こちら、take_whileの他に正規表現を使った実装にすると楽なんですが、grapheme_cluster単位でマッチさせるのがうまく行かなくて断念しました。
quoted_insert(C-v+制御文字 で制御文字を直接入力できる)と、bracketed_paste(テキストのペースト入力)を、それぞれ単一のキー入力としてLineEditorに渡すようにしました。
quoted_insert: C-vをLineEditorが受け取ったら次のキー入力を特別処理する、というのがなくなってシンプルになる
bracketed_past: reline.rbから直接LineEditorのペースト貼り付けメソッドを呼んでいたのが、普通のキーと統一された(キー入力前後にするべき処理を忘れずに実行できる)
自動補完ダイアログが表示されているときに文字をペーストしても補完ダイアログが消えない問題も解消されます。(これが直ってることにはついさっき気づいた)
Reline 0.6.0 released 🎉
ruby/rubyのbundled_gemsのテストでrepl_type_completorが落ちていました。
落ちていたテストは、require済みのgemのsigディレクトリの型情報を読み込んでいるかどうかのテストで、
落ちていた原因は、make test-bundled-gems ではdefault gemはGem.loaded_specsに含まれていないことと、bundled_gemsのsigディレクトリが存在しないことでした。
二つの原因があることに気づくのに時間がかかってぐだぐだに何度も修正し直すことになってしまった。
目的のテストをできる環境ではないので、その場合は単にomitするようにしました。テスト用のダミーgemを作るのが一番良いはず。
ReplTypeCompletor 0.1.9 released 🎉
内容はテストの修正(omit)のみ。
2024/12/18
IRB 1.14.3 released 🎉
2024/12/23
コメントのtypo修正です
どちらも僕(tompng)が入れたtypoっぽい。vscode拡張のspell checker入れた