productivity: 替换默认scratch,使用任意major mode的临时buffer

每次打开emacs都会生成*scratch*这个buffer,为了避免这个问题,我们可以在init.el里加上(kill-buffer "*scratch*")

但是有时有需要写一写临时的代码段,比如想写点elisp或python验证某些想法,又不得不建一个临时buffer。

这段代码能解决这个问题:

(defun kermit/create-scratch-buffer ()
  (interactive)
  (let* ((buf-name (read-from-minibuffer "scratch buffer name: "))
         (mode-suffix (read-from-minibuffer "scratch mode suffix: "))
         (buf (generate-new-buffer (concat "*scratch-" buf-name "*"))))
    (switch-to-buffer buf)
    (dolist (e auto-mode-alist)
      (let ((mode-regex (car e)))
        (if (string-match mode-regex (concat "." mode-suffix))
            (funcall (cdr (assoc mode-regex auto-mode-alist))))))
    (setq buffer-offer-save t)))

输入编程语言的后缀名比如(el, py),就可以创建任意编程语言的临时buffer。

结合一个扩展state,可以快速创建,切换到这个临时buffer。

(defun kermit/get-buffer-by-regex (regex)
  "Get buffer by regex"
  (let ((buffers (mapcar (function buffer-name) (buffer-list)))
        (target nil))
    (dolist (buffername buffers)
      (if (string-match-p regex buffername)
          (setq target buffername)))
    target))

(state-define-state
  scratch
  :key "s"
  :in (string-match "^\*scratch-" (buffer-name))
  :exist (kermit/get-buffer-by-regex "^\*scratch-")
  :switch (switch-to-buffer (kermit/get-buffer-by-regex "^\*scratch-"))
  :create (kermit/create-scratch-buffer))
2 个赞

M-xswitch-to-bufferRET*.py 不是很简单吗?

直接把 scratch 改成 org-mode 不是更快么……

1 个赞

直接创建的buffer,默认是Fundmental mode,不是很方便(可以设置init-major-mode,但是也不很灵活)。

嗯,这个方法也挺好的 :smile:

噢,我忘了已经把快捷键映射到 helm-mini 了,有了 helm 就可以在创建临时 buffer 的时候,识别后缀名,自动启用 major-mode。无需额外的方法/快捷键。

;; 绑定在C-xC-v上,切换成*scratch* 中,若已经在*scratch*中,则切换成上一个buffer
;;;###autoload
(defun switch-to-scratch-buffer ()
  "Toggle between *scratch* buffer and the current buffer.
     If the *scratch* buffer does not exist, create it."
  (interactive)
  (let ((scratch-buffer-name  "*scratch*")
        (prev-major-mode major-mode)
        )
    (if (equal (buffer-name (current-buffer)) scratch-buffer-name)
        (switch-to-buffer (other-buffer))
      (with-current-buffer
          (switch-to-buffer  scratch-buffer-name)
        (when (functionp prev-major-mode) (funcall prev-major-mode ))
        (when (equal major-mode 'fundamental-mode )(emacs-lisp-mode))
        (goto-char (point-max))))))

当前是org-mode ,通过这个命令切换到scratch 后 scratch变成org-mode

1 个赞

我的命令补全是ido和smex,helm确实能做更多。

我自己类似的实现是新建一个能继承上一个buffer的major-mode的buffer,这样的好处是能有多个buffer存放不同的临时代码,不同major-mode工程之间相互独立,而且某些特殊的不能继承major-mode(比如ess-mode)还可以指定为另外一种major-mode。

(defvar yxl-buffer-inherit-whitelist '(latex-mode
                                       markdown-mode
                                       org-mode
                                       R-mode
                                       python-mode
                                       emacs-lisp-mode)
  "modes that are allowed when calling yxl-buffer-inherit")
(defvar yxl-buffer-inherit-special-alist '((ess-mode . R-mode)
                                           (inferior-ess-mode . R-mode)))

(defun yxl-buffer--translate-major-mode ()
  "Check if current `major-mode' is in `yxl-buffer-inherit-special-alist',
if true use the translated major-mode, else use original major-mode."
  (let* ((curr-mode major-mode)
         (curr-mode-sp (cdr (assoc curr-mode
                                   yxl-buffer-inherit-special-alist))))
    (if curr-mode-sp curr-mode-sp
      curr-mode)))

(defun yxl-buffer-inherit (&optional buf-name)
  "Create a new buffer \"untitled\" which inherits the major-mode
of the previous buffer, if the major-mode is listed in
`yxl-buffer-inherit-whitelist'; otherwise use `initial-major-mode'."
  (interactive)
  (unless buf-name (setq buf-name "untitled"))
  (let* ((curr-mode (yxl-buffer--translate-major-mode))
         (newbuf (generate-new-buffer-name buf-name)))
    (switch-to-buffer newbuf)
    (if (member curr-mode yxl-buffer-inherit-whitelist)
        (funcall curr-mode)
      (funcall initial-major-mode))))

完整代码在github

这个想法很不错,赞一个,不过我不用ivy,我想我可以这样来实现你的想法

(defun next-same-major-mode-buffer ()
  (interactive)
  (let ((same-major-mode major-mode)
        (i 0))
    (next-buffer)
    (while (< i 50)
      (let ((cur-major-mode major-mode))
        (if (eq same-major-mode cur-major-mode)
            (setq i 100)
          (progn
            (next-buffer)
            (setq i (1+ i))))))))


(defun prev-same-major-mode-buffer ()
  (interactive)
  (let ((same-major-mode major-mode)
        (i 0))
    (previous-buffer)
    (while (< i 50)
      (let ((cur-major-mode major-mode))
        (if (eq same-major-mode cur-major-mode)
            (setq i 100)
          (progn
            (previous-buffer)
            (setq i (1+ i))))))))

(global-set-key (kbd "C-x ]") 'next-same-major-mode-buffer)
(global-set-key (kbd "C-x [") 'prev-same-major-mode-buffer)

每次要切换到其他mode就用ido切换。


递归版

;;; recursive version
(defun recursive-version/next ()
  (interactive)
  (let ((same-major-mode major-mode))
    (recur-next same-major-mode)))

(defun recur-next (same-major-mode)
  (next-buffer)
  (unless (eq same-major-mode major-mode)
    (recur-next same-major-mode)))

有创意,不得不赞一个。

我是根据每天的日期在固定的位置创建一个类似于2017-05-19-note.org和2017-05-19-scratch.org的文件,前者用来做笔记,后者用来记一些乱七八糟的东西。

这样的好处是所有东西都可以根据时间归档。比如可能有时候粘贴了一些命令。忘了。可以直接过来ag一下。