众所周知,键帽按久了就会掉色,我决定多买一份我最常用的几个按键的键帽。
鉴于我平时码字用的唯一指定软件是Emacs,所以,我要让Emacs告诉我我按哪些键的次数最多。也就是写一个在Emacs里统计按键次数的程序。Emacs有内建的sqlite支持,因此我决定把在Emacs里所有的击键数据都存到一个sqlite数据库里面,便于长时间统计,顺便省掉了写统计界面的麻烦,用sqlite-mode读数据库就好了:index_pointing_up:![]()
(defgroup axis '()
"Statistics of how you play Emacs."
:group 'applications)
(defcustom axis-db-location
(concat user-emacs-directory "axis-data.sqlite")
"A path to axis-db, which is a sqlite database."
:group 'axis
:type 'string)
(defvar axis-db nil
"SQLite database connection for command-key tracking.")
(defun axis-db-init ()
"Initialize the SQLite database with performance optimizations."
(setq axis-db (sqlite-open axis-db-location))
;; Apply performance PRAGMAs
(sqlite-execute axis-db "PRAGMA journal_mode = WAL;")
(sqlite-execute axis-db "PRAGMA synchronous = NORMAL;")
(sqlite-execute axis-db "PRAGMA cache_size = 2000;")
;; Create table if it doesn't exist
(sqlite-execute
axis-db
"CREATE TABLE IF NOT EXISTS command_keys (
command TEXT,
key TEXT,
count INTEGER,
PRIMARY KEY (command, key)
);"))
(defun axis-db-close ()
"Close the SQLite database connection."
(when axis-db
(sqlite-close axis-db)
(setq axis-db nil)))
(defun axis-record-command-and-keys ()
"Record the current command and keys into the database."
(when (and (commandp this-command)
(symbolp this-command))
(let ((key-str (key-description (this-command-keys))))
(sqlite-execute
axis-db
"INSERT INTO command_keys (command, key, count) VALUES (?, ?, 1)
ON CONFLICT(command, key) DO UPDATE SET count = count + 1;"
(list (symbol-name this-command) key-str)))))
(defun axis-show-command-summary ()
"Display commands and their associated keys with usage counts."
(interactive)
(let ((data
(sqlite-select
axis-db
"SELECT command, SUM(count) FROM command_keys GROUP BY command
ORDER BY SUM(count) DESC;"))
)
(with-output-to-temp-buffer "*Axis Commands & Keys*"
(princ "Command Usage Statistics:\n\n")
(dolist (entry data)
(princ (format "Command: %s - %d times\n" (car entry) (cadr entry)))
))))
;;;###autoload
(define-minor-mode axis-mode
"Record statistics of input commands and keys."
:init-value nil
(if axis-mode
(progn
(unless axis-db (axis-db-init))
(add-hook 'pre-command-hook 'axis-record-command-and-keys)
(message "Axis mode enabled."))
(progn
(remove-hook 'pre-command-hook 'axis-record-command-and-keys)
(axis-db-close)
(message "Axis mode disabled.")))
)
(provide ‘axis-mode)
把(axis-mode)添加到你的启动配置里一段时间,然后在你下次购买/保养键盘的时候调用axis-show-command-summary,就可以通过分析统计数据找到最需要关心的键帽了!
P. S. 最初的主意是,我想要找到最常用的命令子序列(我把它叫做Emacs Riff),这样可以知道哪些命令适合封装成一个函数,哪些封装纯属多余。但是,我没来得及想出好的子序列分类算法用来高效的处理10^5-10^7规模的序列数据,这里就抛砖引玉了。也许我们只通过单点的统计情况也可以推断出路径的分布情况?