aboutsummaryrefslogtreecommitdiffstats
path: root/kaarvok.el
diff options
context:
space:
mode:
Diffstat (limited to 'kaarvok.el')
-rw-r--r--kaarvok.el137
1 files changed, 137 insertions, 0 deletions
diff --git a/kaarvok.el b/kaarvok.el
new file mode 100644
index 0000000..40be88a
--- /dev/null
+++ b/kaarvok.el
@@ -0,0 +1,137 @@
+;;; kaarvok --- Generate directory structures from templates
+
+;; Copyright (C) 2013 Tom Willemse
+
+;; Author: Tom Willemse <tom@ryuslash.org>
+;; Keywords: convenience
+;; Package-Version: 0.1.0
+
+;; This file is part of kaarvok.
+
+;; kaarvok 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 of the License, or
+;; (at your option) any later version.
+
+;; kaarvok 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 kaarvok. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This project helps you recreate directory structures from template
+;; directory structures. The files, file names and directory names of
+;; these templates contain variable placeholders, which will be
+;; replaced by whatever value you wish to use when copied.
+
+;;; Code:
+
+(defvar kaarvok-templates-directory "~/.emacs.d/templates"
+ "Where templates are stored.")
+
+(defvar kaarvok-template-var-delimiter "$!"
+ "Strings used to delimit variable names.")
+
+(defun kaarvok-template-var-regexp ()
+ "Create the regexp which identifies a variable in a template."
+ (concat kaarvok-template-var-delimiter
+ "\\([^" kaarvok-template-var-delimiter " \t\n]+\\)"
+ kaarvok-template-var-delimiter))
+
+(defvar kaarvok-value-alist nil
+ "A placeholder where replacement values will be kept.
+
+This is let-bound when `kaarvok-create-project-from-template' is
+called and should not be edited directly.")
+
+(defun kaarvok-replace-all (from to str)
+ "Simply replace all occurrences of FROM with TO in STR."
+ (while (string-match from str)
+ (set 'str (replace-match to t t str)))
+ str)
+
+(defun kaarvok-get-replacement (key)
+ "Find, or ask for and save, the replacement value for KEY."
+ (let ((replacement (assoc key kaarvok-value-alist)))
+ (when (eq replacement nil)
+ (set 'replacement
+ `(,key . ,(read-from-minibuffer (concat key ": "))))
+ (add-to-list 'kaarvok-value-alist replacement))
+ replacement))
+
+(defun kaarvok-parse-file-name (filename)
+ "Parse FILENAME and replace all variables.
+
+Use values provided by the user."
+ (while (string-match (kaarvok-template-var-regexp) filename)
+ (let* ((tpl-var (match-string 1 filename))
+ (replacement-value (kaarvok-get-replacement tpl-var)))
+ (set 'filename (replace-match (cdr replacement-value) t t
+ filename))))
+
+ (let ((noext (file-name-sans-extension filename))
+ (ext (file-name-extension filename t)))
+ (set 'noext (kaarvok-replace-all "\\." "/" noext))
+ (concat noext ext)))
+
+(defun kaarvok-parse-file (file)
+ "Parse FILE and replace all variables."
+ (insert-file-contents file)
+
+ (while (re-search-forward (kaarvok-template-var-regexp) nil t)
+ (let* ((tpl-var (match-string 1))
+ (replacement-value (kaarvok-get-replacement tpl-var)))
+ (replace-match (cdr replacement-value) t t))))
+
+(defun kaarvok-parse-and-copy-file (src dst)
+ "Copy SRC to DST.
+
+If necessary, parse the file and filename first."
+ (let* ((parsed-dst (kaarvok-parse-file-name dst))
+ (parsed-dst-dir (file-name-directory parsed-dst)))
+ (when (not (file-exists-p parsed-dst-dir))
+ (make-directory parsed-dst-dir t))
+
+ (with-temp-file parsed-dst
+ (kaarvok-parse-file src))))
+
+(defun kaarvok-copy-directory (directory to)
+ "Copy template DIRECTORY to TO.
+
+Parse both paths and files in the process."
+ (let ((files (directory-files directory t "[^.]\\{1,2\\}$" t)))
+ (while files
+ (let* ((src-filename (car files))
+ (dst-filename
+ (concat to "/" (file-name-nondirectory src-filename))))
+ (if (file-directory-p src-filename)
+ (kaarvok-copy-directory src-filename dst-filename)
+ (if (string-equal (file-name-extension src-filename) "etpl")
+ (kaarvok-parse-and-copy-file
+ src-filename (file-name-sans-extension dst-filename))
+ (if (not (file-exists-p to))
+ (make-directory to t)
+ (unless (file-directory-p to)
+ (error
+ (concat "Cannot create project at %s, file "
+ "already exists and is not a directory.") to)))
+
+ (copy-file src-filename dst-filename))))
+ (set 'files (cdr files)))))
+
+;;;###autoload
+(defun kaarvok-create-project-from-template (template destination)
+ "Take TEMPLATE, copy it to DESTINATION.
+
+Replace any occurrences of variables with user-povided values."
+ (interactive "MTemplate: \nGDestination: ")
+ (let ((kaarvok-value-alist))
+ (kaarvok-copy-directory
+ (concat kaarvok-templates-directory "/" template) destination)))
+
+(provide 'kaarvok)
+;;; kaarvok.el ends here