给 ivy-occur 添加再次过滤的功能

日常使用 ivy-occur, 但是在打开 occur buffer 后, 有时会存在一些多余的 candidates. 正好最近有空, 准备写个过滤功能, 结果发现之前早就写好了, 一直没怎么用 :rofl:

代码如下:

(defvar ivy-occur-filter-prefix ">>> ")

;;;###autoload
(defun ivy-occur/filter-lines ()
  (interactive)
  (unless (string-prefix-p "ivy-occur" (symbol-name major-mode))
    (user-error "Current buffer is not in ivy-occur mode"))

  (let ((inhibit-read-only t)
        (regexp (read-regexp "Regexp(! for flush)"))
        (start (save-excursion
                 (goto-char (point-min))
                 (re-search-forward "[0-9]+ candidates:"))))
    (if (string-prefix-p "!" regexp)
        (flush-lines (substring regexp 1) start (point-max))
      (keep-lines regexp start (point-max)))
    (save-excursion
      (goto-char (point-min))
      (let ((item (propertize (format "[%s]" regexp) 'face 'ivy-current-match)))
        (if (looking-at ivy-occur-filter-prefix)
            (progn
              (goto-char (line-end-position))
              (insert item))
          (insert ivy-occur-filter-prefix item "\n"))))))

;;;###autoload
(defun ivy-occur/undo ()
  (interactive)
  (let ((inhibit-read-only t))
    (if (save-excursion
          (goto-char (point-min))
          (looking-at ivy-occur-filter-prefix))
        (undo)
      (user-error "Filter stack is empty"))))

(defun ivy|occur-mode-setup ()
  (local-set-key "/" #'ivy-occur/filter-lines)
  (local-set-key (kbd "C-/") #'ivy-occur/undo))

(add-hook 'ivy-occur-mode-hook 'ivy|occur-mode-setup)
(add-hook 'ivy-occur-grep-mode-hook 'ivy|occur-mode-setup)

在打开 ivy-occur buffer 之后, 按 / 过滤行 (支持多次过滤), C-/ 还原.

3 个赞

效果还不错。写了没用是不是说明使用场景很少啊? 循环使用 ivy-occur 不能满足需求吗?

循环使用,指的是在 ivy-occur buffer 里再用 swiper 搜索么?这样得到的新 buffer 里 candidates 的 action 不是原来的

对,除了不是同一个 buffer 之外效果没啥区别。

这样在新 buffer 里 wgrep 就用不了,按 enter 行为也不一样

1 个赞

我也写过一版,隐藏匹配的行,只显示匹配的行 ,不过现在已经不用ivy了,也贴出来,分享给大家

(define-key ivy-occur-grep-mode-map (kbd "z") 'ivy-occur-hide-lines-matching)
(define-key ivy-occur-grep-mode-map (kbd "/") 'ivy-occur-hide-lines-not-matching)

;;;###autoload
(defun ivy-occur-hide-lines-not-matching (search-text)
  "Hide lines that don't match the specified regexp."
  (interactive "MHide lines not matched by regexp: ")
  (set (make-local-variable 'line-move-ignore-invisible) t)
  (save-excursion
    (goto-char (point-min))
    (forward-line 4)
    (let ((inhibit-read-only t)
          (start-position (point))
          (pos (re-search-forward search-text nil t)))
      (while pos
        (beginning-of-line)
        (delete-region start-position (point))
        (forward-line 1)
        (setq start-position (point))
        (if (eq (point) (point-max))
            (setq pos nil)
          (setq pos (re-search-forward search-text nil t))))
              (delete-region start-position (point-max) ))))

;;;###autoload
(defun ivy-occur-hide-lines-matching  (search-text)
  "Hide lines matching the specified regexp."
  (interactive "MHide lines matching regexp: ")
  (set (make-local-variable 'line-move-ignore-invisible) t)
  (save-excursion
    (goto-char (point-min))
    (forward-line 4)
    (let ((inhibit-read-only t)
          (pos (re-search-forward search-text nil t))
          start-position)
      (while pos
        (beginning-of-line)
        (setq start-position (point))
        (end-of-line)
        (delete-region start-position (+ 1 (point)))
        (if (eq (point) (point-max))
            (setq pos nil)
          (setq pos (re-search-forward search-text nil t)))))))

现在用什么呢?

现在不用ivy了,用系统自带的Icomplete-mode + https://github.com/raxod502/prescient.el(用其 过滤算法) rg的功能用 https://github.com/dajva/rg.el, 这是rg.el版本的 (隐藏匹配的行,显示匹配的行) https://github.com/jixiuf/vmacs/blob/master/conf/conf-rg.el#L38

icomplete支持竖排显示吗?

支持 (setq icomplete-separator “\n”)

最近确实有这个复古风潮,如果内置的能解决问题也不是坏事。之前一直用 ido 也还不错,不过扩展性确实不如 ivy。感觉ivy介于 helm 和 ido 之间。icomplete 最近也挺活跃,28 中居然出了个fido-mode,用 icomplete 模拟 ido 行为。我已经用在了 init-mini.el 中,效果还不错。

icomplete里有时候prompt会消失,你有遇到吗?如图,C-x C-f补全路径,prompt和前面的路径会消失,C-a到行首才能看到。配置用了你的

(progn
  (setq icomplete-prospects-height 20)
  (setq icomplete-delay-completions-threshold 0)
  (setq icomplete-max-delay-chars 0)
  (setq icomplete-delay-completions-threshold 2000)
  (setq icomplete-compute-delay 0)
  (setq icomplete-show-matches-on-no-input t)
  (setq icomplete-hide-common-prefix nil)
  (setq icomplete-separator "\n")
  (setq icomplete-with-completion-tables t)
  (setq icomplete-in-buffer t)
  (setq icomplete-tidy-shadowed-file-names t))

遇到了, 解决方案是 minibuffer 独立到一个单独的frame

(require 'mini-frame)
(setq mini-frame-resize-max-height max-mini-window-height)
;; (setq mini-frame-ignore-commands nil)
(add-to-list 'mini-frame-ignore-commands 'dired-narrow)
(setq mini-frame-show-parameters
      '((top . 0.4) (width . 0.7) (left . 0.3)
        (min-height .  2)
        (height . 10)
        (minibuffer-exit . t)
        ;; (font . "Sarasa Mono CL-30")
        (alpha . 100)
        (left-fringe . 10 )
        (cursor-color . "Yellow")
        ;; (border-color . "green")
        ;; (background-mode 'light)
        (background-mode 'dark)
        (foreground-color . "#bbc2cf") ;;
        (background-color . "#242730")))

1 个赞

谢谢,能说说为什么吗?可以的话我不想用childframe。

没调查清楚, 怀疑是加了overlay 故意给隐藏的。