diff options
Diffstat (limited to '')
-rw-r--r-- | emacs.d/lisp/deft.el | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/emacs.d/lisp/deft.el b/emacs.d/lisp/deft.el new file mode 100644 index 0000000..9b010b8 --- /dev/null +++ b/emacs.d/lisp/deft.el @@ -0,0 +1,764 @@ +;;; deft.el --- quickly browse, filter, and edit plain text notes + +;; Copyright (C) 2011 Jason R. Blevins <jrblevin@sdf.org> +;; 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. +;; 3. Neither the names of the copyright holders nor the names of any +;; contributors may be used to endorse or promote products derived from +;; this software without specific prior written permission. + +;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + +;; Version: 0.3 +;; Author: Jason R. Blevins <jrblevin@sdf.org> +;; Keywords: plain text, notes, Simplenote, Notational Velocity +;; URL: http://jblevins.org/projects/deft/ + +;; This file is not part of GNU Emacs. + +;;; Commentary: + +;; Deft is an Emacs mode for quickly browsing, filtering, and editing +;; directories of plain text notes, inspired by Notational Velocity. +;; It was designed for increased productivity when writing and taking +;; notes by making it fast and simple to find the right file at the +;; right time and by automating many of the usual tasks such as +;; creating new files and saving files. + +;; Deft is open source software and may be freely distributed and +;; modified under the BSD license. Version 0.3 is the latest stable +;; version, released on September 11, 2011. You may download it +;; directly here: + +;; * [deft.el](http://jblevins.org/projects/deft/deft.el) + +;; To follow or contribute to Deft development, you can either +;; [browse](http://jblevins.org/git/deft.git) or clone the Git +;; repository: + +;; git clone git://jblevins.org/git/deft.git + +;; ![File Browser](http://jblevins.org/projects/deft/browser.png) + +;; The Deft buffer is simply a file browser which lists the titles of +;; all text files in the Deft directory followed by short summaries +;; and last modified times. The title is taken to be the first line +;; of the file and the summary is extracted from the text that +;; follows. Files are sorted in terms of the last modified date, from +;; newest to oldest. + +;; All Deft files or notes are simple plain text files where the first +;; line contains a title. As an example, the following directory +;; structure generated the screenshot above. +;; +;; % ls ~/.deft +;; about.txt browser.txt directory.txt operations.txt +;; ack.txt completion.txt extensions.txt text-mode.txt +;; binding.txt creation.txt filtering.txt +;; +;; % cat ~/.deft/about.txt +;; About +;; +;; An Emacs mode for slicing and dicing plain text files. + +;; ![Filtering](http://jblevins.org/projects/deft/filter.png) + +;; Deft's primary operation is searching and filtering. The list of +;; files can be limited or filtered using a search string, which will +;; match both the title and the body text. To initiate a filter, +;; simply start typing. Filtering happens on the fly. As you type, +;; the file browser is updated to include only files that match the +;; current string. + +;; To open the first matching file, simply press `RET`. If no files +;; match your search string, pressing `RET` will create a new file +;; using the string as the title. This is a very fast way to start +;; writing new notes. The filename will be generated automatically. +;; If you prefer to provide a specific filename, use `C-RET` instead. + +;; To open files other than the first match, navigate up and down +;; using `C-p` and `C-n` and press `RET` on the file you want to open. + +;; Press `C-c C-c` to clear the filter string and display all files +;; and `C-c C-g` to refresh the file browser using the current filter +;; string. + +;; Static filtering is also possible by pressing `C-c C-l`. This is +;; sometimes useful on its own, and it may be preferable in some +;; situations, such as over slow connections or on older systems, +;; where interactive filtering performance is poor. + +;; Common file operations can also be carried out from within Deft. +;; Files can be renamed using `C-c C-r` or deleted using `C-c C-d`. +;; New files can also be created using `C-c C-n` for quick creation or +;; `C-c C-m` for a filename prompt. You can leave Deft at any time +;; with `C-c C-q`. + +;; Files opened with deft are automatically saved after Emacs has been +;; idle for a customizable number of seconds. This value is a floating +;; point number given by `deft-auto-save-interval' (default: 1.0). + +;; Getting Started +;; --------------- + +;; To start using it, place it somewhere in your Emacs load-path and +;; add the line + +;; (require 'deft) + +;; in your `.emacs` file. Then run `M-x deft` to start. It is useful +;; to create a global keybinding for the `deft` function (e.g., a +;; function key) to start it quickly (see below for details). + +;; When you first run Deft, it will complain that it cannot find the +;; `~/.deft` directory. You can either create a symbolic link to +;; another directory where you keep your notes or run `M-x deft-setup` +;; to create the `~/.deft` directory automatically. + +;; One useful way to use Deft is to keep a directory of notes in a +;; Dropbox folder. This can be used with other applications and +;; mobile devices, for example, Notational Velocity or Simplenote +;; on OS X, Elements on iOS, or Epistle on Android. + +;; Customization +;; ------------- + +;; Customize the `deft` group to change the functionality. + +;; By default, Deft looks for notes by searching for files with the +;; extension `.txt` in the `~/.deft` directory. You can customize +;; both the file extension and the Deft directory by running +;; `M-x customize-group` and typing `deft`. Alternatively, you can +;; configure them in your `.emacs` file: + +;; (setq deft-extension "txt") +;; (setq deft-directory "~/Dropbox/notes") + +;; You can also customize the major mode that Deft uses to edit files, +;; either through `M-x customize-group` or by adding something like +;; the following to your `.emacs` file: + +;; (setq deft-text-mode 'markdown-mode) + +;; Note that the mode need not be a traditional text mode. If you +;; prefer to write notes as LaTeX fragments, for example, you could +;; set `deft-extension' to "tex" and `deft-text-mode' to `latex-mode'. + +;; You can easily set up a global keyboard binding for Deft. For +;; example, to bind it to F8, add the following code to your `.emacs` +;; file: + +;; (global-set-key [f8] 'deft) + +;; The faces used for highlighting various parts of the screen can +;; also be customized. By default, these faces inherit their +;; properties from the standard font-lock faces defined by your current +;; color theme. + +;; Acknowledgments +;; --------------- + +;; Thanks to Konstantinos Efstathiou for writing simplnote.el, from +;; which I borrowed liberally, and to Zachary Schneirov for writing +;; Notational Velocity, which I have never had the pleasure of using, +;; but whose functionality and spirit I wanted to bring to other +;; platforms, such as Linux, via Emacs. + +;; History +;; ------- + +;; Version 0.3 (2011-09-11): + +;; * Internationalization: support filtering with multibyte characters. + +;; Version 0.2 (2011-08-22): + +;; * Match filenames when filtering. +;; * Automatically save opened files (optional). +;; * Address some byte-compilation warnings. + +;; Deft was originally written by Jason Blevins. +;; The initial version, 0.1, was released on August 6, 2011. + +;;; Code: + +(require 'widget) + +;; Customization + +(defgroup deft nil + "Emacs Deft mode." + :group 'local) + +(defcustom deft-directory (expand-file-name "~/.deft/") + "Deft directory." + :type 'directory + :safe 'stringp + :group 'deft) + +(defcustom deft-extension "txt" + "Deft file extension." + :type 'string + :safe 'stringp + :group 'deft) + +(defcustom deft-text-mode 'text-mode + "Default mode used for editing files." + :type 'function + :group 'deft) + +(defcustom deft-auto-save-interval 1.0 + "Idle time in seconds before automatically saving buffers opened by Deft. +Set to zero to disable." + :type 'float + :group 'deft) + +;; Faces + +(defgroup deft-faces nil + "Faces used in Deft mode" + :group 'deft + :group 'faces) + +(defface deft-header-face + '((t :inherit font-lock-keyword-face :bold t)) + "Face for Deft header." + :group 'deft-faces) + +(defface deft-filter-string-face + '((t :inherit font-lock-string-face)) + "Face for Deft filter string." + :group 'deft-faces) + +(defface deft-title-face + '((t :inherit font-lock-function-name-face :bold t)) + "Face for Deft file titles." + :group 'deft-faces) + +(defface deft-separator-face + '((t :inherit font-lock-comment-delimiter-face)) + "Face for Deft separator string." + :group 'deft-faces) + +(defface deft-summary-face + '((t :inherit font-lock-comment-face)) + "Face for Deft file summary strings." + :group 'deft-faces) + +(defface deft-time-face + '((t :inherit font-lock-variable-name-face)) + "Face for Deft last modified times." + :group 'deft-faces) + +;; Constants + +(defconst deft-version "0.3") + +(defconst deft-buffer "*Deft*" + "Deft buffer name.") + +(defconst deft-separator " --- " + "Text used to separate file titles and summaries.") + +(defconst deft-line-width 63 + "Total width of lines in file browser, not including modified time.") + +;; Global variables + +(defvar deft-mode-hook nil + "Hook run when entering Deft mode.") + +(defvar deft-filter-regexp nil + "Current filter regexp used by Deft.") + +(defvar deft-current-files nil + "List of files matching current filter.") + +(defvar deft-all-files nil + "List of files matching current filter.") + +(defvar deft-hash-contents nil + "Hash containing complete cached file contents, keyed by filename.") + +(defvar deft-hash-mtimes nil + "Hash containing cached file modification times, keyed by filename.") + +(defvar deft-hash-titles nil + "Hash containing cached file titles, keyed by filename.") + +(defvar deft-hash-summaries nil + "Hash containing cached file summaries, keyed by filename.") + +(defvar deft-auto-save-buffers nil + "List of buffers that will be automatically saved.") + +;; File processing + +(defun deft-chomp (str) + "Trim leading and trailing whitespace from STR." + (let ((s str)) + (replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" s))) + +(defun deft-base-filename (file) + "Strip the path and extension from filename FILE." + (setq file (file-name-nondirectory file)) + (setq file (replace-regexp-in-string (concat "\." deft-extension "$") "" file))) + +(defun deft-find-all-files () + "Return a list of all files in the Deft directory." + (if (file-exists-p deft-directory) + (let (files result) + ;; List all files + (setq files + (directory-files deft-directory t + (concat "\." deft-extension "$") t)) + ;; Filter out files that are not readable or are directories + (dolist (file files) + (when (and (file-readable-p file) + (not (file-directory-p file))) + (setq result (cons file result)))) + result))) + +(defun deft-parse-title (contents) + "Parse the given file CONTENTS and determine the title. +The title is taken to be the first non-empty line of a file." + (let ((begin (string-match "^.+$" contents))) + (when begin + (substring contents begin (min (match-end 0) + (+ begin deft-line-width)))))) + +(defun deft-parse-summary (contents title) + "Parse the file CONTENTS, given the TITLE, and extract a summary. +The summary is a string extracted from the contents following the +title." + (let* ((contents (replace-regexp-in-string "\n" " " contents)) + (begin (when title (string-match (regexp-quote title) contents))) + (size (- deft-line-width (length deft-separator) (match-end 0)))) + (when begin + (when (< 0 size) + (setq contents (substring contents (match-end 0) (length contents))) + (setq contents (deft-chomp contents)) + (substring contents 0 (min size (length contents))))))) + +(defun deft-cache-file (file) + "Update file cache if FILE exists." + (when (file-exists-p file) + (let ((mtime-cache (deft-file-mtime file)) + (mtime-file (nth 5 (file-attributes file)))) + (if (or (not mtime-cache) + (time-less-p mtime-cache mtime-file)) + (deft-cache-newer-file file mtime-file))))) + +(defun deft-cache-newer-file (file mtime) + "Update cached information for FILE with given MTIME." + ;; Modification time + (puthash file mtime deft-hash-mtimes) + (let (contents title) + ;; Contents + (with-current-buffer (get-buffer-create "*Deft temp*") + (insert-file-contents file nil nil nil t) + (setq contents (concat (buffer-string)))) + (puthash file contents deft-hash-contents) + ;; Title + (setq title (deft-parse-title contents)) + (puthash file title deft-hash-titles) + ;; Summary + (puthash file (deft-parse-summary contents title) deft-hash-summaries)) + (kill-buffer "*Deft temp*")) + +(defun deft-file-newer-p (file1 file2) + "Return non-nil if FILE1 was modified since FILE2 and nil otherwise." + (let (time1 time2) + (setq time1 (deft-file-mtime file1)) + (setq time2 (deft-file-mtime file2)) + (time-less-p time2 time1))) + +(defun deft-cache-initialize () + "Initialize hash tables for caching files." + (setq deft-hash-contents (make-hash-table :test 'equal)) + (setq deft-hash-mtimes (make-hash-table :test 'equal)) + (setq deft-hash-titles (make-hash-table :test 'equal)) + (setq deft-hash-summaries (make-hash-table :test 'equal))) + +(defun deft-cache-update () + "Update cached file information." + (setq deft-all-files (deft-find-all-files)) ; List all files + (mapc 'deft-cache-file deft-all-files) ; Cache contents + (setq deft-all-files (deft-sort-files deft-all-files))) ; Sort by mtime + +;; Cache access + +(defun deft-file-contents (file) + "Retrieve complete contents of FILE from cache." + (gethash file deft-hash-contents)) + +(defun deft-file-mtime (file) + "Retrieve modified time of FILE from cache." + (gethash file deft-hash-mtimes)) + +(defun deft-file-title (file) + "Retrieve title of FILE from cache." + (gethash file deft-hash-titles)) + +(defun deft-file-summary (file) + "Retrieve summary of FILE from cache." + (gethash file deft-hash-summaries)) + +;; File list display + +(defun deft-print-header () + "Prints the *Deft* buffer header." + (if deft-filter-regexp + (progn + (widget-insert + (propertize "Deft: " 'face 'deft-header-face)) + (widget-insert + (propertize deft-filter-regexp 'face 'deft-filter-string-face))) + (widget-insert + (propertize "Deft" 'face 'deft-header-face))) + (widget-insert "\n\n")) + +(defun deft-buffer-setup () + "Render the file browser in the *Deft* buffer." + (let ((inhibit-read-only t)) + (erase-buffer)) + (remove-overlays) + (deft-print-header) + + ;; Print the files list + (if (not (file-exists-p deft-directory)) + (widget-insert (deft-no-directory-message)) + (if deft-current-files + (progn + (mapc 'deft-file-widget deft-current-files)) + (widget-insert (deft-no-files-message)))) + + (use-local-map deft-mode-map) + (widget-setup) + (goto-char 1) + (forward-line 2)) + +(defun deft-file-widget (file) + "Add a line to the file browser for the given FILE." + (when file + (let ((key (file-name-nondirectory file)) + (text (deft-file-contents file)) + (title (deft-file-title file)) + (summary (deft-file-summary file)) + (mtime (deft-file-mtime file))) + (widget-create 'link + :button-prefix "" + :button-suffix "" + :button-face 'deft-title-face + :format "%[%v%]" + :tag file + :help-echo "Edit this file" + :notify (lambda (widget &rest ignore) + (deft-open-file (widget-get widget :tag))) + (or title "[Empty file]")) + (when summary + (widget-insert (propertize deft-separator 'face 'deft-separator-face)) + (widget-insert (propertize summary 'face 'deft-summary-face))) + (while (< (current-column) deft-line-width) + (widget-insert " ")) + (widget-insert (propertize (format-time-string " %Y-%m-%d %H:%M" mtime) + 'face 'deft-time-face)) + (widget-insert "\n")))) + +(defun deft-refresh () + "Refresh the *Deft* buffer in the background." + (interactive) + (when (get-buffer deft-buffer) + (set-buffer deft-buffer) + (deft-cache-update) + (deft-filter-update) + (deft-buffer-setup))) + +(defun deft-no-directory-message () + "Return a short message to display when the Deft directory does not exist." + (concat "Directory " deft-directory " does not exist.\n")) + +(defun deft-no-files-message () + "Return a short message to display if no files are found." + (if deft-filter-regexp + "No files match the current filter string.\n" + "No files found.")) + +;; File list file management actions + +(defun deft-open-file (file) + "Open FILE in a new buffer and setting its mode." + (prog1 (find-file file) + (funcall deft-text-mode) + (add-to-list 'deft-auto-save-buffers (buffer-name)) + (add-hook 'after-save-hook + (lambda () (save-excursion (deft-refresh))) + nil t))) + +(defun deft-find-file (file) + "Find FILE interactively using the minibuffer." + (interactive "F") + (deft-open-file file)) + +(defun deft-new-file-named (file) + "Create a new file named FILE (or interactively prompt for a filename). +If the filter string is non-nil, use it as the title." + (interactive "sNew filename (without extension): ") + (setq file (concat (file-name-as-directory deft-directory) + file "." deft-extension)) + (if (file-exists-p file) + (message (concat "Aborting, file already exists: " file)) + (when deft-filter-regexp + (write-region deft-filter-regexp nil file nil)) + (deft-open-file file))) + +(defun deft-new-file () + "Create a new file quickly, with an automatically generated filename. +If the filter string is non-nil, use it as the title." + (interactive) + (let (fmt filename counter temp-buffer) + (setq counter 0) + (setq fmt (concat "deft-%d." deft-extension)) + (setq filename (concat deft-directory (format fmt counter))) + (while (or (file-exists-p filename) + (get-file-buffer filename)) + (setq counter (1+ counter)) + (setq filename (concat deft-directory (format fmt counter)))) + (when deft-filter-regexp + (write-region (concat deft-filter-regexp "\n\n") nil filename nil)) + (deft-open-file filename) + (with-current-buffer (get-file-buffer filename) + (goto-char (point-max))))) + +(defun deft-delete-file () + "Delete the file represented by the widget at the point. +If the point is not on a file widget, do nothing. Prompts before +proceeding." + (interactive) + (let ((filename (widget-get (widget-at) :tag))) + (when filename + (when (y-or-n-p + (concat "Delete file " (file-name-nondirectory filename) "? ")) + (delete-file filename) + (delq filename deft-current-files) + (delq filename deft-all-files) + (deft-refresh))))) + +(defun deft-rename-file () + "Rename the file represented by the widget at the point. +If the point is not on a file widget, do nothing." + (interactive) + (let (old-filename new-filename old-name new-name) + (setq old-filename (widget-get (widget-at) :tag)) + (when old-filename + (setq old-name (deft-base-filename old-filename)) + (setq new-name (read-string + (concat "Rename " old-name " to (without extension): "))) + (setq new-filename + (concat (file-name-as-directory deft-directory) + new-name "." deft-extension)) + (rename-file old-filename new-filename) + (deft-refresh)))) + +;; File list filtering + +(defun deft-sort-files (files) + "Sort FILES in reverse order by modified time." + (sort files (lambda (f1 f2) (deft-file-newer-p f1 f2)))) + +(defun deft-filter-initialize () + "Initialize the filter string (nil) and files list (all files)." + (interactive) + (setq deft-filter-regexp nil) + (setq deft-current-files deft-all-files)) + +(defun deft-filter-update () + "Update the filtered files list using the current filter regexp." + (if (not deft-filter-regexp) + (setq deft-current-files deft-all-files) + (setq deft-current-files (mapcar 'deft-filter-match-file deft-all-files)) + (setq deft-current-files (delq nil deft-current-files)))) + +(defun deft-filter-match-file (file) + "Return FILE if FILE matches the current filter regexp." + (if (or (string-match deft-filter-regexp (deft-file-title file)) + (string-match deft-filter-regexp file) + (string-match deft-filter-regexp (deft-file-contents file))) + file)) + +;; Filters that cause a refresh + +(defun deft-filter-clear () + "Clear the current filter string and refresh the file browser." + (interactive) + (when deft-filter-regexp + (setq deft-filter-regexp nil) + (setq deft-current-files deft-all-files) + (deft-refresh)) + (message "Filter cleared.")) + +(defun deft-filter (str) + "Set the filter string to STR and update the file browser." + (interactive "sFilter: ") + (if (= (length str) 0) + (setq deft-filter-regexp nil) + (setq deft-filter-regexp str) + (setq deft-current-files (mapcar 'deft-filter-match-file deft-all-files)) + (setq deft-current-files (delq nil deft-current-files))) + (deft-refresh)) + +(defun deft-filter-increment () + "Append character to the filter regexp and update `deft-current-files'." + (interactive) + (let ((char last-command-event)) + (if (= char ?\S-\ ) + (setq char ?\s)) + (setq char (char-to-string char)) + (setq deft-filter-regexp (concat deft-filter-regexp char)) + (setq deft-current-files (mapcar 'deft-filter-match-file deft-current-files)) + (setq deft-current-files (delq nil deft-current-files))) + (deft-refresh)) + +(defun deft-filter-decrement () + "Remove last character from the filter regexp and update `deft-current-files'." + (interactive) + (if (> (length deft-filter-regexp) 1) + (deft-filter (substring deft-filter-regexp 0 -1)) + (deft-filter-clear))) + +(defun deft-complete () + "Complete the current action. +If there is a widget at the point, press it. If a filter is +applied and there is at least one match, open the first matching +file. If there is an active filter but there are no matches, +quick create a new file using the filter string as the title. +Otherwise, quick create a new file." + (interactive) + (cond + ;; Activate widget + ((widget-at) + (widget-button-press (point))) + ;; Active filter string with match + ((and deft-filter-regexp deft-current-files) + (deft-open-file (car deft-current-files))) + ;; Default + (t + (deft-new-file)))) + +;;; Automatic File Saving + +(defun deft-auto-save () + (save-excursion + (dolist (buf deft-auto-save-buffers) + (if (get-buffer buf) + ;; Save open buffers that have been modified. + (progn + (set-buffer buf) + (when (buffer-modified-p) + (basic-save-buffer))) + ;; If a buffer is no longer open, remove it from auto save list. + (delq buf deft-auto-save-buffers))))) + +;;; Mode definition + +(defun deft-show-version () + "Show the version number in the minibuffer." + (interactive) + (message "Deft %s" deft-version)) + +(defun deft-setup () + "Prepare environment by creating the Deft notes directory." + (interactive) + (when (not (file-exists-p deft-directory)) + (make-directory deft-directory t)) + (deft-refresh)) + +(defvar deft-mode-map + (let ((i 0) + (map (make-keymap))) + ;; Make multibyte characters extend the filter string. + (set-char-table-range (nth 1 map) (cons #x100 (max-char)) + 'deft-filter-increment) + ;; Extend the filter string by default. + (setq i ?\s) + (while (< i 256) + (define-key map (vector i) 'deft-filter-increment) + (setq i (1+ i))) + ;; Handle backspace and delete + (define-key map (kbd "DEL") 'deft-filter-decrement) + ;; Handle return via completion or opening file + (define-key map (kbd "RET") 'deft-complete) + ;; Filtering + (define-key map (kbd "C-c C-l") 'deft-filter) + (define-key map (kbd "C-c C-c") 'deft-filter-clear) + ;; File creation + (define-key map (kbd "C-c C-n") 'deft-new-file) + (define-key map (kbd "C-c C-m") 'deft-new-file-named) + (define-key map (kbd "<C-return>") 'deft-new-file-named) + ;; File management + (define-key map (kbd "C-c C-d") 'deft-delete-file) + (define-key map (kbd "C-c C-r") 'deft-rename-file) + (define-key map (kbd "C-c C-f") 'deft-find-file) + ;; Miscellaneous + (define-key map (kbd "C-c C-g") 'deft-refresh) + (define-key map (kbd "C-c C-q") 'quit-window) + ;; Widgets + (define-key map [down-mouse-1] 'widget-button-click) + (define-key map [down-mouse-2] 'widget-button-click) + (define-key map (kbd "<tab>") 'widget-forward) + (define-key map (kbd "<backtab>") 'widget-backward) + (define-key map (kbd "<S-tab>") 'widget-backward) + map) + "Keymap for Deft mode.") + +(defun deft-mode () + "Major mode for quickly browsing, filtering, and editing plain text notes. +Turning on `deft-mode' runs the hook `deft-mode-hook'. + +\\{deft-mode-map}." + (interactive) + (kill-all-local-variables) + (setq truncate-lines t) + (setq buffer-read-only t) + (setq default-directory deft-directory) + (use-local-map deft-mode-map) + (deft-cache-initialize) + (deft-cache-update) + (deft-filter-initialize) + (setq major-mode 'deft-mode) + (setq mode-name "Deft") + (deft-buffer-setup) + (when (> deft-auto-save-interval 0) + (run-with-idle-timer deft-auto-save-interval t 'deft-auto-save)) + (run-mode-hooks 'deft-mode-hook)) + +(put 'deft-mode 'mode-class 'special) + +;;;###autoload +(defun deft () + "Switch to *Deft* buffer and load files." + (interactive) + (switch-to-buffer deft-buffer) + (if (not (eq major-mode 'deft-mode)) + (deft-mode))) + +(provide 'deft) + +;;; deft.el ends here |