วิธีที่เร็วกว่าในการรับ 'หมายเลขบรรทัดที่ตำแหน่ง pos' ในบัฟเฟอร์ขนาดใหญ่


19

ฟังก์ชั่นline-number-at-pos(เมื่อทำซ้ำประมาณ 50 ครั้ง) ทำให้เกิดการชะลอตัวลงอย่างเห็นได้ชัดในบัฟเฟอร์กึ่งใหญ่เช่น 50,000 บรรทัด - เมื่อจุดใกล้ถึงจุดสิ้นสุดของบัฟเฟอร์ เมื่อชะลอความเร็วลงฉันหมายถึงผลรวมทั้งหมดประมาณ 1.35 วินาที

แทนที่จะใช้elispfunciton 100% เพื่อนับจำนวนบรรทัดและข้ามส่วนบนสุดของบัฟเฟอร์ฉันสนใจวิธีไฮบริดที่แตะเข้าไปในความสามารถ C ในตัวที่รับผิดชอบต่อหมายเลขบรรทัดที่ปรากฏบนโหมดบรรทัด หมายเลขบรรทัดที่ปรากฏบนโหมดบรรทัดเกิดขึ้นที่ความเร็วแสงโดยไม่คำนึงถึงขนาดของบัฟเฟอร์


นี่คือฟังก์ชั่นทดสอบ:

(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))

คำตอบ:


17

ลอง

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

คุณสามารถดึงข้อมูลอื่น ๆ ได้โดยใช้% -Constructs ที่อธิบายไว้ในคู่มือ Emacs Lisp

ข้อแม้:

นอกจากข้อ จำกัด ที่อธิบายโดยwasamasa และStefan (ดูความคิดเห็นด้านล่าง) สิ่งนี้ใช้ไม่ได้กับบัฟเฟอร์ที่ไม่แสดง

ลองสิ่งนี้:

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

และเปรียบเทียบกับ

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

ใช่มันลดจาก 1.35 วินาทีเป็น 0.003559! ขอบคุณมาก - ชื่นชมอย่างมาก! :)
ฏหมาย

6
โปรดทราบว่าวิธีการนี้จะให้ "?" สำหรับสายเกินline-number-display-limit-widthซึ่งเป็นชุดที่มีมูลค่า 200 ต่อค่าเริ่มต้นเป็นฉันพบที่นี่
wasamasa

3
IIRC ผลลัพธ์อาจไม่น่าเชื่อถือหากมีการแก้ไขในบัฟเฟอร์ตั้งแต่เล่นซ้ำครั้งล่าสุด
สเตฟาน

ฉันเชื่อว่ามันจำเป็นที่จะต้องแก้ไขการทดสอบในคำตอบเพื่อให้ตัวอักษรตัวที่สองiถูกแทนที่ด้วย(string-to-number (format-mode-line "%l"))สำหรับการทดสอบครั้งแรกและตัวอักษรตัวที่สองiจะถูกแทนที่ด้วย(line-number-at-pos)สำหรับการทดสอบครั้งที่สอง
รายการ

5

nlinum.el ใช้สิ่งต่อไปนี้:

(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))

ด้วยการตั้งค่าพิเศษต่อไปนี้ในฟังก์ชั่นโหมด:

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

1
อ่า ... ฉันเพิ่งคิดถึงห้องสมุดของคุณเมื่อเช้านี้ line-number-at-posอาจถูกแทนที่ด้วยคำตอบโดยคอนสแตนติและที่จะเพิ่มความเร็วในห้องสมุดของคุณมากยิ่งขึ้นกว่าที่เป็นอยู่แล้ว - โดยเฉพาะอย่างยิ่งในบัฟเฟอร์ขนาดใหญ่ count-linesควรแก้ไขโดยใช้วิธีการโดย Constantine ฉันยังคิดที่จะส่งการแนะนำในกล่องแนะนำไปยังสายด่วนรายงาน - emacs-bug เพื่อแก้ไขฟังก์ชั่นเหล่านั้น
ฏหมาย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.