【求助】帮忙看看函数搜索符号数量导致卡死的原因


#1

我写了在modeline中判断当前的symbol使用数量和当前是第几个的函数。这个函数在遇到某些特殊字符或者通过鼠标选中多个字符的时候会卡死emacs。没有必现条件。都是偶发。还没找到规律。

我判断是获取当前符号的时候某些条件判断有问题。由于对elisp不是很熟。道友们帮忙看看函数是否有不合理的地方?还所某些特殊情况没有想到导致无限循环卡死了?

;;

(defun vw/modeline–symbol-count-info ()

(let* ((symbol (thing-at-point 'symbol))
	   (cur-bound (bounds-of-thing-at-point 'symbol)))
  (when (and symbol cur-bound)
	(let*((cur (point))
		  (cur-start (car cur-bound))
		  (cur-end (cdr cur-bound))
		  (cur-length (- cur-end cur-start))
		  (total 0)
		  (curindex 0))
	  (save-excursion
		(save-restriction
		  (when symbol
			(goto-char (point-min))
			(while (re-search-forward symbol nil t)
			  (let* ((bound (bounds-of-thing-at-point 'symbol))
					 (end (cdr bound))
					 (start (car bound))
					 (len (- end start)))
				(if (= cur-length len)
					(progn
					  (setq total (+ total 1))
					  (if (and (>= cur start) (<= cur end))
						  (setq curindex total))))))
			(format "T:%d.C:%d" total curindex))))))))

doom-modeline 调用是这样的

(doom-modeline-def-segment vw/modeline–symbol-count

"Displays Symbol Count info."
(unless (minibufferp)
  (vw/modeline--symbol-count-info)))

#2

卡应该不意外,因为:

  1. Mode Line 上的需要频繁更新(你输入 hello 可能就会更新 5 次)
  2. 你的函数比较复杂,应该很耗时,尤其是 Buffer 比较大的话。thing-at-point 和 bounds-of-thing-at-point 可能会很慢,应节制使用。re-search-forward 很快。直接用 \_<your-quoted-symbol\_> 应该就完了。

至于「卡死」就不清楚了。


#3

可以用benchmark-run测试代码重量


#4

@xuchunyang re-search-forward 没法定位一个词阿。如果是我想找出所有的hello。用re-search-forward会把helloword这个也找出来吧。


#5

@casouri benchmark-run 这个怎么用?没用过。可以给我 个范例吗?谢谢


#6

@xuchunyang 大神,我在while循环前加了这句话

(goto-char (point-min))

(setq symbol  (concat "\\_<" (regexp-quote symbol) "\\_>"))

(while (re-search-forward symbol nil t)

在我发现亮出必卡死的地方,就不会出现卡死情况。能不能帮我解读下是为什么呢?


#7

对于re-search-forward, 还有string-match looking-at这些API,他们会修改全局的match-data。你可以用match-beginningmatch-end来获取定位信息。

(with-temp-buffer
  (insert "helloworld")
  (goto-char (point-min))
  (re-search-forward (rx "hello" (group "world")))
  `((,(match-beginning 0) . ,(match-end 0))
    (,(match-beginning 1) . ,(match-end 1))))
;; => ((1 . 11) (6 . 11))

match-{beginning,end}后面跟的参数代表获取第N个分组,如果为0,则获取整个匹配


#8

C-h f看文档就知道了

(benchmark-run 1000 (vw/modeline–symbol-count-info))

#9

编程比做数学题好的地方就是可以实验,楼里大家怀疑是performance问题,那就profiler-start profiler-report一下再说。我前两天碰到过一个卡死的问题,C-g可以结束,profile了一下马上就看出来了


#10

你应该清楚 (concat "\\_<" (regexp-quote symbol) "\\_>") 的效果,它会比 symbol 更安全、更快。

至于卡死,用 M-: (vw/modeline–symbol-count-info) 调查下。