From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Michal Nazarewicz Newsgroups: gmane.emacs.devel Subject: [PATCH 3/3] Add `notes' function to store random notes across Emacs restarts. Date: Fri, 21 Jun 2013 14:16:43 +0200 Message-ID: <990e767594187215853e2ab54e1ab524e5f33aac.1371816337.git.mina86@mina86.com> References: NNTP-Posting-Host: plane.gmane.org X-Trace: ger.gmane.org 1371817082 26847 80.91.229.3 (21 Jun 2013 12:18:02 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 21 Jun 2013 12:18:02 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier , Juanma Barranquero Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Jun 21 14:18:03 2013 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Uq0Hx-0003No-GW for ged-emacs-devel@m.gmane.org; Fri, 21 Jun 2013 14:18:01 +0200 Original-Received: from localhost ([::1]:60225 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Uq0Hx-0008EG-39 for ged-emacs-devel@m.gmane.org; Fri, 21 Jun 2013 08:18:01 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40284) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Uq0HD-0006xX-BO for emacs-devel@gnu.org; Fri, 21 Jun 2013 08:17:22 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Uq0H8-00080G-5c for emacs-devel@gnu.org; Fri, 21 Jun 2013 08:17:15 -0400 Original-Received: from mail-ea0-x231.google.com ([2a00:1450:4013:c01::231]:35824) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Uq0H7-000805-TG for emacs-devel@gnu.org; Fri, 21 Jun 2013 08:17:10 -0400 Original-Received: by mail-ea0-f177.google.com with SMTP id j14so4544172eak.8 for ; Fri, 21 Jun 2013 05:17:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:in-reply-to:references; bh=FjBNye27sQIr2vRQx8JKiuAhjfjyOtiujIB3WrvnRKc=; b=DgL769BEJzDYBn4Vh6BozwuRReXok+aweA/xgVOg7MN+nJu7qE8luw2FD0RKXVTZk3 NQT2wQ4q+kA43eO1WGj07sL+BCaDO6FZ0vMIYXnjntBz2TDxvHG1DFrsJ8REDbFrg0Zu +vwZXnIbrKM+zOeZgQisRLVtvpGoNn53iD/aD8SOQzbZz9oE+YocUodtXQvmdJ2zukcf +8mEbui5VjNupcL83zhqPhuNN/70mNOOBwc27JFFBfB7ps5RIaLH9+Fs0/he6Jde3o8p JZKKxKais4GPilseq6RGDulkbZ3dZq549HoTHlWnUlOjP8PMlqgDp6SoFOgFP2wERbot qFLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:in-reply-to:references:x-gm-message-state; bh=FjBNye27sQIr2vRQx8JKiuAhjfjyOtiujIB3WrvnRKc=; b=kqfp97Fz1LZ9TdY6dpKHDN2ZPl/G2UrIO9NdnLKRtO815SZsyhx9LQdm5M5x+YfUF2 EfaFm9dQvCezzBx6nyZkESkC/pxHABb7c28W7PYVoUINz33bSLSEYYXd/gzTObdmKCqY lxTXkpuA4r9+In/hh8O7BJbc5M9yMklivDHZTwbepVRauudifrPKcu7gzQAqrGXEDWFt 4p6nC4HIuqTkBaMtvXX8DR96j4r0nWZCcXRLLMyLK2iBOv3Cntm/yZUlum8JMda3SdQz wEwHPRNg3lFNlIwIkmj/TrTLhqclYMzmFoQ2dPp2BEXZZo6OW8AG2z9qv2Wq2AzdxVmI 8Sdg== X-Received: by 10.15.73.197 with SMTP id h45mr12158578eey.146.1371817029121; Fri, 21 Jun 2013 05:17:09 -0700 (PDT) Original-Received: from mpn-glaptop.corp.google.com ([2620:0:105f:301:9083:48af:8870:116f]) by mx.google.com with ESMTPSA id p49sm7416094eeu.2.2013.06.21.05.17.07 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 21 Jun 2013 05:17:08 -0700 (PDT) X-Mailer: git-send-email 1.8.3.1 In-Reply-To: In-Reply-To: Original-References: X-Gm-Message-State: ALoCoQnEgFvzZ8+AK7RvKP+dtEXRzBjOukTdEh3BdUKvdNx/LcXdvynD3Igq815O45rR2ouJUIb7P/pNVfwgfyfRPkubn8IUtCqihHjnEou1gQ9cbsOVcwvSjUWGKHkmxaQcE9av3VIK/iF/JTR06q+ye4nS+vKsGDbSJ0TuFrRhr20RNV7UXwxGMphhdyF8+3z3KsK3EX+0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4013:c01::231 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:160825 Archived-At: You may think of it as a *scratch* buffer whose content is preserved. In fact, it was designed as a replacement for *scratch* buffer and can be used that way by setting `initial-buffer-choice' to 'notes an `notes-buffer-name' to "*scratch*". Without the second change, *scratch* buffer will still be there for notes that do not need to be preserved. * notes.el: New file. * remember.el (remember-data-file): Added :set callback to affect notes buffer (if any). (remember-append-to-file): Fixed buffer visiting a file checking. Function used `find-buffer-visiting' to check whether such buffer exists but then `get-buffer-visiting' to retrieve it. However, the latter requires exact string match so it could return nil even though the former found a buffer. (notes, toggle-notes): New functions for showing the notes buffer. (notes-file, notes-recover-from-auto-save-file, notes-buffer-name) (bury-notes-on-kill): New defcustoms for the notes buffer. (notes--buffer, notes-map): New variables for the `notes' function. (notes--custom-set-file, notes--insert-content) (notes--kill-buffer-query): New helper functions. * startup.el (initial-buffer-choice): Added notes to custom type. * window.el (save-and-bury-buffer): New function doing what the name says. --- etc/NEWS | 8 +++ lisp/ChangeLog | 21 +++++++ lisp/startup.el | 3 +- lisp/textmodes/remember.el | 152 ++++++++++++++++++++++++++++++++++++++++++++- lisp/window.el | 8 +++ 5 files changed, 190 insertions(+), 2 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 475b4b2..ebe6589 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -87,6 +87,14 @@ simply disabling Transient Mark mode does the same thing. ** `initial-buffer-choice' can now specify a function to set up the initial buffer. +** `notes' function creates a buffer whose content is saved on kill-emacs. +You may think of it as a *scratch* buffer whose content is preserved. +In fact, it was designed as a replacement for *scratch* buffer and can +be used that way by setting `initial-buffer-choice' to 'notes an +`notes-buffer-name' to "*scratch*". Without the second +change, *scratch* buffer will still be there for notes that do not +need to be preserved. + ** `write-region-inhibit-fsync' now defaults to t in batch mode. ** ACL support has been added. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index d7a16a6..2a7caf8 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,26 @@ 2013-06-21 Michal Nazarewicz + Add `notes' function to store random notes across Emacs restarts. + * notes.el: New file. + * remember.el (remember-data-file): Added :set callback to affect + notes buffer (if any). + (remember-append-to-file): Fixed buffer visiting a file checking. + Function used `find-buffer-visiting' to check whether such buffer + exists but then `get-buffer-visiting' to retrieve it. However, + the latter requires exact string match so it could return nil even + though the former found a buffer. + (notes, toggle-notes): New functions for showing the notes buffer. + (notes-file, notes-recover-from-auto-save-file, notes-buffer-name) + (bury-notes-on-kill): New defcustoms for the notes buffer. + (notes--buffer, notes-map): New variables for the `notes' function. + (notes--custom-set-file, notes--insert-content) + (notes--kill-buffer-query): New helper functions. + * startup.el (initial-buffer-choice): Added notes to custom type. + * window.el (save-and-bury-buffer): New function doing what the + name says. + +2013-06-19 Michal Nazarewicz + * remember.el (remember-append-to-file): Function used `find-buffer-visiting' to check whether a file visiting `remember-data-file` existed but then `get-buffer-visiting' to diff --git a/lisp/startup.el b/lisp/startup.el index 77b2bce..7004015 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -53,7 +53,8 @@ or directory when no target file is specified." (const :tag "Startup screen" nil) (directory :tag "Directory" :value "~/") (file :tag "File" :value "~/.emacs") - (function :tag "Function") + (const :tag "Notes buffer" notes) + (function :tag "Function") (const :tag "Lisp scratch buffer" t)) :version "24.4" :group 'initialization) diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el index a14a34c..6b106c7 100644 --- a/lisp/textmodes/remember.el +++ b/lisp/textmodes/remember.el @@ -382,8 +382,12 @@ Subject: %s\n\n" ;; Remembering to plain files (defcustom remember-data-file (locate-user-emacs-file "notes" ".notes") - "The file in which to store unprocessed data." + "The file in which to store unprocessed data. +When set via customize, visited file of the notes buffer (if it exists) +might be changed. This is only of importance if you are using `notes'." :type 'file + :set 'notes--custom-set-file + :initialize 'custom-initialize-default :group 'remember) (defcustom remember-leader-text "** " @@ -554,4 +558,150 @@ the data away for latter retrieval, and possible indexing. \\{remember-mode-map}" (set-keymap-parent remember-mode-map nil)) +;; Notes buffer showing the notes: + +(defvar notes--buffer nil + "The notes buffer.") + +(defcustom notes-file t + "File to save notes in or t to use `remember-data-file'. +When set via customize, visited file of the notes buffer \(if it exists) +will be changed." + :type '(choice (const "Same as `remember-data-file'" t) + (file "Filename")) + :set 'notes--custom-set-file + :initialize 'custom-initialize-default + :group 'remember) + +(defcustom notes-recover-from-auto-save-file 'ask + "What to do if notes autosave file is newer than the notes file. + +t means to always recover content from auto-save file, 'ask means +to ask user, and nil means never to recover auto-save file (which +also disables `auto-save-mode' in the notes buffer. + +When set via customize, `auto-save-mode' will be enabled or disabled +in the notes buffer according to this variable's value." + :type '(choice (const :tag "Always recover auto-save" t) + (const :tag "Never recover auto-save" nil) + (const :tag "Ask whether to recover auto-save" ask)) + :set (lambda (symbol value) + (set-default symbol value) + (when (buffer-live-p notes--buffer) + (with-current-buffer notes--buffer + (auto-save-mode (if value 1 -1))))) + :group 'remember) + +(defcustom notes-buffer-name "*notes*" + "Name of the notes buffer. +Setting it to *scratch* will hijack the *scratch* buffer for the +purpose of storing notes." + :type 'string + :group 'remember) + +(defcustom initial-notes-major-mode t + "Major mode to set to notes buffer when it's created. +If set to t will use the same mode as `initial-major-mode'." + :type '(choice (const :tag "Same as `initial-major-mode'" t) + (function :tag "Major mode" text-mode)) + :group 'remember) + +(defcustom bury-notes-on-kill t + "Whether to bury notes buffer instead of killing." + :type 'boolean + :group 'remember) + +(defvar notes-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-c" 'save-and-bury-buffer) + map)) + +(defun notes--custom-set-file (symbol value) + (set-default symbol value) + (when (buffer-live-p notes--buffer) + (with-current-buffer notes--buffer + (setq buffer-file-name + (expand-file-name + (if (eq notes-file t) remember-data-file notes-file)))))) + +;;;###autoload +(defun notes () + "Creates notes buffer and switches to it if called interactively. + +Name of the created buffer is taken from `notes-buffer-name' variable +and if a buffer with that name already exist (but was not created by +`notes' function), its content will be overwritten. +\\ +`notes-map' is active in the notes buffer which by default contains +only one \\[save-and-bury-buffer] binding which saves and buries the buffer. + +Function returns notes buffer. + +Notes buffer is meant for keeping random notes which you'd like to +preserve across Emacs restarts. The notes will be stored in the +`notes-file'." + (interactive) + (unless (buffer-live-p notes--buffer) + (setq notes--buffer (get-buffer-create notes-buffer-name)) + (with-current-buffer notes--buffer + (funcall (if (eq initial-notes-major-mode t) + initial-major-mode + initial-notes-major-mode)) + (setq buffer-file-name + (if (eq notes-file t) remember-data-file notes-file)) + (setq buffer-save-without-query t) + (auto-save-mode (if notes-recover-from-auto-save-file 1 -1)) + (add-hook 'kill-buffer-query-functions 'notes--kill-buffer-query) + (setq minor-mode-overriding-map-alist + (cons (cons 'notes--buffer notes-map) + minor-mode-overriding-map-alist)) + (notes--insert-content))) + (when (called-interactively-p 'all) + (switch-to-buffer notes--buffer)) + notes--buffer) + +;;;###autoload +(defun toggle-notes () + "Switches to notes buffer unless already there in which case buries it." + (interactive) + (if (eq (current-buffer) notes--buffer) + (bury-buffer) + (switch-to-buffer (notes)))) + +(defun notes--insert-content () + (let* ((have-file (file-readable-p buffer-file-name)) + (have-auto-save (and buffer-auto-save-file-name + (file-readable-p buffer-auto-save-file-name)))) + ;; If autosave is older, pretend it does not exist. + (and have-file + have-auto-save + (not (file-newer-than-file-p buffer-auto-save-file-name + buffer-file-name)) + (setq have-auto-save nil)) + ;; If user wants us to always recover, pretend there's no base file. + (and have-auto-save + (eq t notes-recover-from-auto-save-file) + (setq have-file nil)) + ;; Ask user what to do. + (and have-file + have-auto-save + (if (y-or-n-p "Recover notes file? ") + (setq have-file nil) + (setq have-auto-save nil))) + (let ((file (cond (have-file buffer-file-name) + (have-auto-save buffer-auto-save-file-name)))) + (when file + (insert-file-contents file nil nil nil t) + (goto-char (point-min)) + (set-buffer-modified-p nil))))) + +(defun notes--kill-buffer-query () + (if (not (eq (current-buffer) notes--buffer)) + t + (when (buffer-modified-p) + (save-buffer)) + (if bury-notes-on-kill + (bury-buffer) + t))) + ;;; remember.el ends here diff --git a/lisp/window.el b/lisp/window.el index 5b00198..7eda7ea 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -3429,6 +3429,14 @@ displayed there." ;; Always return nil. nil)) +(defun save-and-bury-buffer () + "Saves and buries current buffer. +Buffer is saved only if `buffer-modified-p' returns non-nil." + (interactive) + (when (buffer-modified-p) + (save-buffer)) + (bury-buffer)) + (defun unbury-buffer () "Switch to the last buffer in the buffer list." (interactive) -- 1.8.3.1