parent
f1130d19fe
commit
f1062c1a11
18 changed files with 1280 additions and 123 deletions
@ -0,0 +1 @@ |
||||
Subproject commit 6f360b3901edce0b4dbdfd1fdc15a99f78cbfc8a |
||||
@ -0,0 +1 @@ |
||||
Subproject commit 9725bd8bbf9109903d54cb0c850ab81a27d261c5 |
||||
@ -0,0 +1 @@ |
||||
Subproject commit 0ef000bac76abae30601222e6f06c7d133ab4942 |
||||
@ -1,96 +0,0 @@ |
||||
(load "auctex.el" nil t t) |
||||
(setq TeX-auto-save t |
||||
TeX-parse-self t |
||||
TeX-insert-braces nil) |
||||
(setq-default TeX-master nil) |
||||
(setq font-latex-fontify-script nil) |
||||
(setq LaTeX-equation-label "e_") |
||||
(setq LaTeX-section-label "s_") |
||||
(setq LaTeX-figure-label "f_") |
||||
(require 'reftex) |
||||
|
||||
(defun add-delimiter (delim-begin delim-end r-begin r-end) |
||||
"Add the pair of delimiters given in delim at the ends of the region if it is activated" |
||||
(interactive "cBegin delimiter: \ncEnd delimiter: \nr") |
||||
(if (use-region-p) |
||||
(progn |
||||
(save-excursion |
||||
(goto-char r-end) (insert delim-end) |
||||
(goto-char r-begin) (insert delim-begin))) |
||||
(progn |
||||
(save-excursion |
||||
(insert delim-end)) |
||||
(insert delim-begin)))) |
||||
|
||||
(add-hook 'LaTeX-mode-hook (lambda () |
||||
(turn-on-auto-fill) |
||||
(subword-mode) |
||||
;; Move around commands in the Right Way™ |
||||
(modify-syntax-entry ?\\ "w" LaTeX-mode-syntax-table) |
||||
(setq subword-forward-regexp "\\W*\\(\\([\\\\[:upper:]]*\\W?\\)[[:lower:][:digit:]]*\\)") |
||||
(setq subword-backward-regexp "\\(\\(\\W\\|[[:lower:][:digit:]]\\)\\([\\\\[:upper:]]+\\W*\\)\\|\\W\\w+\\)") |
||||
;; FIXME: this breaks sourcepair for other modes. |
||||
(setq sourcepair-source-extensions '(".tex")) |
||||
(setq sourcepair-header-extensions '(".p.tex")) |
||||
|
||||
(define-key LaTeX-mode-map (kbd "C-c C-v") |
||||
(lambda (arg) |
||||
(interactive "P") |
||||
(insert "~") |
||||
(if arg (TeX-insert-macro "eqref") |
||||
(TeX-insert-macro "ref")))) |
||||
(define-key LaTeX-mode-map (kbd "M-S-<return>") |
||||
(lambda (arg) |
||||
(interactive "P") |
||||
(if arg (LaTeX-insert-environment "align") |
||||
(LaTeX-insert-environment "align*")))) |
||||
|
||||
(define-key LaTeX-mode-map (kbd "S-SPC") (lambda() (interactive) (insert "\\"))) |
||||
(define-key LaTeX-mode-map (kbd "M-S-SPC") 'TeX-insert-braces) |
||||
(define-key LaTeX-mode-map (kbd "s-SPC") (lambda() (interactive) (insert "~"))) |
||||
(define-key LaTeX-mode-map (kbd "M-_") (lambda (r-begin r-end) (interactive "r") (add-delimiter "_{" "}" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "M-^") (lambda (r-begin r-end) (interactive "r") (add-delimiter "^{" "}" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "M-$") (lambda (r-begin r-end) (interactive "r") (add-delimiter "$" "$" r-begin r-end))) ;; This overlaps with the spell-checker; not that I ever remember that key |
||||
(define-key LaTeX-mode-map (kbd "C-c C-d") |
||||
(lambda (arg r-begin r-end) (interactive "P\nr") |
||||
(if arg |
||||
(add-delimiter "\\todo[inline]{" "}{}" r-begin r-end) |
||||
(add-delimiter "\\todo{" "}{}" r-begin r-end)))) |
||||
(define-key LaTeX-mode-map (kbd "C-c C-g") 'magit-status) |
||||
)) |
||||
|
||||
;; this reimplements TeX-insert-braces to work with negative argument |
||||
(defun TeX-insert-braces (arg) |
||||
"Make a pair of braces around next ARG sexps and leave point inside. |
||||
No argument is equivalent to zero: just insert braces and leave point |
||||
between. |
||||
|
||||
If there is an active region, ARG will be ignored, braces will be |
||||
inserted around the region, and point will be left after the |
||||
closing brace." |
||||
(interactive "P") |
||||
(if (TeX-active-mark) |
||||
(progn |
||||
(if (< (point) (mark)) |
||||
(exchange-point-and-mark)) |
||||
(insert TeX-grcl) |
||||
(save-excursion |
||||
(goto-char (mark)) |
||||
(insert TeX-grop))) |
||||
(if (and arg (< arg 0)) |
||||
(progn |
||||
(save-excursion |
||||
(backward-sexp (prefix-numeric-value (- 0 arg))) |
||||
(insert TeX-grop)) |
||||
(insert TeX-grcl)) |
||||
(insert TeX-grop) |
||||
(save-excursion |
||||
(if arg (forward-sexp (prefix-numeric-value arg))) |
||||
(insert TeX-grcl))))) |
||||
|
||||
(defun TeX-back-insert-braces (arg) |
||||
(interactive "P") |
||||
(if arg (TeX-insert-braces (- 0 arg)) |
||||
(insert TeX-grcl))) |
||||
|
||||
(load "latex-compile-filters.el") |
||||
@ -0,0 +1,5 @@ |
||||
(add-hook 'c-mode-hook 'linum-mode) |
||||
|
||||
(add-hook 'c++-mode-hook (lambda () |
||||
(linum-mode) |
||||
(subword-mode))) |
||||
@ -0,0 +1,5 @@ |
||||
(add-hook 'c-mode-hook 'linum-mode) |
||||
|
||||
(add-hook 'c++-mode-hook (lambda () |
||||
(linum-mode) |
||||
(subword-mode)) |
||||
@ -0,0 +1,149 @@ |
||||
(load "auctex.el" nil t t) |
||||
(setq TeX-auto-save t |
||||
TeX-parse-self t |
||||
TeX-insert-braces nil) |
||||
(setq-default TeX-master nil) |
||||
(setq font-latex-fontify-script nil) |
||||
(setq LaTeX-equation-label "e_") |
||||
(setq LaTeX-section-label "s_") |
||||
(setq LaTeX-figure-label "f_") |
||||
(setq TeX-fold-ellipsis " …") |
||||
(require 'reftex) |
||||
|
||||
(defun dabbrev-expand-helper () |
||||
(interactive) |
||||
(call-interactively 'dabbrev-expand)) |
||||
|
||||
|
||||
(defun add-delimiter (delim-begin delim-end r-begin r-end) |
||||
"Add the pair of delimiters given in delim at the ends of the region if it is activated" |
||||
(interactive "cBegin delimiter: \ncEnd delimiter: \nr") |
||||
(if (use-region-p) |
||||
(progn |
||||
(save-excursion |
||||
(goto-char r-end) (insert delim-end) |
||||
(goto-char r-begin) (insert delim-begin))) |
||||
(progn |
||||
(save-excursion |
||||
(insert delim-end)) |
||||
(insert delim-begin)))) |
||||
|
||||
(add-hook 'LaTeX-mode-hook (lambda () |
||||
(turn-on-auto-fill) |
||||
(subword-mode) |
||||
(TeX-fold-mode 1) |
||||
;; Move around commands in the Right Way™ |
||||
(modify-syntax-entry ?\\ "w" LaTeX-mode-syntax-table) |
||||
(setq subword-forward-regexp "\\W*\\(\\([\\\\[:upper:]]*\\W?\\)[[:lower:][:digit:]]*\\)") |
||||
(setq subword-backward-regexp "\\(\\(\\W\\|[[:lower:][:digit:]]\\)\\([\\\\[:upper:]]+\\W*\\)\\|\\W\\w+\\)") |
||||
;; ;; FIXME: this breaks sourcepair for other modes. |
||||
;; (setq sourcepair-source-extensions '(".tex")) |
||||
;; (setq sourcepair-header-extensions '(".p.tex")) |
||||
|
||||
(define-key LaTeX-mode-map (kbd "C-c C-v") |
||||
(lambda (arg) |
||||
(interactive "P") |
||||
(insert "~") |
||||
(if arg (TeX-insert-macro "eqref") |
||||
(TeX-insert-macro "ref")))) |
||||
(define-key LaTeX-mode-map (kbd "C-M-<return>") |
||||
(lambda (arg) |
||||
(interactive "P") |
||||
(if arg (LaTeX-insert-environment "align") |
||||
(LaTeX-insert-environment "align*")))) |
||||
|
||||
(define-key LaTeX-mode-map (kbd "S-SPC") (lambda() (interactive) (insert "\\"))) |
||||
(define-key LaTeX-mode-map (kbd "M-S-SPC") 'TeX-insert-braces) |
||||
(define-key LaTeX-mode-map (kbd "s-SPC") (lambda() (interactive) (insert "~"))) |
||||
(define-key LaTeX-mode-map (kbd "M-_") (lambda (r-begin r-end) (interactive "r") (add-delimiter "_{" "}" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "M-^") (lambda (r-begin r-end) (interactive "r") (add-delimiter "^{" "}" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "M-|") (lambda (r-begin r-end) (interactive "r") (add-delimiter "|" "|" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "M-$") (lambda (r-begin r-end) (interactive "r") (message "deprecated") (add-delimiter "$" "$" r-begin r-end))) ;; This overlaps with the spell-checker; not that I ever remember that key |
||||
|
||||
;; This is the rationale: C-M-SPC starts inline math C-M-RET starts display math |
||||
(define-key LaTeX-mode-map (kbd "C-M-SPC") (lambda (r-begin r-end) (interactive "r") (add-delimiter "$" "$" r-begin r-end))) |
||||
(define-key LaTeX-mode-map (kbd "C-c C-d") |
||||
(lambda (arg r-begin r-end) (interactive "P\nr") |
||||
(if arg |
||||
(add-delimiter "\\todo[inline]{" "}{}" r-begin r-end) |
||||
(add-delimiter "\\todo{" "}{}" r-begin r-end)))) |
||||
(define-key LaTeX-mode-map (kbd "C-M-d") 'kill-sexp) |
||||
(define-key LaTeX-mode-map (kbd "C-M-i") 'down-list) ;; -i stands for /in/ |
||||
(define-key LaTeX-mode-map (kbd "C-M-o") 'up-list) ;; -o stands for /out/ |
||||
|
||||
|
||||
(define-key LaTeX-mode-map (kbd "=") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "≠") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd ">") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "<") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "≥") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "≤") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "⇒") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "∩") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "∪") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "∨") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "∧") 'insert-char-with-padding) |
||||
(define-key LaTeX-mode-map (kbd "×") 'insert-char-with-padding) |
||||
|
||||
|
||||
;; ;; Unicode shortcuts… |
||||
;; (define-key LaTeX-mode-map (kbd "α") (lambda() (interactive) (insert "\\alpha"))) |
||||
;; (define-key LaTeX-mode-map (kbd "β") (lambda() (interactive) (insert "\\beta"))) |
||||
;; (define-key LaTeX-mode-map (kbd "δ") (lambda() (interactive) (insert "\\delta"))) |
||||
;; (define-key LaTeX-mode-map (kbd "Δ") (lambda() (interactive) (insert "\\Delta"))) |
||||
;; (define-key LaTeX-mode-map (kbd "θ") (lambda() (interactive) (insert "\\theta"))) |
||||
;; (define-key LaTeX-mode-map (kbd "Θ") (lambda() (interactive) (insert "\\Theta"))) |
||||
;; (define-key LaTeX-mode-map (kbd "λ") (lambda() (interactive) (insert "\\lambda"))) |
||||
;; (define-key LaTeX-mode-map (kbd "Λ") (lambda() (interactive) (insert "\\Lambda"))) |
||||
;; (define-key LaTeX-mode-map (kbd "ω") (lambda() (interactive) (insert "\\omega"))) |
||||
;; (define-key LaTeX-mode-map (kbd "Ω") (lambda() (interactive) (insert "\\Omega"))) |
||||
|
||||
;; (define-key LaTeX-mode-map (kbd "∈") (lambda() (interactive) (insert "\\in"))) |
||||
;; (define-key LaTeX-mode-map (kbd "ℓ") (lambda() (interactive) (insert "\\ell"))) |
||||
|
||||
|
||||
)) |
||||
|
||||
;; this reimplements TeX-insert-braces to work with negative argument |
||||
(defun TeX-insert-braces (arg) |
||||
"Make a pair of braces around next ARG sexps and leave point inside. |
||||
No argument is equivalent to zero: just insert braces and leave point |
||||
between. |
||||
|
||||
If there is an active region, ARG will be ignored, braces will be |
||||
inserted around the region, and point will be left after the |
||||
closing brace." |
||||
(interactive "P") |
||||
(if (TeX-active-mark) |
||||
(progn |
||||
(if (< (point) (mark)) |
||||
(exchange-point-and-mark)) |
||||
(insert TeX-grcl) |
||||
(save-excursion |
||||
(goto-char (mark)) |
||||
(insert TeX-grop))) |
||||
(if (and arg (< arg 0)) |
||||
(progn |
||||
(save-excursion |
||||
(backward-sexp (prefix-numeric-value (- 0 arg))) |
||||
(insert TeX-grop)) |
||||
(insert TeX-grcl)) |
||||
(insert TeX-grop) |
||||
(save-excursion |
||||
(if arg (forward-sexp (prefix-numeric-value arg))) |
||||
(insert TeX-grcl))))) |
||||
|
||||
(defun TeX-back-insert-braces (arg) |
||||
(interactive "P") |
||||
(if arg (TeX-insert-braces (- 0 arg)) |
||||
(insert TeX-grcl))) |
||||
|
||||
(defun insert-char-with-padding (arg) |
||||
(interactive "*P") |
||||
(if (string= (string (preceding-char)) " ") () |
||||
(if (string= (string (preceding-char)) "\&") () (insert " "))) |
||||
(self-insert-command (prefix-numeric-value arg)) |
||||
(if (string= (string (following-char)) " ") () (insert " ")) ;; decide what to do with the point |
||||
) |
||||
|
||||
(load "latex-compile-filters.el") |
||||
@ -0,0 +1,747 @@ |
||||
;;; bibsnarf --- get BibTeX format bibliography entries from the net |
||||
|
||||
;; Author: Hans Halvorson (hhalvors -at- princeton -dot- edu) |
||||
;; Version: 0.2 |
||||
;; Time-stamp: <2007-04-25 04:50:23 hhalvors> |
||||
|
||||
;;; Commentary: |
||||
;; |
||||
;; This program searches simultaneously through several bibliography |
||||
;; databases, and produces a summary of the results. You can then |
||||
;; view records (using "v"), append records to other buffers (usingz |
||||
;; "c"), or append records into local BibTeX files (using "f"). |
||||
;; |
||||
;; As of January 26, 2007, the supported search backends are: |
||||
;; |
||||
;; MathSciNet: www.ams.org/mathscinet (requires a subscription) |
||||
;; citebase: www.citebase.org |
||||
;; math arxive: front.math.ucdavis.edu |
||||
;; spires-hep: www.slac.stanford.edu/spires/ |
||||
;; |
||||
;; In theory, it is easy to add any backend for which a single URL |
||||
;; returns an html page with BibTeX formatted entries. |
||||
;; If you know of any such additional backends, please email the maintainer. |
||||
;; |
||||
;; To start a search: M-x bibsnarf RET |
||||
;; You will then be queried for Author and Title (you need only enter one of the two fields). |
||||
;; If everything goes well, in a few short seconds you will |
||||
;; find yourself in a buffer that summarizes your results, one line |
||||
;; per result. The following keybindings apply in the summary buffer: |
||||
;; |
||||
;; v - view the full BibTeX entry for the record at the point |
||||
;; SPC - ditto |
||||
;; RET - ditto |
||||
;; f - append the full BibTeX of the record at the point to some local file |
||||
;; (*CAUTION*: if you have made modifications to the file and have not saved, then you will |
||||
;; lose your changes! For that case, you should instead use "a" |
||||
;; c - append the full BibTeX of the record at the point to some buffer |
||||
;; |
||||
;; At present, all search results are dumped into a single buffer. But it would not be diffcult |
||||
;; to arrange things differently. |
||||
;; |
||||
;; |
||||
;; Technical discussion: Here is what actually happens after you ask bibsnarf to search: |
||||
;; 1. bibsnarf figures out which urls to get |
||||
;; 2. bibsnarf calls an external browser (e.g. links) to download the urls. |
||||
;; (Why not a native emacs browser, e.g. w3? For one, w3 is no longer maintained. |
||||
;; Second, using an external browser allows us to do asynchronous downloads. Maybe that is also |
||||
;; possible with w3; I don't know.) |
||||
;; 3. bibsnarf processes each downloaded html page in two stages: (a) It cleans out the html cruft, |
||||
;; hopefully (!) resulting in a valid BibTeX file. (b) It parses the BibTeX file by turning each |
||||
;; valid entry into a hash table whose keys are field names and whose values are field contents, and |
||||
;; then it makes a big hash table called *bib* whose keys are random, and whose values are the entry |
||||
;; hash tables. into a hash table called '*bib*'. Question: would it be better just to store the entries |
||||
;; in a list? Does hashing provide any advantage ;; in this case? |
||||
;; 4. bibsnarf writes out a summary string for each entry in *bib* in the buffer *bibsnarf results*. |
||||
;; |
||||
|
||||
;; requires an external web client: e.g., links, w3m, lynx |
||||
|
||||
;; TO DO: use async from url.el |
||||
|
||||
;; TO DO: add SciTation support, eprintweb.org support |
||||
|
||||
;; Acknowledgments: Much of the code is inspired by Eric Marsden's |
||||
;; watson.el, and some is borrowed from Nevin Kapur's bibfind.el. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'mm-url) |
||||
(require 'bibtex) |
||||
(require 'cl) |
||||
|
||||
(defvar bsn-summary-mode-map nil |
||||
"Keymap for the bsn-summary buffer.") |
||||
|
||||
(if bsn-summary-mode-map |
||||
() |
||||
(setq bsn-summary-mode-map (make-keymap)) |
||||
(suppress-keymap bsn-summary-mode-map) |
||||
;; basic commands |
||||
(define-key bsn-summary-mode-map "v" 'bsn-summary-view) |
||||
(define-key bsn-summary-mode-map " " 'bsn-summary-view) |
||||
(define-key bsn-summary-mode-map [return] 'bsn-summary-view) |
||||
(define-key bsn-summary-mode-map "f" 'bsn-summary-file) |
||||
(define-key bsn-summary-mode-map "c" 'bsn-summary-copy) |
||||
) |
||||
|
||||
(defgroup bibsnarf nil |
||||
"BibSnarf: snarf a bibliography from the internet." |
||||
:group 'tools) |
||||
|
||||
(defconst bibsnarf-version "0.1" |
||||
"bibsnarf version.") |
||||
|
||||
(defvar bsn-frame-parameters '((menu-bar-lines . 0)) |
||||
"*Parameters to use when putting *bibsnarf results* buffer in a new frame.") |
||||
|
||||
(defvar bsn-frame) |
||||
|
||||
(defcustom bsn-backends '(msn arxive citebase spires) |
||||
"A list of backends to search. Currently supported: msn arxive citebase spires." |
||||
:group 'bibsnarf) |
||||
|
||||
|
||||
(defcustom bsn-notify-method 'bully |
||||
"*How to select the *bibsnarf results* buffer once it is ready. |
||||
Possible values are: |
||||
* 'newframe: create a dedicated new frame (see `bsn-frame-parameters') |
||||
* 'pushy: make *bibsnarf results* the current buffer in the current window |
||||
* 'bully: make *bibsnarf results* the current buffer and only window |
||||
* 'aggressive: make *bibsnarf results* the current buffer in the other window |
||||
* 'friendly: display *bibsnarf results* in the other window but don't make current |
||||
* 'polite: don't display *bibsnarf results*, but print message and beep when ready |
||||
* 'quiet: like `polite', but don't beep |
||||
* 'meek: make no indication that *bibsnarf results* is ready |
||||
You can also use a lisp expression that evaluates to your own notification method -- e.g. you can use \"man-notify-method\"." |
||||
:group 'bibsnarf) |
||||
|
||||
|
||||
(defun bsn-executable-exists-p (exe &rest args) |
||||
"Test whether the executable EXE exists. |
||||
Try to execute it with CALL-PROCESS with arguments ARGS, |
||||
returning its return status or nil if not found." |
||||
(condition-case nil |
||||
(apply #'call-process exe nil nil nil args) |
||||
(file-error nil))) |
||||
|
||||
(defvar bsn-get-command |
||||
;; please send me any others which might be useful |
||||
(cond ((bsn-executable-exists-p "curl" "-h") "curl -x 127.0.01:8118") |
||||
((bsn-executable-exists-p "links" "-version") "links -source -http-proxy 127.0.0.1:8118") |
||||
((bsn-executable-exists-p "wget" "--version") "wget --output-document=~/out.txt") |
||||
((bsn-executable-exists-p "lynx" "-help") "lynx -source") |
||||
((bsn-executable-exists-p "w3m") "w3m -dump_source") |
||||
(t "")) |
||||
) |
||||
|
||||
;; To Do: could we also invoke Firefox or Opera with -noraise flag? |
||||
|
||||
(defvar bsn-timeout 15 |
||||
"*Number of seconds to wait before assuming a request is late. |
||||
Bibsnarf will activate its buffer (according to the value of the |
||||
variable `bsn-notify-method') when all queries have completed |
||||
or after this number of seconds. If you have a slow Internet |
||||
connection it may be useful to set this to a higher value |
||||
than the default, particularly if you are using bl in |
||||
synchronous mode.") |
||||
|
||||
(defvar bsn-frame) |
||||
(defvar bsn-arguments "") |
||||
(defvar bsn-match-count "0") |
||||
(defvar bsn-timer nil) |
||||
(defvar bsn-tick 0) |
||||
(defvar bsn-jobs (make-hash-table)) |
||||
(defvar *bib* (make-hash-table :test #'equal)) |
||||
|
||||
(defvar bsn-extract-hook nil |
||||
"*Hook to run before a search-engine specific extraction function.") |
||||
|
||||
;; placate the byte-compiler |
||||
(defvar bsn-buffer-url nil) |
||||
|
||||
(defun bibsnarf () |
||||
(interactive) |
||||
(let* ((author (read-string "Author: ")) |
||||
(title (read-string "Title: "))) |
||||
(bsn-init) |
||||
(message "Looking for matches...") |
||||
(dolist (backend bsn-backends) |
||||
(bsn-fetch backend author title)))) |
||||
|
||||
(defun bsn-init () |
||||
(let ((buf (get-buffer "*bibsnarf results*"))) |
||||
(setq bsn-frame (selected-frame)) |
||||
(setq bsn-match-count "0") |
||||
(clrhash *bib*) ; remove previous matches |
||||
(clrhash bsn-jobs) ; remove any uncompleted async jobs |
||||
(setq bsn-tick 0) |
||||
(bsn-timer-start) |
||||
(when buf ; update the output buffer: ?? |
||||
(set-buffer buf) |
||||
(setq buffer-read-only nil) |
||||
(erase-buffer)))) |
||||
|
||||
;;; Main async fetch function |
||||
(defun bsn-fetch (backend author title) |
||||
(let* ((components (split-string bsn-get-command)) ; splits on whitespace |
||||
(bsn-get-program (car components)) ; e.g. "links" |
||||
(bsn-get-arguments (cdr components)) ; e.g. "-source" |
||||
(backend-str (symbol-name backend)) |
||||
(extractor (intern (concat "bsn-" backend-str "-extract"))) |
||||
(urler (intern (concat "bsn-" (symbol-name backend) "-url"))) |
||||
(url (funcall urler author title)) |
||||
) |
||||
(apply #'bsn-add-job |
||||
`(lambda () |
||||
(run-hooks 'bsn-extract-hook) |
||||
(,extractor) |
||||
(bsn-display-matches)) |
||||
bsn-get-program |
||||
(append bsn-get-arguments (list url)) |
||||
) |
||||
) |
||||
) |
||||
|
||||
(defun bsn-add-job (handler job &rest args) |
||||
(let* ((buf (generate-new-buffer " *bsn-async*")) |
||||
(proc (apply #'start-process "bsn-async" buf job args))) |
||||
(setf (gethash proc bsn-jobs) handler) |
||||
(set-process-sentinel proc #'bsn-sentinel))) |
||||
|
||||
(defun bsn-sentinel (process event) |
||||
(when (eq (process-status process) 'exit) |
||||
(let ((buf (process-buffer process)) |
||||
(handler (gethash process bsn-jobs))) |
||||
(when handler |
||||
(save-excursion |
||||
(unwind-protect |
||||
(progn |
||||
(set-buffer buf) |
||||
(funcall handler)) |
||||
(remhash process bsn-jobs) |
||||
(kill-buffer buf))))))) |
||||
|
||||
|
||||
;; (verbatim from watson.el) this is run regularly while a bsn search |
||||
;; is in progress. If all the requests have been treated, we switch to |
||||
;; the *bibsnarf results* buffer (using user-customizable method from |
||||
;; `bsn-notify-method'). If `bsn-timeout' seconds have passed without |
||||
;; all requests having finished, we display the buffer anyway. If no |
||||
;; matches have been found at timeout, display a "no matches" message. |
||||
(defun bsn-timer-function (&rest ignore) |
||||
(incf bsn-tick) |
||||
(cond ((zerop (hash-table-count bsn-jobs)) |
||||
(bsn-timer-stop) |
||||
(bsn-notify-when-ready)) |
||||
((> bsn-tick bsn-timeout) |
||||
(bsn-timer-stop) |
||||
(if (zerop (hash-table-count *bib*)) |
||||
(message "bib search: no matches found after %s seconds" bsn-timeout) |
||||
(bsn-notify-when-ready))))) |
||||
|
||||
(defun bsn-timer-start () |
||||
(setq bsn-timer (run-with-timer 1 1 #'bsn-timer-function))) |
||||
|
||||
(defun bsn-timer-stop () |
||||
(cancel-timer bsn-timer) |
||||
(setq bsn-timer nil)) |
||||
|
||||
;; adapted from `Man-notify-method' in man.el. |
||||
(defun bsn-notify-when-ready () |
||||
"Notify the user when the *bibsnarf results* buffer is ready. |
||||
See the variable `bsn-notify-method' for the different notification behaviors." |
||||
(cond |
||||
((eq bsn-notify-method 'newframe) |
||||
;; Since we run asynchronously, perhaps while Emacs is waiting |
||||
;; for input, we must not leave a different buffer current. We |
||||
;; can't rely on the editor combibsnarfd loop to reselect the |
||||
;; selected window's buffer. |
||||
(save-excursion |
||||
(let ((frame (make-frame bsn-frame-parameters))) |
||||
(set-window-buffer (frame-selected-window frame) "*bibsnarf results*") |
||||
(set-window-dedicated-p (frame-selected-window frame) t)))) |
||||
((eq bsn-notify-method 'pushy) |
||||
(switch-to-buffer "*bibsnarf results*")) |
||||
((eq bsn-notify-method 'bully) |
||||
(and window-system |
||||
(frame-live-p bsn-frame) |
||||
(select-frame bsn-frame)) |
||||
(pop-to-buffer "*bibsnarf results*") |
||||
(delete-other-windows)) |
||||
((eq bsn-notify-method 'aggressive) |
||||
(and window-system |
||||
(frame-live-p bsn-frame) |
||||
(select-frame bsn-frame)) |
||||
(pop-to-buffer "*bibsnarf results*")) |
||||
((eq bsn-notify-method 'friendly) |
||||
(and window-system |
||||
(frame-live-p bsn-frame) |
||||
(select-frame bsn-frame)) |
||||
(display-buffer "*bibsnarf results*" 'not-this-window)) |
||||
((eq bsn-notify-method 'polite) |
||||
(beep) |
||||
(message "bibsnarf search results are not ready")) |
||||
((eq bsn-notify-method 'quiet) |
||||
(message "bibsnarf search results are not ready")) |
||||
((or (eq bsn-notify-method 'meek) |
||||
t) |
||||
(message "")))) |
||||
|
||||
;;;; SECTION: BACKENDS:: these are the databases we will search through |
||||
|
||||
;;; MathSciNet |
||||
;; N.B.: msn wants "Surname, First" |
||||
;; should we query for author firstname and author surname separately?? |
||||
|
||||
(defun bsn-msn-url (author title) |
||||
"What's the URL for MathSciNet." |
||||
(let* ((pairs `(("bdlback" . "r=1") |
||||
("dr" . "all") |
||||
("l" . "20") |
||||
("pg3" . "TI") |
||||
("s3" . ,title) |
||||
("pg4" . "ICN") |
||||
("s4" . ,author) |
||||
("fn" . "130") |
||||
("fmt" . "bibtex") |
||||
("bdlall" . "Retrieve+All")))) |
||||
(concat "http://www.ams.org/mathscinet/search/publications.html?" (mm-url-encode-www-form-urlencoded pairs)))) |
||||
|
||||
|
||||
;;; Zentralblatt Mathematik |
||||
;;; As of Jan 2007, ZBM limits to only 3 results for non-subscribers |
||||
|
||||
(defun bsn-zbm-url (author title) |
||||
"What's the URL for ZBM?" |
||||
(let* ((pairs `(("ti" . ,title) |
||||
("au" . ,author) |
||||
("type" . "bibtex") |
||||
("format" . "short") |
||||
("maxdocs" . "20")))) |
||||
(concat "http://www.emis.de/cgi-bin/zmen/ZMATH/en/quick.html?" (mm-url-encode-www-form-urlencoded pairs)))) |
||||
|
||||
;;; MRL support |
||||
;;; As of Jan 2007, MRL seems to be defunct |
||||
|
||||
(defun bsn-mrl-url (author title) |
||||
"What's the URL for mrl?" |
||||
(let* ((pairs `(("s3" . ,author) |
||||
("pg3" . "ICN") |
||||
("s4" . ,title) |
||||
("pg4" . "TI") |
||||
("s5" . "") |
||||
("pg5" . "JOUR") |
||||
("format" . "bibtex") |
||||
("Search" . "Search")))) |
||||
(concat "http://www.ams.org/mrlookup?" (mm-url-encode-www-form-urlencoded pairs)))) |
||||
|
||||
(defun bsn-msn-wash () |
||||
"Wash the output returned." |
||||
(goto-char (point-min)) |
||||
(let ((case-fold-search t)) |
||||
(when (re-search-forward "^@" nil t) |
||||
(delete-region (point-min) (match-beginning 0))) |
||||
(goto-char (point-max)) |
||||
(when (re-search-backward "</pre>" nil t) |
||||
(delete-region (point-max) (match-beginning 0))) |
||||
;; Handle the case when nothing matches |
||||
(goto-char (point-min)) |
||||
(when (re-search-forward "No Records Selected" nil t) |
||||
(replace-match "@Comment No matches") |
||||
(delete-region (point-min) (match-beginning 0))) |
||||
(goto-char (point-max)) |
||||
(when (re-search-backward "</title>" nil t) |
||||
(delete-region (point-max) (match-beginning 0))))) |
||||
|
||||
(defun bsn-msn-extract () |
||||
"Extract BibTeX entries from the html source delivered by MathSciNet." |
||||
;; TO DO: informative error messages |
||||
(bsn-msn-wash) ; the result of this should be a valid BibTeX file |
||||
; (bibtex-validate) |
||||
(bsn-read *bib* t) ; read these entries into the hashtable *bib* using "randomly" generated keys |
||||
(message "Successfully parsed MSN results buffer.") ; debugging |
||||
) |
||||
|
||||
;; Note: arxive puts an extra pair of brackets around titles |
||||
;; (presumably to maintain capitalization); we want to strip these. |
||||
|
||||
(defun bsn-arxive-wash () |
||||
"Clean up the ArXive buffer." |
||||
(let ((case-fold-search t)) |
||||
(goto-char (point-min)) |
||||
(when (re-search-forward "<dt><pre>@" nil t) |
||||
(delete-region (point-min) (match-beginning 0))) |
||||
(goto-char (point-max)) |
||||
(when (re-search-backward "</pre>" nil t) |
||||
(delete-region (point-max) (match-beginning 0))) |
||||
(goto-char (point-min)) |
||||
(while (re-search-forward |
||||
(concat "^<dt><pre>\\|^</pre></td>\\|<a href" "=.*?>\\|</a>") ;; syntactic hack to allow posting on emacswiki |
||||
nil t) |
||||
(replace-match "")) |
||||
;; Handle the case when no matches are found |
||||
(goto-char (point-min)) |
||||
(when (re-search-forward "Query not found" nil t) |
||||
(replace-match "@Comment No matches") |
||||
(delete-region (point-min) (match-beginning 0))) |
||||
(goto-char (point-max)) |
||||
(when (re-search-backward "</title>" nil t) |
||||
(delete-region (point-max) (match-beginning 0))))) |
||||
|
||||
(defun bsn-arxive-extract () |
||||
(bsn-arxive-wash) |
||||
(bsn-read *bib* t) ; optional t to assign random external keys |
||||
(message "Successfully parsed ARXIVE results buffer.") |
||||
) |
||||
|
||||
(defun bsn-citebase-extract () |
||||
(bsn-read *bib* t) |
||||
(message "Successfully parsed CITEBASE results buffer.") |
||||
) |
||||
|
||||
(defun bsn-spires-extract () |
||||
(bsn-read *bib* t) |
||||
(message "Successfully parsed SPIRES results buffer.") |
||||
) |
||||
|
||||
;;; math arXive support |
||||
|
||||
(defun bsn-arxive-url (author title) |
||||
(concat "http://front.math.ucdavis.edu/search?" |
||||
"a=" (mm-url-form-encode-xwfu author) |
||||
"&" |
||||
"t=" (mm-url-form-encode-xwfu title) |
||||
"&" |
||||
"s=BibTeX")) |
||||
|
||||
;;; CITEBASE support |
||||
|
||||
(defun bsn-citebase-wash () |
||||
t) |
||||
|
||||
(defun bsn-citebase-url (author title) |
||||
(let* ((pairs `(("submitted" . "Search") |
||||
("author" . ,author) |
||||
("format" . "BibTeX") |
||||
("yearfrom" . "") |
||||
("maxrows" . "100") |
||||
("order" . "DESC") |
||||
("yearuntil" . "") |
||||
("publication" . "") |
||||
("title" . ,title) |
||||
("type" . "metadata") |
||||
("rank" . "accession") ; in what order should we list? |
||||
))) |
||||
(concat "http://www.citebase.org/search?" (mm-url-encode-www-form-urlencoded pairs)))) |
||||
|
||||
;; no html washing necessary for citebase |
||||
|
||||
;;; SPIRES-HEP support |
||||
|
||||
;; Note that the SPIRES server is quite slow .... maybe don't search |
||||
;; it if you're in a hurry |
||||
|
||||
(defun bsn-spires-rawcmd (author title) |
||||
(cond |
||||
((zerop (length author)) (concat "T+" title)) |
||||
((zerop (length title)) (concat "A+" author)) |
||||
(t (concat "A+" author "+and+" "T+" title)))) |
||||
|
||||
(defun bsn-simple-encode (pairs) |
||||
(cond |
||||
((not pairs) nil) |
||||
((= (length pairs) 1) (concat (caar pairs) "=" (cdar pairs))) |
||||
(t (concat (bsn-simple-encode (list (car pairs))) "&" (bsn-simple-encode (cdr pairs)))))) |
||||
|
||||
(defun bsn-spires-url (author title) |
||||
(let* ((rawcmd (bsn-spires-rawcmd author title)) |
||||
(pairs `(("rawcmd" . ,rawcmd) |
||||
("FORMAT" . "wwwbriefbibtex") |
||||
("SEQUENCE" . "")))) |
||||
(concat "http://www.slac.stanford.edu/spires/find/hep/www?" (bsn-simple-encode pairs)))) |
||||
|
||||
(defun bsn-spires-wash () |
||||
"Wash the output returned." |
||||
(goto-char (point-min)) |
||||
(let ((case-fold-search t)) |
||||
(re-search-forward "<!-- START RESULTS -->" nil t) |
||||
(delete-region (point-min) (match-end 0)) |
||||
(goto-char (point-max)) |
||||
(re-search-backward "<!-- END RESULTS -->" nil t) |
||||
(delete-region (point-max) (match-beginning 0)) |
||||
(goto-char (point-min)) |
||||
(while (search-forward-regexp "<[a-z]+>\\|</[a-z]+>") |
||||
(replace-match "")) |
||||
;; TO DO: Handle the case when nothing matches |
||||
) |
||||
) |
||||
|
||||
(defun bsn-wash (backend) |
||||
(cond |
||||
((string= backend "msn") (lambda () (bsn-msn-wash))) |
||||
((string= backend "arxive") (lambda () (bsn-arxive-wash))) |
||||
((string= backend "spires") (lambda () (bsn-spires-wash))) |
||||
(t (lambda () t)))) |
||||
|
||||
(defun bsn-gethash (key hash) |
||||
; a gethash function that ignores the case of the key, and that |
||||
; returns an empty string if there is nothing that matches (because |
||||
; we cannot use 'truncate-string-to-width' on 'nil'. |
||||
(or (gethash key hash) (gethash (upcase key) hash) (gethash (downcase key) hash) "")) |
||||
|
||||
(defun bsn-record-summary-string (hash) |
||||
(let* ((author (truncate-string-to-width (bsn-gethash "author" hash) 20)) |
||||
(title (truncate-string-to-width (bsn-gethash "title" hash) 40)) |
||||
(title (remove ?\{ (remove ?\} title))) |
||||
(journal (truncate-string-to-width (bsn-gethash "journal" hash) 25)) |
||||
(volume (bsn-gethash "volume" hash)) |
||||
(year (bsn-gethash "year" hash)) |
||||
(pages (bsn-gethash "pages" hash))) |
||||
(format " %-25s %-45s %-28s : %-10s (%s)" (concat "[ " author " ]") (concat "\"" title "\"") journal pages year))) |
||||
|
||||
(defun bsn-display-match (hash) |
||||
(message "asdfasdf") |
||||
(let (first start local-start end) |
||||
(goto-char (point-max)) |
||||
(setq first (point)) |
||||
(setq start (point)) |
||||
; (if (gethash key *bib*) ; debug |
||||
(insert (bsn-record-summary-string hash)) |
||||
(setq end (point)) |
||||
(add-text-properties start end '(face bsn-summary-default-face)) ;;; FIX |
||||
(insert "\n"))) |
||||
|
||||
(defvar helper nil) |
||||
|
||||
(defun bsn-really-display-matches () |
||||
(let ((buf (get-buffer-create "*bibsnarf results*"))) |
||||
(save-excursion |
||||
(set-buffer buf) |
||||
(setq buffer-read-only nil) |
||||
(erase-buffer) |
||||
(set (make-local-variable 'helper) (make-hash-table :test #'equal)) ; aux will keep track of where entries are inserted |
||||
(loop for k being the hash-keys in *bib* using (hash-value v) do |
||||
(puthash (line-number-at-pos) k helper) |
||||
(bsn-display-match v)) |
||||
(goto-char (point-min)) |
||||
(bsn-summary-mode) |
||||
(set-buffer-modified-p nil)))) |
||||
|
||||
(defun bsn-display-matches () |
||||
;; display them, avoiding locking up emacs if possible. For some |
||||
;; reason the XEmacs #'run-with-idle-timer doesn't work. |
||||
(if (and (fboundp 'run-with-idle-timer) |
||||
(not (featurep 'xemacs))) |
||||
(run-with-idle-timer 1 nil #'bsn-really-display-matches) |
||||
(bsn-really-display-matches))) |
||||
|
||||
|
||||
;;;; Reconstitute BibTeX format entries from hash ;;;;;;;;;;;;;;;;;; |
||||
|
||||
(defun bsn-print-bibtex-string (key bibhash) |
||||
(let ((record (gethash key bibhash))) |
||||
(concat (format "@%s{ %s,\n" (gethash "=type=" record) (gethash "=key=" record)) |
||||
(substring |
||||
(apply #'concat |
||||
(loop for k being the hash-keys in record using (hash-value v) |
||||
collect (unless (or (equal k "=key=") (equal k "=type=")) |
||||
(format "%15s = {%s},\n" k v)) |
||||
) |
||||
) 0 -2) |
||||
"\n}" |
||||
) |
||||
) |
||||
) |
||||
|
||||
(defun bsn-print-bibtex (key bibhash) |
||||
(insert (concat "\n" (bsn-print-bibtex-string key bibhash) "\n\n"))) |
||||
|
||||
|
||||
;;;;;;; actions in the summary buffer |
||||
|
||||
(defun bsn-display-record (key bibhash) |
||||
(let ((origin (buffer-name))) |
||||
(pop-to-buffer "*bibsnarfed record*") |
||||
(setq buffer-read-only nil) |
||||
(erase-buffer) |
||||
(bibtex-mode) |
||||
(goto-char (point-min)) |
||||
(bsn-print-bibtex key bibhash) |
||||
(shrink-window-if-larger-than-buffer) ; FIXME: this needs to be recalibrated for each record |
||||
(goto-char (point-min)) |
||||
(setq buffer-read-only t) |
||||
(pop-to-buffer origin) |
||||
)) |
||||
|
||||
(defun bsn-display-rec (line-no bibhash) |
||||
;; give line number in summary buffer and relevant bibhash, display the full BibTeX record |
||||
(if (gethash line-no helper) ; check first that we have a valid line number |
||||
(let ((key (gethash line-no helper))) |
||||
(bsn-display-record key bibhash) |
||||
(message "")) ; hack to erase previous error messages |
||||
(message "No record here to view."))) |
||||
|
||||
(defun bsn-file-record (key bibhash) |
||||
(interactive) |
||||
(let* ((record (gethash key bibhash)) |
||||
(file (read-file-name (format "Append record \"%s\" to file: " (gethash "=key=" record)))) |
||||
(bibstring (concat "\n\n" (bsn-print-bibtex-string key bibhash)))) |
||||
(write-region bibstring nil file t) |
||||
(message (format "Record \"%s\" appended to %s" key file)))) |
||||
|
||||
(defun bsn-file-rec (line-no bibhash) |
||||
(interactive) |
||||
(if (gethash line-no helper) |
||||
(let ((key (gethash line-no helper))) |
||||
(bsn-file-record key bibhash) |
||||
) |
||||
(message "No record here to file."))) |
||||
|
||||
(defun bsn-summary-file () |
||||
(interactive) |
||||
(let ((line-no (line-number-at-pos))) |
||||
(bsn-file-rec line-no *bib*))) |
||||
|
||||
(defun bsn-summary-view () |
||||
(interactive) |
||||
(let ((line-no (line-number-at-pos))) |
||||
(bsn-display-rec line-no *bib*))) |
||||
|
||||
|
||||
;; the following is similar to 'append-to-buffer' in simple.el, but |
||||
;; that takes a region as input |
||||
|
||||
(defun bsn-copy-record (key bibhash) |
||||
(interactive) |
||||
(let* ((record (gethash key bibhash)) |
||||
(buffer (read-buffer (format "Append record \"%s\" to buffer: " (gethash "=key=" record)) (other-buffer (current-buffer) t))) |
||||
(oldbuf (current-buffer)) |
||||
(bibstring (concat "\n\n" (bsn-print-bibtex-string key bibhash)))) |
||||
(save-excursion |
||||
(let* ((append-to (get-buffer-create buffer)) |
||||
(windows (get-buffer-window-list append-to t t)) |
||||
point) |
||||
(set-buffer append-to) |
||||
(setq point (point)) |
||||
(barf-if-buffer-read-only) |
||||
(insert bibstring) |
||||
(dolist (window windows) |
||||
(when (= (window-point window) point) |
||||
(set-window-point window (point)))))))) |
||||
|
||||
(defun bsn-copy-rec (line-no bibhash) |
||||
(interactive) |
||||
(if (gethash line-no helper) |
||||
(let ((key (gethash line-no helper))) |
||||
(bsn-copy-record key bibhash) |
||||
) |
||||
(message "No record here to copy."))) |
||||
|
||||
(defun bsn-summary-copy () |
||||
(interactive) |
||||
(let ((line-no (line-number-at-pos))) |
||||
(bsn-copy-rec line-no *bib*))) |
||||
|
||||
(defvar helper (make-hash-table :test #'equal)) ; buffer local variable to keep association of bibrecords and line numbers |
||||
|
||||
(defun bsn-summary-mode () |
||||
; TO DO: modeline |
||||
(setq major-mode 'bsn-summary-mode) |
||||
(setq mode-name "bibsnarf summary") |
||||
(use-local-map bsn-summary-mode-map) |
||||
) |
||||
|
||||
(defun bsn-print-summary (bib-hash buffer-name) |
||||
(pop-to-buffer buffer-name) |
||||
(setq buffer-read-only nil) |
||||
(erase-buffer) |
||||
(loop for k being the hash-keys in bib-hash using (hash-value v) |
||||
do |
||||
(insert (format " [ %s ] %s\n" (cl-gethash "author" v) (cl-gethash "title" v)))) |
||||
(setq buffer-read-only t)) |
||||
|
||||
|
||||
|
||||
;; TO DO: underline the record at which the point is located |
||||
|
||||
(defgroup bsn-summary-faces nil |
||||
"BibSnarf, Faces of summary buffer." |
||||
:prefix "bsn-highlight-" |
||||
:group 'bibsnarf) |
||||
|
||||
(defface bsn-summary-default-face |
||||
'( |
||||
(((type tty) |
||||
(background dark)) |
||||
(:foreground "blue")) |
||||
(((class color) |
||||
(background dark)) |
||||
(:foreground "GreenYellow")) |
||||
(((class color) |
||||
(background light)) |
||||
(:foreground "green4"))) |
||||
"Face used for displaying bibliography record summaries." |
||||
:group 'bibsnarf) |
||||
|
||||
;;; BibTeX parsing |
||||
|
||||
;; compare the following with bibtex-parse-entry (in bibtex.el), which |
||||
;; converts the entry to an association list. This is just like that, |
||||
;; except that we store the entry in a hash table. |
||||
|
||||
(defvar bounds nil) |
||||
|
||||
(defun bsn-parse-entry (&optional content) |
||||
"Parse entry at point, return a hash table. |
||||
The hash table elements have the form (FIELD . TEXT), where FIELD |
||||
and TEXT are strings, and FIELD can also be the special strings |
||||
\"=type=\" and \"=key=\". For the FIELD \"=key=\" TEXT may be |
||||
nil. Remove \"OPT\" and \"ALT\" from FIELD. Move point to the |
||||
end of the last field. If optional arg CONTENT is non-nil |
||||
extract content of text fields." |
||||
(let (alist (entry (make-hash-table :test #'equal :size 14))) |
||||
(when (looking-at bibtex-entry-maybe-empty-head) |
||||
(puthash "=type=" (bibtex-type-in-head) entry) |
||||
(puthash "=key=" (bibtex-key-in-head) entry) |
||||
(goto-char (match-end 0)) |
||||
(while (setq bounds (bibtex-parse-field)) |
||||
(puthash (bibtex-name-in-field bounds t) |
||||
(bibtex-text-in-field-bounds bounds content) |
||||
entry) |
||||
(goto-char (bibtex-end-of-field bounds)))) |
||||
entry)) |
||||
|
||||
|
||||
(defun bsn-read (output &optional random) |
||||
"Read bibliography into an already existing hash table OUTPUT. |
||||
If optional argument is set to t, then we generate hash keys from |
||||
the current time (to avoid conflicts with previously added |
||||
entries)." |
||||
(goto-char (point-min)) |
||||
(while (bibtex-skip-to-valid-entry) |
||||
(let* ((internal-key (bibtex-key-in-head)) |
||||
(external-key (if random (current-time) |
||||
internal-key))) |
||||
(puthash external-key (bsn-parse-entry t) output))) |
||||
output) |
||||
|
||||
(provide 'bibsnarf) |
||||
|
||||
|
||||
;;;;; TO DO: journal shortname display replacement strings; e.g. "Communications in Mathematical Physics" ==> "CMP" |
||||
|
||||
;; (defun bsn-summary-dump () |
||||
;; "Dump the entire bibliography into a file." |
||||
;; (interactive) |
||||
;; ; query for filename |
||||
;; ) |
||||
|
||||
; (defun bsn-copy-record (line-no bibhash) |
||||
; (interactive ;; destination bibliography |
||||
|
||||
; (defun bsn-delete-record (line-no bibhash) |
||||
; (interactive) |
||||
|
||||
|
||||
;;; end of file bibsnarf.el |
||||
@ -0,0 +1,196 @@ |
||||
;;; highlight-sexps.el --- highlight surrounding parentheses |
||||
;; |
||||
;; Copyright (C) 2011 David Rysdam |
||||
;; |
||||
;; Author: David Rysdam <david * rysdam org> |
||||
;; Version: 0.9.1 |
||||
;; Keywords: faces, matching, s-expression, sexp |
||||
;; URL: http://david.rysdam.org/src/emacs/highlight-sexps.el |
||||
;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x |
||||
;; |
||||
;; Based on highlight-parentheses: |
||||
;; |
||||
;; Author: Nikolaj Schumacher <bugs * nschum de> |
||||
;; Version: 1.0.1 |
||||
;; Keywords: faces, matching |
||||
;; URL: http://nschum.de/src/emacs/highlight-parentheses/ |
||||
;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x |
||||
;; |
||||
;; 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 2 |
||||
;; of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. |
||||
;; |
||||
;;; Commentary: |
||||
;; |
||||
;; Add the following to your .emacs file: |
||||
;; (require 'highlight-sexps) |
||||
;; |
||||
;; Enable `highlight-sexps-mode'. |
||||
;; |
||||
;; Or also add one or both of the following your .emacs file: |
||||
;; (add-hook 'lisp-mode-hook 'highlight-sexps-mode) |
||||
;; (add-hook 'emacs-lisp-mode-hook 'highlight-sexps-mode) |
||||
;; |
||||
;; highlight-sexps-mode supports customization. You will likely find |
||||
;; it most useful to customize the hl-sexp-background-colors |
||||
;; variable. The number of nexted s-expressions highlighted is |
||||
;; determined by the number of colors defined. |
||||
;; |
||||
;;; Change Log: |
||||
;; |
||||
;; 2012-01-31 (0.9.1) |
||||
;; lisp-mode namespace collision fixed (but probably not The Right |
||||
;; Way) |
||||
;; |
||||
;; 2012-01-31 (0.9) |
||||
;; Initial Release. |
||||
;; |
||||
;;; Code: |
||||
|
||||
(eval-when-compile (require 'cl)) |
||||
|
||||
(provide 'highlight-sexps) |
||||
|
||||
(defgroup highlight-sexps nil |
||||
"Highlight the nested s-expressions around point" |
||||
:group 'faces |
||||
:group 'matching) |
||||
|
||||
(defun hl-sexp-set (variable value) |
||||
(set variable value) |
||||
(when (fboundp 'hl-sexp-color-update) |
||||
(hl-sexp-color-update))) |
||||
|
||||
(defcustom hl-sexp-colors |
||||
nil |
||||
"*List of colors for the highlighted parentheses. |
||||
The list starts with the the inside parentheses and moves |
||||
outwards." |
||||
:type '(repeat color) |
||||
:set 'hl-sexp-set |
||||
:group 'highlight-sexps) |
||||
|
||||
(defcustom hl-sexp-background-colors |
||||
'("cyan" "white") |
||||
"*List of colors for the background highlighted parentheses. |
||||
The list starts with the the inside parentheses and moves |
||||
outwards." |
||||
:type '(repeat color) |
||||
:set 'hl-sexp-set |
||||
:group 'highlight-sexps) |
||||
|
||||
(defface hl-sexp-face nil |
||||
"*Face used for highlighting parentheses. |
||||
Color attributes might be overriden by `hl-sexp-colors' and |
||||
`hl-sexp-background-colors'." |
||||
:group 'highlight-sexps) |
||||
|
||||
(defvar hl-sexp-overlays nil |
||||
"This buffers currently active overlays.") |
||||
(make-variable-buffer-local 'hl-sexp-overlays) |
||||
|
||||
(defvar hl-sexp-last-point 0 |
||||
"The last point for which parentheses were highlighted. |
||||
This is used to prevent analyzing the same context over and |
||||
over.") |
||||
(make-variable-buffer-local 'hl-sexp-last-point) |
||||
|
||||
(defun hl-sexp-highlight () |
||||
"Highlight the nested s-expressions around point" |
||||
(unless (= (point) hl-sexp-last-point) |
||||
(setq hl-sexp-last-point (point)) |
||||
(let ((overlays hl-sexp-overlays) |
||||
(sexp-list (hl-sexp-end-points (point) |
||||
(length hl-sexp-overlays))) |
||||
pos1 pos2) |
||||
(condition-case err |
||||
(while (and overlays sexp-list) |
||||
(let* ((overlay (pop overlays)) |
||||
(sexp (pop sexp-list)) |
||||
(pos1 (car sexp)) |
||||
(pos2 (cadr sexp))) |
||||
(move-overlay overlay pos1 pos2))) |
||||
(error nil)) |
||||
(dolist (ov overlays) |
||||
(move-overlay ov 1 1))))) |
||||
|
||||
;;;###autoload |
||||
(define-minor-mode highlight-sexps-mode |
||||
"Minor mode to highlight an expanding set of surrounding s-expressions." |
||||
nil " hl-s" nil |
||||
(if highlight-sexps-mode |
||||
(progn |
||||
(hl-sexp-create-overlays) |
||||
(add-hook 'post-command-hook 'hl-sexp-highlight nil t)) |
||||
(mapc 'delete-overlay hl-sexp-overlays) |
||||
(kill-local-variable 'hl-sexp-overlays) |
||||
(kill-local-variable 'hl-sexp-last-point) |
||||
(remove-hook 'post-command-hook 'hl-sexp-highlight t))) |
||||
|
||||
(defun hl-sexp-create-overlays () |
||||
"Create some 'overlays-in-waiting' with the right priorities and attributes." |
||||
(let* ((fg hl-sexp-colors) |
||||
(bg hl-sexp-background-colors) |
||||
(count (max (length fg) (length bg))) |
||||
(num count) |
||||
attributes) |
||||
(while (> num 0) |
||||
(setq attributes (face-attr-construct 'hl-sexp-face)) |
||||
(when (car fg) |
||||
(setq attributes (plist-put attributes :foreground (car fg)))) |
||||
(pop fg) |
||||
(when (car bg) |
||||
(setq attributes (plist-put attributes :background (car bg)))) |
||||
(pop bg) |
||||
(push (make-overlay 0 0) hl-sexp-overlays) |
||||
(overlay-put (car hl-sexp-overlays) 'face attributes) |
||||
(overlay-put (car hl-sexp-overlays) 'priority num) |
||||
(decf num)) |
||||
(setq hl-sexp-overlays (nreverse hl-sexp-overlays)))) |
||||
|
||||
(defun hl-sexp-color-update () |
||||
(dolist (buffer (buffer-list)) |
||||
(with-current-buffer buffer |
||||
(when hl-sexp-overlays |
||||
(mapc 'delete-overlay hl-sexp-overlays) |
||||
(setq hl-sexp-overlays nil) |
||||
(hl-sexp-create-overlays) |
||||
(let ((hl-sexp-last-point -1)) ;; force update |
||||
(hl-sexp-highlight)))))) |
||||
|
||||
(defun hl-sexp-start-of-sexp (pt) |
||||
"Start of the s-expression surrounding PT." |
||||
(save-excursion (cadr (syntax-ppss pt)))) |
||||
|
||||
(defun hl-sexp-end-of-sexp (pt) |
||||
"End of s-expression that matches beginning point PT." |
||||
(condition-case nil |
||||
(scan-sexps pt 1) |
||||
(error nil))) |
||||
|
||||
(defun hl-sexp-end-points (pt n) |
||||
"Get beginning and ending points of N depths of s-expressions |
||||
surrounding PT." |
||||
(let (results prev next |
||||
(p pt)) |
||||
(dotimes (i n (nreverse results)) |
||||
(setq prev (hl-sexp-start-of-sexp p)) |
||||
(when prev |
||||
(setq next (hl-sexp-end-of-sexp prev)) |
||||
(when next |
||||
(push (list prev next) results) |
||||
(setq p (1- prev))))))) |
||||
|
||||
;;; highlight-sexps.el ends here |
||||
|
||||
@ -0,0 +1 @@ |
||||
;; org-persist.el - fourspoons at <2014-12-11 Thu 09:27> |
||||
@ -0,0 +1 @@ |
||||
;; org-persist.el - fourspoons at <2014-12-23 Tue 15:11> |
||||
@ -0,0 +1 @@ |
||||
Subproject commit 3ab61f959214b8ce76aad8a4ae52320652eca29b |
||||
@ -0,0 +1 @@ |
||||
Subproject commit 9ab439efba008834ccf37b6a80a953cf2da6e40d |
||||
Loading…
Reference in new issue