emacs/code/elpa/scratch-20220319.1705/scratch.el

258 lines
8.0 KiB
EmacsLisp
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; scratch.el --- Mode-specific scratch buffers
;; Author: Ian Eure <ian.eure@gmail.com>
;; Version: 1.4
;; Package-Version: 20220319.1705
;; Package-Commit: f000648c9663833a76a8de9b1e78c99a9d698e48
;; Package-Requires: ((emacs "25.1"))
;; URL: https://github.com/ieure/scratch-el
;; Keywords: convenience, tools, files
;; Copyright (c) 1999-2017, 2019, 2022 Ian Eure <ian.eure@gmail.com>
;; All rights reserved.
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions
;; are met:
;; 1. Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;; 2. Redistributions in binary form must reproduce the above
;; copyright notice, this list of conditions and the following
;; disclaimer in the documentation and/or other materials provided
;; with the distribution.
;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
;; TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
;; PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
;; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
;; USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
;; OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
;; SUCH DAMAGE.
;;; Commentary:
;;
;; Scratch
;; =======
;;
;; Scratch is an extension to Emacs that enables one to create scratch
;; buffers that are in the same mode as the current buffer. This is
;; notably useful when working on code in some language; you may grab
;; code into a scratch buffer, and, by virtue of this extension, do so
;; using the Emacs formatting rules for that language.
;;
;; Scratch is available from MELPA.
;;
;;
;; Usage
;; =====
;;
;; - `M-x scratch' Immediately create a scratch buffer with the same
;; major mode as the current buffers. If the region is active, copy
;; it to the scratch buffer. If a scratch buffer already exists, pop
;; to it (and do nothing with the region).
;;
;; - `C-u M-x scratch' Prompts for a major mode to create a scratch
;; buffer with.
;;
;;
;; Binding
;; =======
;;
;; `C-c s' is a good mnemonic binding for scratch-el:
;;
;;
;; (define-key (current-global-map) "\C-cs" #'scratch)
;;
;;
;; Customization
;; =============
;;
;; If you want to customize the behavior of all scratch buffers, you
;; can place hooks in `scratch-create-buffer-hook'.
;;
;; For per-mode customizations, you can add a hook to the mode, and
;; check `scratch-buffer' inside it. For example, to set a default
;; title on all `org-mode' scratch buffers, you could do:
;;
;;
;; (add-hook 'org-mode-hook
;; (lambda ()
;; (when scratch-buffer
;; (save-excursion
;; (goto-char (point-min))
;; (insert "#+TITLE: Scratch\n\n")))))
;;
;;; History:
;; 1999 Ian Eure
;; Initial version.
;; 2010-08-16 Ian Eure
;; Broke out into its own file.
;; 2012-08-30 Ian Eure
;; Dump current region into new scratch buffer
;; 2017-05-23 Ian Eure
;; Set up *sql* buffers so they know about the inferior process they
;; were created from.
;; Add mappings for additional inferior modes.
;; Fix checkdoc & package-lint issues.
;;
;; 2019-03-13 Ian Eure (v1.3)
;; Add `scratch-create-buffer-hook', which runs any time a new
;; scratch buffer is created.
;; Fix an issue where SQL scratch buffers weren't linked to the SQLi
;; buffers they were created from.
;; Fix byte-compilation warnings.
;; Substantially refactor & update code.
;;
;; 2022-03-19 Ian Eure (v1.4)
;; Depend on cl-lib instead of cl.
;; Address some minor linter complaints.
;;; Code:
(require 'cl-lib)
(require 'sql)
(require 'subr-x)
(defgroup scratch nil
"Scratch buffers."
:prefix "scratch-"
:group 'editing)
(defcustom scratch-mode-alist
'((erc-mode . fundamental-mode)
(sql-interactive-mode . sql-mode)
(shell-mode . sh-mode)
(inferior-python-mode . python-mode)
(inferior-emacs-lisp-mode . emacs-lisp-mode)
(cider-repl-mode . clojure-mode)
(inferior-tcl-mode . tcl-mode)
(inferior-octave-mode . octave-mode))
"Alist of mappings from major modes to major modes for `scratch'.
Some interactive modes don't lend themselves well to scratch buffers;
this alist is used to change the mode used by `scratch' for those
buffers."
:type '(alist :key-type symbol :value-type symbol))
(defcustom scratch-create-buffer-hook nil
"Hooks to run when creating a scratch buffer."
:type 'cons)
(defvar scratch--history nil
"History of scratch buffers.")
(defvar scratch--major-mode-list nil
"List of major modes `scratch' may use. See `scratch-list-modes'.")
(defvar scratch-parent nil
"The parent buffer of this scratch buffer.")
(make-variable-buffer-local 'scratch-parent)
;;;###autoload
(defvar scratch-buffer nil
"Non-nil if the current buffer is a scratch buffer.")
(make-variable-buffer-local 'scratch-buffer)
(defun scratch--list-modes ()
"List known major modes."
(cl-loop for sym the symbols of obarray
for name = (symbol-name sym)
when (and (functionp sym)
(not (member sym minor-mode-list))
(string-match "-mode$" name)
(not (string-match "--" name)))
collect (substring name 0 -5)))
(defun scratch--link-sql ()
"Link a scratch buffer to a SQLi buffer.
This sets up the scratch buffer so `sql-send-buffer' etc work as
expected."
(let ((product (with-current-buffer scratch-parent sql-product)))
(setq sql-product product
sql-buffer scratch-parent)))
(defun scratch--link-buffers ()
"Link a parent and child buffer.
When a scratch buffer is created from a mode for an inferior process,
and has features which rely on knowing the inferior process, link
them."
(cond
((eq (with-current-buffer scratch-parent major-mode) 'sql-interactive-mode)
(scratch--link-sql))
(t nil)))
(defun scratch--buffer-querymode ()
"Return the mode to use for a new scratch buffer.
When called with a prefix argument, prompt the user."
(cond
;; Prompt user for mode
(current-prefix-arg
(intern (concat (completing-read
"Mode: " (scratch--list-modes)
nil t nil scratch--history)
"-mode")))
;; Overriden mode for ex. sql->sqli, shell->sh
((assoc major-mode scratch-mode-alist)
(cdr (assoc major-mode scratch-mode-alist)))
;; Default is the current mode
(t major-mode)))
(defun scratch--create (mode name)
"Create scratch buffer for mode MODE, with base name NAME.
Returns the new buffer."
(let ((scratch-buffer t)
(parent (current-buffer))
(contents (when (region-active-p)
(buffer-substring-no-properties
(region-beginning) (region-end)))))
(with-current-buffer (get-buffer-create name)
(funcall mode)
(when contents
(save-excursion (insert contents)))
(setq-local scratch-buffer t)
(unless current-prefix-arg
(setq-local scratch-parent parent)
(scratch--link-buffers))
(run-hooks 'scratch-create-buffer-hook)
(current-buffer))))
;;;###autoload
(defun scratch (mode)
"Get a scratch buffer for the MODE.
When called interactively with a prefix arg, prompt for the mode."
(interactive (list (scratch--buffer-querymode)))
(let* ((name (thread-last (symbol-name mode)
(replace-regexp-in-string "-mode$" "")
(format "*%s*")))
(buf (get-buffer name)))
(pop-to-buffer
(if (bufferp buf)
buf ; Existing scratch buffer
;; New scratch buffer
(scratch--create mode name)))))
(provide 'scratch)
;;; scratch.el ends here