Created
June 22, 2012 04:13
-
-
Save matthew-ball/2970172 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; FILE: /home/chu/Programming/lisp/elisp/ref-man/org-ref-man.el | |
;; AUTHOR: Matthew Ball (copyleft 2012) | |
;; TIME: Fri 25 May 2012 02:46:58 EST | |
;;; COMMENT: | |
;; Welcome to `org-ref-man', a reference manager for GNU Emacs utilising the functionality of `org-mode'. | |
;; The project's goals state: | |
;; 1. Creates and manages a database of source material. | |
;; 2. Interact with this database with emacs-lisp. | |
;; 3. Creates an `org-mode' buffer with the information read from the database. | |
;; 4. Writes information to the database created from the corresponding `org-mode' buffer. | |
;; TODO: | |
;; 1. Populate database. | |
;; 2. Write parser to read from `org-table' entries. | |
(require 'ref-man-db) | |
(require 'org-table) | |
(eval-when-compile (require 'cl)) | |
;; COMMENT: custom variables | |
(defcustom ref-man-directory (expand-file-name "~/Documents/Papers/PDFs/") | |
"`ref-man' main directory; for storing/locating reference material." | |
:type 'directory :safe 'stringp :group 'ref-man) | |
(defcustom ref-man-extension "pdf" ;; TODO: should make this a list | |
"`ref-man' file extension." | |
:type 'string :safe 'stringp :group 'ref-man) | |
;; COMMENT: constants | |
(defconst ref-man-version "0.3" "Version of the system's `ref-man' install.") | |
(defconst ref-man-mode-name "org-ref-man" "The `ref-man' mode name.") | |
(defconst ref-man-buffer-name (concat "*" ref-man-mode-name "*") "The `ref-man' buffer name.") | |
(defconst ref-man-column-length 20 "Column length for `ref-man'.") | |
;; COMMENT: variables | |
(defvar ref-man-mode-hook nil "Run hook when entering `ref-man' mode.") | |
(defvar ref-man-files nil "List of files.") | |
(defvar ref-man-filter-regexp nil "Current filter regexp used by `ref-man' mode.") ;; NOTE: should be able to filter `tags' | |
;; COMMENT: functions | |
(defun ref-man-reset-files () | |
"Reset the `ref-man-files' list." | |
(setq ref-man-files nil)) | |
(defun ref-man-find-files () | |
"Return a list of all files in the `ref-man-directory' directory which matches the `ref-man-extension' extension." | |
(if (file-exists-p ref-man-directory) | |
(let (files result) | |
(setq files (directory-files ref-man-directory t (concat "\." ref-man-extension "$") t)) | |
(dolist (file-name files) | |
(when (and (file-readable-p file-name) (not (file-directory-p file-name))) | |
(setq result (cons file-name result)))) | |
result))) | |
(defun ref-man-buffer-setup () | |
"Render the file browser in the `*ref-man*' buffer." | |
(if (y-or-n-p "Scan `ref-man-directory' location?") | |
(setq ref-man-files (ref-man-find-files)) ;; NOTE: find files | |
(setq ref-man-files (ref-man-load-database)) ;; NOTE: load database | |
) | |
;;(ref-man-populate-database) | |
(ref-man-read-from-database) | |
(if (not (file-exists-p ref-man-directory)) | |
(insert (concat "ERROR: Directory " ref-man-directory " does not exist.")) | |
(if ref-man-files | |
(progn | |
(insert "|----------------------------------------+----------+--------|\n") | |
(insert "| *Title* | *Author* | *Year* |\n") | |
(insert "|----------------------------------------+----------+--------|\n") | |
;; TODO: need to write a mini-parser to remove the cruft from the list | |
(dolist (entry ref-man-files) | |
(insert | |
(concat "| [[" (plist-get entry :file) "][" (plist-get entry :title) "]] | " | |
(plist-get entry :author) " | " | |
(plist-get entry :year) " |")) | |
(insert "\n")) | |
(insert "|----------------------------------------+----------+--------|\n\n") | |
(insert "* Bibliography Information\n")) | |
(insert (concat "ERROR: No files were loaded.")) | |
))) | |
;; NOTE: this is redundant | |
;; (defun ref-man-populate-database () | |
;; "Populate the `ref-man' database with the contents of the `ref-man-files' variable." | |
;; (dolist (entry ref-man-files) | |
;; ;; TODO: write a "mini-parser" | |
;; (ref-man-create-record | |
;; (plist-get entry :file) | |
;; (plist-get entry :title) | |
;; (plist-get entry :author) | |
;; (plist-get entry :type) | |
;; (plist-get entry :year) | |
;; (plist-get entry :tags)))) | |
(defun ref-man-read-from-database () | |
"..." | |
(dolist (record ref-man-record-database) ;; NOTE: loop through the records of the (external) `ref-man-db' database | |
(add-to-list 'ref-man-files record) ;; NOTE: ... add the record to the (internal) `ref-man' database | |
)) | |
;; TODO: this could probably be moved into the `org-config.el' file | |
(defun my-org-extract-link () | |
"Extract the link location at point and put it on the killring." | |
(interactive) | |
(save-excursion | |
;; TODO: capture `file-name' details | |
;; TODO: capture `title' details | |
(when (org-in-regexp org-bracket-link-regexp 1) | |
(let ((record-file (org-link-unescape (org-match-string-no-properties 1))) | |
(record-title (org-link-unescape (org-match-string-no-properties 3)))) | |
(message (concat "File: " record-file ", Title: " record-title)))))) | |
(defun ref-man-save-to-database () ;; TODO: this function is very close to working | |
"Read a list structure from the `org-table' entries. | |
NOTE: This function needs to manipulate the contents of the `org-table' - namely, it removes the first three entries (headings) and any `hline' entries. | |
The function `org-table-to-lisp' extracts /exactly/ the contents of the table. Since there is a different structure to the database file, this attempts to clean things up, extracting the necessary data." | |
(let ((list-data (org-table-to-lisp)) | |
(save-file-list '())) | |
(setq list-data (cdr (cdr (cdr list-data)))) ;; NOTE: remove the hline, headings and hline | |
(dolist (record list-data) ;; NOTE: go through the `list-data' list and add each element to `save-file-list' | |
(when (not (eq record 'hline)) ;; NOTE: remove the final hline | |
;; NOTE: the following is really hackish | |
(let ((record-file (car record)) | |
(record-title nil) | |
(record-author (car (cdr record))) | |
(record-year (car (cdr (cdr record))))) | |
(with-temp-buffer | |
(switch-to-buffer "ref-man-save-file-list") | |
(print (concat "(:file " record-file | |
" :title " record-title | |
" :author " record-author | |
" :year " record-year ")\n") | |
(current-buffer)))) | |
(add-to-list 'save-file-list record))) | |
;; TODO: manipulate `save-file-list' data structure | |
;; It's currently in the form: | |
;; ("[[file-name][title]]" "author" "year") | |
;; ... and needs to be ... | |
;; (:file "file-name" :title "title" :author "author" :year "year") | |
;; (insert (replace-regexp "\"[[file-name][title]]\"" ":file file-name :title title")) | |
;; sed -i 's/"\[\[\([^\]]*\)][\([^\]]*\)\]" "\([^"]*\)" "\([^"]*\)"/:file "\1" :title "\2"/' :author "\3" :year "\4"/' | |
;; DEBUG: saving the database ... | |
(with-temp-buffer | |
(switch-to-buffer "ref-man-test") | |
(print save-file-list (current-buffer)) | |
;; (replace-regexp "[[*][*]]" ":file :title") ;; FIX: doesn't work | |
) | |
;; (ref-man-save-database list-data) ;; NOTE: save the contents of the `org-table' | |
;; (ref-man-save-database ref-man-files) ;; NOTE: save the `ref-man-files' list | |
)) | |
(defun ref-man-parse-table (table-string &rest junk) | |
"Parse an `org-table' entry.") | |
;; COMMENT: commands | |
(defun ref-man-add-file (file &optional title author type notes) ;; TODO: ... | |
"Add a file to the `ref-man-files' database." | |
(interactive "f\nSelect file:")) | |
(defun ref-man-quit (&rest junk) | |
"Bury the `*ref-man*' buffer." | |
(interactive) | |
(setq ref-man-files nil) ;; NOTE: clear database | |
(when (string= (buffer-name) ref-man-buffer-name) | |
(kill-buffer)) | |
(delete-other-windows)) | |
(defun ref-man-show-version (&rest junk) | |
"Print the `ref-man' version number." | |
(interactive) | |
(message (concat "`ref-man' - Version: " ref-man-version))) | |
(defun ref-man-goto-file (&rest junk) ;; NOTE: this is a bit limiting, requires *all* files to be in the same main directory | |
"Follow filename in `*ref-man*' buffer." | |
(interactive) | |
(find-file (concat ref-man-directory (thing-at-point 'filename)))) | |
;; COMMENT: mode configuration | |
(defvar ref-man-mode-map | |
(let ((map (make-keymap))) | |
;; sorting | |
;; (define-key map (kbd "s") 'ref-man-sort-files) ;; sort by FILE or {AUTHOR, JOURNAL, YEAR, TAGS} ;; ERROR: this won't work | |
;; open file | |
(define-key map (kbd "RET") 'ref-man-goto-file) | |
;; file management | |
(define-key map (kbd "a") 'ref-man-add-file) | |
(define-key map (kbd "r") 'ref-man-remove-file) ;; TODO: rename to `ref-man-delete-file' | |
;; misc | |
(define-key map (kbd "g") 'ref-man-refresh) | |
(define-key map (kbd "q") 'ref-man-quit) | |
(define-key map (kbd "v") 'ref-man-show-version) | |
;; 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 `ref-man' major mode") | |
(defun ref-man-mode (&rest junk) | |
"Major mode for managing reference files in GNU Emacs." | |
(kill-all-local-variables) | |
(setq truncate-lines t) | |
(ref-man-buffer-setup) ;; NOTE: render `*ref-man*' buffer | |
(org-mode) | |
;; NOTE: the following ... | |
(beginning-of-buffer) | |
(next-line) | |
(org-cycle) | |
(beginning-of-buffer) | |
;; NOTE: ... is there just to set up the display (there is a better way) | |
(use-local-map ref-man-mode-map) | |
(toggle-read-only)) | |
(put 'ref-man-mode 'mode-class 'special) | |
;;;###autoload | |
(defun ref-man () | |
"Switch to `*ref-man*' buffer and start mode." | |
(interactive) | |
(save-excursion | |
(split-window-below) | |
(switch-to-buffer ref-man-buffer-name) | |
(when (not (eq major-mode 'ref-man-mode)) | |
(ref-man-mode)))) | |
(provide 'org-ref-man) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment