- 作成者投稿
- 2012年12月11日 6:09 am #11370redakt55参加者
Ruby スクリプトの編集に使っていて,自動インデントが非常に使いづらく感じています。
以下のようなことに気づきました。※なお,この掲示板では行頭スペースが勝手に削除されてしまうので,インデントを表すために便宜的に全角スペースを入れることにします。
◎インデント開始のキーワードの判定
「インデント開始」が^(.*([|({|do)s*(|.*|)?)s*|(s*(module|class|def|unless|if|else|elsif|case|when|begin|rescue|ensure|for|while|until).*))$
になっているのですが,「module」などのキーワードのあとにさらに英字が続いてもマッチしてしまいます。
したがって,form=nil
などと入力して(form は予約語ではない),Enter を押すと,次行はインデントされた位置にカーソルが来てしまいます。
「until)」の後ろに b を入れるべきかと思います。◎elsif に条件が続くとき
以下のようなコードが入力したいとします。if x==0
puts “zero”
elsif x>0
puts “positive”
else
puts “negative”
end2 行めまで入力して Enter を押すと,カーソルはインデントされたところに来ます。
ここで「elsif」と打つと,インデントが無くなります。
ここまでは正常です。次にスペースと「x」を打つと,再びインデントされます。これは変です。
elsif に何かが続いていても「インデント終了」の正規表現
^s*([}]]s*|(end|rescue|ensure|else|elsif|when)b)
に合致しているように思えるのですが,なぜでしょう。
ふと思い立って,b の末尾に .* を付けてみたら,正常になりました。ということは,「インデント開始」や「インデント終了」に入れた正規表現は,行の一部ではなく全体にマッチしないといけない,という判定なのでしょうか?
もしそうなら,「インデント開始」の ^ $ は不要です。従って,全体を囲っている一番外側の ( ) も省くことができます。同様に「インデント終了」の ^ も省けます。
実際,省いても正しく動作するようです。
正規表現は簡素な方が保守性が良いので,省けるものは省いてほしいと思います。◎インデント終了のキーワードの判定
次のような,コードが入力したいとします。if x>0
endeavor=nil
end2 行目の「end」まで打つと,この行のインデントが無くなります。
ここまでは正常です。しかし,続きの「eavor=nil」を打っても,インデントは回復しません。
最初に挙げた elsif の件では,「インデント終了」の条件に当てはまらなくなった時点でインデントが回復したのに,この違いはどうしたことでしょうか。
elsif と end の違いは,「インデント開始」に含まれているか否かですが,それが影響するのでしょうか?ここで,さっぱり分からなくなり,調べるのを諦めました。
自動インデントがどういうアルゴリズムで働いているのか,どこかに書かれていますか?
2012年12月11日 6:14 am #11371redakt55参加者一つ書き忘れました。
「インデント開始」で,「do」の判定も不十分です。
「todo」+ Enter を打つと,インデントされてしまいます。「do」の前に「b」が必要だと思います。2012年12月12日 3:57 am #11379Yutaka Emuraキーマスターredakt55 様
いつも EmEditor Professional をお使いいただき、誠にありがとうございます。
これについては、詳しく調べて、また何かわかりましたら回答したいと思います。ヘルプにも記述を追加したいと考えています。
どうぞよろしくお願い申し上げます。
2012年12月17日 1:34 am #11394Yutaka Emuraキーマスターredakt55 様
いつも EmEditor Professional をお使いいただき、誠にありがとうございます。
ご質問の elsif x>0 の場合と endeavor=nil の場合との違いですが、インデントの動作は、指定したどれかの正規表現に一致した場合のみ、インデント (右へ) または逆インデント (左へ) が発生します。
elsif x>0 は、「インデント開始」の正規表現に一致するため、インデントが発生します。
endeavor=nil は、end の後 e を入力した後、「インデント開始」にも「インデント終了」にも一致しないため、インデントが発生しなくなります。
以上が、現在の仕様になりますが、確かに endeavor とタイプする場合は、一度逆インデントが発生した後、インデントが戻らないのは、不便だと思いますので、何かいい方法を考えたいと思います。
ご指摘の通り、「インデント開始」の「do」の前に「b」を、「until)」の後ろに b を追加し、「インデント終了」のb の末尾に .* を追加します。また、書かれているとおり、正規表現は、その分全体に一致しないといけないという判定です。したがって、^ $ は不要になります。既定の正規表現はご指摘のように修正したいと思います。
これでご理解いただけましたでしょうか? もし他に不明瞭な点がございましたらご連絡ください。
どうぞよろしくお願い申し上げます。
2012年12月18日 1:34 pm #11395redakt55参加者実際はもっと複雑な気がします。
一文字タイプしたとき,自行が終了行とみなされると,自行のインデントが -1 される。
開始行とみなされ,かつ前行が開始行でない場合は自行のインデントが前行に合わせられる。
開始行の末尾で Enter を入れると,次行のインデントが +1 される。
というような感じでしょうか?それから「ステートメント終了」というのは何でしょうか?
ともかく,完璧に動作する自動インデントが不可能である以上,既に入力した行を修正したときにインデントが変化してしまうのはやめてほしいです。
たとえば,
case foo
when /[a-zA-Z]/
puts “Alphabet”
when /d/
puts “digit”
end
のようなものを打って,4 行目の正規表現を変更すると,この行がぴょこんとインデント +1 されてしまいます。
EmEditor が誤ったインデントを手作業でせっかく直しても,一文字修正しただけでまた誤ったインデントにされてしまいます。いたちごっこというか,賽の河原というか。Python や CoffeeScript のようにインデントに意味を持たせた言語の編集では,一時的にせよ勝手にインデントがゆがめられるのは非常に危険でストレスを感じます。
2012年12月20日 12:18 am #11396Yutaka Emuraキーマスターredakt55 様
いつも EmEditor Professional をお使いいただき、誠にありがとうございます。
ご指摘のようにかなり複雑です。
「ステートメント終了」には、C++ などの言語の場合、ステートメントの終了を表す ; または ; を含む正規表現を指定しておきます。すると、; で終了していない場合は、次の行がインデントされ、; で終了する場合は、インデントが、インデントされる前の行と同じに戻ります (逆インデント)。
今日は一日中このことを調べていたのですが、Ruby などの言語の場合、Enter を入力するとき以外は、インデントが変わらないようなオプションを追加したいと思います。しかし、C++ などの言語では、現在と同じ仕様のままです。これで、ほとんどの方に問題なく使っていただけるのではないかと思います。次のメジャー バージョンのベータ版が公開されましたら、お試しいただけると幸いです。
どうぞよろしくお願い申し上げます。
2012年12月20日 12:46 am #11397redakt55参加者そのオプションで問題の大部分が解決しそうな気がします。
それともう一つご検討いただきたいのが,既に挙げた Ruby の case 文です。以下のように書きます。
if hoge
case foo
when x
aaa
when y
bbb
end
endこの最初の when を打ったときに,case ではなく if に揃う位置にされてしまいます。この問題は,たぶんそのオプションの導入や正規表現の工夫では解決しないのではないかと思います。
それと,インデントがどのように決定されるかをマニュアルに記載していただけると非常に嬉しいです。
2012年12月20日 2:26 am #11399Yutaka Emuraキーマスターredakt55 様
いつも EmEditor Professional をお使いいただき、誠にありがとうございます。
これは確かに難しそうな気がしますが、調べてみます。
マニュアルにも追加します。どうぞよろしくお願い申し上げます。
- 作成者投稿
- このトピックに返信するにはログインしてください。