Một phương thức nhanh hơn để có được `line-number-at-pos` trong các bộ đệm lớn


19

Hàm line-number-at-pos(khi lặp lại khoảng 50 lần) đang gây ra sự chậm chạp đáng chú ý trong các bộ đệm bán lớn - ví dụ: 50.000 dòng - khi điểm gần cuối bộ đệm. Làm chậm lại, ý tôi là tổng cộng khoảng 1,35 giây.

Thay vì sử dụng elispfunciton 100% để đếm các dòng và goto trên cùng của bộ đệm, tôi quan tâm đến một phương pháp kết hợp khai thác các khả năng C tích hợp chịu trách nhiệm cho số dòng xuất hiện trên dòng chế độ. Số dòng xuất hiện trên dòng chế độ xảy ra ở tốc độ ánh sáng, bất kể kích thước của bộ đệm.


Đây là một chức năng kiểm tra:

(defmacro measure-time (&rest body)
"Measure the time it takes to evaluate BODY.
http://lists.gnu.org/archive/html/help-gnu-emacs/2008-06/msg00087.html"
  `(let ((time (current-time)))
     ,@body
     (message "%.06f" (float-time (time-since time)))))

(measure-time
  (let* (
      line-numbers
      (window-start (window-start))
      (window-end (window-end)))
    (save-excursion
      (goto-char window-end)
      (while
        (re-search-backward "\n" window-start t)
        (push (line-number-at-pos) line-numbers)))
    line-numbers))

Câu trả lời:


17

Thử

(string-to-number (format-mode-line "%l"))

Bạn có thể trích xuất thông tin khác bằng cách sử dụng % -Xây dựng được mô tả trong Hướng dẫn Lisp của Emacs.

Hãy cẩn thận:

Ngoài những hạn chế được chỉ ra bởi wasamasaStefan (xem bình luận bên dưới), điều này không hoạt động đối với các bộ đệm không được hiển thị.

Thử đi:

(with-temp-buffer
  (dotimes (i 10000)
    (insert (format "%d\n" i)))
  (string-to-number (format-mode-line "%l")))

và so sánh với

(with-temp-buffer
  (dotimes (i 10000)
    (insert (format "%d\n" i)))
  (line-number-at-pos))

Vâng, điều đó đã giảm nó từ 1,35 giây xuống 0,003559! Cảm ơn bạn rất nhiều - đánh giá rất cao! :)
luật

6
Hãy lưu ý rằng phương pháp này sẽ cung cấp cho bạn "??" đối với các dòng vượt quá line-number-display-limit-widthđược đặt thành giá trị 200 mỗi mặc định như tôi đã tìm thấy ở đây .
wasamasa

3
IIRC kết quả cũng có thể không đáng tin cậy nếu đã có sửa đổi trong bộ đệm kể từ lần hiển thị lại lần trước.
Stefan

Tôi tin rằng sẽ cần phải sửa đổi các bài kiểm tra trong câu trả lời sao cho chữ cái thứ hai iđược thay thế (string-to-number (format-mode-line "%l"))cho bài kiểm tra đầu tiên và chữ cái thứ hai iđược thay thế bằng (line-number-at-pos)bài kiểm tra thứ hai.
luật

5

nlinum.el sử dụng như sau:

(defvar nlinum--line-number-cache nil)
(make-variable-buffer-local 'nlinum--line-number-cache)

;; We could try and avoid flushing the cache at every change, e.g. with:
;;   (defun nlinum--before-change (start _end)
;;     (if (and nlinum--line-number-cache
;;              (< start (car nlinum--line-number-cache)))
;;         (save-excursion (goto-char start) (nlinum--line-number-at-pos))))
;; But it's far from clear that it's worth the trouble.  The current simplistic
;; approach seems to be good enough in practice.

(defun nlinum--after-change (&rest _args)
  (setq nlinum--line-number-cache nil))

(defun nlinum--line-number-at-pos ()
  "Like `line-number-at-pos' but sped up with a cache."
  ;; (assert (bolp))
  (let ((pos
         (if (and nlinum--line-number-cache
                  (> (- (point) (point-min))
                     (abs (- (point) (car nlinum--line-number-cache)))))
             (funcall (if (> (point) (car nlinum--line-number-cache))
                          #'+ #'-)
                      (cdr nlinum--line-number-cache)
                      (count-lines (point) (car nlinum--line-number-cache)))
           (line-number-at-pos))))
    ;;(assert (= pos (line-number-at-pos)))
    (setq nlinum--line-number-cache (cons (point) pos))
    pos))

với cấu hình bổ sung sau trong chức năng chế độ:

(add-hook 'after-change-functions #'nlinum--after-change nil t)

1
À ... tôi chỉ đang nghĩ về thư viện của bạn vào sáng sớm hôm nay. Các line-number-at-posthể được thay thế bằng câu trả lời bởi Constantine, và đó sẽ tăng tốc độ thư viện của bạn thậm chí nhiều hơn nó đã nó - đặc biệt là trong bộ đệm lớn. count-linescũng nên được sửa bằng phương pháp của Constantine. Tôi thậm chí đã nghĩ đến việc gửi một hộp thư đề xuất đến đường dây nóng báo cáo-emacs-bug để sửa các chức năng đó.
luật
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.