diff --git a/contrib/deft.el b/contrib/deft.el deleted file mode 100644 index 0613be3be..000000000 --- a/contrib/deft.el +++ /dev/null @@ -1,1498 +0,0 @@ -;;; deft.el --- quickly browse, filter, and edit plain text notes - -;;; Copyright (C) 2011-2015 Jason R. Blevins -;; 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.6 -;;; Author: Jason R. Blevins -;;; 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.6 is the latest stable -;; version, released on June 26, 2015. 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 - -;; ![Deft 0.6 Screencast](http://jblevins.org/projects/deft/deft-v0.6.gif) - -;; 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, by default, 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.org -;; binding.txt creation.txt filtering.txt -;; -;; % cat ~/.deft/about.txt -;; # About -;; -;; An Emacs mode for slicing and dicing plain text files. - -;; 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. -;; When opening a file, Deft searches forward and leaves the point -;; at the end of the first match of the filter string. - -;; You can also press `C-o` to open a file in another window, without -;; switching to the other window. Issue the same command with a prefix -;; argument, `C-u C-o`, to open the file in another window and switch -;; to that window. - -;; To edit the filter string, press `DEL` (backspace) to remove the -;; last character or `M-DEL` to remove the last "word". To yank -;; (paste) the most recently killed (cut or copied) text into the -;; filter string, press `C-y`. 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. - -;; For more advanced editing operations, you can also edit the filter -;; string in the minibuffer by pressing `C-c C-l`. While in the -;; minibuffer, the history of previous edits can be cycled through by -;; pressing `M-p` and `M-n`. This form of static, one-time filtering -;; (as opposed to incremental, on-the-fly filtering) may be preferable -;; in some situations, such as over slow connections or on systems -;; where interactive filtering performance is poor. - -;; By default, Deft filters files in incremental string search mode, -;; where "search string" will match all files containing both "search" -;; and "string" in any order. Alternatively, Deft supports direct -;; regexp filtering, where the filter string is interpreted as a -;; formal regular expression. For example, `^\(foo\|bar\)` matches -;; foo or bar at the beginning of a line. Pressing `C-c C-t` will -;; toggle between incremental and regexp search modes. Regexp -;; search mode is indicated by an "R" in the mode line. - -;; 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`. - -;; Unused files can be archived by pressing `C-c C-a`. Files will be -;; moved to `deft-archive-directory', which is a directory named -;; `archive` within your `deft-directory' by default. - -;; 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, [nvALT][], [Notational Velocity][], or -;; [Simplenote][] on OS X or [Editorial][], [Byword][], or [1Writer][] -;; on iOS. - -;; [nvALT]: http://brettterpstra.com/projects/nvalt/ -;; [Notational Velocity]: http://notational.net/ -;; [Simplenote]: http://simplenote.com/ -;; [Editorial]: https://geo.itunes.apple.com/us/app/editorial/id673907758?mt=8&uo=6&at=11l5Vs&ct=deft -;; [Byword]: https://geo.itunes.apple.com/us/app/byword/id482063361?mt=8&uo=6&at=11l5Vs&ct=deft -;; [1Writer]: https://geo.itunes.apple.com/us/app/1writer-note-taking-writing/id680469088?mt=8&uo=6&at=11l5Vs&ct=deft - -;; Basic Customization -;; ------------------- - -;; You can customize items in the `deft` group to change the default -;; functionality. - -;; By default, Deft looks for notes by searching for files with the -;; extensions `.txt`, `.text`, `.md`, `.markdown`, or `.org` 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-extensions '("txt" "tex" "org") -;; (setq deft-directory "~/Dropbox/notes")) - -;; The first element of `deft-extensions' (or in Lisp parlance, the -;; car) is the default extension used to create new files. - -;; By default, Deft only searches for files in `deft-directory' but -;; not in any subdirectories. Set `deft-recursive' to a non-nil value -;; to enable recursive searching for files in subdirectories: - -;; (setq deft-recursive t) - -;; 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) - -;; Reading Files -;; ------------- - -;; The displayed title of each file is taken to be the first line of -;; the file, with certain characters removed from the beginning. Hash -;; characters, as used in Markdown headers, and asterisks, as in Org -;; Mode headers, are removed. Additionally, Org mode `#+TITLE:` tags, -;; MultiMarkdown `Title:` tags, LaTeX comment markers (`%`), and -;; Emacs mode-line declarations (e.g., `-*-mode-*-`) are stripped from -;; displayed titles. This can be customized by changing -;; `deft-strip-title-regexp'. - -;; More generally, the title post-processing function itself can be -;; customized by setting `deft-parse-title-function', which accepts -;; the first line of the file as an argument and returns the parsed -;; title to display in the file browser. The default function is -;; `deft-strip-title', which removes all occurrences of -;; `deft-strip-title-regexp' as described above. - -;; For compatibility with other applications which use the filename as -;; the title of a note (rather than the first line of the file), set the -;; `deft-use-filename-as-title' flag to a non-`nil' value. Deft will then -;; use note filenames to generate the displayed titles in the Deft -;; file browser. To enable this, add the following to your `.emacs` file: - -;; (setq deft-use-filename-as-title t) - -;; Creating Files -;; -------------- - -;; Filenames for newly created files are generated by Deft automatically. -;; The process for doing so is determined by the variables -;; `deft-use-filename-as-title' and `deft-use-filter-string-for-filename' -;; as well as the rules in the `deft-file-naming-rules' alist. -;; The possible cases are as follows: - -;; 1. **Default** (`deft-use-filename-as-title' and -;; `deft-use-filter-string-for-filename' are both `nil'): - -;; The filename will be automatically generated with prefix `deft-` -;; and a numerical suffix as in `deft-0.ext', `deft-1.ext', ... -;; The filter string will be inserted as the first line of the file -;; (which is also used as the display title). - -;; 2. **Filenames as titles** (`deft-use-filename-as-title' is non-`nil'): - -;; When `deft-use-filename-as-title' is non-`nil', the filter string -;; will be used as the filename for new files (with the appropriate -;; file extension appended to the end). - -;; 3. **Readable filenames** (`deft-use-filename-as-title' is -;; `nil' but `deft-use-filter-string-for-filename' is non-`nil'): - -;; In this case you can choose to display the title as parsed from -;; the first line of the file while also generating readable -;; filenames for new files based on the filter string. The -;; variable `deft-use-filter-string-for-filename' controls this -;; behavior and decouples the title display -;; (`deft-use-filename-as-title') from the actual filename. New -;; filenames will be generated from the filter string and -;; processed according to the rules defined in the -;; `deft-file-naming-rules' alist. By default, slashes are removed -;; and replaced by hyphens, but many other options are possible -;; (camel case, replacing spaces by hyphens, and so on). See the -;; documentation for `deft-file-naming-rules' for additional -;; details. - -;; Titles inserted into files from the filter string can also be -;; customized for two common modes, `markdown-mode' and `org-mode', by -;; setting the following variables: - -;; * `deft-markdown-mode-title-level' - When set to a positive -;; integer, determines how many hash marks will be added to titles -;; in new Markdown files. In other words, setting -;; `deft-markdown-mode-title-level' to `2` will result in new files -;; being created with level-2 headings of the form `## Title`. - -;; * `deft-org-mode-title-prefix' - When non-nil, automatically -;; generated titles in new `org-mode' files will be prefixed with -;; `#+TITLE:`. - -;; Other Customizations -;; -------------------- - -;; Deft, by default, lists files from newest to oldest. You can set -;; `deft-current-sort-method' to 'title to sort by file titles, case -;; ignored. Or, you can toggle sorting method using -;; `deft-toggle-sort-method'. - -;; Incremental string search is the default method of filtering on -;; startup, but you can set `deft-incremental-search' to nil to make -;; regexp search the default. - -;; Deft also provides a function for opening files without using the -;; Deft buffer directly. Calling `deft-find-file' will prompt for a -;; file to open, just like `find-file', but starting from -;; `deft-directory'. If the file selected is in `deft-directory', it -;; is opened with the usual deft features (automatic saving, automatic -;; updating of the Deft buffer, etc.). Otherwise, the file will be -;; opened by `find-file' as usual. Therefore, you can set up a global -;; keybinding for this function to open Deft files anywhere. For -;; example, to use `C-x C-g`, a neighbor of `C-x C-f`, use the -;; following: - -;; (global-set-key (kbd "C-x C-g") 'deft-find-file) - -;; 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 simplenote.el, from -;; which I borrowed liberally, and to Zachary Schneirov for writing -;; Notational Velocity, whose functionality and spirit I wanted to -;; bring to Emacs. - -;; History -;; ------- - -;; Version 0.6 (2015-06-26): - -;; * Recursive search in subdirectories (optional). Set -;; `deft-recursive' to a non-nil value to enable. -;; * Support for multiple extensions via the `deft-extensions' list. -;; As such, `deft-extension' is now deprecated. -;; * New variable `deft-create-file-from-filter-string' can enable -;; generation of new filenames based on the filter string. This decouples -;; the title display (`deft-use-filename-as-title') from the actual filename -;; generation. -;; * New variable `deft-file-naming-rules' allows customizing generation -;; of filenames with regard to letter case and handling of spaces. -;; * New variables `deft-markdown-mode-title-level' and -;; `deft-org-mode-title-prefix' for automatic insertion of title markup. -;; * Archiving of files in `deft-archive-directory'. -;; * Ability to sort by either title or modification time via -;; `deft-current-sort-method'. -;; * Update default `deft-strip-title-regexp' to remove the following: -;; - org-mode `#+TITLE:` tags -;; - MultiMarkdown `Title:` tags -;; - LaTeX comment markers (i.e., `%`) -;; - Emacs mode-line declarations (e.g., `-*-mode-*-`) -;; * Remove leading and trailing whitespace from titles. -;; * Disable visual line mode to prevent lines from wrapping. -;; * Enable line truncation to avoid displaying truncation characters. -;; * Show the old filename as the default prompt when renaming a file. -;; * Call `hack-local-variables' to read file-local variables when -;; opening files. -;; * Fixed several byte-compilation warnings. -;; * Bug fix: more robust handling of relative and absolute filenames. -;; * Bug fix: use width instead of length of strings for calculations. -;; * Bug fix: fix `string-width' error with empty file. - -;; Version 0.5.1 (2013-01-28): - -;; * Bug fix: creating files with `C-c C-n` when both the filter string and -;; `deft-use-filename-as-title' are non-nil resulted in an invalid path. -;; * Bug fix: killed buffers would persist in `deft-auto-save-buffers'. - -;; Version 0.5 (2013-01-25): - -;; * Implement incremental string search (default) and regexp search. -;; These search modes can be toggled by pressing `C-c C-t`. -;; * Default search method can be changed by setting `deft-incremental-search'. -;; * Support custom `deft-parse-title-function' for post-processing titles. -;; * The default `deft-parse-title-function' simply strips occurrences of -;; `deft-strip-title-regexp', which removes Markdown and Org headings. -;; * Open files in another window with `C-o`. Prefix it with `C-u` to -;; switch to the other window. -;; * For symbolic links, use modification time of taget for sorting. -;; * When opening files, move point to the end of the first match of -;; the filter string. -;; * Improved filter editing: delete (`DEL`), delete word (`M-DEL`), -;; and yank (`C-y`). -;; * Advanced filter editing in minibuffer (`C-c C-l`). - -;; Version 0.4 (2011-12-11): - -;; * Improved filtering performance. -;; * Optionally take title from filename instead of first line of the -;; contents (see `deft-use-filename-as-title'). -;; * Dynamically resize width to fit the entire window. -;; * Customizable time format (see `deft-time-format'). -;; * Handle `deft-directory' properly with or without a trailing slash. - -;; 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](http://jblevins.org/). -;; The initial version, 0.1, was released on August 6, 2011. - -;;; Code: - -(require 'cl) -(require 'widget) -(require 'wid-edit) - -;; 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-extensions '("txt" "text" "md" "markdown" "org") - "Any files with these extensions will be listed." - :type '(repeat string) - :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) - -(defcustom deft-time-format " %Y-%m-%d %H:%M" - "Format string for modification times in the Deft browser. -Set to nil to hide." - :type '(choice (string :tag "Time format") - (const :tag "Hide" nil)) - :group 'deft) - -(defcustom deft-use-filename-as-title nil - "Use filename as title in the *Deft* buffer." - :type 'boolean - :group 'deft) - -(defcustom deft-use-filter-string-for-filename nil - "Use the filter string to generate name for the new file." - :type 'boolean - :group 'deft) - -(defcustom deft-markdown-mode-title-level 0 - "Prefix titles in new Markdown files with required number of hash marks." - :type 'integer - :group 'deft) - -(defcustom deft-org-mode-title-prefix t - "Prefix the auto generated title in a new org-mode deft file with #+TITLE:." - :type 'boolean - :group 'deft) - -(defcustom deft-incremental-search t - "Use incremental string search when non-nil and regexp search when nil. -During incremental string search, substrings separated by spaces are -treated as subfilters, each of which must match a file. They need -not be adjacent and may appear in any order. During regexp search, the -entire filter string is interpreted as a single regular expression." - :type 'boolean - :group 'deft) - -(defcustom deft-recursive nil - "Recursively search for files in subdirectories when non-nil." - :type 'boolean - :group 'deft) - -(defcustom deft-parse-title-function 'deft-strip-title - "Function for post-processing file titles." - :type 'function - :group 'deft) - -(defcustom deft-strip-title-regexp - (concat "\\(?:" - "^%+" ; line beg with % - "\\|^#\\+TITLE: *" ; org-mode title - "\\|^[#* ]+" ; line beg with #, * and/or space - "\\|-\\*-[[:alpha:]]+-\\*-" ; -*- .. -*- lines - "\\|^Title:[ ]*" ; MultiMarkdown metadata - "\\|#+" ; line with just # chars - "$\\)") - "Regular expression to remove from file titles. -Presently, it removes leading LaTeX comment delimiters, leading -and trailing hash marks from Markdown ATX headings, leading -astersisks from Org Mode headings, and Emacs mode lines of the -form -*-mode-*-." - :type 'regexp - :safe 'stringp - :group 'deft) - -(defcustom deft-archive-directory "archive/" - "Deft archive directory. -This may be a relative path from `deft-directory', or an absolute path." - :type 'directory - :safe 'stringp - :group 'deft) - -(defcustom deft-file-naming-rules '( (noslash . \"-\") ) - "Alist of cons cells (SYMBOL . VALUE) for `deft-absolute-filename'. - -Supported cons car values: `noslash', `nospace', `case-fn'. - -Value of `slash' is a string which should replace the forward slash characters -in the file name. The default behavior is to replace slashes with hyphens in the -file name. To change the replacement charcter to an underscore, one could use: - - (setq deft-file-naming-rules '((noslash . \"_\"))) - -Value of `nospace' is a string which should replace the space characters in the -file name. Below example replaces spaces with underscores in the file names: - - (setq deft-file-naming-rules '((nospace . \"_\"))) - -Value of `case-fn' is a function name that takes a string as input that has to -be applied on the file name. Below example makes the file name all lower case: - - (setq deft-file-naming-rules '((case-fn . downcase))) - -It is also possible to use a combination of the above cons cells to get file -name in various case styles like, - -snake_case: - - (setq deft-file-naming-rules '((noslash . \"_\") - (nospace . \"_\") - (case-fn . downcase))) - -or CamelCase - - (setq deft-file-naming-rules '((noslash . \"\") - (nospace . \"\") - (case-fn . capitalize))) - -or kebab-case - - (setq deft-file-naming-rules '((noslash . \"-\") - (nospace . \"-\") - (case-fn . downcase))) -" - :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-filter-string-error-face - '((t :inherit font-lock-warning-face)) - "Face for Deft filter string when regexp is invalid." - :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.6") - -(defconst deft-buffer "*Deft*" - "Deft buffer name.") - -(defconst deft-separator " --- " - "Text used to separate file titles and summaries.") - -(defconst deft-empty-file-title "[Empty file]" - "Text to use as title for empty files.") - -;; Global variables - -(defvar deft-mode-hook nil - "Hook run when entering Deft mode.") - -(defvar deft-filter-regexp nil - "A list of string representing the current filter used by Deft. - -In incremental search mode, when `deft-incremental-search' is -non-nil, the elements of this list are the individual words of -the filter string, in reverse order. That is, the car of the -list is the last word in the filter string. - -In regexp search mode, when `deft-incremental-search' is nil, -this list has a single element containing the entire filter -regexp.") - -(defvar deft-current-files nil - "List of files matching current filter.") - -(defvar deft-current-sort-method 'mtime - "Current file soft method. -Available methods are 'mtime and 'title.") - -(defvar deft-all-files nil - "List of all files in `deft-directory'.") - -(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.") - -(defvar deft-window-width nil - "Width of Deft buffer.") - -(defvar deft-filter-history nil - "History of interactive filter strings.") - -(defvar deft-regexp-error nil - "Flag for indicating invalid regexp errors.") - -(defvar deft-default-extension nil - "Default file extension of newly created files.") - -;; Keymap definition - -(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) - (define-key map (kbd "M-DEL") 'deft-filter-decrement-word) - ;; 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) - (define-key map (kbd "C-y") 'deft-filter-yank) - ;; 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 "") '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) - (define-key map (kbd "C-c C-a") 'deft-archive-file) - ;; Settings - (define-key map (kbd "C-c C-t") 'deft-toggle-incremental-search) - (define-key map (kbd "C-c C-s") 'deft-toggle-sort-method) - ;; 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 "") 'widget-forward) - (define-key map (kbd "") 'widget-backward) - (define-key map (kbd "") 'widget-backward) - (define-key map (kbd "C-o") 'deft-open-file-other-window) - map) - "Keymap for Deft mode.") - -;; Helpers - -(defun deft-whole-filter-regexp () - "Join incremental filters into one." - (mapconcat 'identity (reverse deft-filter-regexp) " ")) - -(defun deft-search-forward (str) - "Function to use when matching files against filter strings. -This function calls `search-forward' when `deft-incremental-search' -is non-nil and `re-search-forward' otherwise." - (if deft-incremental-search - (search-forward str nil t) - (re-search-forward str nil t))) - -(defun deft-set-mode-name () - (if deft-incremental-search - (setq mode-name "Deft") - (setq mode-name "Deft/R"))) - -(defun deft-toggle-incremental-search () - "Toggle the `deft-incremental-search' setting." - (interactive) - (cond - (deft-incremental-search - (setq deft-incremental-search nil) - (message "Regexp search")) - (t - (setq deft-incremental-search t) - (message "Incremental string search"))) - (deft-filter (deft-whole-filter-regexp) t) - (deft-set-mode-name)) - -(defun deft-toggle-sort-method () - "Toggle file sorting method defined in `deft-current-sort-method'." - (interactive) - (setq deft-current-sort-method - (if (eq deft-current-sort-method 'mtime) 'title 'mtime)) - (deft-refresh)) - -(defun deft-filter-regexp-as-regexp () - "Return a regular expression corresponding to the current filter string. -When `deft-incremental-search' is non-nil, we must combine each individual -whitespace separated string. Otherwise, the `car' of `deft-filter-regexp' -is the complete regexp." - (if deft-incremental-search - (mapconcat 'regexp-quote (reverse deft-filter-regexp) "\\|") - (car deft-filter-regexp))) - -;; File processing - -(defun deft-chomp (str) - "Trim leading and trailing whitespace from STR." - (replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" str)) - -(defun deft-base-filename (file) - "Strip `deft-directory' and `deft-extension' from filename FILE." - (let* ((deft-dir (file-name-as-directory (expand-file-name deft-directory))) - (len (length deft-dir)) - (file (substring file len))) - (file-name-base file))) - -(defun deft-find-all-files () - "Return a list of all files in the Deft directory. - -See `deft-find-files'." - (deft-find-files deft-directory)) - -(defun deft-find-files (dir) - "Return a list of all files in the directory DIR. - -It is important to note that the return value is a list of -absolute filenames. These absolute filenames are used as keys -for the various hash tables used for storing file metadata and -contents. So, any functions looking up values in these hash -tables should use `expand-file-name' on filenames first. - -If `deft-recursive' is non-nil, then search recursively in -subdirectories of `deft-directory' (with the exception of -`deft-archive-directory'). - -See `deft-find-all-files'." - (if (file-exists-p dir) - (let ((archive-dir (expand-file-name (concat deft-directory "/" - deft-archive-directory "/"))) - (files (directory-files dir t "." t)) - result) - (dolist (file files) - (cond - ;; Recurse into subdirectory if `deft-recursive' is non-nil - ;; and the directory is not ".", "..", or `deft-archive-directory'. - ((file-directory-p file) - (when (and deft-recursive - (not (string-match "/\\(\\.\\|\\.\\.\\)$" file)) - (not (string-prefix-p archive-dir - (expand-file-name (concat file "/"))))) - (setq result (append (deft-find-files file) result)))) - ;; Collect names of readable files ending in `deft-extension' - ((and (file-readable-p file) - (not (backup-file-name-p file)) - (member (file-name-extension file) deft-extensions)) - (setq result (cons file result))))) - result))) - -(defun deft-strip-title (title) - "Remove all strings matching `deft-strip-title-regexp' from TITLE." - (deft-chomp (replace-regexp-in-string deft-strip-title-regexp "" title))) - -(defun deft-parse-title (file contents) - "Parse the given FILE and CONTENTS and determine the title. -If `deft-use-filename-as-title' is `nil', the title is taken to -be the first non-empty line of the FILE. Else the base name of the FILE is -used as title." - (if deft-use-filename-as-title - (deft-base-filename file) - (let ((begin (string-match "^.+$" contents))) - (if begin - (funcall deft-parse-title-function - (substring contents begin (match-end 0))))))) - -(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 ((summary (replace-regexp-in-string "[\n\t]" " " contents))) - (if (and (not deft-use-filename-as-title) title) - (if (string-match (regexp-quote title) summary) - (deft-chomp (substring summary (match-end 0) nil)) - "") - summary))) - -(defun deft-cache-file (file) - "Update file cache if FILE exists." - (when (file-exists-p file) - (add-to-list 'deft-all-files file) - (let ((mtime-cache (deft-file-mtime file)) - (mtime-file (nth 5 (file-attributes (file-truename 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 file 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-file-title-lessp (file1 file2) - "Return non-nil if the title of FILE1 is less than FILE2's in -lexicographic order. -Case is ignored." - (let ((t1 (deft-file-title file1)) - (t2 (deft-file-title file2))) - (string-lessp (and t1 (downcase t1)) - (and t2 (downcase t2))))) - -(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-all () - "Update file list and update cached information for each file." - (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 - -(defun deft-cache-update-file (file) - "Update cached information for a single file." - (deft-cache-file file) ; 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-whole-filter-regexp) 'face - (if (and (not deft-incremental-search) deft-regexp-error) - 'deft-filter-string-error-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." - (setq deft-window-width (window-width)) - (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-string-width (str) - "A wrapper function for the original string-width which does -not handle nil. This function return 0 if the given STR is nil, -call the original string-width otherwise" - (if str - (string-width str) - 0)) - -(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 (when deft-time-format - (format-time-string deft-time-format (deft-file-mtime file)))) - (mtime-width (deft-string-width mtime)) - (line-width (- deft-window-width mtime-width)) - (title-width (min line-width (deft-string-width title))) - (summary-width (min (deft-string-width summary) - (- line-width - title-width - (length deft-separator))))) - (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))) - (if title (truncate-string-to-width title title-width) - deft-empty-file-title)) - (when (> summary-width 0) - (widget-insert (propertize deft-separator 'face 'deft-separator-face)) - (widget-insert (propertize (truncate-string-to-width summary summary-width) - 'face 'deft-summary-face))) - (when mtime - (while (< (current-column) line-width) - (widget-insert " ")) - (widget-insert (propertize mtime 'face 'deft-time-face))) - (widget-insert "\n")))) - -(add-hook 'window-configuration-change-hook - (lambda () - (when (and (eq (current-buffer) (get-buffer deft-buffer)) - (not (eq deft-window-width (window-width)))) - (deft-buffer-setup)))) - -(defun deft-refresh () - "Update the file cache, reapply the filter, and refresh the *Deft* buffer." - (interactive) - (deft-cache-update-all) - (deft-refresh-filter)) - -(defun deft-refresh-filter () - "Reapply the filter and refresh the *Deft* buffer. -Call this after any actions which update the cache." - (interactive) - (deft-filter-update) - (deft-refresh-browser)) - -(defun deft-refresh-browser () - "Refresh the *Deft* buffer in the background. -Call this function after any actions which update the filter and file list." - (when (get-buffer deft-buffer) - (with-current-buffer deft-buffer - (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-absolute-filename (slug &optional extension) - "Return an absolute filename to file named SLUG with optional EXTENSION. -If EXTENSION is not given, `deft-extension' is assumed. - -Refer to `deft-file-naming-rules' for setting rules for formatting the file -name." - (let* ((slug (deft-chomp slug)) ; remove leading/trailing spaces - (slash-replacement (cdr (assq 'noslash deft-file-naming-rules))) - (space-replacement (cdr (assq 'nospace deft-file-naming-rules))) - (case-fn (cdr (assq 'case-fn deft-file-naming-rules)))) - (when slash-replacement - (setq slug (replace-regexp-in-string "\/" slash-replacement slug))) - (when space-replacement - (setq slug (replace-regexp-in-string " " space-replacement slug))) - (when case-fn - (setq slug (funcall case-fn slug))) - (concat (file-name-as-directory (expand-file-name deft-directory)) - slug "." (or extension deft-default-extension)))) - -(defun deft-unused-slug () - "Return an unused filename slug (short name) in `deft-directory'." - (let* ((fmt "deft-%d") - (counter 0) - (slug (format fmt counter)) - (file (deft-absolute-filename slug))) - (while (or (file-exists-p file) (get-file-buffer file)) - (setq counter (1+ counter)) - (setq slug (format fmt counter)) - (setq file (deft-absolute-filename slug))) - slug)) - -(defun deft-update-visiting-buffers (old new) - "Rename visited file of buffers visiting file OLD to NEW." - (let ((buffer (get-file-buffer old))) - (when buffer - (with-current-buffer (get-file-buffer old) - (set-visited-file-name new nil t) - (hack-local-variables))))) - -(defun deft-open-file (file &optional other switch) - "Open FILE in a new buffer and setting its mode. -When OTHER is non-nil, open the file in another window. When -OTHER and SWITCH are both non-nil, switch to the other window. -FILE must be a relative or absolute path, with extension." - (let ((buffer (find-file-noselect file))) - (with-current-buffer buffer - (hack-local-variables) - (when deft-filter-regexp - (goto-char (point-min)) - (re-search-forward (deft-filter-regexp-as-regexp) nil t)) - ;; Ensure that Deft has been initialized - (when (not (get-buffer deft-buffer)) - (with-current-buffer (get-buffer-create deft-buffer) - (deft-mode))) - ;; Set up auto save hooks - (add-to-list 'deft-auto-save-buffers buffer) - (add-hook 'after-save-hook - (lambda () (save-excursion - (deft-cache-update-file buffer-file-name) - (deft-refresh-filter))) - nil t)) - (if other - (if switch - (switch-to-buffer-other-window buffer) - (display-buffer buffer other)) - (switch-to-buffer buffer)))) - -;;;###autoload -(defun deft-find-file (file) - "Find FILE interactively using the minibuffer. -FILE must exist and be a relative or absolute path, with extension. -If FILE is not inside `deft-directory', fall back to using `find-file'." - (interactive - (list (read-file-name "Deft find file: " deft-directory))) - (if (and (file-exists-p file) - (string-match (concat "^" (expand-file-name deft-directory)) file)) - (deft-open-file file) - (find-file file))) - -(defun deft-auto-populate-title-maybe (file) - "If the filter string is non-nil and `deft-use-filename-as-title' is `nil' -use the filter string to populate the title line in the newly created FILE." - (when (and deft-filter-regexp (not deft-use-filename-as-title)) - (write-region - (concat - (cond - ((and (> deft-markdown-mode-title-level 0) - (string-match "^\\(txt\\|text\\|md\\|mdown\\|markdown\\)" - deft-default-extension)) - (concat (make-string deft-markdown-mode-title-level ?#) " ")) - ((and deft-org-mode-title-prefix - (string-equal deft-default-extension "org")) - "#+TITLE: ")) - (deft-whole-filter-regexp) - "\n\n") - nil file nil))) - -(defun deft-new-file-named (slug) - "Create a new file named SLUG. -SLUG is the short filename, without a path or a file extension. " - (interactive "sNew filename (without extension): ") - (let ((file (deft-absolute-filename slug))) - (if (file-exists-p file) - (message "Aborting, file already exists: %s" file) - (deft-auto-populate-title-maybe file) - (deft-cache-update-file file) - (deft-refresh-filter) - (deft-open-file file) - (with-current-buffer (get-file-buffer file) - (goto-char (point-max)))))) - -;;;###autoload -(defun deft-new-file () - "Create a new file quickly. -Use either an automatically generated filename or the filter string if non-nil -and `deft-use-filter-string-for-filename' is set. If the filter string is -non-nil and title is not from filename, use it as the title." - (interactive) - (let (slug) - (if (and deft-filter-regexp deft-use-filter-string-for-filename) - ;; If the filter string is non-emtpy and titles are taken from - ;; filenames is set, construct filename from filter string. - (setq slug (deft-whole-filter-regexp)) - ;; If the filter string is empty, or titles are taken from file - ;; contents, then use an automatically generated unique filename. - (setq slug (deft-unused-slug))) - (deft-new-file-named slug))) - -(defun deft-open-file-other-window (&optional arg) - "When the point is at a widget, open the file in the other window." - (interactive "P") - (let ((file (widget-get (widget-at) :tag))) - (when file - (deft-open-file file t arg)))) - -(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 (widget-get (widget-at) :tag)) - (deft-dir (file-name-as-directory deft-directory)) - new-filename old-name new-name) - (when old-filename - (setq old-name (deft-base-filename old-filename)) - (setq new-name (read-string - (concat "Rename " old-name " to (without extension): ") - old-name)) - (setq new-filename - (concat deft-dir new-name "." deft-default-extension)) - (rename-file old-filename new-filename) - (deft-update-visiting-buffers old-filename new-filename) - (deft-refresh)))) - -(defun deft-archive-file () - "Archive the file represented by the widget at the point. -If the point is not on a file widget, do nothing." - (interactive) - (let (old new name-ext) - (setq old (widget-get (widget-at) :tag)) - (when old - (setq name-ext (file-name-nondirectory old)) - (setq new (concat deft-archive-directory name-ext)) - (when (y-or-n-p (concat "Archive file " name-ext "? ")) - ;; if the filename already exists ask for a new name - (while (file-exists-p new) - (setq name-ext (read-string "File exists, choose a new name: " name-ext)) - (setq new (concat deft-archive-directory name-ext))) - (when (not (file-exists-p deft-archive-directory)) - (make-directory deft-archive-directory t)) - (rename-file old new) - (deft-update-visiting-buffers old new) - (deft-refresh))))) - -;; File list filtering - -(defun deft-sort-files-by-mtime (files) - "Sort FILES in reverse order by modified time." - (sort files (lambda (f1 f2) (deft-file-newer-p f1 f2)))) - -(defun deft-sort-files-by-title (files) - "Sort FILES by title. Case is ignored" - (sort files (lambda (f1 f2) (deft-file-title-lessp f1 f2)))) - -(defun deft-sort-files (files) - "Sort FILES by sort methods selected by -`deft-current-sort-method'." - (funcall (if (eq deft-current-sort-method 'title) - 'deft-sort-files-by-title - 'deft-sort-files-by-mtime) files)) - -(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-match-file (file &optional batch) - "Return FILE if FILE matches the current filter regexp." - (with-temp-buffer - (insert file) - (let ((title (deft-file-title file)) - (contents (deft-file-contents file))) - (when title (insert title)) - (when contents (insert contents))) - (if batch - (if (every (lambda (filter) - (goto-char (point-min)) - (deft-search-forward filter)) - deft-filter-regexp) - file) - (goto-char (point-min)) - (if (deft-search-forward (car deft-filter-regexp)) - file)))) - -(defun deft-filter-files (files) - "Update `deft-current-files' given a list of paths, FILES. -Apply `deft-filter-match-file' to `deft-all-files', handling -any errors that occur." - (delq nil - (condition-case nil - ;; Map `deft-filter-match-file' onto FILES. Return - ;; filtered files list and clear error flag if no error. - (progn - (setq deft-regexp-error nil) - (mapcar (lambda (file) (deft-filter-match-file file t)) files)) - ;; Upon an error (`invalid-regexp'), set an error flag - (error - (progn - (setq deft-regexp-error t) - files))))) - -(defun deft-filter-update () - "Update the filtered files list using the current filter regexp. -Starts from scratch using `deft-all-files'. Does not refresh the -Deft buffer." - (if (not deft-filter-regexp) - (setq deft-current-files deft-all-files) - (setq deft-current-files - (deft-filter-files deft-all-files)))) - -;; 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 &optional reset) - "Update the filter with STR and update the file browser. - -In incremental search mode, the car of `deft-filter-regexp' will -be replaced with STR. If STR has zero length and the length of -the list is greater than one, the empty string will be retained -to simulate whitespace. However, if STR has zero length and the -list is of length one, then the filter will be cleared. If STR -is nil, then the car is removed from the list. - -In regexp search mode, the current filter string will be replaced -with STR. - -When called interactively, or when RESET is non-nil, always -replace the entire filter string." - (interactive - (list (read-from-minibuffer "Filter: " (deft-whole-filter-regexp) - nil nil 'deft-filter-history))) - (if deft-incremental-search - ;; Incremental search mode - (if (or (called-interactively-p 'any) reset) - ;; Called interactively or RESET non-nil - (if (= (length str) 0) - (setq deft-filter-regexp nil) - (setq deft-filter-regexp (reverse (split-string str " ")))) - ;; Called noninteractively - (if (not str) - ;; If str is nil, remove it and filter with the cdr - (setq deft-filter-regexp (cdr deft-filter-regexp)) - ;; Use STR it as the new car, even when empty (to simulate - ;; whitespace), unless this is the only element in the list. - (if (and (= (length deft-filter-regexp) 1) - (= (length str) 0)) - (setq deft-filter-regexp nil) - (setcar deft-filter-regexp str)))) - ;; Regexp search mode - (if (> (length str) 0) - (setq deft-filter-regexp (list str)) - (setq deft-filter-regexp nil))) - (deft-filter-update) - (deft-refresh-browser)) - -(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)) - (if (and deft-incremental-search (string= char " ")) - (setq deft-filter-regexp (cons "" deft-filter-regexp)) - (progn - (if (car deft-filter-regexp) - (setcar deft-filter-regexp (concat (car deft-filter-regexp) char)) - (setq deft-filter-regexp (list char))) - (setq deft-current-files (deft-filter-files deft-current-files)) - (setq deft-current-files (delq nil deft-current-files)) - (deft-refresh-browser))))) - -(defun deft-filter-decrement () - "Remove last character from the filter, if possible, and update. - -In incremental search mode, the elements of `deft-filter-regexp' -are the words of the filter string in reverse order. In regexp -search mode, the list is a single element containing the entire -filter regexp. Therefore, in both cases, only the car of -`deft-filter-regexp' is modified." - (interactive) - (let ((str (car deft-filter-regexp))) - (deft-filter - (if (> (length str) 0) - ;; If the last string element has at least one character, - ;; simply remove the last character. - (substring str 0 -1) - ;; Otherwise, return nil - nil)))) - -(defun deft-filter-decrement-word () - "Remove last word from the filter, if possible, and update." - (interactive) - (deft-filter - (if deft-incremental-search - ;; In incremental search mode, remove the car - nil - ;; In regexp search mode, remove last "word" component - ;(replace-regexp-in-string "[[:space:]\n]*$" "" s) - (let ((str (car deft-filter-regexp))) - (if (> (length str) 0) - (with-temp-buffer - (insert (concat "\"" str "\"")) - (lisp-interaction-mode) - (goto-char (- (point-max) 1)) - (backward-word 1) - (buffer-substring 2 (point))) - nil))))) - -(defun deft-filter-yank () - "Append the most recently killed or yanked text to the filter." - (interactive) - (deft-filter - (concat (deft-whole-filter-regexp) (current-kill 0 t)) t)) - -(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 (buffer-name 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)) - -;; Deft mode is suitable only for specially-prepared text -(put 'deft-mode 'mode-class 'special) - -(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}." - (message "Deft initializing...") - (kill-all-local-variables) - (setq truncate-lines t) - (setq buffer-read-only t) - (setq default-directory (expand-file-name deft-directory)) - - ;; Visual line mode causes lines to wrap, so turn it off. - (when (fboundp 'visual-line-mode) - (visual-line-mode 0)) - - ;; Backwards compatibility with deft-extension - (when (boundp 'deft-extension) - (setq deft-extensions (cons deft-extension '()))) - - (setq deft-default-extension (car deft-extensions)) - (use-local-map deft-mode-map) - (deft-cache-initialize) - (deft-cache-update-all) - (deft-filter-initialize) - (setq major-mode 'deft-mode) - (deft-set-mode-name) - (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) - (message "Deft loaded %d files." (length deft-all-files))) - -(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) - -;; Local Variables: -;; byte-compile-warnings: (not cl-functions) -;; End: - -;;; deft.el ends here diff --git a/contrib/helm-deft.el b/contrib/helm-deft.el deleted file mode 100644 index b4ac332de..000000000 --- a/contrib/helm-deft.el +++ /dev/null @@ -1,162 +0,0 @@ -;;; helm-deft.el --- helm module for grepping note files over directories - -;; Copyright (C) 2014 Derek Feichtinger - -;; Author: Derek Feichtinger -;; Keywords: convenience -;; Homepage: https://github.com/dfeich/helm-deft -;; Version: TODO -;; Package-Requires: ((helm "1.7.7") (f "0.17.0") (cl-lib "0.5")) - -;; This file is not part of GNU Emacs. - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Code: - -(require 'helm) -(require 'helm-grep) -(require 'helm-files) -(require 'f) -(require 'cl-lib) - -(defgroup helm-deft nil - "customization group for the helm-deft utility" :group 'helm :version 24.3) - -(defcustom helm-deft-dir-list - '("~/Documents") - "list of directories in which to search recursively for candidate files" - :group 'helm-deft - ) - -(defcustom helm-deft-extension "org" - "defines file extension for identifying candidate files to be searched for") - -(defvar helm-deft-file-list "" - "variable to store the list of candidate files") - -(defvar helm-source-deft-fn - '((name . "File Names") - (init . (lambda () - (progn (setq helm-deft-file-list (helm-deft-fname-search)) - (with-current-buffer (helm-candidate-buffer 'local) - (insert (mapconcat 'identity - helm-deft-file-list "\n")))))) - (candidates-in-buffer) - ;; matching is done in the buffer when candidates-in-buffer is used - ;; We only want against the basename and not the full path - (match-part . (lambda (c) (helm-basename c))) - (type . file) - ;; Note: We override the transformer that the file type brings. We - ;; want the file list sorted - (candidate-transformer . (lambda (c) (sort (helm-highlight-files c) - (lambda (a b) - (string< (downcase (car a)) - (downcase (car b))))))) - ;; (action . (("open file" . (lambda (candidate) - ;; (find-file candidate))))) - ;;(persistent-help . "show name") - ) - "Source definition for matching filenames of the `helm-deft' utility") - -(defvar helm-source-deft-filegrep - '((name . "File Contents") - (candidates-process . helm-deft-fgrep-search) - ;; We use the action from the helm-grep module - (action . helm-grep-action) - (requires-pattern) - (filter-one-by-one . helm-grep-filter-one-by-one) - (cleanup . (lambda () (when (get-buffer "*helm-deft-proc*") - (let ((kill-buffer-query-functions nil)) - (kill-buffer "*helm-deft-proc*"))))) - ) - "Source definition for matching against file contents for the - `helm-deft' utility") - -(defun helm-deft-rotate-searchkeys () - "rotate the words of the search pattern in the helm minibuffer" - (interactive) - (helm-log "Executing helm-deft-rotate-searchkeys") - (let ((patlst (split-string helm-pattern " *"))) - (when (and (>= (length patlst) 1) - (> (length (car patlst)) 0)) - (delete-minibuffer-contents) - (insert (mapconcat #'identity - (append (cdr patlst) (list (car patlst))) - " ")) - (helm-update))) - ) - -(defvar helm-deft-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map helm-map) - (define-key map (kbd "C-r") 'helm-deft-rotate-searchkeys) - (delq nil map)) - "helm keymap used for helm deft sources") - -(defun helm-deft-fname-search () - "search all preconfigured directories for matching files and return the -filenames as a list" - (cl-assert helm-deft-extension nil "No file extension defined for helm-deft") - (cl-assert helm-deft-dir-list nil "No directories defined for helm-deft") - (cl-loop for dir in helm-deft-dir-list - do (cl-assert (file-exists-p dir) nil - (format "Directory %s does not exist. Check helm-deft-dir-list" dir)) - collect (f--files dir (equal (f-ext it) helm-deft-extension) t) - into reslst - finally (return (apply #'append reslst))) - ) - -(defun helm-deft-build-cmd (ptrnstr filelst) - "Builds a grep command where PTRNSTR may contain multiple search patterns -separated by spaces. The first pattern will be used to retrieve matching lines. -All other patterns will be used to pre-select files with matching lines. -FILELST is a list of file paths" - (let* ((ptrnlst (remove "" (reverse (split-string ptrnstr " *")))) - (firstp (pop ptrnlst)) - (filelst (mapconcat 'identity filelst " ")) - (innercmd (if ptrnlst - (cl-labels ((build-inner-cmd - (ptrnlst filelst) - (let ((pattern (pop ptrnlst))) - (if ptrnlst - (format "$(grep -Elie \"%s\" %s)" pattern - (build-inner-cmd ptrnlst filelst)) - (format "$(grep -Elie \"%s\" %s)" - pattern filelst))))) - (build-inner-cmd ptrnlst filelst)) - filelst))) - (format "grep -EHine \"%s\" %s" firstp innercmd)) - ) - -(defun helm-deft-fgrep-search () - "greps for the helm search pattern in the configuration defined -file list" - (let* ((shcmd (helm-deft-build-cmd helm-pattern helm-deft-file-list))) - (helm-log "grep command: %s" shcmd) - (start-process-shell-command "helm-deft-proc" "*helm-deft-proc*" - shcmd)) - ) - -;;;###autoload -(defun helm-deft () - "Preconfigured `helm' module for locating note files where either the -filename or the file contents match the query string. Inspired by the -emacs `deft' extension" - (interactive) - (helm :sources '(helm-source-deft-fn helm-source-deft-filegrep) - :keymap helm-deft-map)) - -(provide 'helm-deft) -;;; helm-deft.el ends here diff --git a/contrib/ob-rust.el b/contrib/ob-rust.el deleted file mode 100644 index d0bad3e07..000000000 --- a/contrib/ob-rust.el +++ /dev/null @@ -1,207 +0,0 @@ -;;; ob-rust.el --- org-babel functions for rust - -;; Author: Philip Munksgaard -;; Keywords: literate programming, reproducible research -;; Homepage: http://orgmode.org - -;;; Commentary: - -;; Org-Babel support for evaluating rust code. -;; -;; This is simply an adaptation of ob-C.el that instead targets rust code. -;; Thanks to the original creators Eric Schulte and Thierry Banel -;; -;; Very limited implementation: -;; - currently only support :results output -;; - not much in the way of error feedback - -;;; Code: -(eval-when-compile - (require 'cl)) -(require 'ob) -(require 'cc-mode) - -(declare-function org-entry-get "org" - (pom property &optional inherit literal-nil)) - - -(defvar org-babel-tangle-lang-exts) -(add-to-list 'org-babel-tangle-lang-exts '("rust")) - -(defvar org-babel-default-header-args:rust '()) - -(defvar org-babel-rust-compiler "rustc" - "Command used to compile a rust source code file into an -executable.") - -(defun org-babel-expand-body:rust (body params) - (org-babel-rust-expand body params)) - -(defun org-babel-execute:rust (body params) - "Execute a block of rust code with org-babel. -This function is called by `org-babel-execute-src-block'." - (print body) - (princ params) - (let* ((tmp-src-file (org-babel-temp-file - "rust-src-" - ".rs")) - (tmp-bin-file (org-babel-temp-file "rust-bin-" org-babel-exeext)) - (cmdline (cdr (assoc :cmdline params))) - (flags (cdr (assoc :flags params))) - (full-body (org-babel-rust-expand body params)) - (compile - (progn - (with-temp-file tmp-src-file (insert full-body)) - (org-babel-eval - (format "%s -o %s %s %s" - org-babel-rust-compiler - (org-babel-process-file-name tmp-bin-file) - (mapconcat 'identity - (if (listp flags) flags (list flags)) " ") - (org-babel-process-file-name tmp-src-file)) "")))) - (let ((results - (org-babel-trim - (org-babel-eval - (concat tmp-bin-file (if cmdline (concat " " cmdline) "")) "")))) - (org-babel-reassemble-table - (org-babel-result-cond (cdr (assoc :result-params params)) - (org-babel-read results) - (let ((tmp-file (org-babel-temp-file "rust-"))) - (with-temp-file tmp-file (insert results)) - (org-babel-import-elisp-from-file tmp-file))) - (org-babel-pick-name - (cdr (assoc :colname-names params)) (cdr (assoc :colnames params))) - (org-babel-pick-name - (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params))))) - )) - -(defun org-babel-rust-expand (body params) - "Expand a block of rust code with org-babel." - (print params) - (print body) - (let ((vars (mapcar #'cdr (org-babel-get-header params :var))) - (main-p (not (string= (cdr (assoc :main params)) "no"))) - (uses (or (cdr (assoc :uses params)) - (org-babel-read (org-entry-get nil "uses" t)))) - (externs (org-babel-read - (or (cdr (assoc :externs params)) - (org-babel-read (org-entry-get nil "externs" t))))) - (attributes (org-babel-read - (or (cdr (assoc :attributes params)) - (org-babel-read (org-entry-get nil "attributes" t)))))) - (mapconcat 'identity - (list - ;; attributes - (mapconcat - (lambda (attr) (format "#[%s]" attr)) - (if (listp attributes) attributes (list attributes)) "\n") - ;; externs - (mapconcat - (lambda (ext) (format "extern crate %s;" ext)) - (if (listp externs) externs (list externs)) "\n") - ;; uses - (mapconcat - (lambda (use) (format "use %s;" use)) - (if (listp uses) uses (list uses)) "\n") - ;; variables - (mapconcat 'org-babel-rust-var-to-rust vars "\n") - ;; body - (if main-p - (org-babel-rust-ensure-main-wrap body) - body) "\n") "\n"))) - -(defun org-babel-rust-ensure-main-wrap (body) - "Wrap BODY in a \"main\" function call if none exists." - (if (string-match "[ \t]*fn+[ \t\n\r]*main[ \t]*(.*)" body) - body - (format "fn main() {\n%s\n}\n" body))) - -(defun org-babel-prep-session:rust (session params) - "This function does nothing as rust is a compiled language with no -support for sessions" - (error "rust is a compiled languages -- no support for sessions")) - -(defun org-babel-load-session:rust (session body params) - "This function does nothing as rust is a compiled language with no -support for sessions" - (error "rust is a compiled languages -- no support for sessions")) - -;; helper functions - -(defun org-babel-rust-format-val (type val) - "Handle the FORMAT part of TYPE with the data from VAL." - (let ((format-data (cadr type))) - (if (stringp format-data) - (cons "" (format format-data val)) - (funcall format-data val)))) - -(defun org-babel-rust-val-to-rust-type (val) - "Determine the type of VAL. -Return a list (TYPE-NAME FORMAT). TYPE-NAME should be the name of the type. -FORMAT can be either a format string or a function which is called with VAL." - (cond - ((integerp val) '("int" "%d")) - ((floatp val) '("f64" "%f")) - ((or (listp val) (vectorp val)) - (lexical-let ((type (org-babel-rust-val-to-rust-list-type val))) - (list (concat "&'static [" (car type) "]") - (lambda (val) - (cons - (format "[%d]%s" - (length val) - (car (org-babel-rust-format-val type (elt val 0)))) - (concat "&[" - (mapconcat (lambda (v) - (cdr (org-babel-rust-format-val type v))) - val - ", ") - "]")))))) - (t ;; treat unknown types as string - '("&'static str" (lambda (val) - (let ((s (format "%s" val))) ;; convert to string for unknown types - (cons (format "[%d]" (1+ (length s))) - (concat "\"" s "\"")))))))) - -(defun org-babel-rust-val-to-rust-list-type (val) - "Determine the rust array type of a VAL." - (let (type) - (mapc - #'(lambda (i) - (let* ((tmp-type (org-babel-rust-val-to-rust-type i)) - (type-name (car type)) - (tmp-type-name (car tmp-type))) - (when (and type (not (string= type-name tmp-type-name))) - (if (and (member type-name '("int" "f64")) - (member tmp-type-name '("int" "f64"))) - (setq tmp-type '("f64" "" "%f")) - (error "Only homogeneous lists are supported by rust. You can not mix %s and %s" - type-name - tmp-type-name))) - (setq type tmp-type))) - val) - type)) - -(defun org-babel-rust-var-to-rust (pair) - "Convert an elisp val into a string of rust code specifying a var -of the same value." - ;; TODO list support - (let ((var (car pair)) - (val (cdr pair))) - (when (symbolp val) - (setq val (symbol-name val)) - (when (= (length val) 1) - (setq val (string-to-char val)))) - (let* ((type-data (org-babel-rust-val-to-rust-type val)) - (type (car type-data)) - (formated (org-babel-rust-format-val type-data val)) - ;; (suffix (car formated)) - (data (cdr formated))) - (format "static %s: %s = %s;" - var - type - ;suffix - data)))) - -(provide 'ob-rust) - -;;; ob-rust.el ends here diff --git a/contrib/rotate-text.el b/contrib/rotate-text.el deleted file mode 100644 index 4676388ba..000000000 --- a/contrib/rotate-text.el +++ /dev/null @@ -1,92 +0,0 @@ -;; From - -(provide 'rotate-text) - -(defvar rotate-text-rotations - '(("true" "false") - ("True" "False") - ("yes" "no") - ("t" "nil") - ("left" "right" "top" "bottom") - ("width" "height"))) - -;;;###autoload -(defun rotate-region (beg end) - "Rotate all matches in `rotate-text-rotations' between point and mark." - (interactive "r") - (let ((regexp (rotate-convert-rotations-to-regexp - rotate-text-rotations)) - (end-mark (copy-marker end))) - (save-excursion - (goto-char beg) - (while (re-search-forward regexp (marker-position end-mark) t) - (let* ((found (match-string 0)) - (replace (rotate-next found))) - (replace-match replace)))))) - -(defun rotate-string (string &optional rotations) - "Rotate all matches in STRING using associations in ROTATIONS. -If ROTATIONS are not given it defaults to `rotate-text-rotations'." - (let ((regexp (rotate-convert-rotations-to-regexp - (or rotations rotate-text-rotations))) - (start 0)) - (while (string-match regexp string start) - (let* ((found (match-string 0 string)) - (replace (rotate-next - found - (or rotations rotate-text-rotations)))) - (setq start (+ (match-end 0) - (- (length replace) (length found)))) - (setq string (replace-match replace nil t string)))) - string)) - -(defun rotate-next (string &optional rotations) - "Return the next element after STRING in ROTATIONS." - (let ((rots (rotate-get-rotations-for - string - (or rotations rotate-text-rotations)))) - (if (> (length rots) 1) - (error (format "Ambiguous rotation for %s" string)) - (if (< (length rots) 1) - ;; If we get this far, this should not occur: - (error (format "Unknown rotation for %s" string)) - (let ((occurs-in-rots (member string (car rots)))) - (if (null occurs-in-rots) - ;; If we get this far, this should *never* occur: - (error (format "Unknown rotation for %s" string)) - (if (null (cdr occurs-in-rots)) - (caar rots) - (cadr occurs-in-rots)))))))) - -(defun rotate-get-rotations-for (string &optional rotations) - "Return the string rotations for STRING in ROTATIONS." - (remq nil (mapcar (lambda (rot) (if (member string rot) rot)) - (or rotations rotate-text-rotations)))) - -(defun rotate-convert-rotations-to-regexp (rotations) - (regexp-opt (rotate-flatten-list rotations))) - -(defun rotate-flatten-list (list-of-lists) - "Flatten LIST-OF-LISTS to a single list. -Example: - (rotate-flatten-list '((a b c) (1 ((2 3))))) - => (a b c 1 2 3)" - (if (null list-of-lists) - list-of-lists - (if (listp list-of-lists) - (append (rotate-flatten-list (car list-of-lists)) - (rotate-flatten-list (cdr list-of-lists))) - (list list-of-lists)))) - -;;;###autoload -(defun rotate-word-at-point () - "Rotate word at point based on sets in `rotate-text-rotations'." - (interactive) - (let ((bounds (bounds-of-thing-at-point 'word)) - (opoint (point))) - (when (consp bounds) - (let ((beg (car bounds)) - (end (copy-marker (cdr bounds)))) - (rotate-region beg end) - (goto-char (if (> opoint end) end opoint)))))) -