consult-ripgrepの検索対象をカレントバッファに限定するには

以下の関数を使う。 consult-lineと実質的な働きは変わらないのがメリット。 つまり、 consult-ripgrepの設定(migemo化など)が活きるので、例えばconsult-line系に限定したmigemo化の設定は不要となる点。 そのほか、consult-lineをmigemo化すると、最初の数文字の入力で表示がもたつく(おそらくmigemoに関する正規表現の展開がデカイ)ので、今回のconsult-ripgrep-single-fileによりそれを回避したスムーズな入力と候補絞り込みが実現できる。

(defun consult-ripgrep-single-file ()
    "Call `consult-ripgrep' for the current buffer (a single file)."
    (interactive)
    (let ((consult-project-function (lambda (x) nil))
          (consult-ripgrep-args
           (concat "rg "
                   "--null "
                   "--line-buffered "
                   "--color=never "
                   "--line-number "
                   "--smart-case "
                   "--no-heading "
                   "--max-columns=1000 "
                   "--max-columns-preview "
                   "--with-filename "
                   (shell-quote-argument buffer-file-name))))
      (consult-ripgrep)))

参考

github.com

カーソル下のシンボルを初期入力にしてconsult-ripgrepをするには

こうする。

(defun consult-ripgrep-symbol-at-point ()
  (interactive)
  (consult-ripgrep nil (thing-at-point 'symbol)))

C-uつきで呼び出したときにシンボル初期入力を行いたい場合は

(defun my-consult-ripgrep (use-symbol)
  (interactive "p")
  (cond ((eq use-symbol 1)
         (call-interactively 'consult-ripgrep))
        ((eq use-symbol 4)
         (call-interactively 'consult-ripgrep-symbol-at-point))))

とする。C-uなしで呼び出せば通常のconsult-ripgrepとなる。つまり

  • M-x my-consult-ripgrep ... 通常のconsult-ripgrep
  • C-u M-x my-consult-ripgrep ... カーソル下のシンボルでconsult-ripgrep

である。

consult-ripgrepのmigemo化

consult-ripgrepmigemo化に取り組んだ方がいらっしゃった。 www.yewton.net

しかしながら、上記の記事で紹介されている設定では手元の環境でうまく動かなかったので、少し修正してみたという話。

(require 'consult)
(defvar consult--migemo-regexp "")
(defun consult--migemo-regexp-compiler (input type ignore-case)
  (setq consult--migemo-regexp
        (mapcar #'migemo-get-pattern (consult--split-escaped input)))
  (cons (mapcar (lambda (x) (consult--convert-regexp x type))
                consult--migemo-regexp)
        (lambda (str)
          (consult--highlight-regexps consult--migemo-regexp str))))
(setq consult--regexp-compiler #'consult--migemo-regexp-compiler)

ひとまずこれで動くようになった。ただし以下のmigemo関連の設定を事前にしておくこと。

(require 'migemo)
(setq migemo-directory "/usr/share/cmigemo/utf-8")
(setq migemo-command (executable-find "cmigemo"))
(setq migemo-options '("-q" "--emacs" "--nonewline"))
(setq migemo-dictionary (expand-file-name "migemo-dict" migemo-directory))
(setq migemo-coding-system 'utf-8-unix) ;この指定が極めて重要
(setq migemo-user-dictionary nil)
(setq migemo-regex-dictionary nil)
(add-hook 'after-init-hook #'migemo-init)

perspective-modeの設定

書いておく

(require 'perspective)

(setq persp-show-modestring 'header)

;; 有効化
(persp-mode 1)

;; persp-modeはC-x xがプレフィックス

;; 現在のperspectiveに限定したbs-show
(global-set-key (kbd "C-x C-M-b")
                '(lambda (arg)
                   (interactive "p")
                   (require 'bs nil t)
                   (call-interactively 'persp-bs-show)))

;; perspectiveの状態をEmacs終了時に保存し、復元できるようにする
(setq persp-state-default-file "~/.emacs.d/persp-state-file")
(add-hook 'kill-emacs-hook #'persp-state-save)

(defvar persp-switch-prefix "C-M-%d")
(defvar persp-first-perspective "2") ;; 最初のワークスペースは"2"に設定
(defvar persp-top-perspective "0")
(defvar persp-bottom-perspective "9")

(defun persp-set-keybind ()
  (mapc (lambda (i)
          (persp-switch (int-to-string i))
          (global-set-key (kbd (format persp-switch-prefix i))
                          `(lambda ()
                             (interactive)
                             (persp-switch ,(int-to-string i)))))
        (number-sequence (string-to-number persp-top-perspective)
                         (string-to-number persp-bottom-perspective))))

(defun persp-my-setup ()
  (persp-set-keybind)
  (persp-switch persp-first-perspective)
  (persp-kill "main"))

(add-hook 'persp-state-after-load-hook 'persp-my-setup)
(add-hook 'after-init-hook 'persp-my-setup)

;; *で始まるバッファ名を候補から削除 -> たとえば*scratch*に変えられない副作用
(setq ido-ignore-buffers (append '("\\`\\*") ido-ignore-buffers))

;; *で始まるバッファ名を候補から非表示・表示をトグルする関数
(defun persp-toggle-ignore-buffers ()
  (interactive)
  (if (member "\\`\\*" ido-ignore-buffers)
      (setq ido-ignore-buffers '("\\` "))
    (setq ido-ignore-buffers (append '("\\`\\*") ido-ignore-buffers))))

;; .で始まるファイル名を削除
(setq ido-ignore-files (append '("\\`\\.") ido-ignore-files))

畳み込みのスクラッチ実装(Python)

ディジタル信号処理を勉強するひとは、すべからくマスターすべき演算が畳み込みである(私見)。 畳み込み演算の重要性は論を俟たない。いわゆる線形時不変システムはインパルス応答と入力信号との畳み込みにより記述される。音声のディジタル信号処理の文脈でいえば、分析合成フィルタ(いわゆるボコーダー)の実現に畳み込み演算が用いられる。

Pythonライブラリのnumpyには畳み込みを実行する関数convolveがあり、またscipyにもconvolveがあるため、実用上はそれらを使えば良い(というかぜひ使うべきである)。 ただスクラッチで畳み込みを実装せよと言われたとき、はたと手が止まる人も多いのではなかろうか。

本記事ではディジタル信号処理を対象とし、FIRフィルタ(インパルス応答が有限長)としての畳み込み演算の実装について説明する。

説明

インパルス応答とはデジタルシステムにインパルス信号を入力したときの出力を指す。ここで,入力信号を$x[n]$,インパルス応答を$h[n]$,出力信号を$y[n]$とする。$n$は時間インデックスである。出力信号$y[n]$は次式で示される。

$$ y[n] = \sum\limits_{m = -\infty}^{\infty} x[n-m]h[m] $$

ただし$x[n]$の長さを$N$とする。

$$ x[0], x[1], \ldots, x[N-1] $$

さらに$h[n]$の長さを${M}$とする。

$$ h[0], h[1], \ldots, h[M -1] $$

すると上式の総和は$m=0$から$M - 1$までとなり、$y[n]$の長さは$N + M -1$となる。

上記の説明より、$n = 0, 1, ..., N + M - 1$について

$$ y[n] = \sum\limits_{m = 0}^{M -1} x[n-m]h[m] $$

である。

$x[n]$は長さ$N$の条件を持っている。しかしながら、例えば上記の畳み込みの式において、$n - m $が $N$以上になることが起こり得る。一方で、実際のデータとしては

$$ x[0], x[1], \ldots, x[N-1] $$

しか手元にない。そのとき、$x[n - m] = 0$としたいので、事前に$x[n]$を拡張し、長さ$N + M -1$の系列となるよう、$x[n]$の右側に0を詰めておくのがスマートである。

\begin{align} \tilde{x}[n] = \begin{cases} x[n] & (0 \leq n \leq N-1)\\ 0 & (N\leq n \leq N + M - 2) \end{cases} \end{align}

この結果として、$\tilde{x}[n]$が長さ$N + M -1$の系列になる。 さらに$\tilde{x}[n-m]$のインデックスが非負になる$n \geq m $の範囲で和を取ればよい。 つまり、 $$y[n] = \sum\limits_{m = 0}^{n} \tilde{x}[n-m]h[m]$$ である。 このとき、和のインデックス上限$n$と$h[m]$のインデックス上限$M - 1$の兼ね合いで、$x[n]$と類似の問題が起きる。この問題の煩わしさを避けるため、$h[n]$についても同様の拡張を行う。

\begin{align} \tilde{h}[n] = \begin{cases} h[n] & (0 \leq n \leq N-1)\\ 0 & (N\leq n \leq N + M - 2) \end{cases} \end{align}

最終的に畳み込みは以下のように書ける。 $$ y[n] = \sum\limits_{m = 0}^{n} \tilde{x}[n-m]\tilde{h}[m] \; \; \; (0 \leq n \leq N + M -1) $$

実装

素直にPythonコードに落とし込めばよい。入力の拡張としてのゼロ詰めにはnumpyzeros関数を使う。 地のfor文を使うという、ナイーブな実装なのでPython的には(とても)遅く、あまり実用的ではないのは承知のうえで。

# 前提
# 入力 x[0] ... x[N-1]
# インパルス応答 h[0], ... h[M-1]

import numpy as np

# 出力 y[0] ... y[M+N-2]
y = np.zeros(len(h) + len(x) - 1, dtype=np.float32)

# ゼロづめによる拡張
hzero = np.hstack([h, np.zeros(len(x) - 1)])
xzero = np.hstack([x, np.zeros(len(h) - 1)])

for n in range(0, len(y)):
  for k in range(0, n + 1):
    y[n] = y[n] + hzero[k] * xzero[n - k]

プロットの実例はそのうち追記予定(ほんまか)。

参考

これを読もう。 www.ic.is.tohoku.ac.jp

畳み込みと相互相関の違いとか。 qiita.com

consultの設定 2022

(require 'consult)

;; consult-line ... swiper の代替
;; consult-isearch ... isearch中にconsultインタフェースでクエリを再入力し、isearch再実行
;; consult-multi-occur ... multi-occurの代替
;; consult-focus-line ... クエリにヒットする部分のみを抽出して「表示」する(他が隠れる, narrowing)。
;; その後、C-uつきで呼び出すと、隠れていた部分が表示される(もとに戻る, widen)
;; consult-recent-file ... 最近開いたファイルを選択

(setq consult-async-refresh-delay 0.2)

;; consult-buffer時などにおけるpreview機能の調整
;; (setq consult-preview-key nil) ; 常にプレビューOFF
;; (setq consult-preview-key 'any) ; 常にプレビューON
;; (setq consult-preview-key (kbd "C-M-p")) ; これを押したときだけプレビュー
(consult-customize
 consult-ripgrep consult-git-grep consult-grep
 consult-bookmark consult-recent-file consult-xref
 consult--source-recent-file
 consult--source-project-recent-file
 consult--source-bookmark
 :preview-key (kbd "M-."))

;; カーソル下のシンボルを拾ってconsult-line発動
(defun consult-line-symbol-at-point (&optional at-point)
  (interactive "P")
  (if at-point
      (consult-line (thing-at-point 'symbol))
    (consult-line)))

(define-key isearch-mode-map (kbd "C-:") #'consult-isearch-history) ; 実質的な絞り込み
(define-key isearch-mode-map (kbd "C-;") #'consult-line) ; swiperに対応

;; 絞り込み対象をバッファに限定 : b SPC
;; 絞り込み対象をファイル(recentf)に限定 : f SPC
;; 絞り込み対象をブックマークに限定 : m SPC
;; 絞り込み対象を隠れバッファに限定 : SPC
(global-set-key (kbd "C-x b") #'consult-buffer)

;; consult--source-fileの公式実装では「現在バッファとして保持しているファイル」が
;; ファイル(recentf)の検索対象から除外されるので、
;; それをやめるため単純にitemsにrecentf-listだけを持ってくる。
;; この設定の影響範囲はconsult-bufferのみ。consult-recent-fileは影響を受けない。
(setq consult--source-recent-file
  `(:name     "File"
    :narrow   ?f
    :category file
    :face     consult-file
    :history  file-name-history
    :action   ,#'consult--file-action
    :enabled   ,(lambda () recentf-mode)
    :items ,recentf-list))

(global-set-key (kbd "C-z C-n") #'consult-recent-file)

(global-set-key (kbd "M-g e") 'consult-compile-error)
(global-set-key (kbd "M-g f") 'consult-flymake)
(global-set-key (kbd "M-g g") 'consult-goto-line)
(global-set-key (kbd "M-g M-g") 'consult-goto-line)
(global-set-key (kbd "M-g o") 'consult-outline)
(global-set-key (kbd "M-g m") 'consult-mark)
(global-set-key (kbd "M-g k") 'consult-global-mark)
(global-set-key (kbd "M-g i") 'consult-imenu)
(global-set-key (kbd "M-g I") 'consult-imenu-multi)
(global-set-key (kbd "M-y") 'consult-yank-pop)
(global-set-key (kbd "M-s f") 'consult-find)
(global-set-key (kbd "M-s F") 'consult-locate)
(global-set-key (kbd "M-s g") 'consult-grep)
(global-set-key (kbd "M-s G") 'consult-git-grep)
(global-set-key (kbd "M-s r") 'consult-ripgrep)
(global-set-key (kbd "M-s l") 'consult-line)
(global-set-key (kbd "M-s L") 'consult-line-multi)
(global-set-key (kbd "M-s m") 'consult-multi-occur)
(global-set-key (kbd "M-s k") 'consult-keep-lines)
(global-set-key (kbd "M-s u") 'consult-focus-lines)

;; linum表示中の行番号表示は邪魔なので
(setq consult-goto-line-numbers nil)

;; settings with perspective
;; Use consult-buffer with perspective-el.
;; This would hide the default consult--source-buffer,
;; and show the list of perspective buffers on the top
(require 'perspective)
(declare-function persp-get-buffer-names "perspective")
(with-eval-after-load "perspective"
  (consult-customize consult--source-buffer :hidden t :default nil)
  (defvar consult--source-perspective
    `(:name     "Perspective"
      :narrow   ?s ;; 絞り込みのキー
      :category buffer
      :state    ,#'consult--buffer-state
      :default  t
      :items    ,#'persp-get-buffer-names))
  (add-to-list 'consult-buffer-sources consult--source-perspective))

corfuまわりの設定(vertico, marginalia, orderless, cape, kind-icon, affe)

corfuおよび関連するパッケージの設定をメモとして残す。

  • corfu ... companyパッケージの代わり。カーソル位置での補完UIを提供。
  • vertico ... ido-vertical-modeやivy, selectrumの代わり。ウィンドウ下部(ミニバッファ)で垂直表示な補完UIを提供。
  • consult ... counselの代わり。補完入力を活用し、他のコマンドをラップした便利なコマンド群を提供。
  • marginalia ... consultに表示される候補に「補助情報」を追加する(ファイル属性、ファイル更新日、ファイルサイズなど)。
  • orderless ... 補完候補の絞り込みに活躍。「イニシャル入力」などにより高速かつ柔軟な候補絞り込みを実現。
  • cape ... corfuとの組み合わせが前提。カーソル位置での補完対象が拡張される。
  • kind-icon ... corfu/orderlessと相性の良いパッケージ。各候補の左側に「アイコン」(SVG形式)が追加される。
  • affe ... fuzzy-matchingなconsult-grepやconsult-findに相当するコマンドを提供する。

embarkは割愛。

以下、ほぼ公式の設定を参考にしたもの。verticoについてはvertico-directoryも使う。すごく便利なので。

;; -*- mode: emacs-lisp; coding: utf-8-unix -*-

(require 'corfu)
(corfu-global-mode)
(setq corfu-cycle t) ;; 候補ウィンドウの移動において、上端/下端に達したら下端/上端に回り込む
(setq corfu-auto t) ;; 補完を自動で開始
(setq corfu-quit-no-match 'separator)
(setq corfu-quit-at-boundary nil)

;; 候補スクロール開始位置が、候補ウィンドウの下から何行目か
(setq corfu-scroll-margin 2)

;; ミニバッファでの補完を有効にする
(defun corfu-enable-always-in-minibuffer ()
  "Enable Corfu in the minibuffer if Vertico/Mct are not active."
  (unless (or (bound-and-true-p mct--active)
              (bound-and-true-p vertico--input))
    ;; (setq-local corfu-auto nil) Enable/disable auto completion
    (corfu-mode 1)))
(add-hook 'minibuffer-setup-hook #'corfu-enable-always-in-minibuffer 1)

;; TAB cycle if there are only few candidates
(setq completion-cycle-threshold 3)

(defun corfu-beginning-of-prompt ()
  "Move to beginning of completion input."
  (interactive)
  (corfu--goto -1)
  (goto-char (car completion-in-region--data)))

(defun corfu-end-of-prompt ()
  "Move to end of completion input."
  (interactive)
  (corfu--goto -1)
  (goto-char (cadr completion-in-region--data)))

(define-key corfu-map [remap move-beginning-of-line] #'corfu-beginning-of-prompt)
(define-key corfu-map [remap move-end-of-line] #'corfu-end-of-prompt)

(require 'vertico)
(vertico-mode)
(setq vertico-count 20)

(require 'vertico-directory)
(define-key vertico-map (kbd "C-l") #'vertico-directory-up)
(define-key vertico-map "\r" #'vertico-directory-enter)  ;; enter dired
(define-key vertico-map "\d" #'vertico-directory-delete-char)

(require 'marginalia)
(marginalia-mode +1)
;; marginalia-annotatorsをサイクルする
(define-key minibuffer-local-map (kbd "C-M-a") #'marginalia-cycle)

(require 'orderless)
(setq completion-styles '(orderless))

(orderless-define-completion-style orderless+initialism
  (orderless-matching-styles '(orderless-initialism ;;一番最初にinitializm
                               orderless-literal  ;;次にリテラルマッチ
                               orderless-regexp)))

;; (setq completion-category-defaults nil)
(setq completion-category-overrides
      '((eglot (styles orderless+initialism))
        (command (styles orderless+initialism))
        (symbol (styles orderless+initialism))
        (variable (styles orderless+initialism))))
(setq orderless-component-separator #'orderless-escapable-split-on-space)

(require 'cape)
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-tex)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-abbrev)
(add-to-list 'completion-at-point-functions #'cape-ispell)
(add-to-list 'completion-at-point-functions #'cape-symbol)

;; EmacsのSVG対応コンパイルが必要
(require 'kind-icon)
(setq kind-icon-default-face 'corfu-default)
(add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)

;; Available commands
;; affe-grep: Filters the content of all text files in the current directory
;; affe-find: Filters the file paths of all files in the current directory
(require 'affe)
(consult-customize affe-grep :preview-key (kbd "M-."))
(defvar affe-orderless-regexp "")
(defun affe-orderless-regexp-compiler (input _type)
  (setq affe-orderless-regexp (orderless-pattern-compiler input))
  (cons affe-orderless-regexp
        (lambda (str) (orderless--highlight affe-orderless-regexp str))))
(setq affe-regexp-compiler #'affe-orderless-regexp-compiler)