Skip to content

Instantly share code, notes, and snippets.

@takaxp
Created January 12, 2012 07:05
Show Gist options
  • Save takaxp/1599131 to your computer and use it in GitHub Desktop.
Save takaxp/1599131 to your computer and use it in GitHub Desktop.
my-find-headings
(defun my-find-headings ()
(let ((eob (point-max))
(head-list '()))
(save-excursion
(goto-char (point-min))
(while (when (search-forward-regexp "^\*\\([^*]\\|$\\)" eob t)
(setq head-list (cons (match-beginning 0) head-list))
(forward-line))))
(reverse head-list)))
@cvmat
Copy link

cvmat commented Jan 12, 2012

The version without requiring face follows

(defun my-find-headings ()
  (let ((pos (point-min))
        (end (point-max))
        (head-list '()))
    (save-excursion
      (goto-char pos)
      (while
          (let ((head (search-forward-regexp "^\*\\([^*]\\|$\\)" end t)))
            (when head
              (goto-char head)
              (setq head-list (cons head head-list))
              (let ((next (line-end-position)))
                (unless (= next end)
                  (goto-char next)))))))
    (reverse head-list)))

It uses a simple regexp, which requires less computational cost than that for totally rendering.
How about it?

@takaxp
Copy link
Author

takaxp commented Jan 12, 2012

1st ヘッダのある行頭のPOINTをリストで取得できました.

(defun my-find-headings ()
  (interactive)
  (let ((pos (point-min))
        (end (point-max))
        (head-list '()))
    (save-excursion
      (goto-char pos)
      (while
          (let
          ((head (search-forward-regexp "^\*\\([^*]\\|$\\)" end t)))
            (when head
          (beginning-of-line)
              (setq head-list (cons (point) head-list))
              (let ((next (line-end-position)))
                (unless (= next end)
                  (goto-char next)))))))
    (message "%s" (reverse head-list))))

@takaxp
Copy link
Author

takaxp commented Jan 12, 2012

リファクタリングしてみました.
リストは reverse する方が高速なのか検証したいところ '-'

(defun my-find-headings ()
  (interactive)
  (let
      ((head-list nil))
    (save-excursion
      (goto-char (point-min))
      (while (not (eobp))
    (when (search-forward-regexp "^\*\\([^*]\\|$\\)" (point-max) t)
      (setq head-list (append head-list (list (match-beginning 0)))))
    (forward-line 1)))
    (message "%s" head-list)))

@cvmat
Copy link

cvmat commented Jan 12, 2012

eobpはbufferがnarrow状態のときはそこまでしか見てくれません。
また、実際にはsearch-forward-regexpがnilを返した時点でやめられるので、
さらにまとめるとこんな感じでしょうか。

(defun my-find-headings ()
  (let ((end (point-max))
        (head-list '()))
    (save-excursion
      (goto-char (point-min))
      (while (when (search-forward-regexp "^\*\\([^*]\\|$\\)" end t)
               (add-to-list 'head-list (match-beginning 0) t)
               (forward-line))))
    head-list))

buffer内容は変更しないので(point-max)を繰り返し呼ぶことはせずに
一度取得した値を使い回しています。add-to-listとcons+reverseの
どちらが効率的かはちょっと分かりませんがスライド数がせいぜい数十なら
どちらを選んでも計算量が大きく変わることはないでしょうね。

@takaxp
Copy link
Author

takaxp commented Jan 12, 2012

あ.確かにwhile内部ですね point-max はOrz
ちなみに head-list を '() を nil としないは理由がありますか?

スライド数が数十だと,実は既存の実装でもあまり問題にならなかったりします.
5000千行,スライド数400,キーボードリピート30[ms] という環境でもたつくので,レア環境と言えばそこまでなのですが,でもこの実装はとり込もうと思います!

@cvmat
Copy link

cvmat commented Jan 12, 2012

'()を使うのは、(これから値を追加していく)空のリストであることを強調したつもりです。
nilだとnilであることに(真偽などの)意味があるような気がしてしまうので…。
スライド数が多くなるなら、consで結合しておいて最後にnreverseするのが一番速いと思います。
appendにしてもadd-to-listにしても毎ループごとにリストの末尾まで辿らないといけませんから。
add-to-listは破壊的なので、add-to-listappendならadd-to-listの方が速いと思います。

@takaxp
Copy link
Author

takaxp commented Jan 12, 2012

うう.たくさんのコメントありがとうございます(T-T)
ノウハウを色々と教えていただいたので本当に勉強になりますっ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment