我想给kill-ring
搞个类似的。。。
這個怎麼樣
單純說kill-ring的話,我用counsel-yank-pop
配合ivy-posframe
挺好的
company-mode 的应该是用 (elisp) Overlays 自己写的;auto-complete 用的是一个专门的库 popup.el,用的也是 Overlay。
等有机会我试试从头写个,我也好奇这个效果是怎么模拟出来的。
喔喔,我折腾了一个四不像出来,最懒的方法,没用 Overlay:
(global-set-key (kbd "C-c y")
'(lambda ()
(interactive)
(let* ((trim (lambda (str)
(when (stringp str)
(setq str (string-trim str))
(while (equal (string-to-char str)
(string-to-char "\n"))
(setq str (string-trim-left (substring str 1)))))
str))
(trim-kill-ring (lambda (tkr kr)
(when (consp kr)
(setcar kr (funcall trim (car kr)))
(funcall tkr tkr (cdr kr))))))
(funcall trim-kill-ring trim-kill-ring kill-ring)
(setcdr yank-menu (mapcar (lambda (item)
(let ((str (funcall trim (car item))))
(cons str (cdr item))))
(cdr yank-menu)))
(popup-menu 'yank-menu))))
其实lambda
里只要最后一行的(popup-menu 'yank-menu)
就行,不过在terminal环境有个问题,就是如果开头是换行符的话,字符串的内容显示不出来,所以多了这一大堆。不过这个问题还是有。。。
还有一个就是我不太想改kill-ring
和yank-menu
的内容。
期待你的结果。喔,不对,我有空再看看 Overlay相关的。。。
里面有个make-popup
,我没找到定义,应该是很关键的函数。。。
我个人是不太想就为kill-ring下一个包下来。
或者直接寫一個company的backend也行
(defun cm/company-kill-ring (command &optional arg &rest _)
(interactive (list 'interactive))
(let ((kill (progn
(ignore-errors (current-kill 0))
;; Keep things consistent with the rest of Emacs
(dolist (sym '(kill-ring kill-ring-yank-pointer))
(set sym (cl-delete-duplicates
(cl-delete-if-not counsel-yank-pop-filter (symbol-value sym))
:test #'equal-including-properties :from-end t)))
kill-ring)))
(cl-case command
(interactive (company-begin-backend #'cm/company-kill-ring))
(prefix (if kill (company-grab ".*")))
(candidates kill)
(no-cache t)
)))
Update 如果candidates太長,適當截斷
(defun cm/company-kill-ring (command &optional arg &rest _)
(interactive (list 'interactive))
(let* ((kill (progn
(ignore-errors (current-kill 0))
;; Keep things consistent with the rest of Emacs
(dolist (sym '(kill-ring kill-ring-yank-pointer))
(set sym (cl-delete-duplicates
(cl-delete-if-not counsel-yank-pop-filter (symbol-value sym))
:test #'equal-including-properties :from-end t)))
kill-ring))
(shorten (mapcar (lambda (s)
(if (> (length s) 20)
(concat (substring s 0 16) "...")
s))
kill)))
(cl-case command
(interactive (company-begin-backend #'cm/company-kill-ring))
(prefix (if kill (company-grab ".*")))
(candidates shorten)
(no-cache t)
(require-match nil)
(post-completion
(save-match-data
(when (search-backward arg nil t)
(replace-match (nth (cl-position arg shorten :test #'string=)
kill) nil t)))))))
缺点是需要开company-mode
。感觉在说废话,不过我经常在用ansi-term
时复制粘贴,这种情况,开company-mode
不太合适。。。
不是有个了吗?GitHub - waymondo/popup-kill-ring: browse your emacs kill ring in an autocomplete style popup menu
這個不但要用popup,還要用pos-tip的。依賴好重
楼主可以参考啊,其实也足够用了,虽然我现在已经不用了。
開了好像也沒什麼,我沒有觸發奇奇怪怪的backend。
另外可以 make-variable-local
改造company-backends
company-backends
本身就是buffer-local然後在ansi-term buffer設置爲nil手動屏蔽backend的觸發吧
现在会改列表里显示的内容了,虽然property
没用(x-popup-menu
是C函数),但还是先留着。几个使用 Overlay 的例子看着比较难受,一步步来吧。
(global-set-key (kbd "C-c y") ;; '(lambda () (interactive) (popup-menu 'yank-menu))
'(lambda ()
(interactive)
(setcdr yank-menu
(mapcar (lambda (item)
(let ((str-ori (car item)))
(set-text-properties 0 (length str-ori) nil str-ori)
(let* ((str (let ((newline "\\n")
(tab "\\t")
(nl (string-to-char "\n"))
(tb (string-to-char "\t")))
(add-face-text-property 0 2 '(:box t) nil newline)
(add-face-text-property 0 2 '(:box t) nil tab)
(apply 'concat
(mapcan (lambda (char)
(cond ((char-equal char nl) `(,newline))
((char-equal char tb) `(,tab))
(t `(,(char-to-string char)))))
(string-to-list str-ori)))))
(str (if (>= (window-width) (length str)) str
(let ((ell "..."))
(add-face-text-property 0 3 '(:underline t) nil ell)
(concat (substring str 0 (- (window-width) 3)) ell)))))
(cons str-ori (cons str (cddr item))))))
(cdr yank-menu)))
(popup-menu 'yank-menu)))