`(Hello ,world)

ツッコミ、添削大歓迎です。いろいろ教えてください。

2010-12-07

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20101207

2010-10-19

TaronTaron2012/02/15 08:07Great isngiht. Relieved I'm on the same side as you.

wjznrttpciwjznrttpci2012/02/16 23:53MfeY7f , [url=http://jvlwpdhaenxr.com/]jvlwpdhaenxr[/url], [link=http://owtzzxssuqlq.com/]owtzzxssuqlq[/link], http://izwkxhqbfliq.com/

tgbwlhvtgbwlhv2012/02/17 21:009etuGL <a href="http://kjvppqjcgzal.com/">kjvppqjcgzal</a>

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20101019

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を削除しないと反映されなくてハマった。

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100914

2010-08-23

アクトインディ技術部隊報告書

アクトインディ技術部隊報告書

濃いな〜センスがぶっとんでて面白すぎる。「隙があればlispを詰め込んで行きたい」誰得感がすごい。一番のお気に入りはInternal Server Error「メッセージは依然適当にスルーされています」chibaさんのこういう軽快な文章が大好きです。

VenkaVenka2012/02/17 13:01You've got it in one. Couldn't have put it beettr.

ugemxdaetugemxdaet2012/02/19 21:57jDcAfQ , [url=http://azvvwaqprjld.com/]azvvwaqprjld[/url], [link=http://uywfmbugagpq.com/]uywfmbugagpq[/link], http://xhhzftmkruxb.com/

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100823

2010-08-12

BiwaSchemeにオートインデントを組み込む

仮に、オートインデントをBiwaSchemeのREPLに組み込んでみる:

mokehehe.com: The Leading Moke Hehe Site on the Net

BiwaSchemeはprototype.jsを使ってて、オートインデントはjQueryを組み込んじゃったので、共存させるには prototype.jsと同時に使うには - jQuery 日本語リファレンス。できればjQueryを使わないようにしたい。

組み込みはまあ簡単に、jQuerylisp-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だけ解決できれば、まあ使えそうな。

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100812

2010-08-11

Opera...

テキストエリアでオートインデントさせるのに、JavaScriptであれこれ書いてる。動作確認は、IEははなから切り捨ててChromeFireFoxで主に試してる。一応動いて、Operaでも試してみるかとやってみると、挙動が全然違う。

RETを押したときにonkeydownでfalseを返してもRETが挿入される
改行
  • テキストエリア内に "\n" を突っ込むとChromeFireFoxでは10の1文字なのに、Opera だと[13, 10] の2文字になる?カーソル位置を計算できない…
選択範囲のセット
  • カーソル位置を移動させるのにテキストエリアの選択範囲のセットを使うが、なぜかひとつ前の位置になってしまう。+1してやらないといけない。

いろいろ、クロスブラウザめんどい…

閉じ括弧で対応範囲をハイライト

Lispの場合オートインデントが必要というよりは、閉じ括弧を入力したときに対応する開き括弧の位置を示してくれないとまともに使えないと個人的には思う。xyzzyなどでは対応する開き括弧の位置に一定時間ポイントが移って、また戻るようになっている。同じような機能をテキストエリアに組み込んでみる。

テスト (jsソース

up_list_backward()だかgoto_matched_open()で開き括弧の位置を取れるようにしたので、その範囲をtextarea.setSelectRange()で選択してやる。setTimeout()で一定時間が経過したり、その間になにかキーが押されたら、その選択ははずす。

keydownなどのイベントで、jQueryを使ったほうがクロスブラウザで楽かな、と思って使ってみた。

  • たくさん入力してスクロールするときになってもしてくれない。textarea.setSelectRange()でカーソル位置を設定しても自動的にはスクロールされない。どうやってやったらいいんだろう?
  • 続きを読む

BubbaBubba2011/09/28 19:20It's much easier to undtersand when you put it that way!

tmpsudwettmpsudwet2011/09/30 23:35liO20A , [url=http://zadlxadxclvw.com/]zadlxadxclvw[/url], [link=http://tcqdslhtzjnq.com/]tcqdslhtzjnq[/link], http://bqwcgwoepkhx.com/

xjpxpbxjpxpb2011/10/03 00:57FO5BJY <a href="http://tmtrrzwxbfet.com/">tmtrrzwxbfet</a>

uxivysrkxuxivysrkx2011/10/05 20:199XWpF5 , [url=http://jupxwtefqhfo.com/]jupxwtefqhfo[/url], [link=http://jfncwwxmrxjx.com/]jfncwwxmrxjx[/link], http://ubppqxsodzor.com/

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100811

2010-08-10

テキストエリアでオートインデントさせてみる

テキストエディタでどうやってオートインデントしてるか知りたくてxyzzyのソースを見てみたところ、地道にやるしかないということだったので、力任せにJavaScriptで組んでみた:

テスト

ChromeFireFoxで確認。Operaだとカーソル位置がおかしくなるっぽい。一応なんとなく動いてるけど、こうなるとタブ押したときもなって欲しいし、閉じ括弧を入力したときに対応する開き括弧を示して欲しい。タブはFireFoxではフックできるぽい。閉じ括弧はChromeでは取れるぽい。

  • リスト、シンボル、数値などのみ。文字列やコメントにはまだ非対応。

続きを読む

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100810

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ソースは、クラス別じゃなくて機能別に分かれてて面白いなと思った

CrystalCrystal2012/02/17 14:13I came, I read this atircle, I conquered.

fwxmyanfwxmyan2012/02/17 19:343dPY7L <a href="http://dxrlnazknhlp.com/">dxrlnazknhlp</a>

kwjzdlnzhkwjzdlnzh2012/02/19 22:58ZLwiev , [url=http://uquxvqflsxzz.com/]uquxvqflsxzz[/url], [link=http://rajoylgljzvu.com/]rajoylgljzvu[/link], http://ctutljidkpkm.com/

ueaofsuketfueaofsuketf2012/02/22 02:13ZdVikp <a href="http://csbezacksyuz.com/">csbezacksyuz</a>

トラックバック - http://cadr.g.hatena.ne.jp/mokehehe/20100803