2010-12-07
2010-10-19
Taron2012/02/15 08:07Great isngiht. Relieved I'm on the same side as you.
wjznrttpci2012/02/16 23:53MfeY7f , [url=http://jvlwpdhaenxr.com/]jvlwpdhaenxr[/url], [link=http://owtzzxssuqlq.com/]owtzzxssuqlq[/link], http://izwkxhqbfliq.com/
tgbwlhv2012/02/17 21:009etuGL <a href="http://kjvppqjcgzal.com/">kjvppqjcgzal</a>
2010-09-14
xyzzyでArcのifのインデント
ArcのifはLisp/Schemeのcondの括弧が少ない版といった感じで
(if pred1 exp1 pred2 exp2 ... ... else-value)
という風に複数の条件を続けて書ける。このオートインデントをxyzzyで実現しようと思うと元々のlispmodeのインデント計算のままではうまくいかない。lispmodeのインデント計算はifなどのシンボルによって、引数の何個目までは*lisp-body-indent*の2倍、それ以降は*lisp-body-indent*、となってしまっていて融通が利かない。
そこで、シンボルに関数を設定できるようにする。lispmode.lのcalc-lisp-indent関数内でシンボルのlisp-indent-hookに設定された値の型が関数だったら、その関数を呼び出してインデントを決定するようにする:
(defun calc-lisp-indent (opoint) ... (cond ((numberp method) ...) ;追加 ((functionp method) (let ((count -1)) (while (< (point) opoint) ; 何個目の引数かを数える (skip-white-forward) (setq count (+ count 1)) (or (forward-sexp 1 t) (return))) (+ column -1 (funcall method count)))) (method ...
こうして、ifのlisp-indent-hookに関数を設定する:
(setf (get 'if 'lisp-indent-hook) #'(lambda (count) (if (zerop (mod count 2)) *lisp-body-indent* (* *lisp-body-indent* 2))))
でOK。
注意点は、M-x byte-compile-file で lispmode.l をバイトコンパイルするだけじゃなく、いったんxyzzy.wxpを削除しないと反映されなくてハマった。
2010-08-23
アクトインディ技術部隊報告書
濃いな〜センスがぶっとんでて面白すぎる。「隙があればlispを詰め込んで行きたい」誰得感がすごい。一番のお気に入りはInternal Server Error「メッセージは依然適当にスルーされています」chibaさんのこういう軽快な文章が大好きです。
VenkaYou've got it in one. Couldn't have put it beettr.
ugemxdaetjDcAfQ , [url=http://azvvwaqprjld.com/]azvvwaqprjld[/url], [link=http://uywfmbugagpq.com/]uywfmbugagpq[/link], http://xhhzftmkruxb.com/
2010-08-12
BiwaSchemeにオートインデントを組み込む
仮に、オートインデントをBiwaSchemeのREPLに組み込んでみる:
mokehehe.com: The Leading Moke Hehe Site on the Net
BiwaSchemeはprototype.jsを使ってて、オートインデントはjQueryを組み込んじゃったので、共存させるには prototype.jsと同時に使うには - jQuery 日本語リファレンス。できればjQueryを使わないようにしたい。
組み込みはまあ簡単に、jQueryとlisp-mode.jsを組み込んで、set_lisp_mode() でテキストエリアのjQueryオブジェクトを渡せばキーイベントをのっとってくれる:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="lisp-mode.js"></script> <script type="text/javascript"><!-- jQuery.noConflict(); jQuery(document).ready(function($){ var target = $("#bs-input"); set_lisp_mode($, target); }); --></script>
あとはスクロールしない点とOperaだけ解決できれば、まあ使えそうな。
2010-08-11
Opera...
テキストエリアでオートインデントさせるのに、JavaScriptであれこれ書いてる。動作確認は、IEははなから切り捨ててChromeとFireFoxで主に試してる。一応動いて、Operaでも試してみるかとやってみると、挙動が全然違う。
RETを押したときにonkeydownでfalseを返してもRETが挿入される
- キーイベント (keydown, keypress) の、ブラウザ/OS による微妙な違い - 刺身☆ブーメランのはてなダイアリー
- Operaの場合、onkeypressで処理しないといけない
- しかし一律onkeypressで処理しようとすると、firefoxではkeyCodeが0になってしまうのでダメ
- onkeydown->onkeypressの順で呼ばれるので、onkeydownでfalseを返してたらonkeypressでもfalseを返すようにしてみる
改行
選択範囲のセット
- カーソル位置を移動させるのにテキストエリアの選択範囲のセットを使うが、なぜかひとつ前の位置になってしまう。+1してやらないといけない。
いろいろ、クロスブラウザめんどい…
閉じ括弧で対応範囲をハイライト
Lispの場合オートインデントが必要というよりは、閉じ括弧を入力したときに対応する開き括弧の位置を示してくれないとまともに使えないと個人的には思う。xyzzyなどでは対応する開き括弧の位置に一定時間ポイントが移って、また戻るようになっている。同じような機能をテキストエリアに組み込んでみる。
up_list_backward()だかgoto_matched_open()で開き括弧の位置を取れるようにしたので、その範囲をtextarea.setSelectRange()で選択してやる。setTimeout()で一定時間が経過したり、その間になにかキーが押されたら、その選択ははずす。
keydownなどのイベントで、jQueryを使ったほうがクロスブラウザで楽かな、と思って使ってみた。
- たくさん入力してスクロールするときになってもしてくれない。textarea.setSelectRange()でカーソル位置を設定しても自動的にはスクロールされない。どうやってやったらいいんだろう?
BubbaIt's much easier to undtersand when you put it that way!
tmpsudwetliO20A , [url=http://zadlxadxclvw.com/]zadlxadxclvw[/url], [link=http://tcqdslhtzjnq.com/]tcqdslhtzjnq[/link], http://bqwcgwoepkhx.com/
xjpxpbFO5BJY <a href="http://tmtrrzwxbfet.com/">tmtrrzwxbfet</a>
uxivysrkx9XWpF5 , [url=http://jupxwtefqhfo.com/]jupxwtefqhfo[/url], [link=http://jfncwwxmrxjx.com/]jfncwwxmrxjx[/link], http://ubppqxsodzor.com/
2010-08-10
テキストエリアでオートインデントさせてみる
テキストエディタでどうやってオートインデントしてるか知りたくてxyzzyのソースを見てみたところ、地道にやるしかないということだったので、力任せにJavaScriptで組んでみた:
ChromeとFireFoxで確認。Operaだとカーソル位置がおかしくなるっぽい。一応なんとなく動いてるけど、こうなるとタブ押したときもなって欲しいし、閉じ括弧を入力したときに対応する開き括弧を示して欲しい。タブはFireFoxではフックできるぽい。閉じ括弧はChromeでは取れるぽい。
- リスト、シンボル、数値などのみ。文字列やコメントにはまだ非対応。
2010-08-03
オートインデント2
前回xyzzyでオートインデントをどうやってるかを追おうと見てみたけど、主要な関数だと思われる up-list がビルトインでXyzzyLispで行われてなかったので、C++のソースを見てみる。
Lisp側のup-listと関連付けられているビルトインのC関数
どうやって関連付けられているのかわからなかった…
DEFCMD3 (up-list, 0, 2, 0, "p"),
- たぶんFup_list()
Fup_list()
syntax.cc:1884
lisp
Fup_list (lisp arg, lisp noerror)
{
return up_down_list (arg, noerror, 0);
}
- 単に up_down_list() 関数の呼び出し
up_down_list()
syntax.cc:1863
static lisp up_down_list (lisp arg, lisp noerror, int downp) { int n = (!arg || arg == Qnil) ? 1 : fixnum_value (arg); if (!n) return Qnil; Window *wp = selected_window (); wp->w_disp_flags |= Window::WDF_GOAL_COLUMN; Buffer *bp = wp->w_bufp; Point &point = wp->w_point; point_t opoint = point.p_point; int status = bp->up_down_list (point, n, downp); if (!status) return Qt; bp->goto_char (point, opoint); if (!noerror || noerror == Qnil) sexp_error (status); return Qnil; }
- 現在のバッファ、ポイントに対して Buffer::up_down_list() メソッドの呼び出し
Buffer::up_down_list()
syntax.cc:1791
int Buffer::up_down_list (Point &point, int n, int downp) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int i = 0; int (Buffer::*skip_white)(Point &, int) const; int (Buffer::*skip_sexp)(Point &) const; int dir; if (n > 0) { dir = 1; skip_white = &Buffer::skip_white_forward; skip_sexp = &Buffer::skip_sexp_forward; } else { dir = -1; n = -n; skip_white = &Buffer::skip_white_backward; skip_sexp = &Buffer::skip_sexp_backward; } while (1) { if (dir < 0 && ((!eobp (point) && bolp (point) && (syntax (tab, point) == SCopen || syntax (tab, point) == SCtag_start)) || !forward_char (point, -1))) return Send_sexp; int status; point_t before; do { before = point.p_point; status = (this->*skip_white)(point, 0); } while (status == Sin_comment && point.p_point != before); if (status && (dir > 0 || status != Sbob)) return status; if (dir > 0 && !eobp (point) && (syntax (tab, point) == SCopen || syntax (tab, point) == SCtag_start)) { if (downp) { forward_char (point, 1); if (++i == n) return 0; } else if (bolp (point)) return Sunmatched_paren; } status = (this->*skip_sexp)(point); if (!downp && status == Send_sexp) { if (dir > 0) forward_char (point, 1); if (++i == n) return 0; } else if (status) return status; if (dir < 0 && bobp (point)) return Sbob; } }
- 結果は引数の point に返る
- 方向によって、skip_sexp でS式を飛ばす
- ネストしたS式は skip_sexp 側で処理するだろうから、このメソッドでは指定個の開き括弧または閉じ括弧を数えるだけ
- skip_sexp の戻り値は、リストの終端だったら Send_sexp が返る?
Buffer::skip_sexp_forward(), Buffer::skip_sexp_backward()
syntax.cc:1490
int Buffer::skip_sexp_forward (Point &point) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int status; if (eobp (point)) return Seob; while (1) { Char c = point.ch (); if (!SBCP (c)) return skip_symbol_forward (point); switch (xchar_syntax (tab, c)) { case SCclose: case SCtag_end: if (escaped_char_p (point)) goto symbol; return Send_sexp; case SCopen: case SCtag_start: case SCmath: if (escaped_char_p (point)) goto symbol; status = goto_matched_close (point, c); if (!status) forward_char (point, 1); return status; case SCstring: if (escaped_char_p (point)) goto symbol; status = skip_string_forward (point, c); if (!status) forward_char (point, 1); return status; case SCword: case SCsymbol: case SCsymbol_prefix: case SCkanji: case SCkana: symbol: return skip_symbol_forward (point); case SCescape: case SCquote: break; default: return 0; } if (!forward_char (point, 1) || eobp (point)) return Seob; } } int Buffer::skip_sexp_backward (Point &point) const { const syntax_table *tab = xsyntax_table (lsyntax_table); if (eobp (point) && !forward_char (point, -1)) return Sbob; while (1) { Char c = point.ch (); if (!SBCP (c)) return skip_symbol_backward (point); switch (xchar_syntax (tab, c)) { case SCopen: case SCtag_start: if (escaped_char_p (point)) goto symbol; return Send_sexp; case SCclose: case SCmath: case SCtag_end: if (escaped_char_p (point)) goto symbol; return goto_matched_open (point, c); case SCstring: if (escaped_char_p (point)) goto symbol; return skip_string_backward (point, c); case SCword: case SCsymbol: case SCsymbol_prefix: case SCkanji: case SCkana: symbol: return skip_symbol_backward (point); case SCescape: case SCquote: break; default: return 0; } if (!forward_char (point, -1)) return Sbob; } }
- 文字によってスキップ
- リストを前方に飛ばすところだけ見ようか。goto_matched_close()
Buffer::goto_matched_close()
syntax.cc:1155
int Buffer::goto_matched_close (Point &point, Char openc) const { const syntax_table *tab = xsyntax_table (lsyntax_table); int depth = 1, status; Char prev_ch = 0; while (1) { if (tab->comment_column >= 0 && !eobp (point)) prev_ch = point.ch (); if (!forward_char (point, 1) || eobp (point)) return Sunmatched_paren; if (tab->comment_column >= 0 && prev_ch == '\n' && column_comment_p (tab, point)) { status = skip_single_char_comment_forward (point); if (status) return status; continue; } Char c = point.ch (); if (!SBCP (c)) continue; if (xcomment_end_first_char_p (tab, c) && forward_comment_end_p (point)) return Sin_comment; if (xcomment_start_first_char_p (tab, c) && forward_comment_start_p (point)) { status = skip_multi_chars_comment_forward (point); if (status) return status; continue; } if (xcplusplus_comment_char_p (tab, c) && !xparse_sexp_ignore_comment_p (tab, c) && forward_cplusplus_comment_p (point)) { status = skip_cplusplus_comment_forward (point); if (status) return status; continue; } switch (xchar_syntax (tab, c)) { case SCclose: case SCtag_end: if (escaped_char_p (point)) break; if (c == xchar_match (tab, openc)) { if (!--depth) return 0; } else return Sunbalanced_paren; break; case SCopen: case SCtag_start: if (escaped_char_p (point)) break; if (c == openc) depth++; else { status = goto_matched_close (point, c); if (status) return status; } break; case SCmath: if (escaped_char_p (point)) break; if (c == openc) return 0; status = goto_matched_close (point, c); if (status) return status; break; case SCstring: if (escaped_char_p (point)) break; status = skip_string_forward (point, c); if (status) return status; break; case SCcomment_start: if (escaped_char_p (point)) break; if (xparse_sexp_ignore_comment_p (tab, c)) break; status = skip_single_char_comment_forward (point); if (status) return status; break; default: break; } } }
syntax()
syntax.cc:745
static inline syntax_code syntax (const syntax_table *tab, const Point &point) { return syntax (tab, point.ch ()); }
- ポイントのキャラを取り出して、別名の syntax() 呼び出し
syntax.cc:737
static inline syntax_code syntax (const syntax_table *tab, Char c) { if (SBCP (c)) return syntax_code (xchar_syntax (tab, c)); return SCkanji; }
- 文字の種類を返す
- syntax_code は単なる enum。この形式のキャストは関数呼び出しと紛らわしいね…
SBCP()
inline int SBCP (Char c) {return c < 256;}
- 多バイト文字じゃないか?
syntax_code
syntax.h:43
enum syntax_code
{
SCwhite,
SCpunct,
SCopen,
SCclose,
SCmath,
SCstring,
SCcomment_start,
SCcomment_end,
SCcplusplus_comment_end,
SCescape,
SCquote,
SCsymbol,
SCword,
SCkana,
SCkanji,
SCjunk,
SCtag_start,
SCtag_end,
SCsymbol_prefix,
SCmax
};
xchar_syntax()
# define xchar_syntax(t, c) ((t)->type[(c)])
- 単なるテーブルからの取り出し
Buffer::forward_char()
move.cc:37
int Buffer::forward_char (Point &point, long nchars) const { long d = min (max (point.p_point + nchars, b_contents.p1), b_contents.p2) - point.p_point; int f = d == nchars; const Chunk *cp = point.p_chunk; if (d > 0) { while (1) { int size = cp->c_used - point.p_offset; if (d <= size) { point.p_point += d; if (d == size && cp->c_next) { cp = cp->c_next; point.p_offset = 0; } else point.p_offset += d; point.p_chunk = (Chunk *)cp; break; } d -= size; point.p_point += size; point.p_offset = 0; cp = cp->c_next; assert (cp); } } else if (d < 0) { while (1) { if (point.p_offset + d >= 0) { point.p_offset += d; point.p_point += d; point.p_chunk = (Chunk *)cp; break; } d += point.p_offset + 1; point.p_point -= point.p_offset + 1; cp = cp->c_prev; assert (cp); point.p_offset = cp->c_used - 1; } } return f; }
Buffer::goto_char()
move.cc:91
void Buffer::goto_char (Point &point, point_t goal) const { goal = min (max (goal, b_contents.p1), b_contents.p2); if (goal < point.p_point / 2) { point.p_point = 0; point.p_chunk = b_chunkb; point.p_offset = 0; } else if (goal > (point.p_point + b_nchars) / 2) { point.p_point = b_nchars; point.p_chunk = b_chunke; point.p_offset = b_chunke->c_used; } forward_char (point, goal - point.p_point); }
結局
- 地道にやるより他ない
- xyzzyのCソースは、クラス別じゃなくて機能別に分かれてて面白いなと思った
CrystalI came, I read this atircle, I conquered.
fwxmyan3dPY7L <a href="http://dxrlnazknhlp.com/">dxrlnazknhlp</a>
kwjzdlnzhZLwiev , [url=http://uquxvqflsxzz.com/]uquxvqflsxzz[/url], [link=http://rajoylgljzvu.com/]rajoylgljzvu[/link], http://ctutljidkpkm.com/
ueaofsuketfZdVikp <a href="http://csbezacksyuz.com/">csbezacksyuz</a>
