diff --git a/emacs.config.org/emacs.org b/emacs.config.org/emacs.org new file mode 100644 index 0000000..1a69109 --- /dev/null +++ b/emacs.config.org/emacs.org @@ -0,0 +1,28 @@ +#+TITLE: Emacs Configuration +#+AUTHOR: Rongsong Shen +#+EMAIL: rshen@shenrs.eu +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall + +* Initialize Emacs Package System + +** Using Emacs package mirror in China + #+BEGIN_SRC emacs-lisp + (package-initialize) + (setq package-archives '(("gnu_cn" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/") + ("melpa_cn" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/"))) + #+END_SRC + +** Using use-package as basic + + #+BEGIN_SRC emacs-lisp + (unless (package-installed-p 'use-package) + (package-refresh-contents) + (package-install 'use-package)) + (require 'use-package) + (setq use-package-always-ensure t) + #+END_SRC + +# Local Variables: +# End: + diff --git a/emacs.config.org/init.el b/emacs.config.org/init.el new file mode 100644 index 0000000..13d108a --- /dev/null +++ b/emacs.config.org/init.el @@ -0,0 +1,16 @@ +;; Using org as the configuration file of Emacs +;; + +(defun load-config (name) + (let ((config-org (concat name ".org")) + (config-el (concat name ".el"))) + (when (file-exists-p config-org) + (if (or (not (file-exists-p config-el)) + (file-newer-than-file-p config-org + config-el)) + (org-babel-load-file config-org) + (load-file config-el))))) + +(require 'org) + +(load-config "~/.emacs.d/emacs") diff --git a/jars/ditaa.jar b/jars/ditaa.jar new file mode 100644 index 0000000..5894de4 Binary files /dev/null and b/jars/ditaa.jar differ diff --git a/jars/eclim_2.3.2.jar b/jars/eclim_2.3.2.jar new file mode 100644 index 0000000..e0b98d3 Binary files /dev/null and b/jars/eclim_2.3.2.jar differ diff --git a/jars/mathtoweb.jar b/jars/mathtoweb.jar new file mode 100644 index 0000000..bedac5e Binary files /dev/null and b/jars/mathtoweb.jar differ diff --git a/jars/plantuml.jar b/jars/plantuml.jar new file mode 100644 index 0000000..e36ad32 Binary files /dev/null and b/jars/plantuml.jar differ diff --git a/layers.personal/customized/README.org b/layers.personal/customized/README.org new file mode 100644 index 0000000..a7f2de8 --- /dev/null +++ b/layers.personal/customized/README.org @@ -0,0 +1,29 @@ +#+TITLE: customized layer +#+HTML_HEAD_EXTRA: + +#+CAPTION: logo + +# The maximum height of the logo should be 200 pixels. +[[img/customized.png]] + +* Table of Contents :TOC_4_org:noexport: + - [[Description][Description]] + - [[Install][Install]] + - [[Key bindings][Key bindings]] + +* Description +This layer does wonderful things: + - thing01 + +* Install +To use this contribution add it to your =~/.spacemacs= + +#+begin_src emacs-lisp + (setq-default dotspacemacs-configuration-layers '(customized)) +#+end_src + +* Key bindings + +| Key Binding | Description | +|-----------------+----------------| +| ~ x x x~ | Does thing01 | diff --git a/layers.personal/customized/config.el b/layers.personal/customized/config.el new file mode 100644 index 0000000..051559d --- /dev/null +++ b/layers.personal/customized/config.el @@ -0,0 +1,2 @@ +(defvar my-default-c-style nil + "Choose the default style of c mode") diff --git a/layers.personal/customized/local/my-c-styles/my-c-styles.el b/layers.personal/customized/local/my-c-styles/my-c-styles.el new file mode 100644 index 0000000..d035622 --- /dev/null +++ b/layers.personal/customized/local/my-c-styles/my-c-styles.el @@ -0,0 +1,85 @@ +;;;###autoload +(defun add-my-c-styles () + (c-add-style "Personal" + '("gnu" + (c-basic-offset . 4) ; Guessed value + (c-offsets-alist + (block-close . 0) ; Guessed value + (defun-block-intro . +) ; Guessed value + (defun-close . 0) ; Guessed value + (defun-open . 0) ; Guessed value + (statement . 0) ; Guessed value + (statement-block-intro . +) ; Guessed value + (topmost-intro . 0) ; Guessed value + (topmost-intro-cont . 0) ; Guessed value + (access-label . -) + (annotation-top-cont . 0) + (annotation-var-cont . +) + (arglist-close . c-lineup-close-paren) + (arglist-cont c-lineup-gcc-asm-reg 0) + (arglist-cont-nonempty . c-lineup-arglist) + (arglist-intro . +) + (block-open . 0) + (brace-entry-open . 0) + (brace-list-close . 0) + (brace-list-entry . 0) + (brace-list-intro . +) + (brace-list-open . 0) + (c . c-lineup-C-comments) + (case-label . 0) + (catch-clause . 0) + (class-close . 0) + (class-open . 0) + (comment-intro . c-lineup-comment) + (composition-close . 0) + (composition-open . 0) + (cpp-define-intro c-lineup-cpp-define +) + (cpp-macro . -1000) + (cpp-macro-cont . +) + (do-while-closure . 0) + (else-clause . 0) + (extern-lang-close . 0) + (extern-lang-open . 0) + (friend . 0) + (func-decl-cont . +) + (inclass . +) + (incomposition . +) + (inexpr-class . +) + (inexpr-statement . +) + (inextern-lang . +) + (inher-cont . c-lineup-multi-inher) + (inher-intro . +) + (inlambda . c-lineup-inexpr-block) + (inline-close . 0) + (inline-open . +) + (inmodule . +) + (innamespace . +) + (knr-argdecl . 0) + (knr-argdecl-intro . +) + (label . 2) + (lambda-intro-cont . +) + (member-init-cont . c-lineup-multi-inher) + (member-init-intro . +) + (module-close . 0) + (module-open . 0) + (namespace-close . 0) + (namespace-open . 0) + (objc-method-args-cont . c-lineup-ObjC-method-args) + (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call +) + (objc-method-intro . + [0]) + (statement-case-intro . +) + (statement-case-open . 0) + (statement-cont . +) + (stream-op . c-lineup-streamop) + (string . -1000) + (substatement . +) + (substatement-label . 2) + (substatement-open . +) + (template-args-cont c-lineup-template-args +))))) + +;;;###autoload +(defun use-my-c-style () + (c-set-style "Personal")) + +(provide 'my-c-styles) diff --git a/layers.personal/customized/packages.el b/layers.personal/customized/packages.el new file mode 100644 index 0000000..dc81454 --- /dev/null +++ b/layers.personal/customized/packages.el @@ -0,0 +1,85 @@ +;;; packages.el --- customized layer packages file for Spacemacs. +;; +;; Copyright (c) 2012-2016 Sylvain Benner & Contributors +;; +;; Author: Rongsong Shen +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;;; Commentary: + +;; See the Spacemacs documentation and FAQs for instructions on how to implement +;; a new layer: +;; +;; SPC h SPC layers RET +;; +;; +;; Briefly, each package to be installed or configured by this layer should be +;; added to `customized-packages'. Then, for each package PACKAGE: +;; +;; - If PACKAGE is not referenced by any other Spacemacs layer, define a +;; function `customized/init-PACKAGE' to load and initialize the package. + +;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so +;; define the functions `customized/pre-init-PACKAGE' and/or +;; `customized/post-init-PACKAGE' to customize the package as it is loaded. + +;;; Code: + +(defconst customized-packages + '( + (my-c-styles :location local) + google-c-style + cc-mode) + "The list of Lisp packages required by the customized layer. + +Each entry is either: + +1. A symbol, which is interpreted as a package to be installed, or + +2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun customized/init-my-c-styles () + (use-package my-c-styles + :defer t + :commands (add-my-c-styles use-my-c-style) + :config (progn + (add-my-c-styles)))) + +(defun customized/post-init-cc-mode () + (spacemacs/add-to-hooks #'(lambda () + (when my-default-c-style + (cond + ((eq my-default-c-style "google") (google-set-c-style)) + (t (use-my-c-style))))) + '(c-mode-hook c++-mode-hook))) + +(defun customized/init-google-c-style () + (use-package google-c-style + :defer t + :commands google-set-c-style)) + +;;; packages.el ends here diff --git a/layers.personal/misctools/my-polymode/README.org b/layers.personal/misctools/my-polymode/README.org new file mode 100644 index 0000000..bd9be82 --- /dev/null +++ b/layers.personal/misctools/my-polymode/README.org @@ -0,0 +1,30 @@ +#+TITLE: my-polymode layer + +# The maximum height of the logo should be 200 pixels. +[[img/my-polymode.png]] + +# TOC links should be GitHub style anchors. +* Table of Contents :TOC_4_gh:noexport: +- [[#description][Description]] +- [[#install][Install]] +- [[#key-bindings][Key bindings]] + +* Description +This layer does wonderful things: + - thing01 + +* Install +To use this configuration layer, add it to your =~/.spacemacs=. You will need to +add =my-polymode= to the existing =dotspacemacs-configuration-layers= list in this +file. + +* Key bindings + +| Key Binding | Description | +|-------------+----------------| +| ~SPC x x x~ | Does thing01 | +# Use GitHub URLs if you wish to link a Spacemacs documentation file or its heading. +# Examples: +# [[https://github.com/syl20bnr/spacemacs/blob/master/doc/VIMUSERS.org#sessions]] +# [[https://github.com/syl20bnr/spacemacs/blob/master/layers/%2Bfun/emoji/README.org][Link to Emoji layer README.org]] +# If space-doc-mode is enabled, Spacemacs will open a local copy of the linked file. diff --git a/layers.personal/misctools/my-polymode/local/polymode/.dir-locals.el b/layers.personal/misctools/my-polymode/local/polymode/.dir-locals.el new file mode 100644 index 0000000..cb39f4c --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/.dir-locals.el @@ -0,0 +1,16 @@ +;;; Directory Local Variables +;;; See Info node `(emacs) Directory Variables' for more information. + +((nil + (require-final-newline . t) + ;; not tabs in code + (indent-tabs-mode) + ;; checkdoc, one space is enough + (sentence-end-double-space . nil) + ;; checkdoc, don't botch English grammar + (checkdoc-arguments-in-order-flag . nil) + ;; checkdoc, we don't want docs for internal vars + (checkdoc-force-docstrings-flag . nil)) + (emacs-lisp-mode + ;; remove trailing whitespace + (eval . (add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))) diff --git a/layers.personal/misctools/my-polymode/local/polymode/.gitignore b/layers.personal/misctools/my-polymode/local/polymode/.gitignore new file mode 100644 index 0000000..e6d7d9e --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/.gitignore @@ -0,0 +1,10 @@ +*~ +*# +#* +auto/ +*\[weaved\]* +tmp/ +*woven* +*exported* +.tmd +tmp* \ No newline at end of file diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/Rmd.png b/layers.personal/misctools/my-polymode/local/polymode/img/Rmd.png new file mode 100644 index 0000000..5b31d68 Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/Rmd.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/cppR.png b/layers.personal/misctools/my-polymode/local/polymode/img/cppR.png new file mode 100644 index 0000000..76a4eb7 Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/cppR.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/debug.png b/layers.personal/misctools/my-polymode/local/polymode/img/debug.png new file mode 100644 index 0000000..6b8c790 Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/debug.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/ess-help.png b/layers.personal/misctools/my-polymode/local/polymode/img/ess-help.png new file mode 100644 index 0000000..b8e234a Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/ess-help.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/org.png b/layers.personal/misctools/my-polymode/local/polymode/img/org.png new file mode 100644 index 0000000..50a7764 Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/org.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/rapport.png b/layers.personal/misctools/my-polymode/local/polymode/img/rapport.png new file mode 100644 index 0000000..b346c93 Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/rapport.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/img/slim.png b/layers.personal/misctools/my-polymode/local/polymode/img/slim.png new file mode 100644 index 0000000..fa8577a Binary files /dev/null and b/layers.personal/misctools/my-polymode/local/polymode/img/slim.png differ diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-R.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-R.el new file mode 100644 index 0000000..074e559 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-R.el @@ -0,0 +1,466 @@ +;;; poly-R.el --- Popymodes for R +;; +;; Filename: poly-R.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; URL: https://github.com/vitoshka/polymode +;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'polymode) + +(defcustom pm-poly/R + (pm-polymode-one "R" + :hostmode 'pm-host/R + :innermode 'pm-inner/fundamental) + "R root polymode. Not intended to be used directly." + :group 'polymodes + :type 'object) + +;; NOWEB +(require 'poly-noweb) +(defcustom pm-poly/noweb+R + (clone pm-poly/noweb :innermode 'pm-inner/noweb+R) + "Noweb for R configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/noweb+R + (clone pm-inner/noweb + :mode 'R-mode) + "Noweb for R" + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-noweb+r-mode "poly-R") +(define-polymode poly-noweb+r-mode pm-poly/noweb+R :lighter " PM-Rnw") + + + +;; MARKDOWN +(require 'poly-markdown) +;;;###autoload (autoload 'poly-markdown+r-mode "poly-R") +(define-polymode poly-markdown+r-mode pm-poly/markdown :lighter " PM-Rmd") + + +;; RAPPORT +(defcustom pm-poly/rapport + (clone pm-poly/markdown "rapport" + :innermodes '(pm-inner/brew+R + pm-inner/rapport+YAML)) + "Rapport template configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/rapport+YAML + (pm-hbtchunkmode "rapport+YAML" + :mode 'yaml-mode + :head-reg "") + "YAML header in Rapport files" + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-rapport-mode "poly-R") +(define-polymode poly-rapport-mode pm-poly/rapport nil) + + + +;; HTML +(defcustom pm-poly/html+R + (clone pm-poly/html "html+R" :innermode 'pm-inner/html+R) + "HTML + R configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/html+R + (pm-hbtchunkmode "html+R" + :mode 'R-mode + :head-reg "") + "HTML KnitR innermode." + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-html+r-mode "poly-R") +(define-polymode poly-html+r-mode pm-poly/html+R) + + + +;;; R-brew +(defcustom pm-poly/brew+R + (clone pm-poly/brew "brew+R" + :innermode 'pm-inner/brew+R) + "Brew + R configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/brew+R + (pm-hbtchunkmode "brew+R" + :mode 'R-mode + :head-reg "<%[=%]?" + :tail-reg "[#=%=-]?%>") + "Brew R chunk." + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-brew+r-mode "poly-R") +(define-polymode poly-brew+r-mode pm-poly/brew+R) + + + +;;; R+C++ +;; todo: move into :matcher-subexp functionality? +(defun pm--R+C++-head-matcher (ahead) + (when (re-search-forward "cppFunction(\\(['\"]\n\\)" + nil t ahead) + (cons (match-beginning 1) (match-end 1)))) + +(defun pm--R+C++-tail-matcher (ahead) + (when (< ahead 0) + (goto-char (car (pm--R+C++-head-matcher -1)))) + (goto-char (max 1 (1- (point)))) + (let ((end (or (ignore-errors (scan-sexps (point) 1)) + (buffer-end 1)))) + (cons (max 1 (1- end)) end))) + +(defcustom pm-poly/R+C++ + (clone pm-poly/R "R+C++" :innermode 'pm-inner/R+C++) + "R + C++ configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/R+C++ + (pm-hbtchunkmode "R+C++" + :mode 'c++-mode + :head-mode 'host + :head-reg 'pm--R+C++-head-matcher + :tail-reg 'pm--R+C++-tail-matcher + :font-lock-narrow nil) + "HTML KnitR chunk." + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-r+c++-mode "poly-R") +(define-polymode poly-r+c++-mode pm-poly/R+C++) + + + +;;; C++R +(defun pm--C++R-head-matcher (ahead) + (when (re-search-forward "^[ \t]*/[*]+[ \t]*R" nil t ahead) + (cons (match-beginning 0) (match-end 0)))) + +(defun pm--C++R-tail-matcher (ahead) + (when (< ahead 0) + (error "backwards tail match not implemented")) + ;; may be rely on syntactic lookup ? + (when (re-search-forward "^[ \t]*\\*/") + (cons (match-beginning 0) (match-end 0)))) + +(defcustom pm-poly/C++R + (clone pm-poly/C++ "C++R" :innermode 'pm-inner/C++R) + "R + C++ configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/C++R + (pm-hbtchunkmode "C++R" + :mode 'R-mode + :head-reg 'pm--C++R-head-matcher + :tail-reg 'pm--C++R-tail-matcher) + "HTML KnitR chunk." + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-c++r-mode "poly-R") +(define-polymode poly-c++r-mode pm-poly/C++R) + + + +;;; R help +(defcustom pm-poly/ess-help+R + (pm-polymode-one "ess-R-help" + :innermode 'pm-inner/ess-help+R) + "ess-R-help" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/ess-help+R + (pm-hbtchunkmode "ess-help+R" + :mode 'R-mode + :head-reg "^Examples:" + :tail-reg "\\'" + :indent-offset 5 + :switch-buffer-functions '(pm--ess-help+R-turn-off-read-only)) + "Ess help R chunk" + :group 'innermodes + :type 'object) + +(defun pm--ess-help+R-turn-off-read-only (&rest ignore) + ;; don't transfer read only status from main help buffer + (cl-case pm/type + (body (read-only-mode -1)) + (head (read-only-mode 1)))) + +;;;###autoload (autoload 'poly-ess-help+r-mode "poly-R") +(define-polymode poly-ess-help+r-mode pm-poly/ess-help+R) + +(add-hook 'ess-help-mode-hook '(lambda () + (when (string= ess-dialect "R") + (poly-ess-help+r-mode)))) + + +(defun pm--Rd-examples-head-matcher (ahead) + (when (re-search-forward "\\examples *\\({\n\\)" nil t ahead) + (cons (match-beginning 1) (match-end 1)))) + +(defun pm--Rd-examples-tail-matcher (ahead) + (when (< ahead 0) + (goto-char (car (pm--R+C++-head-matcher -1)))) + (let ((end (or (ignore-errors (scan-sexps (point) 1)) + (buffer-end 1)))) + (cons (max 1 (- end 1)) end))) + +(defcustom pm-poly/Rd + (pm-polymode-one "R-documentation" + :innermode 'pm-inner/Rd) + "R polymode for Rd files" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/Rd + (pm-hbtchunkmode "R+C++" + :mode 'R-mode + :head-mode 'host + :head-reg 'pm--Rd-examples-head-matcher + :tail-reg 'pm--Rd-examples-tail-matcher) + "Rd examples chunk." + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-Rd-mode "poly-R") +(define-polymode poly-Rd-mode pm-poly/Rd) +(add-hook 'Rd-mode-hook 'poly-Rd-mode) + + + +;; Rmarkdown +(defcustom pm-exporter/Rmarkdown + (pm-shell-exporter "Rmarkdown" + :from + '(("Rmarkdown" "\\.[rR]?md\\|rapport\\'" "R Markdown" + "Rscript -e \"rmarkdown::render('%i', output_format = '%t', output_file = '%o',encoding='UTF-8')\"")) + :to + '(("auto" . pm--rmarkdown-shell-auto-selector) + ("html" "html" "html document" "html_document") + ("pdf" "pdf" "pdf document" "pdf_document") + ("word" "docx" "word document" "word_document") + ("md" "md" "md document" "md_document") + ("ioslides" "html" "ioslides presentation" "ioslides_presentation") + ("slidy" "html" "slidy presentation" "slidy_presentation") + ("beamer" "pdf" "beamer presentation" "beamer_presentation") + ("tufte handout pdf" "pdf" "pdf with tufte handout" "tufte::tufte_handout") + ("tufte book pdf" "pdf" "tufte book in PDF" "tufte::tufte_book") + ("tufte handout html" "html" "html with tufte handout" "tufte::tufte_html"))) + "R Markdown exporter. +Please not that with 'AUTO DETECT' export options, output file +names are inferred by Rmarkdown from YAML description +block. Thus, output file names don't comply with +`polymode-exporter-output-file-format'." + :group 'polymode-export + :type 'object) + +(polymode-register-exporter pm-exporter/Rmarkdown nil + pm-poly/markdown pm-poly/rapport) + +(defun pm--rmarkdown-shell-auto-selector (action &rest ignore) + (cl-case action + (doc "AUTO DETECT") + (command "Rscript -e \"rmarkdown::render('%i', output_format = 'all', encoding='UTF-8')\"") + (output-file #'pm--rmarkdown-output-file-sniffer))) + +(defcustom pm-exporter/Rmarkdown-ESS + (pm-callback-exporter "Rmarkdown-ESS" + :from + '(("Rmarkdown" "\\.[rR]?md\\|rapport\\'" "R Markdown" + "rmarkdown::render('%I', output_format = '%t', output_file = '%O')\n")) + :to + '(("auto" . pm--rmarkdown-callback-auto-selector) + ("html" "html" "html document" "html_document") + ("pdf" "pdf" "pdf document" "pdf_document") + ("word" "docx" "word document" "word_document") + ("md" "md" "md document" "md_document") + ("ioslides" "html" "ioslides presentation" "ioslides_presentation") + ("slidy" "html" "slidy presentation" "slidy_presentation") + ("beamer" "pdf" "beamer presentation" "beamer_presentation") + ("tufte handout pdf" "pdf" "pdf with tufte handout" "tufte::tufte_handout") + ("tufte book pdf" "pdf" "tufte book in PDF" "tufte::tufte_book") + ("tufte handout html" "html" "html with tufte handout" "tufte::tufte_html")) + :function 'pm--ess-run-command + :callback 'pm--ess-callback) + "R Markdown exporter. +Please not that with 'AUTO DETECT' export options, output file +names are inferred by Rmarkdown from YAML description +block. Thus, output file names don't comply with +`polymode-exporter-output-file-format'." + :group 'polymode-export + :type 'object) + +(polymode-register-exporter pm-exporter/Rmarkdown-ESS nil + pm-poly/markdown pm-poly/rapport) + +(defun pm--rmarkdown-callback-auto-selector (action &rest ignore) + (cl-case action + (doc "AUTO DETECT") + ;; last file is not auto-detected unless we cat new line + (command "rmarkdown::render('%I', output_format = 'all')") + (output-file #'pm--rmarkdown-output-file-sniffer))) + +(defun pm--rmarkdown-output-file-sniffer () + (goto-char (point-min)) + (let (files) + (while (re-search-forward "Output created: +\\(.*\\)" nil t) + (push (expand-file-name (match-string 1)) files)) + (reverse (delete-dups files)))) + + +;; KnitR +(defcustom pm-weaver/knitR + (pm-shell-weaver "knitr" + :from-to + '(("latex" "\\.\\(tex\\|[rR]nw\\)\\'" "tex" "LaTeX" "Rscript -e \"knitr::knit('%i', output='%o',encoding='UTF-8')\"") + ("html" "\\.x?html?\\'" "html" "HTML" "Rscript -e \"knitr::knit('%i', output='%o',encoding='UTF-8')\"") + ("markdown" "\\.[rR]?md]\\'" "md" "Markdown" "Rscript -e \"knitr::knit('%i', output='%o')\"") + ("rst" "\\.rst" "rst" "ReStructuredText" "Rscript -e \"knitr::knit('%i', output='%o', encoding='UTF-8')\"") + ("brew" "\\.[rR]?brew\\'" "brew" "Brew" "Rscript -e \"knitr::knit('%i', output='%o', encoding='UTF-8')\"") + ("asciidoc" "\\.asciidoc\\'" "txt" "AsciiDoc" "Rscript -e \"knitr::knit('%i', output='%o', encoding='UTF-8')\"") + ("textile" "\\.textile\\'" "textile" "Textile" "Rscript -e \"knitr::knit('%i', output='%o', encoding='UTF-8')\""))) + "Shell knitR weaver." + :group 'polymode-weave + :type 'object) + +(polymode-register-weaver pm-weaver/knitR nil + pm-poly/noweb+R pm-poly/markdown + pm-poly/rapport pm-poly/html+R) + +(defcustom pm-weaver/knitR-ESS + (pm-callback-weaver "knitR-ESS" + :from-to + '(("latex" "\\.\\(tex\\|rnw\\)\\'" "tex" "LaTeX" "knitr::knit('%I', output='%O', encoding='UTF-8')") + ("html" "\\.x?html?\\'" "html" "HTML" "knitr::knit('%I', output='%O', encoding='UTF-8')") + ("markdown" "\\.r?md\\'" "md" "Markdown" "knitr::knit('%I', output='%O', encoding='UTF-8')") + ("rst" "\\.rst\\'" "rst" "ReStructuredText" "knitr::knit('%I', output='%O', encoding='UTF-8')") + ("brew" "\\.r?brew\\'" "brew" "Brew" "knitr::knit('%I', output='%O', encoding='UTF-8')") + ("asciidoc" "\\.asciidoc\\'" "txt" "AsciiDoc" "knitr::knit('%I', output='%O',encoding='UTF-8')") + ("textile" "\\.textile\\'" "textile" "Textile" "knitr::knit('%I', output='%O',encoding='UTF-8')")) + :function 'pm--ess-run-command + :callback 'pm--ess-callback) + "ESS knitR weaver." + :group 'polymode-weave + :type 'object) + +(polymode-register-weaver pm-weaver/knitR-ESS nil + pm-poly/noweb+R pm-poly/markdown + pm-poly/rapport pm-poly/html+R) + +(defcustom pm-weaver/Sweave-ESS + (pm-callback-weaver "ESS-Sweave" + :from-to '(("latex" "\\.\\(tex\\|r?s?nw\\)\\'" "tex" + "LaTeX" "Sweave('%I', output='%O')")) + :function 'pm--ess-run-command + :callback 'pm--ess-callback) + "ESS 'Sweave' weaver." + :group 'polymode-weave + :type 'object) + +(polymode-register-weaver pm-weaver/Sweave-ESS nil + pm-poly/noweb+R) + + +;; Sweave +(defcustom pm-weaver/Sweave + (pm-shell-weaver "sweave" + :from-to + '(("latex" "\\.\\(tex\\|r?s?nw\\)\\'" + "tex" "LaTeX" "R CMD Sweave %i --options=\"output='%o'\""))) + "Shell 'Sweave' weaver." + :group 'polymode-weave + :type 'object) + +(polymode-register-weaver pm-weaver/Sweave nil + pm-poly/noweb+R) + + +;; ESS command + +(declare-function ess-async-command nil) +(declare-function ess-force-buffer-current nil) +(declare-function ess-process-get nil) +(declare-function ess-process-put nil) +(declare-function comint-previous-prompt nil) + +(defun pm--ess-callback (proc string) + (let ((ofile (process-get proc :output-file))) + ;; This is getting silly. Ess splits output for optimization reasons. So we + ;; are collecting output from 3 places: + ;; - most recent STRING + ;; - string in accumulation buffer 'accum-buffer-name + ;; - string already in output buffer + (with-current-buffer (process-get proc 'accum-buffer-name) + (setq string (concat (buffer-substring (point-min) (point-max)) + string))) + (with-current-buffer (process-buffer proc) + (setq string (concat (buffer-substring (or ess--tb-last-input (comint-previous-prompt)) (point-max)) + string))) + (with-temp-buffer + (message string) + (insert string) + (when (string-match-p "Error\\(:\\| +in\\)" string) + (error "Errors durring ESS async command")) + (unless (stringp ofile) + (setq ofile (funcall ofile)))) + ofile)) + +(defun pm--ess-run-command (command callback &rest ignore) + (require 'ess) + (let ((ess-eval-visibly t) + (ess-dialect "R")) + (ess-force-buffer-current) + (ess-process-put :output-file pm--output-file) + (ess-process-put 'callbacks (list callback)) + (ess-process-put 'interruptable? t) + (ess-process-put 'running-async? t) + (ess-eval-linewise command))) + + +;; COMPAT + +(when (fboundp 'advice-add) + (advice-add 'ess-eval-paragraph :around 'pm-execute-narrowed-to-span) + (advice-add 'ess-eval-buffer :around 'pm-execute-narrowed-to-span) + (advice-add 'ess-beginning-of-function :around 'pm-execute-narrowed-to-span)) + +(provide 'poly-R) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-base.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-base.el new file mode 100644 index 0000000..cf068c2 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-base.el @@ -0,0 +1,109 @@ +;;; CORE POLYMODE AND HOST OBJECTS + + +;;; POLYMODE objects +;; These are simple generic configuration objects. More specialized +;; configuration objects are defined in language-specific files (e.g. poly-R.el, +;; poly-markdown.el etc). + +(defcustom pm-inner/fallback + (pm-chunkmode "FallBack" :mode 'poly-fallback-mode) + "Polymode fall back inner mode." + :group 'hostmodes + :type 'object) + +(defcustom pm-poly/brew + (pm-polymode-one "brew" + :hostmode 'pm-host/text + :innermode 'pm-inner/fallback) + "Typical Brew configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-poly/html + ;; fixme: should probably be pm-polymode-multi + (pm-polymode-one "html" + :hostmode 'pm-host/html + :innermode 'pm-inner/fallback) + "HTML typical configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-poly/C++ + (pm-polymode-one "C++" + :hostmode 'pm-host/C++ + :innermode 'pm-inner/fallback) + "C++ typical configuration" + :group 'polymodes + :type 'object) + + + +;; HOST MODES + +(defcustom pm-host/blank + (pm-bchunkmode "FallBack" :mode nil) + "Blank. Used as a placeholder for currently installed mode. +It is specifically intended to be used with minor modes." + :group 'hostmodes + :type 'object) + +(defcustom pm-host/fallback + (pm-bchunkmode "FallBack" + :mode 'poly-fallback-mode) + "Polymode fall back host mode." + :group 'hostmodes + :type 'object) + +(defcustom pm-host/fundamental + (pm-bchunkmode "fundamental" + :mode 'fundamental-mode) + "Fundamental host mode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/latex + (pm-bchunkmode "latex" + :mode 'latex-mode) + "Latex host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/html + (pm-bchunkmode "html" + :mode 'html-mode) + "HTML host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/R + (pm-bchunkmode "R" + :mode 'R-mode) + "R host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/C++ + (pm-bchunkmode "C++" + :mode 'c++-mode + :font-lock-narrow nil) + "C++ host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/text + (pm-bchunkmode "text" + :mode 'text-mode) + "Text host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/yaml + (pm-bchunkmode "YAML" + :mode 'yaml-mode) + "YAML chunkmode" + :group 'hostmodes + :type 'object) + + +(provide 'poly-base) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-c.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-c.el new file mode 100644 index 0000000..710cbce --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-c.el @@ -0,0 +1,51 @@ +;;; poly-C.el --- Popymodes for C and C++ +;; +;; Filename: poly-C.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; URL: https://github.com/vitoshka/polymode +;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'polymode) + +(require 'poly-noweb) + +(defcustom pm-poly/noweb+c + (clone pm-poly/noweb + :innermode 'pm-inner/noweb+c) + "Noweb polymode for c" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/noweb+c + (clone pm-inner/noweb + :mode 'c-mode) + "Noweb innermode for C" + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-noweb+c-mode "poly-c") +(define-polymode poly-noweb+c-mode pm-poly/noweb+c :lighter " PM-Cnw") diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-erb.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-erb.el new file mode 100644 index 0000000..cbfd875 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-erb.el @@ -0,0 +1,60 @@ +(require 'polymode) + +(defcustom pm-host/coffee + (pm-bchunkmode "coffee" :mode 'coffee-mode) + "coffee host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-host/javascript + (pm-bchunkmode "javascript" :mode 'js-mode) + "javascript host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-inner/erb + (pm-hbtchunkmode "erb" + :mode 'ruby-mode + :head-reg "\"?\<\% *[-=]?" + :tail-reg "\%\>\"?") + "erb typical chunk." + :group 'innermodes + :type 'object) + +(defcustom pm-poly/coffee-erb + (pm-polymode-one "coffee-erb" + :hostmode 'pm-host/coffee + :innermode 'pm-inner/erb) + "coffee-erb typical polymode." + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-coffee+erb-mode "poly-erb") +(define-polymode poly-coffee+erb-mode pm-poly/coffee-erb) +(define-obsolete-function-alias 'poly-coffee-erb-mode 'poly-coffee+erb-mode) + +(defcustom pm-poly/javascript-erb + (pm-polymode-one "javascript-erb" + :hostmode 'pm-host/javascript + :innermode 'pm-inner/erb) + "javascript-erb typical polymode." + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-javascript+erb-mode "poly-erb") +(define-polymode poly-javascript+erb-mode pm-poly/javascript-erb) +(define-obsolete-function-alias 'poly-javascript-erb-mode 'poly-javascript+erb-mode) + +(defcustom pm-poly/html-erb + (pm-polymode-one "html-erb" + :hostmode 'pm-host/html + :innermode 'pm-inner/erb) + "html-erb typical polymode." + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-html+erb-mode "poly-erb") +(define-polymode poly-html+erb-mode pm-poly/html-erb) +(define-obsolete-function-alias 'poly-html-erb-mode 'poly-html+erb-mode) + +(provide 'poly-erb) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-markdown.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-markdown.el new file mode 100644 index 0000000..d9b9709 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-markdown.el @@ -0,0 +1,71 @@ +;;; poly-markdown.el +;; +;; Filename: poly-markdown.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; URL: https://github.com/vitoshka/polymode +;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'polymode) +;; (require 'markdown-mode) + +(defcustom pm-host/markdown + (pm-bchunkmode "Markdown" + :mode 'markdown-mode + :init-functions '(poly-markdown-remove-markdown-hooks)) + "Markdown host chunkmode" + :group 'hostmodes + :type 'object) + +(defcustom pm-inner/markdown + (pm-hbtchunkmode-auto "markdown" + :head-reg "^[ \t]*```[{ \t]*\\w.*$" + :tail-reg "^[ \t]*```[ \t]*$" + :retriever-regexp "```[ ]*{?\\(?:lang *= *\\)?\\([^ \n;=,}]+\\)" + :font-lock-narrow t) + "Markdown typical chunk." + :group 'innermodes + :type 'object) + +(defcustom pm-poly/markdown + (pm-polymode-multi-auto "markdown" + :hostmode 'pm-host/markdown + :auto-innermode 'pm-inner/markdown) + "Markdown typical configuration" + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-markdown-mode "poly-markdown") +(define-polymode poly-markdown-mode pm-poly/markdown) + +;;; FIXES: +(defun poly-markdown-remove-markdown-hooks () + ;; get rid of awful hooks + (remove-hook 'window-configuration-change-hook 'markdown-fontify-buffer-wiki-links t) + (remove-hook 'after-change-functions 'markdown-check-change-for-wiki-link t)) + + +(provide 'poly-markdown) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-noweb.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-noweb.el new file mode 100644 index 0000000..9cdd523 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-noweb.el @@ -0,0 +1,123 @@ +;;; poly-noweb.el +;; +;; Filename: poly-noweb.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; URL: https://github.com/vitoshka/polymode +;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'polymode) + +(defcustom pm-poly/noweb + (pm-polymode-one "noweb" + :hostmode 'pm-host/latex + :innermode 'pm-inner/noweb + :exporters '(pm-exporter/latexmk + pm-exporter/pdflatex + pm-exporter/lualatex + pm-exporter/xelatex) + :map '(("<" . poly-noweb-electric-<))) + "Noweb typical configuration" + :group 'polymodes + :type 'object) + +(defcustom pm-inner/noweb + (pm-hbtchunkmode "noweb" + :head-reg "^[ \t]*<<\\(.*\\)>>=" + :tail-reg "^[ \t]*@ *\\(%def.*\\)?$") + "Noweb typical chunk." + :group 'innermodes + :type 'object) + +;;;###autoload (autoload 'poly-noweb-mode "poly-noweb") +(define-polymode poly-noweb-mode pm-poly/noweb) + +(defun poly-noweb-electric-< (arg) + "Auto insert noweb chunk if at bol followed by white space. +If given an numerical argument, it simply insert `<'. Otherwise, +if at the beginning of a line in a host chunk insert \"<<>>=\", a +closing \"@\" and a newline if necessary." + (interactive "P") + (if (or arg (not (eq pm/type 'host))) + (self-insert-command (if (numberp arg) arg 1)) + (if (not (looking-back "^[ \t]*")) + (self-insert-command 1) + (insert "<<") + (save-excursion + (insert ">>=\n\n@ ") + (unless(looking-at "\\s *$") + (newline))) + (ess-noweb-update-chunk-vector)))) + +(defcustom pm-exporter/pdflatex + (pm-shell-exporter "pdflatex" + :from + '(("latex" "\\.tex\\'" "LaTeX" "pdflatex -jobname %b %t %i")) + :to + '(("pdf" "pdf" "PDF" "")) + :quote t) + "Shell pdflatex exporter." + :group 'polymode-export + :type 'object) + +(defcustom pm-exporter/lualatex + (pm-shell-exporter "LuaLaTeX" + :from + '(("latex" "\\.tex\\'" "LuaLaTeX" "lualatex -jobname %b %t %i")) + :to + '(("pdf" "pdf" "PDF" "")) + :quote t) + "Shell pdflatex exporter." + :group 'polymode-export + :type 'object) + +(defcustom pm-exporter/xelatex + (pm-shell-exporter "XeLaTeX" + :from + '(("latex" "\\.tex\\'" "XeLaTeX" "xelatex -jobname %b %t %i")) + :to + '(("pdf" "pdf" "PDF" "")) + :quote t) + "Shell pdflatex exporter." + :group 'polymode-export + :type 'object) + +(defcustom pm-exporter/latexmk + (pm-shell-exporter "latexmk" + :from + '(("latex" "\\.tex\\'" "LaTeX(MK)" "latexmk -jobname=%b %t %i")) + :to + '(("pdf" "pdf" "latex" "-pdf") + ("xelatex" "pdf" "xe" "-xelatex") + ("lualatex" "pdf" "lua" "-lualatex") + ("ps" "ps" "latex" "-ps") + ("dvi" "dvi" "latex" "-dvi")) + :quote t) + "Shell latexmk dvi, ps and pdf exporter." + :group 'polymode-export + :type 'object) + +(provide 'poly-noweb) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-org.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-org.el new file mode 100644 index 0000000..a31dbaa --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-org.el @@ -0,0 +1,67 @@ +;;; poly-org.el +;; +;; Filename: poly-org.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; URL: https://github.com/vitoshka/polymode +;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'org-src) +(require 'polymode) + +(defcustom pm-host/org + (pm-bchunkmode "Org mode" + :mode 'org-mode) + "Org host innermode" + :group 'hostmodes + :type 'object) + +(defcustom pm-inner/org + (pm-hbtchunkmode-auto "org" + :head-reg "^[ \t]*#\\+begin_src .*$" + :tail-reg "^[ \t]*#\\+end_src" + :head-mode 'host + :tail-mode 'host + :retriever-regexp "#\\+begin_src +\\(\\(\\w\\|\\s_\\)+\\)" + :indent-offset org-edit-src-content-indentation + :font-lock-narrow t) + "Org typical chunk." + :group 'innermodes + :type 'object) + +(defcustom pm-poly/org + (pm-polymode-multi-auto "org" + :hostmode 'pm-host/org + :auto-innermode 'pm-inner/org) + "Org typical configuration" + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-org-mode "poly-org") +(define-polymode poly-org-mode pm-poly/org) + +(provide 'poly-org) + diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/poly-slim.el b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-slim.el new file mode 100644 index 0000000..0fc5a67 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/poly-slim.el @@ -0,0 +1,107 @@ +(require 'polymode) + +;; We cannot have all these "requires" as part of polymode +;; https://github.com/vspinu/polymode/issues/69 +;; (require 'css-mode) +;; (require 'scss-mode) +;; (require 'coffee-mode) +;; (require 'slim-mode) +;; (require 'ruby-mode) +;; (require 'markdown-mode) + +(defcustom pm-host/slim + (pm-bchunkmode "slim" :mode 'slim-mode) + "slim host chunkmode" + :group 'hostmodes + :type 'object) + +(pm-create-indented-block-matchers "slim-coffee" "^[^ ]*\\(.*:? *coffee: *\\)$") +(defcustom pm-inner/slim-coffee + (pm-hbtchunkmode "slim coffee include" + :mode 'coffee-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-coffee-head-matcher + :tail-reg 'pm-slim-coffee-tail-matcher) + "slim-coffee typical chunk." + :group 'innermodes + :type 'object) + +(pm-create-indented-block-matchers "slim-css" "^[^ ]*\\(.*:? *css: *\\)$") +(defcustom pm-inner/slim-css + (pm-hbtchunkmode "slim css include" + :mode 'css-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-css-head-matcher + :tail-reg 'pm-slim-css-tail-matcher) + "slim-css typical chunk." + :group 'innermodes + :type 'object) + +(pm-create-indented-block-matchers "slim-scss" "^[^ ]*\\(.*:? *scss: *\\)$") +(defcustom pm-inner/slim-scss + (pm-hbtchunkmode "slim scss include" + :mode 'scss-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-scss-head-matcher + :tail-reg 'pm-slim-scss-tail-matcher) + "slim-scss typical chunk." + :group 'innermodes + :type 'object) + +(pm-create-indented-block-matchers "slim-ruby" "^[^ ]*\\(.*:? *ruby: *\\)$") +(defcustom pm-inner/slim-ruby + (pm-hbtchunkmode "slim ruby include" + :mode 'ruby-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-ruby-head-matcher + :tail-reg 'pm-slim-ruby-tail-matcher) + "slim-ruby typical chunk." + :group 'innermodes + :type 'object) + +(pm-create-indented-block-matchers "slim-js" "^[^ ]*\\(.*:? *javascript: *\\)$") +(defcustom pm-inner/slim-js + (pm-hbtchunkmode "slim js include" + :mode 'js-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-js-head-matcher + :tail-reg 'pm-slim-js-tail-matcher) + "slim-js typical chunk." + :group 'innermodes + :type 'object) + +(pm-create-indented-block-matchers "slim-md" "^[^ ]*\\(.*:? *markdown: *\\)$") +(defcustom pm-inner/slim-md + (pm-hbtchunkmode "slim markdown include" + :mode 'markdown-mode + :head-mode 'slim-mode + :tail-mode 'slim-mode + :head-reg 'pm-slim-md-head-matcher + :tail-reg 'pm-slim-md-tail-matcher) + "slim-markdown typical chunk." + :group 'innermodes + :type 'object) + +(defcustom pm-poly/slim + (pm-polymode-multi "slim" + :hostmode 'pm-host/slim + :innermodes '(pm-inner/slim-coffee + pm-inner/slim-css + pm-inner/slim-scss + pm-inner/slim-js + pm-inner/slim-md + pm-inner/slim-ruby)) + + "slim typical polymode." + :group 'polymodes + :type 'object) + +;;;###autoload (autoload 'poly-slim-mode "poly-slim") +(define-polymode poly-slim-mode pm-poly/slim) + +(provide 'poly-slim) diff --git a/layers.personal/misctools/my-polymode/local/polymode/modes/readme.md b/layers.personal/misctools/my-polymode/local/polymode/modes/readme.md new file mode 100644 index 0000000..b01993c --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/modes/readme.md @@ -0,0 +1,402 @@ +# Developing with Polymode + +Polymode doesn't keep its modes in a single emacs buffer but in several indirect +buffers, as many as different modes are there in a file. Consequently, polymode +is as fast as switching emacs buffers because it never re-installs major modes +like other multi-modes do. Dave Love's +[multi-mode.el](http://www.loveshack.ukfsn.org/emacs/multi-mode.el) gets full +credit for this idea. + +- [Glossary of Terms](#glossary-of-terms) +- [Class Hierarchy](#class-hierarchy) + - [Polymodes](#polymodes) + - [Chunkmodes](#chunkmodes) +- [Defining New Polymodes](#defining-new-polymodes) + - [One Predefined Innermode](#one-predefined-innermode) + - [Multiple Predefined Innermodes](#multiple-predefined-innermodes) + - [Multiple Automatically Detected Innermodes](#multiple-automatically-detected-innermodes) +- [Visually debugging polymodes](#visually-debugging-polymodes) +- [Defining Literate Programming Backends](#defining-backends) + - [Weavers](#weavers) + - [Exporters](#exporters) + - [Tanglers](#tanglers) +- [Internals](#internals) + - [API](#api) + - [Initialization of polymodes](#initialization-of-polymodes) + +## Glossary of Terms + +Assume the following `org-mode` file: + +```org +* emacs lisp code block + +#+begin_src emacs-lisp :var tbl='() + (defun all-to-string (tbl) + (if (listp tbl) + (mapcar #'all-to-string tbl) + (if (stringp tbl) + tbl + (format "%s" tbl)))) + (all-to-string tbl) +#+end_src + +``` + + - **span** - a syntactically homogeneous fragment of text. In the `org-mode` + example the org span starts at the beginning of the file ends with (but does + not include) `#+begin_src`. Header span is `#+begin_src emacs-lisp :var + tbl='()`. The emacs lisp code span follows next. `#+end_src` is the tail + span. + - **sub-mode** - an emacs mode from inside a span. + - **chunk** is a well delimited fragment of text that consists of one or more + spans. Most common types of chunks are `bchunk` (= *b*ody chunk) and hbtchunk + (= *h*ead + *b*ody + *t*ail spans). In the above example, org-mode emacs-lisp + chunk starts with `#+begin_src` and ends with `#+end_src` (inclusively). + - **polymode** is overloaded with three concurrent meanings which we will + disambiguate from the context: + 1. Like emacs plain modes, polymodes represent an _abstract idea_ of a + collection of related functionality that is available in emacs buffers. + 2. Like emacs modes, polymodes are _functions_ that install a bunch of + functionality into emacs buffer. You can use polymodes just as any other + emacs major or minor mode. + 3. Polymodes are _objects_ of `pm-polymode` class. The functionality of each + polymode is completely characterized by this object and the methods that + act on it. During initialization this object is cloned and its copy is + stored in a buffer-local variable `pm/polymode`. There are several types + of polymode objects. See [hierarchy](#class-hierarchy) below. + - **chunkmode** refers to one of the following: + 1. An abstract idea of the functionality available in chunks of the same type + (e.g. `org-mode chunk`, `emacs-lisp chunk`). + 2. Emacs mode function (e.g. `org-mode`), or a set of such functions (e.g. + `pm-head-tail-mode` for header/tail + `emacs-lisp-mode` for the chunk's + body) what instantiate all of the required functionality of the plain + emacs modes embodies by that chunk. + 3. Object of `pm-chunkmode` class. This object represents the behavior of the + chunkmode and is stored in a buffer-local variable `pm/chunkmode`. There + are several types of chunkmode objects. See [hierarchy](#class-hierarchy) + below. + - **hostmodes** and **innermodes** Chunkmodes could be classified into host and + inner chunkmodes (hostmodes and innermodes in short). In the above example + org chunkmode is a hostmode and emacs-lisp chunkmode is an innermode. + + +It is easy to think of the chunkmodes as inter-weaved threads. Host chunkmode is +a stretched canvas. Each inner chunkmode is a thread weaved into the +hostmode. Visible fragments of the each thread are chunks. + +In light of the above metaphor, it is worth emphasizing the distinctions between +`chunks` and `chunkmodes`. Chunks are fragments of text and there might be +multiple chunks of the same type in the buffer. In contrast, there is only one +chunkmode of some specific type and multiple chunks of this type "share" this +chunkmode. + + +## Class Hierarchy + +Polymode package uses `eieio` to represent its objects. The root class for all +polymode classes is `eieio-instance-inheritor` which provides prototype based +inheritance (in addition to class based). This means that objects instantiated +from polymode classes can be cloned in order to dynamically create a hierarchy +of customizable objects. There are a bunch of such objects already defined, you +can investigate those in `polymodes`, `hostmodes`, `innermodes` customization +groups. + +As polymode uses indirect buffers to implement the multi-mode, storing mode +functionality in objects (in contrast to buffer local variables) is very +convenient strategy for moving stuff around. + +Current polymode class hierarchy: + +``` + +--eieio-instance-inheritor + | +--pm-root + | +--pm-polymode + | | +--pm-polymode-multi + | | | +--pm-polymode-multi-auto + | | +--pm-polymode-one + | | + | +--pm-chunkmode + | | +--pm-hbtchunkmode + | | | +--pm-hbtchunkmode-auto + | | +--pm-bchunkmode + | | + | +--pm-weaver + | | +--pm-shell-weaver + | | +--pm-callback-weaver + | +--pm-exporter + | +--pm-shell-exporter + | +--pm-callback-exporter + +``` + +*Using Help with EIEIO:* Each `eieio` class has a corresponding constructor +whose docstring contains a complete description of the class. In emacs 24.4 or +higher you can use `C-h f pm-foo RET` to inspect the documentation of the +class. Alternatively either use `M-x describe-class pm-foo` or lookup the class +definition directly in [polymode-classes.el](polymode-classes.el). + + +### Polymodes + +As noted earlier, each polymode is a function that walks and quacks like +standard emacs major mode. Hence, things like `poly-XXX-mode-map` and +`poly-XXX-mode-hook` work just as expected. Plymode functions are defined with +`define-polymode` and can be used in place of emacs standard major or minor +modes. + +Each polymode is represented by a customizable `pm-polymode` object which fully +characterizes its behavior. During the initialization this config object is +cloned and installed in every new buffer. + +The most important slot of root config class `pm-polymode` is: + +- `:hostmode` - name of the chunkmode object (typicaly of class `pm-bchunkmode`, + see [Chunkmodes](#chunkmodes)). + +Currently there are three subclasses of `pm-polymode`: + +- `pm-polymode-one` - used for polymdoes with only one predefined innermode. It + extends `pm-polymode` with one slot - `:innermode` - which is a name of the + inner chunkmode (typically objects of class `pm-hbtchunkmode`). +- `pm-polymode-multi` - used for polymodes with multiple predefined inner + modes. It extends `pm-polymode` with `:innermodes` list that contains names of + predefined `pm-hbtchunkmode` objects. +- `pm-polymode-multi-auto` - used for polymodes with multiple dynamically + discoverable chunkmodes. It extends `pm-polymode-multi` with `:auto-innermode` + slot (typically an object of class `pm-hbtchunkmode-auto`). + + +### Chunkmodes + +Most important user visible slots of the root class `pm-chunkmode` are: + +- `:mode` - symbol of corresponding emacs plain mode (e.g. `html-mode`, +`latex-mode` etc) +- `:indent-offset`, `:font-lock-narrow`, `:adjust-face`etc - configuration options. + +Currently, there are three sub classes of `pm-chunkmode`: + +1. `pm-bchunkmode` - represents the mode of plain body chunks + (bchunks). These objects are commonly used to represent functionality in + host chunks and are instances of `pm-bchunkmode`. Currently it doesn't + add any new slots to its parent class `pm-chunkmode`. + +2. `hbtchunkmode` - represents the mode of composite head-body-tail + chunks. These objects are commonly used to represent the functionality of + the innermost chunks of the buffer. `pm-hbtchunkmode` extends + `pm-chunkmode` with additional slots, most importantly: + * `head-mode` and `tail-mode`: names of emacs-modes for header/tail of the + chunk + * `head-reg` and `tail-reg`: regular expressions or functions to detect the + header/tail + +3. `pm-hbtchunkmode-auto` - represents chunkmodes for which the mode type is not + predefined and must be computed at runtime. This class extends + `pm-hbtchunkmode` with `retriver-regexp`, `retriver-num` and + `retriver-function` which can be used to retrive the mode name from the + header of the inner chunk. + + +## Defining New Polymodes + +In order to define a new polymode `poly-cool-mode` you first have to define or +clone a chunkmode object to represent the hostmode, and one or more chunkmodes +to represent innermodes. Then define the polymode object `pm-poly/cool` pointing +to previously defined host and inner chunkmodes. + +There are a lot of polymodes, hostmodes and innermodes already defined. Please +reuse those whenever possible. + +### One Predefined Innermode + +This is a simplified version of `poly-noweb-mode` from +[poly-noweb.el](poly-noweb.el). First define the latex hostmode: + +```lisp +(defcustom pm-host/latex + (pm-bchunkmode "latex" :mode 'latex-mode) + "Latex host chunkmode" + :group 'hostmodes + :type 'object) +``` + +Then define the noweb innermode: + +```lisp +(defcustom pm-inner/noweb + (pm-hbtchunkmode "noweb" + :head-reg "<<\\(.*\\)>>=" + :tail-reg "\\(@ +%def .*\\)$\\|\\(@[ \n]\\)") + "Noweb typical chunk." + :group 'innermodes + :type 'object) +``` + +Finally, define the `pm-polymode` object and the coresponding polymode function: + +```lisp +(defcustom pm-poly/noweb + (pm-polymode-one "noweb" + :hostmode 'pm-host/latex + :innermode 'pm-inner/noweb) + "Noweb typical polymode." + :group 'polymodes + :type 'object) + +(define-polymode poly-noweb-mode pm-poly/noweb) +``` + +The hostmode `pm-host/latex` from above is already defined in +[poly-base.el](poly-base.el), so you need not have declared it. + +Now, let's assume you want a more specialized noweb mode, say `noweb` with `R` +chunks. Instead of declaring root hostmodes and innermodes again you should +clone existing noweb root object. This is how it is done (from +[poly-R.el](poly-R.el)): + +```lisp +(defcustom pm-inner/noweb+R + (clone pm-inner/noweb :mode 'R-mode) + "Noweb innermode for R" + :group 'innermodes + :type 'object) + +(defcustom pm-poly/noweb+R + (clone pm-poly/noweb :innermode 'pm-inner/noweb+R) + "Noweb polymode for R" + :group 'polymodes + :type 'object) + +(define-polymode poly-noweb+r-mode pm-poly/noweb+R :lighter " PM-Rnw") +``` + +That's it. You simply had to define new innermode and polymode by cloning from +previously defined objects and adjusting `:mode` and `:innermode` slots +respectively. + +### Multiple Predefined Innermodes + +No examples yet. Web-mode would probably qualify. + +### Multiple Automatically Detected Innermodes + +This is an example of markdown polymode (from [poly-markdown.el](poly-markdown.el)). + +```lisp +;; 1. Define hostmode object +(defcustom pm-host/markdown + (pm-bchunkmode "Markdown" :mode 'markdown-mode) + "Markdown host chunkmode" + :group 'hostmodes + :type 'object) + + +;; 2. Define innermode object +(defcustom pm-inner/markdown + (pm-hbtchunkmode-auto "markdown" + :head-reg "^[ \t]*```[{ \t]*\\w.*$" + :tail-reg "^[ \t]*```[ \t]*$" + :retriever-regexp "```[ \t]*{?\\(\\(\\w\\|\\s_\\)*\\)" + :font-lock-narrow t) + "Markdown typical chunk." + :group 'innermodes + :type 'object) + +;; 3. Define polymode object +(defcustom pm-poly/markdown + (pm-polymode-multi-auto "markdown" + :hostmode 'pm-host/markdown + :auto-innermode 'pm-inner/markdown + :init-functions '(poly-markdown-remove-markdown-hooks)) + "Markdown typical configuration" + :group 'polymodes + :type 'object) + +;; 4. Define polymode function +(define-polymode poly-markdown-mode pm-poly/markdown) +``` +## Visually Debugging Polymodes + +After defining polymodes you can visually inspect if the polymode does what you +intended by activating globalized minor pm-debug minor mode with `M-x +pm-debug-mode`. When `pm-debug-mode` is active the current span will be +highlighted and brief info displayed in the minibuffer. + +Currently defined commands are: + + - `M-n M-f` Toggle font-locking (`pm-debug-toggle-fontification`) + - `M-n M-h` Map through all spans and briefly blink each span (`pm-debug-map-over-spans-and-highlight`) + - `M-n M-i` Highlight current span and display more info (`pm-debug-info-on-span`) + + + + +## Defining Backends + +### Weavers +todo +### Exporters +todo +### Tanglers +todo + + +## Internals + +Warning: Following description is subject to change and might not be up-to-date. + +### API + +All API classes and methods are named with `pm-` prefix. + + +Buffer local objects: + + - `pm/type` + - `pm/chunkmode` + - `pm/polymode` + +Generics: + + - `pm-initialize` + - `pm-get-buffer-create` + - `pm-select-buffer` + - `pm-get-span` + - `pm-indent-line` + - `pm-get-adjust-face` + +Utilities: + + - `pm-get-innermost-span` + - `pm-map-over-spans` + - `pm-narrow-to-span` + +### Initialization of polymodes + +Note: This description is obsolete. Internals have changed. + +When called, `poly-XXX-mode` (created with `define-polymode`) clones +`pm-poly/XXX` object and calls `pm-initialize` generic on it. The actual +initialization depends on concrete type of the `pm-polymode` object but these +are the common steps: + + 1. assign the config object into local `pm/polymode` variable + 2. clone the `pm-chunkmode` object specified by `:hostmode` slot of + `pm-polymode` + 3. initialize hostmode by running the actual function in `:mode` slot of the + hostmode object. + 4. store hostmode object into local `pm/chunkmode` variable + 5. set local variable `pm/type` to `'host` + 6. run `pm-polymode`'s `:init-functions` as normal hooks + 7. run `pm--setup-buffer` which is common setup function used internally to + set `font-lock` and a range of other stuff + 8. run `poly-XXX-mode-hook`. + +Discovery of the spans is done by `pm-select-buffer` generic which is commonly +called first by `jit-lock`. `pm-select-buffer` fist checks if the corresponding +`pm-chunkmode` object (and associated indirect buffer) has been already +created. If so, `pm-select-buffer` simply selects that buffer. Otherwise, it +calls `pm-get-buffer-create` generic which, in turn, creates `pm-chunkmode` +object and the associated indirect buffer. + diff --git a/layers.personal/misctools/my-polymode/local/polymode/poly-lock.el b/layers.personal/misctools/my-polymode/local/polymode/poly-lock.el new file mode 100644 index 0000000..e93bfd1 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/poly-lock.el @@ -0,0 +1,219 @@ + +;; `font-lock-mode' call graph: +;; -> font-lock-function <- we are replacing this with `poly-lock-mode' +;; -> font-lock-default-function +;; -> font-lock-mode-internal +;; -> font-lock-turn-on-thing-lock +;; -> font-lock-turn-on-thing-lock +;; -> (setq font-lock-flush-function jit-lock-refontify) +;; -> (setq font-lock-ensure-function jit-lock-fontify-now) +;; -> (setq font-lock-fontify-buffer-function jit-lock-refontify) +;; -> (jit-lock-register #'font-lock-fontify-region) +;; -> (add-hook 'jit-lock-functions #'font-lock-fontify-region nil t) +;; -> jit-lock-mode + +(require 'polymode-core) +(require 'polymode-compat) + +(defvar poly-lock-fontification-in-progress nil) +(defvar-local poly-lock-mode nil) +(defvar-local poly-lock--fontify-region-original nil) + +(eval-when-compile + (defmacro with-buffer-prepared-for-poly-lock (&rest body) + "Execute BODY in current buffer, overriding several variables. +Preserves the `buffer-modified-p' state of the current buffer." + (declare (debug t)) + `(let ((inhibit-point-motion-hooks t)) + (with-silent-modifications + ,@body)))) + +(defun poly-lock-no-jit-lock-in-polymode-buffers (orig-fun arg) + "Don't activate `jit-lock-mode' when in `polymode' buffers. +We are reusing some of the jit-lock functionality but don't want +to activate jit-lock." + (unless (and polymode-mode pm/polymode) + (funcall orig-fun arg))) +(pm-around-advice 'jit-lock-mode #'poly-lock-no-jit-lock-in-polymode-buffers) + +(defun poly-lock-mode (arg) + ;; value of `font-lock-function' in polymode buffers + (unless polymode-mode + (error "Trying to (de)activate `poly-lock-mode' in a non-polymode buffer (%s)" (current-buffer))) + (setq poly-lock-mode arg) + + (if arg + (progn + ;; a lot of the following is inspired by what jit-lock does in + ;; `font-lock-turn-on-thing-lock' + + (setq-local font-lock-support-mode 'poly-lock-mode) + (setq-local font-lock-dont-widen t) + + ;; re-use jit-lock registration. Some minor modes (adaptive-wrap) + ;; register extra functionality. + (jit-lock-register 'font-lock-fontify-region) + + ;; don't allow other functions + (setq-local fontification-functions '(poly-lock-fontification-function)) + + (setq-local font-lock-flush-function 'poly-lock-refontify) + (setq-local font-lock-ensure-function 'poly-lock-fontify-now) + (setq-local font-lock-fontify-buffer-function 'poly-lock-refontify) + + ;; There are some more, jit-lock doesn't change those, neither do we: + ;; font-lock-unfontify-region-function (defaults to font-lock-default-unfontify-region) + ;; font-lock-unfontify-buffer-function (defualts to font-lock-default-unfontify-buffer) + + ;; Don't fontify eagerly (and don't abort if the buffer is large). This + ;; is probably not needed but let it be. + (setq-local font-lock-fontified t) + + ;; Now we can finally call `font-lock-default-function' because + ;; `font-lock-support-mode' is set to "unrecognizible" value, only core + ;; font-lock setup happens. + (font-lock-default-function arg) + + ;; Must happen after call to `font-lock-default-function' + (remove-hook 'after-change-functions 'font-lock-after-change-function t) + (remove-hook 'after-change-functions 'jit-lock-after-change t) + (add-hook 'after-change-functions 'poly-lock-after-change nil t) + + ;; Reusing jit-lock var becuase mode populate it directly. We are using + ;; this in `poly-lock-after-change' below. Taken from `jit-lock + ;; initialization. + (add-hook 'jit-lock-after-change-extend-region-functions + 'font-lock-extend-jit-lock-region-after-change + nil t)) + + (remove-hook 'after-change-functions 'poly-lock-after-change t) + (remove-hook 'fontification-functions 'poly-lock-fontification-function t)) + (current-buffer)) + +(defun poly-lock-fontification-function (start) + "The only function in `fontification-functions'. +This is the entry point called by the display engine. START is +defined in `fontification-functions'. This function is has the +same scope as `jit-lock-function'." + (unless pm-initialization-in-progress + (if pm-allow-fontification + (when (and poly-lock-mode (not memory-full)) + (unless (input-pending-p) + (let ((end (or (text-property-any start (point-max) 'fontified t) + (point-max)))) + (when (< start end) + (poly-lock-fontify-now start end))))) + (with-buffer-prepared-for-poly-lock + (put-text-property start (point-max) 'fontified t))))) + +(defun poly-lock-fontify-now (beg end &optional verbose) + "Polymode font-lock fontification function. +Fontifies chunk-by chunk within the region BEG END." + (unless (or poly-lock-fontification-in-progress + pm-initialization-in-progress) + (let* ((font-lock-dont-widen t) + (pmarker (point-marker)) + (dbuffer (current-buffer)) + ;; Fontification in one buffer can trigger fontification in another + ;; buffer. Particularly, this happens when new indirect buffers are + ;; created and `normal-mode' triggers font-lock in those buffers. We + ;; avoid this by dynamically binding + ;; `poly-lock-fontification-in-progress' and un-setting + ;; `fontification-functions' in case re-display suddenly decides to + ;; fontify something else in other buffer. + (poly-lock-fontification-in-progress t) + (fontification-functions nil)) + (save-restriction + (widen) + (save-excursion + (pm-map-over-spans + (lambda () + (with-buffer-prepared-for-poly-lock + (let ((sbeg (nth 1 *span*)) + (send (nth 2 *span*))) + (when (> send sbeg) + (if (not (and font-lock-mode font-lock-keywords)) + ;; when no font-lock, set to t to avoid repeated calls + ;; from display engine + (put-text-property sbeg send 'fontified t) + (let ((new-beg (max sbeg beg)) + (new-end (min send end))) + (condition-case-unless-debug err + ;; (if (oref pm/chunkmode :font-lock-narrow) + ;; (pm-with-narrowed-to-span *span* + ;; (font-lock-unfontify-region new-beg new-end) + ;; (font-lock-fontify-region new-beg new-end verbose)) + ;; (font-lock-unfontify-region new-beg new-end) + ;; (font-lock-fontify-region new-beg new-end verbose)) + (if (oref pm/chunkmode :font-lock-narrow) + (pm-with-narrowed-to-span *span* + (jit-lock-fontify-now new-beg new-end)) + (jit-lock-fontify-now new-beg new-end)) + (error (message "(poly-lock-fontify-now %s %s) -> (%s %s %s %s): %s " + beg end poly-lock--fontify-region-original new-beg new-end verbose + (error-message-string err)))) + ;; even if failed set to t + (put-text-property new-beg new-end 'fontified t)) + + (pm--adjust-chunk-face sbeg send (pm-get-adjust-face pm/chunkmode))))))) + beg end)))) + (current-buffer))) + +(defun poly-lock-refontify (&optional beg end) + "Force refontification of the region BEG..END. +END is extended to the next chunk separator. This function is +pleased in `font-lock-flush-function' and +`font-lock-ensure-function'" + (when (and pm-allow-fontification + (not poly-lock-fontification-in-progress) + (not pm-initialization-in-progress)) + (with-buffer-prepared-for-poly-lock + (save-restriction + (widen) + (cond ((and beg end) + (setq end (cdr (pm-get-innermost-range end)))) + (beg + (setq end (cdr (pm-get-innermost-range beg)))) + (t + (setq beg (point-min) + end (point-max)))) + (put-text-property beg end 'fontified nil))))) + +(defun poly-lock-after-change (beg end old-len) + "Mark changed region as not fontified after change. +Installed on `after-change-functions'." + (save-match-data + (when (and poly-lock-mode + pm-allow-after-change-hook + (not memory-full)) + (let ((jit-lock-start beg) + (jit-lock-end end) + ;; useful info for tracing + (gl-beg end) + (gl-end beg) + exp-error) + (save-excursion + (condition-case err + ;; set jit-lock-start and jit-lock-end locally + (run-hook-with-args 'jit-lock-after-change-extend-region-functions + beg end old-len) + (error (message "(poly-lock-after-change:jl-expand (%s %s %s)): %s" + beg end old-len (error-message-string err)) + (setq jit-lock-start beg + jit-lock-end end))) + (setq beg (min beg jit-lock-start) + end (max end jit-lock-end)) + (pm-map-over-spans + (lambda () + (with-buffer-prepared-for-poly-lock + (let ((sbeg (nth 1 *span*)) + (send (nth 2 *span*))) + (save-restriction + (widen) + (setq gl-beg (min gl-beg (max jit-lock-start sbeg)) + gl-end (max gl-beg jit-lock-end send)) + (put-text-property gl-beg gl-end 'fontified nil))))) + beg end nil nil nil 'no-cache) + (cons gl-beg gl-end)))))) + +(provide 'poly-lock) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-classes.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-classes.el new file mode 100644 index 0000000..70e926e --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-classes.el @@ -0,0 +1,374 @@ +(require 'eieio) +(require 'polymode-core) + +;;; ROOT CLASS +(if (fboundp 'eieio-named) + (progn + (defclass pm-root (eieio-instance-inheritor eieio-named) + ((-props + :initform '() + :type list + :documentation "Internal. Used to store various user + history values. Use `pm--prop-get' and `pm--prop-put' to + place key value pairs into this list.")) + "Root polymode class.") + + ;; bug #22840 + (defmethod clone ((obj eieio-named) &rest params) + "Clone OBJ, initializing `:parent' to OBJ. + All slots are unbound, except those initialized with + PARAMS." + (let* ((newname (and (stringp (car params)) (pop params))) + (nobj (apply #'call-next-method obj params)) + (nm (slot-value obj 'object-name))) + (eieio-oset nobj 'object-name + (or newname + (save-match-data + (if (and nm (string-match "-\\([0-9]+\\)" nm)) + (let ((num (1+ (string-to-number + (match-string 1 nm))))) + (concat (substring nm 0 (match-beginning 0)) + "-" (int-to-string num))) + (concat nm "-1"))))) + nobj))) + + (defclass pm-root (eieio-instance-inheritor) + ((-props + :initform '() + :type list + :documentation "Internal. Plist used to store various extra + metadata such as user history. Use `pm--prop-get' and + `pm--prop-put' to place key value pairs into this list.")) + "Root polymode class.")) + +;;; CONFIG +(defclass pm-polymode (pm-root) + ((hostmode + :initarg :hostmode + :initform 'pm-host/blank + :type symbol + :custom symbol + :documentation + "Symbol pointing to an object of class pm-chunkmode + representing the host chunkmode.") + (minor-mode + :initarg :minor-mode + :initform 'polymode-minor-mode + :type symbol + :custom symbol + :documentation + "Symbol pointing to minor-mode function that should be + activated in all buffers (base and indirect). This is a + \"glue\" mode and is `polymode-minor-mode' by default. You + will rarely need to change this.") + (lighter + :initarg :lighter + :initform " PM" + :type string + :custom string + :documentation "Modline lighter.") + (exporters + :initarg :exporters + :initform '(pm-exporter/pandoc) + :type list + :custom list + :documentation + "List of names of polymode exporters available for this polymode.") + (exporter + :initarg :exporter + :initform nil + :type (or null symbol) + :custom symbol + :documentation + "Current exporter name. If non-nil should be the name of the + default exporter for this polymode. Can be set with + `polymode-set-exporter' command.") + (weavers + :initarg :weavers + :initform '() + :type list + :custom list + :documentation + "List of names of polymode weavers available for this polymode.") + (weaver + :initarg :weaver + :initform nil + :type (or null symbol) + :custom symbol + :documentation + "Current weaver name. If non-nil this is the default weaver + for this polymode. Can be dynamically set with + `polymode-set-weaver'") + (map + :initarg :map + :initform 'polymode-mode-map + :type (or symbol list) + :documentation + "Has a similar role as the :keymap argument in + `define-polymode' with the difference that this argument is + inherited through cloning, but :keymap argument is not. That + is, child objects derived through clone will inherit + the :map argument of its parents through the following + scheme: if :map is nil or an alist of keys, the parent is + inspected for :map argument and the keys are merged + recursively from parent to parent till a symbol :map slot is + met. If :map is a symbol, it must be a keymap, in which case + this keymap is used and no parents are further inspected + for :map slot. If :map is an alist it must be suitable for + `easy-mmode-define-keymap'.") + (init-functions + :initarg :init-functions + :initform '() + :type list + :documentation + "List of functions to run at the initialization time. + All init-functions in the inheritance chain are called. Parents + hooks first. So, if current config object C inherits from object + B, which in turn inherits from object A. Then A's init-functions + are called first, then B's and then C's. + Either customize this slot or use `object-add-to-list' function.") + (switch-buffer-functions + :initarg :switch-buffer-functions + :initform '() + :type list + :documentation + "List of functions to run at polymode buffer switch. + Each function is run with two arguments, OLD-BUFFER and + NEW-BUFFER.") + + (-hostmode + :type (or null pm-chunkmode) + :documentation + "Dynamically populated `pm-chunkmode' object.") + (-innermodes + :type list + :initform '() + :documentation + "Dynamically populated list of chunkmodes objects that + inherit from `pm-hbtchunkmode'.") + (-buffers + :initform '() + :type list + :documentation + "Holds all buffers associated with current buffer. Dynamically populated.")) + + "Configuration for a polymode. Each polymode buffer contains a local +variable `pm/polymode' instantiated from this class or a subclass +of this class.") + +(defclass pm-polymode-one (pm-polymode) + ((innermode + :initarg :innermode + :type symbol + :custom symbol + :documentation + "Symbol of the chunkmode. At run time this object is cloned + and placed in -innermodes slot.")) + + "Configuration for a simple polymode that allows only one +innermode. For example noweb.") + +(defclass pm-polymode-multi (pm-polymode) + ((innermodes + :initarg :innermodes + :type list + :custom list + :initform nil + :documentation + "List of names of the chunkmode objects that are associated + with this configuration. At initialization time, all of + these are cloned and plased in -innermodes slot.")) + + "Configuration for a polymode that allows multiple (known in +advance) innermodes.") + +(defclass pm-polymode-multi-auto (pm-polymode-multi) + ((auto-innermode + :initarg :auto-innermode + :type symbol + :custom symbol + :documentation + "Name of pm-hbtchunkmode-auto object (a symbol). At run time + this object is cloned and placed in -auto-innermodes with + coresponding :mode slot initialized at run time.") + (-auto-innermodes + :type list + :initform '() + :documentation + "List of chunkmode objects that are auto-generated in + `pm-get-span' method for this class.")) + + "Configuration for a polymode that allows multiple innermodes +that are not known in advance. Examples are org-mode and markdown.") + + +;;; CHUNKMODE CLASSES +(defclass pm-chunkmode (pm-root) + ((mode :initarg :mode + :type symbol + :initform nil + :custom symbol) + (protect-indent-line :initarg :protect-indent-line + :type boolean + :initform t + :custom boolean + :documentation + "Whether to modify local `indent-line-function' by narrowing + to current span first") + (indent-offset :initarg :indent-offset + :type integer + :initform 0 + :documentation + "Offset to add when indenting chunk's line. Takes effect only + when :protect-indent-line is non-nil.") + (font-lock-narrow :initarg :font-lock-narrow + :type boolean + :initform t + :documentation + "Whether to narrow to span during font lock") + (adjust-face :initarg :adjust-face + :type (or number face list) + :custom (or number face list) + :initform nil + :documentation + "Fontification adjustments chunk face. It should be either, + nil, number, face or a list of text properties as in + `put-text-property' specification. If nil no highlighting + occurs. If a face, use that face. If a number, it is a + percentage by which to lighten/darken the default chunk + background. If positive - lighten the background on dark + themes and darken on light thems. If negative - darken in + dark thems and lighten in light thems.") + (init-functions + :initarg :init-functions + :initform '() + :type list + :documentation + "List of functions to called after the initialization of chunkmode has finished. + Functions are called the buffer associated with this + chunkmode. All init-functions in the inheritance chain are + called. Parents hooks first. So, if current config object C + inherits from object B, which in turn inherits from object + A. Then A's init-functions are called first, then B's and + then C's. Either customize this slot or use + `object-add-to-list' function.") + (switch-buffer-functions + :initarg :switch-buffer-functions + :initform '() + :type list + :documentation + "List of functions to run at polymode buffer switch. + Each function is run with two arguments, OLD-BUFFER and + NEW-BUFFER. In contrast to identically named slot in + `pm-polymode' class, these functions are run only when + NEW-BUFFER is associated with this chunkmode.") + + (-buffer + :type (or null buffer) + :initform nil)) + + "Representatioin of a generic chunkmode object.") + +(defclass pm-bchunkmode (pm-chunkmode) + () + "Representation of the body-only chunkmodes. Body-only + chunkmodes are commonly used as host modes. For example for a + the web-mdoe the hostmode is `html-mode', for nowweb mode the + host mode is usually `latex-mode', etc.") + +(defclass pm-hbtchunkmode (pm-chunkmode) + ((head-mode + :initarg :head-mode + :type symbol + :initform 'poly-head-tail-mode + :custom symbol + :documentation + "Chunk's header mode. If set to 'body, the head is considered + part of the chunk body. If set to 'host, head is considered + part of the surrounding host mode.") + (tail-mode + :initarg :tail-mode + :type symbol + :initform nil + :custom symbol + :documentation + "Chunk's tail mode. If nil, or 'head, the mode is picked + from :HEAD-MODE slot. If set to 'body, the tail's mode is the + same as chunk's body mode. If set to 'host, the mode will be + of the parent host.") + + (head-reg + :initarg :head-reg + :initform "" + :type (or string symbol) + :custom (or string symbol) + :documentation "Regexp for the chunk start (aka head), or a + function returning the start and end positions of the head. + See `pm--default-matcher' for an example function.") + (tail-reg + :initarg :tail-reg + :initform "" + :type (or string symbol) + :custom (or string symbol) + :documentation "Regexp for chunk end (aka tail), or a + function returning the start and end positions of the tail. + See `pm--default-matcher' for an example function.") + + (adjust-face + :initform 2) + (head-adjust-face + :initarg :head-adjust-face + :initform font-lock-type-face + :type (or null number face list) + :custom (or null number face list) + :documentation + "Can be a number, list or face.") + (tail-adjust-face + :initarg :tail-adjust-face + :initform nil + :type (or null number face list) + :custom (or null number face list) + :documentation + "Can be a number, list or face. If nil, take the + configuration from :head-adjust-face.") + + (-head-buffer + :type (or null buffer) + :initform nil + :documentation + "This buffer is set automatically to -buffer if :head-mode is + 'body, and to base-buffer if :head-mode is 'host") + (-tail-buffer + :initform nil + :type (or null buffer))) + + "Representation of an inner Head-Body-Tail chunkmode.") + +(defclass pm-hbtchunkmode-auto (pm-hbtchunkmode) + ((retriever-regexp :initarg :retriever-regexp + :type (or null string) + :custom string + :initform nil + :documentation + "Regexp that is used to retrive the modes symbol from the + head of the chunkmode chunk. fixme: elaborate") + (retriever-num :initarg :retriever-num + :type integer + :custom integer + :initform 1 + :documentation + "Subexpression to be matched by :retriver-regexp") + (retriever-function :initarg :retriever-function + :type symbol + :custom symbol + :initform nil + :documentation + "Function symbol used to retrive the modes symbol from the + head of the chunkmode chunk. It is called with no arguments + with the point positioned at the beginning of the chunk + header. It must return the mode name string or symbol (need + not include '-mode' postfix).)")) + + "Representation of an inner chunkmode") + +(provide 'polymode-classes) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-compat.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-compat.el new file mode 100644 index 0000000..e2f660a --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-compat.el @@ -0,0 +1,251 @@ +;;; COMPATIBILITY and FIXES + +(require 'polymode-core) +(require 'advice nil t) + +(defgroup polymode-compat nil + "Polymode compatibility settings." + :group 'polymode) + + + +;;; Various Wrappers for Around Advice + +(defvar *span* nil) + +;; advice doesn't provide named symbols. So we need to define specialized +;; wrappers for some key functions (unfinished) +(defmacro pm-define-wrapp-protected (fun) + "Declare protected function with the name fun--pm-wrapped. +Return new name (symbol). FUN is an unquoted name of a function." + (let* ((fun-name (symbol-name fun)) + (new-fun (intern (format "%s--pm-wrapped" fun-name))) + (new-doc (format " Error Protected function created with `pm-define-protected-wrapp'.\n\n%s" + (or (documentation fun) "")))) + `(progn + (defun ,new-fun (&rest args) + ,new-doc + (condition-case err + (apply ',fun args) + (error (message "(%s %s): %s" + ,fun-name + (mapconcat (lambda (x) (format "%s" x)) args " ") + (error-message-string err))))) + ',new-fun))) + +(defun pm-apply-protected (fun args) + (when fun + (condition-case-unless-debug err + (apply fun args) + (error (message "(%s %s): %s %s" + (if (symbolp fun) + (symbol-name fun) + "anonymous") + (mapconcat (lambda (x) (format "%s" x)) args " ") + (error-message-string err) + ;; (or (and (symbolp fun) "") + ;; (replace-regexp-in-string "\n" "" (format "[%s]" fun))) + "[M-x pm-debug-mode RET for more info]" + ) + (when pm-debug-mode + (backtrace)) + nil)))) + +(defun pm-override-output-position (orig-fun &rest args) + "Restrict returned value of ORIG-FUN to fall into the current span. +*span* in `pm-map-over-spans` has precedence over span at point.'" + (if (and polymode-mode pm/polymode) + (let ((range (or (pm-span-to-range *span*) + (pm-get-innermost-range))) + (pos (pm-apply-protected orig-fun args))) + (and pos + (min (max pos (car range)) + (cdr range)))) + (apply orig-fun args))) + +(defun pm-override-output-cons (orig-fun &rest args) + "Restrict returned (beg . end) of ORIG-FUN to fall into the current span. +*span* in `pm-map-over-spans` has precedence over span at point.'" + (if (and polymode-mode pm/polymode) + (let ((range (or (pm-span-to-range *span*) + (pm-get-innermost-range))) + (be (pm-apply-protected orig-fun args))) + (and be + (cons (min (max (car be) (car range)) + (cdr range)) + (max (min (cdr be) (cdr range)) + (car range))))) + (apply orig-fun args))) + +(defun pm-substitute-beg-end (orig-fun beg end &rest args) + "Execute orig-fun with first two arguments limited to current span. +*span* in `pm-map-over-spans` has precedence over span at point." + (if (and polymode-mode pm/polymode) + (let* ((pos (if (and (<= (point) end) (>= (point) beg)) + (point) + end)) + (range (or (pm-span-to-range *span*) + (pm-get-innermost-range pos))) + (new-beg (max beg (car range))) + (new-end (min end (cdr range)))) + (pm-apply-protected orig-fun (append (list new-beg new-end) args))) + (apply orig-fun beg end args))) + +(defun pm-execute-narrowed-to-span (orig-fun &rest args) + "Execute ORIG-FUN narrowed to the current span. +*span* in `pm-map-over-spans` has precedence over span at point." + (if (and polymode-mode pm/polymode) + (pm-with-narrowed-to-span *span* + (pm-apply-protected orig-fun args)) + (apply orig-fun args))) + +(defun pm-execute-with-no-polymode-hooks (orig-fun &rest args) + "Execute ORIG-FUN without allowing polymode core hooks. +That is, bind `pm-allow-post-command-hook' and +`pm-allow-after-change-hook' to nil. *span* in +`pm-map-over-spans' has precedence over span at point." + ;; this advice is nowhere used yet + (if (and polymode-mode pm/polymode) + (let ((pm-allow-post-command-hook t) + (pm-allow-after-change-hook t)) + ;; This advice might be useful when functions can switch buffers to work + ;; inside the base buffer (like basic-save-buffer does). Thus, we sync + ;; points first. + (pm--synchronize-points) + ;; save-excursion might be also often necessary + (apply orig-fun args)) + (apply orig-fun args))) + +(defun pm-execute-with-save-excursion (orig-fun &rest args) + "Execute ORIG-FUN within save-excursion." + ;; This advice is required when other functions switch buffers to work inside + ;; base buffer and don't restore the point. For some not very clear reason + ;; this seem to be necessary for save-buffer which saves buffer but not point. + (if (and polymode-mode pm/polymode) + (progn + (pm--synchronize-points) + (save-excursion + (apply orig-fun args))) + (apply orig-fun args))) + +(defun pm-around-advice (fun advice) + "Apply around ADVICE to FUN. +Check for if new advice is available and if FUN is a symbol, do +nothing otherwise. If FUN is a list, apply advice to each element +in a list. " + (when (and fun (fboundp 'advice-add)) + (cond ((listp fun) + (dolist (el fun) (pm-around-advice el advice))) + ((and (symbolp fun) + (not (advice-member-p advice fun))) + (advice-add fun :around advice))))) + + +;;; Syntax +(defun pm-execute-syntax-propertize-narrowed-to-span (orig-fun pos) + "Execute `syntax-propertize' narrowed to the current span. +Don't throw errors, but give relevant messages instead." + ;; in emacs 25.1 internal--syntax-propertize is called from C. We + ;; cannot advice it, but we can check for its argument. Very hackish + ;; but I don't see another way besides re-defining that function. + (if (and polymode-mode pm/polymode) + (condition-case err + (save-excursion + (when (< syntax-propertize--done pos) + (pm-map-over-spans + (lambda () + (when (< syntax-propertize--done pos) + (pm-with-narrowed-to-span *span* + (funcall orig-fun (min pos (point-max))) + (let ((new--done syntax-propertize--done)) + (dolist (buff (oref pm/polymode -buffers)) + (with-current-buffer buff + (setq-local syntax-propertize--done new--done))))))) + syntax-propertize--done pos))) + (error (message "(syntax-propertize %s): %s [M-x pm-debug-info RET to see backtrace]" + pos (error-message-string err)) + (and pm-debug-mode + (backtrace)))) + (funcall orig-fun pos))) + +(pm-around-advice 'syntax-propertize 'pm-execute-syntax-propertize-narrowed-to-span) + + + +;;; Flyspel +(defun pm--flyspel-dont-highlight-in-chunkmodes (beg end poss) + (or (get-text-property beg :pm-span-type) + (get-text-property end :pm-span-type))) + + +;;; C/C++/Java +(pm-around-advice 'c-before-context-fl-expand-region #'pm-override-output-cons) +(pm-around-advice 'c-state-semi-safe-place #'pm-override-output-position) +;; (advice-remove 'c-state-semi-safe-place #'pm-override-output-position) +;; c-font-lock-fontify-region calls it directly +;; (pm-around-advice 'font-lock-default-fontify-region #'pm-substitute-beg-end) +(pm-around-advice 'c-determine-limit #'pm-execute-narrowed-to-span) + + +;;; Python +(defun pm--python-dont-indent-to-0 (fun) + "Don't cycle to 0 indentation in polymode chunks." + (if (and polymode-mode pm/type) + (let ((last-command (unless (eq (pm--first-line-indent) (current-indentation)) + last-command))) + (funcall fun)) + (funcall fun))) + +(pm-around-advice 'python-indent-line-function #'pm--python-dont-indent-to-0) + + +;;; Core Font Lock +(defun pm-check-for-real-change-in-extend-multiline (fun) + "Fix `font-lock-extend-region-multiline' which causes infloops on point-max. +Propagate only real change." + ;; fixme: report this ASAP! + (let ((obeg font-lock-beg) + (oend font-lock-end) + (change (funcall fun))) + (and change + (not (eq obeg font-lock-beg)) + (not (eq oend font-lock-end))))) + +(pm-around-advice 'font-lock-extend-region-multiline #'pm-check-for-real-change-in-extend-multiline) + + +;;; Editing +(pm-around-advice 'fill-paragraph #'pm-execute-narrowed-to-span) + +;; `save-buffer` misbehaves because after each replacement modification hooks +;; are triggered and poly buffer is switched in unpredictable fashion. +;; +;; https://github.com/vspinu/polymode/issues/93 It can be +;; reproduced with (add-hook 'before-save-hook 'delete-trailing-whitespace nil +;; t) in the base buffer. +;; +;; save-excursion is probably not quite right fix for this but it seem to work +(pm-around-advice 'basic-save-buffer #'pm-execute-with-save-excursion) + +;; Query replace were probably misbehaving due to unsaved match data. +;; (https://github.com/vspinu/polymode/issues/92) The following is probably not +;; necessary. +;; (pm-around-advice 'perform-replace 'pm-execute-inhibit-modification-hooks) + + +;;; EVIL + +(defun polymode-switch-buffer-keep-evil-state-maybe (old-buffer new-buffer) + (when (and (boundp 'evil-state) + evil-state) + (let ((old-state (buffer-local-value 'evil-state old-buffer)) + (new-state (buffer-local-value 'evil-state new-buffer))) + (unless (eq old-state new-state) + (with-current-buffer new-buffer + (evil-change-state old-state)))))) + +(eval-after-load 'evil-core + '(add-hook 'polymode-switch-buffer-hook 'polymode-switch-buffer-keep-evil-state-maybe)) + + +(provide 'polymode-compat) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-configuration.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-configuration.el new file mode 100644 index 0000000..1569448 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-configuration.el @@ -0,0 +1,65 @@ +;; Examples of polymode configuration. Choose what suits your needs and place +;; into your .emacs file. + +(let ((mydir (file-name-directory (or load-file-name buffer-file-name)))) + (let ((modes-dir (concat mydir "modes"))) + (add-to-list 'load-path modes-dir))) + +;;; MARKDOWN +(use-package poly-markdown + :defer t + :commands (poly-markdown-mode) + :init (progn + (add-to-list 'auto-mode-alist '("\\.md$" . poly-markdown-mode)))) + +;; ;;; ORG +;; ;; org is not working presently +(use-package poly-org + :defer t + :commands (poly-org-mode) + :init (progn + (add-to-list 'auto-mode-alist '("\\.org$" . poly-org-mode)))) + +;; ;;; R related modes +(use-package poly-R + :defer t + :commands (poly-noweb+r-mode poly-markdown+r-mode + poly-rapport-mode + poly-html+r-mode + poly-brew+r-mode + poly-r+c++-mode + poly-c++r-mode) + :init (progn + (add-to-list 'auto-mode-alist '("\\.Snw$" . poly-noweb+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rnw$" . poly-noweb+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rmd$" . poly-markdown+r-mode)) + (add-to-list 'auto-mode-alist '("\\.rapport$" . poly-rapport-mode)) + (add-to-list 'auto-mode-alist '("\\.Rhtml$" . poly-html+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rbrew$" . poly-brew+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rcpp$" . poly-r+c++-mode)) + (add-to-list 'auto-mode-alist '("\\.cppR$" . poly-c++r-mode)))) + +;; ;;; ERB modes +(use-package poly-erb + :defer t + :commands (poly-javascript+erb-mode poly-coffee+erb-mode poly-html+erb-mode) + :init (progn + (add-to-list 'auto-mode-alist '("\\.js.erb$" . poly-javascript+erb-mode)) + (add-to-list 'auto-mode-alist '("\\.coffee.erb$" . poly-coffee+erb-mode)) + (add-to-list 'auto-mode-alist '("\\.html.erb$" . poly-html+erb-mode)))) + +;; ;;; Slim mode +(use-package poly-slim + :defer t + :commands (poly-slim-mode) + :init (progn + (add-to-list 'auto-mode-alist '("\\.slim$" . poly-slim-mode)))) + +(defalias 'dot-mode 'graphviz-dot-mode) +(defalias 'r-mode 'ess-r-mode) + +(use-package ob-tikz + :defer t + :commands (tikz-mode)) + +(provide 'polymode-configuration) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-core.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-core.el new file mode 100644 index 0000000..ffea7a3 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-core.el @@ -0,0 +1,661 @@ +;; -*- lexical-binding: t -*- +;; COMMON INITIALIZATION, UTILITIES and INTERNALS which didn't fit anywhere else + +(require 'cl) +(require 'font-lock) +(require 'color) +(require 'eieio) +(require 'eieio-base) +(require 'eieio-custom) +(require 'format-spec) + + +(defgroup polymode nil + "Object oriented framework for multiple modes based on indirect buffers" + :link '(emacs-commentary-link "polymode") + :group 'tools) + +(defgroup polymodes nil + "Polymode Configuration Objects" + :group 'polymode) + +(defgroup hostmodes nil + "Polymode Host Chunkmode Objects" + :group 'polymode) + +(defgroup innermodes nil + "Polymode Chunkmode Objects" + :group 'polymode) + +(defcustom polymode-display-process-buffers t + "When non-nil, display weaving and exporting process buffers." + :group 'polymode + :type 'boolean) + +(defcustom polymode-skip-processing-when-unmodified t + "If non-nil, consider modification times of input and output files. +Skip weaving or exporting process when output file is more recent +than the input file." + :group 'polymode + :type 'boolean) + +(defcustom polymode-mode-name-override-alist '((elisp . emacs-lisp)) +"An alist of inner mode overrides. +When inner mode is automatically detected from the header of the +inner chunk (such as in markdown mode), the detected symbol might +not correspond to the desired mode. This alist maps discovered +symbols into desired modes. + +For example + + (add-to-list 'polymode-mode-name-override-alist '(julia . ess-julia)) + +will cause installation of `ess-julia-mode' in markdown ```julia chunks." +:group 'polymode +:type 'alist) + +(defvar polymode-switch-buffer-hook nil + "Hook run on switching to a different buffer. +Each function is run with two arguments `old-buffer' and +`new-buffer'. This hook is commonly used to transfer state +between buffers. The hook is run in a new buffer, but you should +not rely on that. Slot :switch-buffer-functions in `pm-polymode' +and `pm-chunkmode' objects provides same functionality for +narrower scope.") + +(defvar polymode-init-host-hook nil + "Hook run on initialization of every hostmode. +Ran in a base buffer from `pm-initialze' +methods. Slot :init-functions in `pm-polymode' objects provides +similar hook for more focused scope. See +`polymode-init-inner-hook' and :init-functions slot in +`pm-chunkmode' objects for similar hooks for inner chunkmodes.") + +(defvar polymode-init-inner-hook nil + "Hook run on initialization of every `pm-chunkmode' object. +The hook is run in chunkmode's body buffer from `pm-initialze' +`pm-chunkmode' methods. Slot :init-functions `pm-chunkmode' +objects provides same functionality for narrower scope. See also +`polymode-init-host-hook'.") + +;; esential vars +(defvar-local pm/polymode nil) +(defvar-local pm/chunkmode nil) +(defvar-local pm/type nil) +(defvar-local pm--indent-line-function-original nil) +;; (defvar-local pm--killed-once nil) +(defvar-local polymode-mode nil + "This variable is t if current \"mode\" is a polymode.") + +;; silence the compiler for now +(defvar pm--output-file nil) +(defvar pm--input-buffer nil) +(defvar pm--input-file nil) +(defvar pm--export-spec nil) +(defvar pm--input-not-real nil) +(defvar pm--output-not-real nil) +(defvar pm/type) +(defvar pm/polymode) +(defvar pm/chunkmode) +(defvar *span*) + +(defvar pm-allow-fontification t) +(defvar pm-allow-after-change-hook t) +(defvar pm-allow-post-command-hook t) + +(defvar pm-initialization-in-progress nil + ;; We need this during cascading call-next-method in pm-initialize. + ;; -innermodes are initialized after the hostmode setup has taken place. This + ;; means that pm-get-span and all the functionality that relies on it will + ;; fail to work correctly during the initialization in the call-next-method. + ;; This is particularly relevant to font-lock setup and user hooks. + "Non nil during polymode objects initialization. +If this variable is non-nil, various chunk manipulation commands +relying on `pm-get-span' might not function correctly.") + +;; methods api from polymode-methods.el +(declare-function pm-initialize "polymode-methods") +(declare-function pm-get-buffer-create "polymode-methods") +(declare-function pm-select-buffer "polymode-methods") +(declare-function pm-get-adjust-face "polymode-methods") +(declare-function pm-get-span "polymode-methods") +(declare-function pm-indent-line "polymode-methods") + + +;;; CORE +(defsubst pm-base-buffer () + ;; fixme: redundant with :base-buffer + "Return base buffer of current buffer, or the current buffer if it's direct." + (or (buffer-base-buffer (current-buffer)) + (current-buffer))) + +(defun pm-get-cached-span (&optional pos) + "Get cached span at POS" + (let ((span (get-text-property (or pos (point)) :pm-span))) + (when span + (save-restriction + (widen) + (let* ((beg (nth 1 span)) + (end (max beg (1- (nth 2 span))))) + (when (<= end (point-max)) + (and (eq span (get-text-property beg :pm-span)) + (eq span (get-text-property end :pm-span)) + span))))))) + +(defun pm-get-innermost-span (&optional pos no-cache) + "Get span object at POS. +If NO-CACHE is non-nil, don't use cache and force re-computation +of the span." + (save-excursion + (save-restriction + (widen) + (let* ((span (or (and (not no-cache) + (pm-get-cached-span pos)) + (pm-get-span pm/polymode pos))) + (beg (nth 1 span)) + (end (nth 2 span))) + ;; might be used by external applications like flyspell + (with-silent-modifications + (add-text-properties beg end + (list :pm-span span + :pm-span-type (car span) + :pm-span-beg beg + :pm-span-end end))) + span)))) + +(defun pm-span-to-range (span) + (and span (cons (nth 1 span) (nth 2 span)))) + +(defun pm-get-innermost-range (&optional pos no-cache) + (pm-span-to-range (pm-get-innermost-span pos no-cache))) + +(defvar pm--select-buffer-visibly nil) + +(defun pm-switch-to-buffer (&optional pos-or-span) + "Bring the appropriate polymode buffer to front. +This is done visually for the user with `switch-to-buffer'. All +necessary adjustment like overlay and undo history transport are +performed." + (let ((span (if (or (null pos-or-span) + (number-or-marker-p pos-or-span)) + (pm-get-innermost-span pos-or-span) + pos-or-span)) + (pm--select-buffer-visibly t)) + (pm-select-buffer (car (last span)) span))) + +(defun pm-set-buffer (&optional pos-or-span) + "Set buffer to polymode buffer appropriate for POS-OR-SPAN. +This is done with `set-buffer' and no visual adjustments are +done." + (let ((span (if (or (null pos-or-span) + (number-or-marker-p pos-or-span)) + (pm-get-innermost-span pos-or-span) + pos-or-span)) + (pm--select-buffer-visibly nil)) + (pm-select-buffer (car (last span)) span))) + +(defun pm-map-over-spans (fun beg end &optional count backwardp visiblyp no-cache) + "For all spans between BEG and END, execute FUN. +FUN is a function of no args. It is executed with point at the +beginning of the span. Buffer is *not* narrowed to the span. If +COUNT is non-nil, jump at most that many times. If BACKWARDP is +non-nil, map backwards. During the call of FUN, a dynamically +bound variable *span* holds the current innermost span." + ;; Important! Never forget to save-excursion when calling + ;; map-overs-spans. Mapping can end different buffer and invalidate whatever + ;; caller that used your function. + (save-restriction + (widen) + (setq end (min end (point-max))) + (goto-char (if backwardp end beg)) + (let* ((nr 1) + (*span* (pm-get-innermost-span (point) no-cache)) + old-span + moved) + ;; if beg (end) coincide with span's end (beg) don't process previous (next) span + (if backwardp + (and (eq end (nth 1 *span*)) + (setq moved t) + (not (bobp)) + (forward-char -1)) + (and (eq beg (nth 2 *span*)) + (setq moved t) + (not (eobp)) + (forward-char 1))) + (when moved + (setq *span* (pm-get-innermost-span (point) no-cache))) + (while (and (if backwardp + (> (point) beg) + (< (point) end)) + (or (null count) + (< nr count))) + (let ((pm--select-buffer-visibly visiblyp)) + (pm-select-buffer (car (last *span*)) *span*)) ;; object and span + + ;; FUN might change buffer and invalidate our *span*. How can we + ;; intelligently check for this? After-change functions have not been + ;; run yet (or did they?). We can track buffer modification time + ;; explicitly (can we?) + (goto-char (nth 1 *span*)) + (save-excursion + (funcall fun)) + + ;; enter next/previous chunk as head-tails don't include their boundaries + (if backwardp + (goto-char (max 1 (1- (nth 1 *span*)))) + (goto-char (min (point-max) (1+ (nth 2 *span*))))) + + (setq old-span *span*) + (setq *span* (pm-get-innermost-span (point) no-cache) + nr (1+ nr)) + + ;; Ensure progress and avoid infloop due to bad regexp or who knows + ;; what. Move char by char till we get higher/lower span. Cache is not + ;; used. + (while (and (not (eobp)) + (if backwardp + (> (nth 2 *span*) (nth 1 old-span)) + (< (nth 1 *span*) (nth 2 old-span)))) + (forward-char 1) + (setq *span* (pm-get-innermost-span (point) t))))))) + +(defun pm--reset-ppss-last (&optional span-start force) + "Reset `syntax-ppss-last' cache if it was recorded before SPAN-START. +If SPAN-START is nil, use span at point. If force, reset +regardless of the position `syntax-ppss-last' was recorder at." + ;; syntax-ppss has its own condition-case for this case, but that means + ;; throwing an error each time it calls parse-partial-sexp + (setq span-start (or span-start (car (pm-get-innermost-range)))) + (when (or force + (and syntax-ppss-last + (car syntax-ppss-last) + ;; non-strict is intentional (occasionally ppss is screwed) + (<= (car syntax-ppss-last) span-start))) + (setq syntax-ppss-last + (cons span-start (list 0 nil span-start nil nil nil 0))))) + +(defun pm-narrow-to-span (&optional span) + "Narrow to current chunk." + (interactive) + (unless (= (point-min) (point-max)) + (let ((span (or span + (pm-get-innermost-span)))) + (let ((sbeg (nth 1 span)) + (send (nth 2 span))) + (pm--reset-ppss-last sbeg t) + (narrow-to-region sbeg send))))) + +(defmacro pm-with-narrowed-to-span (span &rest body) + (declare (indent 1) (debug body)) + `(save-restriction + (pm-narrow-to-span ,span) + ,@body)) + + +;;; UTILITIES +(defvar polymode-display-output-file t + "When non-nil automatically display output file in emacs. +This is temporary variable, it might be changed or removed in the +near future.") + +(defun pm--display-file (ofile) + (when ofile + ;; errors might occur (most notably with open-with package errors are intentional) + ;; We need to catch those if we want to display multiple files like with Rmarkdown + (condition-case err + (let ((buff (get-file-buffer ofile))) + ;; silently kill and re-open + (when buff + (with-current-buffer buff + (revert-buffer t t))) + (when polymode-display-output-file + (if (string-match-p "html\\|htm$" ofile) + (browse-url ofile) + (display-buffer (find-file-noselect ofile 'nowarn))))) + (error (message "Error while displaying '%s': %s" + (file-name-nondirectory ofile) + (error-message-string err)))))) + +(defun pm--symbol-name (str-or-symbol) + (if (symbolp str-or-symbol) + (symbol-name str-or-symbol) + str-or-symbol)) + +(defun pm--get-mode-symbol-from-name (str &optional no-fallback) + "Guess and return mode function." + (let* ((str (pm--symbol-name + (or (cdr (assq (intern (pm--symbol-name str)) + polymode-mode-name-override-alist)) + str))) + (mname (if (string-match-p "-mode$" str) + str + (concat str "-mode")))) + (or (pm--get-existent-mode (intern mname) t) + (pm--get-existent-mode (intern (downcase mname))) no-fallback))) + +(defun pm--get-existent-mode (mode &optional no-fallback) + "Check if MODE symbol is defined and is a valid function. +If so, return it, otherwise return `poly-fallback-mode' and issue +a warning." + (cond ((fboundp mode) mode) + (no-fallback nil) + (t (message "Cannot find function `%s', using `poly-fallback-mode'" mode) + 'poly-fallback-mode))) + +(defun pm--oref-with-parents (object slot) + "Merge slots SLOT from the OBJECT and all its parent instances." + (let (VALS) + (while object + (setq VALS (append (and (slot-boundp object slot) ; don't cascade + (eieio-oref object slot)) + VALS) + object (and (slot-boundp object :parent-instance) + (oref object :parent-instance)))) + VALS)) + +(defun pm--abrev-names (list abrev-regexp) + "Abbreviate names in LIST by replacing abrev-regexp with empty string." + (mapcar (lambda (nm) + (let ((str-nm (if (symbolp nm) + (symbol-name nm) + nm))) + (cons (replace-regexp-in-string abrev-regexp "" str-nm) + str-nm))) + list)) + +(defun pm--prop-put (key val &optional object) + (oset (or object pm/polymode) -props + (plist-put (oref (or object pm/polymode) -props) key val))) + +(defun pm--prop-get (key &optional object) + (plist-get (oref (or object pm/polymode) -props) key)) + +(defun pm--comment-region (beg end) + ;; mark as syntactic comment + (when (> end 1) + (with-silent-modifications + (let ((beg (or beg (region-beginning))) + (end (or end (region-end)))) + (let ((ch-beg (char-after beg)) + (ch-end (char-before end))) + (add-text-properties beg (1+ beg) + (list 'syntax-table (cons 11 ch-beg) + 'rear-nonsticky t + 'polymode-comment 'start)) + (add-text-properties (1- end) end + (list 'syntax-table (cons 12 ch-end) + 'rear-nonsticky t + 'polymode-comment 'end))))))) + +(defun pm--uncomment-region (beg end) + ;; Remove all syntax-table properties. + ;; fixme: this beggs for problems + (when (> end 1) + (with-silent-modifications + (let ((props '(syntax-table nil rear-nonsticky nil polymode-comment nil))) + (remove-text-properties (max beg (point-min)) (min end (point-max)) props) + ;; (remove-text-properties beg (1+ beg) props) + ;; (remove-text-properties end (1- end) props) + )))) + +(defun pm--synchronize-points (&rest ignore) + "Synchronize points in all buffers. +IGNORE is there to allow this function in advises." + (when polymode-mode + (let ((pos (point)) + (cbuff (current-buffer))) + (dolist (buff (oref pm/polymode -buffers)) + (when (and (not (eq buff cbuff)) + (buffer-live-p buff)) + (with-current-buffer buff + (goto-char pos))))))) + +(defun pm--completing-read (prompt collection &optional predicate require-match initial-input hist def inherit-input-method) + "Wrapper for `completing-read'. +Takes care when collection is an alist of (name . meta-info). If +so, asks for names, but returns meta-info for that name. Enforce +require-match = t. Also takes care of adding the most relevant +DEF from history." + (if (and (listp collection) + (listp (car collection))) + (let* ((candidates (mapcar #'car collection)) + (thist (and hist + (delq nil (mapcar (lambda (x) (car (member x candidates))) + (symbol-value hist))))) + (def (or def (car thist)))) + (assoc (completing-read prompt candidates predicate t initial-input hist def inherit-input-method) + collection)) + (completing-read prompt candidates predicate require-match initial-input hist def inherit-input-method))) + + +;; Weaving and Exporting common utilities + +(defun pm--wrap-callback (processor slot ifile) + ;; replace processor :sentinel or :callback temporally in order to export-spec as a + ;; followup step or display the result + (let ((sentinel1 (eieio-oref processor slot)) + (cur-dir default-directory) + (exporter (symbol-value (oref pm/polymode :exporter))) + (obuffer (current-buffer))) + (if pm--export-spec + (let ((espec pm--export-spec)) + (lambda (&rest args) + (with-current-buffer obuffer + (let ((wfile (apply sentinel1 args)) + (pm--export-spec nil) + (pm--input-not-real t)) + ;; If no wfile, probably errors occurred. So we stop. + (when wfile + (when (listp wfile) + ;; In an unlikely situation weaver can generate multiple + ;; files. Pick the first one. + (setq wfile (car wfile))) + (pm-export exporter (car espec) (cdr espec) wfile)))))) + (lambda (&rest args) + (with-current-buffer obuffer + (let ((ofile (apply sentinel1 args))) + (when ofile + (let ((ofiles (if (listp ofile) ofile (list ofile)))) + (dolist (f ofiles) + (pm--display-file (expand-file-name f cur-dir))))))))))) + +(defun pm--file-mod-time (file) + (and (stringp file) + (file-exists-p file) + (nth 5 (file-attributes file)))) + + +(defvar-local pm--process-buffer nil) + +(defun pm--run-shell-command (command sentinel buff-name message) + "Run shell command interactively. +Run command in a buffer (in comint-shell-mode) in order to be +able to accept user interaction." + ;; simplified version of TeX-run-TeX + (require 'comint) + (let* ((buffer (get-buffer-create buff-name)) + (process nil) + (command-buff (current-buffer)) + (ofile pm--output-file) + ;; weave/export buffers are re-usable; need to transfer some vars + (dd default-directory) + ;; (command (shell-quote-argument command)) + ) + (with-current-buffer buffer + (setq-local default-directory dd) + (read-only-mode -1) + ;;(erase-buffer) + (message message) + (insert message) + (comint-exec buffer buff-name shell-file-name nil + (list shell-command-switch command)) + (setq process (get-buffer-process buffer)) + (comint-mode) + (set-process-sentinel process sentinel) + (setq pm--process-buffer t) + (set-marker (process-mark process) (point-max)) + ;; for communication with sentinel + (process-put process :output-file pm--output-file) + (process-put process :output-file-mod-time (pm--file-mod-time pm--output-file)) + (process-put process :input-file pm--input-file) + (when polymode-display-process-buffers + (display-buffer buffer `(nil . ((inhibit-same-window . ,pop-up-windows))))) + nil))) + +(defun pm--make-shell-command-sentinel (action) + (lambda (process name) + "Sentinel built with `pm--make-shell-command-sentinel'." + (let ((buff (process-buffer process)) + (status (process-exit-status process))) + (if (> status 0) + (progn + (message "Errors during %s; process exit status %d" action status) + (ding) (sit-for 1) + nil) + (with-current-buffer buff + (let ((ofile (process-get process :output-file))) + (cond + ;; 1. output-file guesser + ((functionp ofile) (funcall ofile)) + ;; 2. string + (ofile + (let ((otime (process-get process :output-file-mod-time)) + (ntime (pm--file-mod-time ofile))) + (if (or (null ntime) + (and otime + (not (time-less-p otime ntime)))) + ;; mod time didn't change + ;; tothink: shall we still return ofile for display? + (progn + (display-buffer (current-buffer)) + (message "Output file unchanged. Either input unchanged or errors during %s." action) + (ding) (sit-for 1) + ofile) + ;; else, all is good, we return the file name + ;; (display-buffer (current-buffer)) + (message "Done with %s" action) + ofile))) + ;; 3. output file is not known; display process buffer + (t (display-buffer (current-buffer)) nil)))))))) + +(fset 'pm-default-export-sentinel (pm--make-shell-command-sentinel "export")) +(fset 'pm-default-shell-weave-sentinel (pm--make-shell-command-sentinel "weaving")) + +(defun pm--make-selector (specs elements) + (cond ((listp elements) + (let ((spec-alist (cl-mapcar #'cons specs elements))) + (lambda (selsym &rest ignore) + (cdr (assoc selsym spec-alist))))) + ((functionp elements) elements) + (t (error "elements argument must be either a list or a function")))) + +(defun pm--selector (processor type id) + (let ((spec (or (assoc id (eieio-oref processor type)) + (error "%s spec '%s' cannot be found in '%s'" + (symbol-name type) id (eieio-object-name processor)))) + (names (cond + ;; exporter slots + ((eq type :from) '(regexp doc command)) + ((eq type :to) '(ext doc t-spec)) + ;; weaver slot + ((eq type :from-to) '(regexp ext doc command)) + (t (error "invalid type '%s'" type))))) + (pm--make-selector names (cdr spec)))) + +(defun pm--selector-match (selector &optional file) + (or (funcall selector 'match file) + (string-match-p (funcall selector 'regexp) + (or file buffer-file-name)))) + +(defun pm--selectors (processor type) + (let ((ids (mapcar #'car (eieio-oref processor type)))) + (mapcar (lambda (id) (cons id (pm--selector processor type id))) ids))) + +(defun pm--output-command.file (output-file-format sfrom &optional sto quote) + ;; !!Must be run in input buffer!! + (cl-flet ((squote (arg) (or (and (stringp arg) + (if quote (shell-quote-argument arg) arg)) + ""))) + (let* ((base-ofile (or (funcall (or sto sfrom) 'output-file) + (let ((ext (funcall (or sto sfrom) 'ext))) + (when ext + (concat (format output-file-format + (file-name-base buffer-file-name)) + "." ext))))) + (ofile (and (stringp base-ofile) + (expand-file-name base-ofile))) + (oname (and (stringp base-ofile) + (file-name-base base-ofile))) + (t-spec (and sto (funcall sto 't-spec))) + (command-w-formats (or (and sto (funcall sto 'command)) + (and (listp t-spec) (car t-spec)) + (funcall sfrom 'command))) + (command (format-spec command-w-formats + (list (cons ?i (squote (file-name-nondirectory buffer-file-name))) + (cons ?I (squote buffer-file-name)) + (cons ?o (squote base-ofile)) + (cons ?O (squote ofile)) + (cons ?b (squote oname)) + (cons ?t (squote t-spec)))))) + (cons command (or ofile base-ofile))))) + +(defun pm--process-internal (processor from to ifile &optional callback quote) + (let ((is-exporter (object-of-class-p processor 'pm-exporter))) + (if is-exporter + (unless (and from to) + (error "For exporter both FROM and TO must be supplied (from: %s, to: %s)" from to)) + (unless from + ;; it represents :from-to slot + (error "For weaver FROM must be supplied (from: %s)" from))) + (let* ((sfrom (if is-exporter + (pm--selector processor :from from) + (pm--selector processor :from-to from))) + (sto (and is-exporter (pm--selector processor :to to))) + (ifile (or ifile buffer-file-name)) + ;; fixme: nowarn is only right for inputs from weavers, you need to + ;; save otherwise + (ibuffer (if pm--input-not-real + ;; for exporter input we silently re-fetch the file + ;; even if it was modified + (find-file-noselect ifile t) + ;; if real user file, get it or fetch it + (or (get-file-buffer ifile) + (find-file-noselect ifile)))) + (output-format (if is-exporter + polymode-exporter-output-file-format + polymode-weave-output-file-format))) + (with-current-buffer ibuffer + (save-buffer) + (let ((comm.ofile (pm--output-command.file output-format sfrom sto quote))) + (message "%s '%s' with '%s' ..." (if is-exporter "Exporting" "Weaving") + (file-name-nondirectory ifile) (eieio-object-name processor)) + (let* ((pm--output-file (cdr comm.ofile)) + (pm--input-file ifile) + ;; skip weaving step if possible + ;; :fixme this should not happen after weaver/exporter change + ;; or after errors in previous exporter + (omt (and polymode-skip-processing-when-unmodified + (stringp pm--output-file) + (pm--file-mod-time pm--output-file))) + (imt (and omt (pm--file-mod-time pm--input-file))) + (ofile (or (and imt (time-less-p imt omt) pm--output-file) + (let ((fun (oref processor :function)) + (args (delq nil (list callback from to)))) + (apply fun (car comm.ofile) args))))) + ;; ofile is non-nil in two cases: + ;; -- synchronous back-ends (very uncommon) + ;; -- when output is transitional (not real) and mod time of input < output + (when ofile + (if pm--export-spec + ;; same logic as in pm--wrap-callback + (let ((pm--input-not-real t) + (espec pm--export-spec) + (pm--export-spec nil)) + (when (listp ofile) + (setq ofile (car ofile))) + (pm-export (symbol-value (oref pm/polymode :exporter)) + (car espec) (cdr espec) + ofile)) + (pm--display-file ofile))))))))) + +(provide 'polymode-core) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-debug.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-debug.el new file mode 100644 index 0000000..cc310b6 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-debug.el @@ -0,0 +1,339 @@ +;;; polymode.el --- Various tools for debugging and tracing polymode + +(defvar pm--underline-overlay + (let ((overlay (make-overlay (point) (point)))) + (overlay-put overlay 'face '(:underline (:color "red" :style wave))) + overlay) + "Overlay used in `pm-debug-mode'.") + +(defvar pm--inverse-video-overlay + (let ((overlay (make-overlay (point) (point)))) + (overlay-put overlay 'face '(:inverse-video t)) + overlay) + "Overlay used by `pm-debug-map-over-spans-and-highlight'.") + +(defvar pm-debug-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "M-n M-i") 'pm-debug-info-on-current-span) + (define-key map (kbd "M-n i") 'pm-debug-info-on-current-span) + (define-key map (kbd "M-n M-p") 'pm-debug-print-relevant-variables) + + (define-key map (kbd "M-n M-t m") 'pm-debug-toogle-info-message) + (define-key map (kbd "M-n M-t f") 'pm-debug-toggle-fontification) + (define-key map (kbd "M-n M-t M-f") 'pm-debug-toggle-fontification) + (define-key map (kbd "M-n M-t p") 'pm-debug-toggle-post-command) + (define-key map (kbd "M-n M-t c") 'pm-debug-toggle-after-change) + (define-key map (kbd "M-n M-t M-c") 'pm-debug-toggle-after-change) + (define-key map (kbd "M-n M-t a") 'pm-debug-toggle-all) + (define-key map (kbd "M-n M-t M-a") 'pm-debug-toggle-all) + (define-key map (kbd "M-n M-t t") 'pm-debug-trace-relevant-functions) + (define-key map (kbd "M-n M-t M-t") 'pm-debug-trace-relevant-functions) + (define-key map (kbd "M-n M-t u") 'pm-debug-untrace-relevant-functions) + (define-key map (kbd "M-n M-t M-u") 'pm-debug-untrace-relevant-functions) + (define-key map (kbd "M-n M-h") 'pm-debug-map-over-spans-and-highlight) + + (define-key map (kbd "M-n M-f t") 'pm-debug-toggle-fontification) + (define-key map (kbd "M-n M-f s") 'pm-debug-fontify-current-span) + (define-key map (kbd "M-n M-f e") 'pm-debug-fontify-last-font-lock-error) + (define-key map (kbd "M-n M-f h") 'pm-debug-highlight-last-font-lock-error-region) + (define-key map (kbd "M-n M-f M-t") 'pm-debug-toggle-fontification) + (define-key map (kbd "M-n M-f M-s") 'pm-debug-fontify-current-span) + (define-key map (kbd "M-n M-f M-e") 'pm-debug-fontify-last-font-lock-error) + map)) + +(define-minor-mode pm-debug-minor-mode + "Turns on/off useful facilities for debugging polymode. + +Key bindings: +\\{pm-debug-minor-mode-map}" + nil + " PMDBG" + :group 'polymode + (interactive) + (if pm-debug-minor-mode + (progn + ;; this is global hook. No need to complicate with local hooks + (add-hook 'post-command-hook 'pm-debug-highlight-current-span)) + (delete-overlay pm--underline-overlay) + (delete-overlay pm--inverse-video-overlay) + (remove-hook 'post-command-hook 'pm-debug-highlight-current-span))) + +(defun pm-debug-minor-mode-on () + ;; activating everywhere (in case font-lock infloops in a polymode buffer ) + ;; this doesn't activate in fundamental mode + (pm-debug-minor-mode t)) + +(define-globalized-minor-mode pm-debug-mode pm-debug-minor-mode pm-debug-minor-mode-on) + +(defun pm-debug-highlight-current-span () + (when polymode-mode + (unless (memq this-command '(pm-debug-info-on-current-span + pm-debug-highlight-last-font-lock-error-region)) + (delete-overlay pm--inverse-video-overlay)) + (condition-case err + (let ((span (pm-get-innermost-span))) + (when pm-debug-display-info-message + (pm--debug-info span)) + (move-overlay pm--underline-overlay (nth 1 span) (nth 2 span) (current-buffer))) + (error (message "%s" (error-message-string err)))))) + +(defgeneric pm-debug-info (chunkmode)) +(defmethod pm-debug-info (chunkmode) + (format "class:%s" (eieio-object-class-name chunkmode))) +(defmethod pm-debug-info ((chunkmode pm-hbtchunkmode)) + (format "head-reg:\"%s\" tail-reg:\"%s\" %s" + (oref chunkmode :head-reg) (oref chunkmode :tail-reg) + (call-next-method))) +(defmethod pm-debug-info ((chunkmode pm-hbtchunkmode)) + (format "head-reg:\"%s\" tail-reg:\"%s\" %s" + (oref chunkmode :head-reg) (oref chunkmode :tail-reg) + (call-next-method))) +(defmethod pm-debug-info ((chunkmode pm-hbtchunkmode-auto)) + (call-next-method)) + +(defun pm--debug-info (&optional span) + (let* ((span (or span (and polymode-mode (pm-get-innermost-span)))) + (message-log-max nil) + (beg (nth 1 span)) + (end (nth 2 span)) + (obj (nth 3 span)) + (type (and span (or (car span) 'host)))) + (list (current-buffer) + (point-min) (point) (point-max) + major-mode + type beg end + (and obj (pm-debug-info obj)) + (format "lppss:%s" + syntax-ppss-last)))) + +(defun pm-debug-info-on-current-span () + (interactive) + (if (not polymode-mode) + (message "not in a polymode buffer") + (let ((span (pm-get-innermost-span))) + (apply 'message "min:%d pos:%d max:%d || (%s) type:%s span:%s-%s %s" (pm--debug-info span)) + (move-overlay pm--inverse-video-overlay (nth 1 span) (nth 2 span) (current-buffer))))) + +(defvar pm-debug-display-info-message nil) +(defun pm-debug-toogle-info-message () + (interactive) + (setq pm-debug-display-info-message (not pm-debug-display-info-message))) + +(defun pm-debug-toggle-fontification () + (interactive) + (if pm-allow-fontification + (progn + (message "fontificaiton disabled") + (setq pm-allow-fontification nil)) + (message "fontificaiton enabled") + (setq pm-allow-fontification t))) + +(defun pm-debug-toggle-after-change () + (interactive) + (if pm-allow-after-change-hook + (progn + (message "after-change disabled") + (setq pm-allow-after-change-hook nil)) + (message "after-change enabled") + (setq pm-allow-after-change-hook t))) + +(defun pm-debug-toggle-post-command () + (interactive) + (if pm-allow-post-command-hook + (progn + (message "post-command disabled") + (setq pm-allow-post-command-hook nil)) + (message "post-command enabled") + (setq pm-allow-post-command-hook t))) + +(defun pm-debug-toggle-all () + (interactive) + (if pm-allow-fontification + (progn + (message "fontificaiton, after-chnage and command-hook disabled") + (setq pm-allow-fontification nil + pm-allow-after-change-hook nil + pm-allow-post-command-hook nil)) + (message "fontificaiton, after-change and command-hook enabled") + (setq pm-allow-fontification t + pm-allow-after-change-hook t + pm-allow-post-command-hook t))) + +(defun pm-debug-fontify-current-span () + (interactive) + (let ((span (pm-get-innermost-span)) + (pm-allow-fontification t)) + (poly-lock-fontify-region (nth 1 span) (nth 2 span)))) + +(defun pm-debug-fontify-last-font-lock-error () + (interactive) + (let ((reg (pm--debug-get-last-fl-error)) + (pm-allow-fontification t)) + (if reg + (progn + ;; (pm-debug-blink-region (car reg) (cdr reg) 2) + (poly-lock-fontify-region (car reg) (cdr reg))) + (message "No last font-lock errors found")))) + +(defun pm--debug-get-last-fl-error () + (with-current-buffer (messages-buffer) + (goto-char (point-max)) + (when (re-search-backward "(poly-lock-fontify-region \\([0-9]+\\) \\([0-9]+\\))" nil t) + (cons (string-to-number (match-string 1)) + (string-to-number (match-string 2)))))) + +(defun pm-debug-highlight-last-font-lock-error-region () + (interactive) + (let ((reg (pm--debug-get-last-fl-error))) + (if reg + (progn + (goto-char (car reg)) + (recenter) + (move-overlay pm--inverse-video-overlay (car reg) (cdr reg) (current-buffer)) + (message "Region %s" reg)) + (message "No last font-lock errors found")))) + +(defvar pm-debug-relevant-functions-alist + '((polymode-initialization . (pm-initialize pm--mode-setup pm--common-setup + pm--get-chunkmode-buffer-create)) + (poly-lock . (poly-lock-mode poly-lock-fontify-region + poly-lock-fontification-function + poly-lock-after-change + poly-lock-refontify + poly-lock--fontify-region-original)) + (jit-loc . (jit-lock-refontify jit-lock-mode jit-lock-fontify-now)) + (font-lock . (;; font-lock-mode turn-on-font-lock-if-desired + turn-on-font-lock + font-lock-after-change-function + font-lock-default-fontify-region + font-lock-fontify-syntactically-region + font-lock-extend-region-wholelines + font-lock-extend-region-multiline + font-lock-fontify-syntactic-keywords-region + font-lock-fontify-keywords-region + font-lock-unfontify-region + font-lock-fontify-region font-lock-flush + font-lock-fontify-buffer font-lock-ensure)) + (methods . (pm-select-buffer pm-get-buffer-create)) + (select . (pm-get-innermost-span pm-map-over-spans)) + (insert . (self-insert-command)))) + +(defun pm-debug-trace-background-1 (fn) + (interactive (trace--read-args "Trace function in background: ")) + (unless (symbolp fn) + (error "can trace symbols only")) + (unless (get fn 'cl--class) + (trace-function-background fn nil + '(lambda () + (format " [buf:%s pos:%s type:%s (%f)]" + (current-buffer) (point) + (get-text-property (point) :pm-span-type) + (float-time)))))) + +(defun pm-debug-trace-relevant-functions (&optional group) + "GROUP is either a string or a list of functions to trace. +If string, it must b an entry in +`pm-debug-relevant-functions-alist'." + (interactive) + (require 'trace) + (if (and group (listp group)) + (mapc #'pm-debug-trace-background-1 group) + (let* ((groups (append '("*ALL*") (mapcar #'car pm-debug-relevant-functions-alist))) + (group-name (or group (completing-read "Trace group: " groups nil t)))) + (if (equal group-name "*ALL*") + (mapc (lambda (group) + (mapc #'pm-debug-trace-background-1 + (assoc group pm-debug-relevant-functions-alist))) + (cdr groups)) + (mapc #'pm-debug-trace-background-1 + (assoc (intern group-name) pm-debug-relevant-functions-alist)))))) + +(defun pm-debug-trace-functions-by-regexp (regexp) + "Trace all functions whose name matched REGEXP." + (cl-loop for sym being the symbols + when (and (fboundp sym) + (not (eq sym 'pm-debug-trace-background-1))) + when (string-match regexp (symbol-name sym)) + do (pm-debug-trace-background-1 sym))) + +(defvar pm-debug-relevant-variables '(fontification-functions + font-lock-flush-function + font-lock-ensure-function + font-lock-fontify-region-function + font-lock-fontify-buffer-function + font-lock-unfontify-region-function + font-lock-unfontify-buffer-function + post-command-hook + indent-line-function)) + +(defun pm-debug-print-relevant-variables () + (interactive) + (let ((buff (get-buffer-create "*polymode-vars*")) + (vars (mapcar (lambda (v) (cons v (buffer-local-value v (current-buffer)))) + pm-debug-relevant-variables)) + (cbuff (current-buffer))) + (require 'pp) + (with-current-buffer buff + (goto-char (point-max)) + (insert "===============================================================\n") + (insert (format "relevant vars in buffer: %s\n" cbuff)) + (insert (pp-to-string vars)) + (toggle-truncate-lines -1)) + (display-buffer buff))) + +(defun pm-debug-untrace-relevant-functions () + (interactive) + (require 'trace) + (let* ((groups (append `("*ALL*") (mapcar #'car pm-debug-relevant-functions-alist))) + (group-name (completing-read "Trace group: " groups nil t))) + (if (equal group-name "*ALL*") + (mapc (lambda (group) + (mapc #'untrace-function (assoc group pm-debug-relevant-functions-alist))) + (cdr groups)) + (mapc #'untrace-function (assoc groups pm-debug-relevant-functions-alist))))) + +(defun pm-debug-blink-region (start end &optional delay) + (move-overlay pm--inverse-video-overlay start end (current-buffer)) + (run-with-timer (or delay 0.4) nil (lambda () (delete-overlay pm--inverse-video-overlay)))) + +(defun pm-debug-map-over-spans-and-highlight () + (interactive) + (pm-map-over-spans (lambda () + (let ((start (nth 1 *span*)) + (end (nth 2 *span*))) + (pm-debug-blink-region start end) + (sit-for 1))) + (point-min) (point-max) nil nil t)) + +(defun pm--highlight-span (&optional hd-matcher tl-matcher) + (interactive) + (let* ((hd-matcher (or hd-matcher (oref pm/chunkmode :head-reg))) + (tl-matcher (or tl-matcher (oref pm/chunkmode :tail-reg))) + (span (pm--span-at-point hd-matcher tl-matcher))) + (pm-debug-blink-region (nth 1 span) (nth 2 span)) + (message "span: %s" span))) + +(defun pm-debug-run-over-check () + (interactive) + (goto-char (point-min)) + (let ((start (current-time)) + (count 1)) + (pm-switch-to-buffer) + (while (< (point) (point-max)) + (setq count (1+ count)) + (forward-char) + (pm-switch-to-buffer)) + (let ((elapsed (float-time (time-subtract (current-time) start)))) + (message "elapsed: %s per-char: %s" elapsed (/ elapsed count))))) + +(defun pm-dbg (msg &rest args) + (let ((cbuf (current-buffer)) + (cpos (point))) + (with-current-buffer (get-buffer-create "*pm-dbg*") + (save-excursion + (goto-char (point-max)) + (insert "\n") + (insert (apply 'format (concat "%f [%s at %d]: " msg) + (float-time) cbuf cpos args)))))) + +(provide 'polymode-debug) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-export.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-export.el new file mode 100644 index 0000000..e9a16e1 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-export.el @@ -0,0 +1,392 @@ +(require 'polymode-core) +(require 'polymode-classes) + +(defgroup polymode-export nil + "Polymode Exporters" + :group 'polymode) + +(defcustom polymode-exporter-output-file-format "%s" + "Format of the exported files. +%s is substituted with the current file name sans extension." + :group 'polymode-export + :type 'string) + +(defclass pm-exporter (pm-root) + ((from + :initarg :from + :initform '() + :type list + :custom list + :documentation + "Input exporter specifications. + This is an alist of elements of the form (id regexp doc + commmand) or (id . selector). ID is the unique identifier of + the spec. REGEXP is a regexp which, if matched on current + file name, implies that the current file can be exported + with this specification. DOC is a short help string shown + during interactive export. COMMAND is the exporter + command (string). It can contain the following format specs: + + %i - input file (no dir) + %I - input file (full path) + %o - output file (no dir) + %O - output file (full path) + %b - output file (base name only) + %t - 4th element of the :to spec + + When specification is of the form (id . selector), SELECTOR + is a function of variable arguments that accepts at least + one argument ACTION. ACTION is a symbol and can be one of + the following: + + match - must return non-nil if this specification + applies to the file that current buffer is visiting, + or :nomatch if specification does not apply. This + selector can receive an optional file-name + argument. In that case the decision must be made + solely on that file and current buffer must be + ignored. This is useful for matching exporters to + weavers when exported file does not exist yet. + + regexp - return a string which is used to match input + file name. If nil, `match' selector must return + non-nil value. This selector is ignored if `match' + returned non-nil. + + doc - return documentation string + + commmand - return a string with optional %i, %f, + etc. format specs as described above. It will be + passed to the processing :function.") + + (to + :initarg :to + :initform '() + :type list + :custom list + :documentation + "Output specifications alist. Each element is either a list + of the form (id ext doc t-spec) or a cons (id . selector). + + In the former case EXT is an extension of the output + file. DOC is a short documentation string. t-spec is a + string what is substituted instead of %t in :from spec + commmand. `t-spec' can be a list of one element '(command), + in which case the whole :from spec command is substituted + with command from %t-spec. + + When specification is of the form (id . selector), SELECTOR + is a function of variable arguments that accepts at least + one argument ACTION. This function is called in a buffer + visiting input file. ACTION is a symbol and can one of the + following: + + output-file - return an output file name or a list of file + names. Receives input-file as argument. If this + command returns nil, the output is built from input + file and value of 'output-ext command. + + + This selector can also return a function. This + function will be called in the callback or sentinel of + the weaving process after the weaving was + completed. This function should sniff the output of + the process for errors or file names. It must return a + file name, a list of file names or nil if no such + files have been detected. + + ext - extension of output file. If nil and + `output' also returned nil, the exporter won't be able + to identify the output file and no automatic display + or preview will be available. + + doc - return documentation string + + command - return a string to be used instead of + the :from command. If nil, :from spec command is used. + + t-spec - return a string to be substituted as %t :from + spec in :from command. If `command' selector returned + non-nil, this spec is ignored.") + (function + :initarg :function + :initform (lambda (command from to) + (error "Function not defined for this exporter")) + :type (or symbol function) + :documentation + "Function to process the commmand. Must take 3 arguments + COMMAND, FROM-ID and TO-ID. COMMAND is the 4th argument + of :from spec with all the formats substituted. FROM-ID is + the id of requested :from spec, TO-ID is the id of the :to + spec.")) + "Root exporter class.") + +(defclass pm-callback-exporter (pm-exporter) + ((callback + :initarg :callback + :initform (lambda (&optional rest) + (error "No callback defined for this exporter.")) + :type (or symbol function) + :documentation + "Callback function to be called by :function. There is no + default callback. Callback must return the output file + name.")) + "Class to represent asynchronous exporters.") + +(defclass pm-shell-exporter (pm-exporter) + ((function + :initform 'pm-default-shell-export-function) + (sentinel + :initarg :sentinel + :initform 'pm-default-export-sentinel + :type (or symbol function) + :documentation + "Sentinel function to be called by :function when a shell + call is involved. Sentinel should return the output file + name.") + (quote + :initarg :quote + :initform nil + :type boolean + :documentation "Non-nil when file arguments must be quoted + with `shell-quote-argument'.")) + "Class to represent exporters that call external processes.") + +(defun pm-default-shell-export-function (command sentinel from to) + "Run exporting command interactively. +Run command in a buffer (in comint-shell-mode) so that it accepts +user interaction. This is a default function in all exporters +that call a shell command" + (pm--run-shell-command command sentinel "*polymode export*" + (concat "Exporting " from "-->" to " with command:\n\n " + command "\n\n"))) + + +;;; METHODS + +(defgeneric pm-export (exporter from to &optional ifile) + "Process IFILE with EXPORTER.") + +(defmethod pm-export ((exporter pm-exporter) from to &optional ifile) + (pm--process-internal exporter from to ifile)) + +(defmethod pm-export ((exporter pm-callback-exporter) from to &optional ifile) + (let ((cb (pm--wrap-callback exporter :callback ifile))) + (pm--process-internal exporter from to ifile cb))) + +(defmethod pm-export ((exporter pm-shell-exporter) from to &optional ifile) + (let ((cb (pm--wrap-callback exporter :sentinel ifile))) + (pm--process-internal exporter from to ifile cb (oref exporter :quote)))) + + +;; UI + +(defvar pm--exporter-hist nil) +(defvar pm--export:from-hist nil) +(defvar pm--export:from-last nil) +(defvar pm--export:to-hist nil) +(defvar pm--export:to-last nil) +(declare-function polymode-set-weaver "polymode-weave") +(declare-function pm-weave "polymode-weave") + +(defun polymode-export (&optional from to) + "Export current file. + +FROM and TO are the ids of the :from and :to slots of the current +exporter. If the current exporter hasn't been set yet, set the +exporter with `polymode-set-exporter'. You can always change the +exporter manually by invoking `polymode-set-exporter'. + +When FROM or TO are missing they are determined automatically +from the current exporter's specifications and file's +extension. If no appropriate export specification has been found, +look into current weaver and try to match weaver's output to +exporters input extension. When such combination is possible, +settle on weaving first and exporting the weaved output. When +none of the above worked, ask the user for `from' and `to' specs. + +When called interactively with C-u argument, ask for FROM and TO +interactively. See class `pm-exporter' for the complete +specification." + (interactive "P") + (cl-flet ((to-name.id (el) (let* ((ext (funcall (cdr el) 'ext)) + (name (if ext + (format "%s (%s)" (funcall (cdr el) 'doc) ext) + (funcall (cdr el) 'doc)))) + (cons name (car el)))) + (from-name.id (el) (cons (funcall (cdr el) 'doc) (car el)))) + (let* ((exporter (symbol-value (or (oref pm/polymode :exporter) + (polymode-set-exporter)))) + (fname (file-name-nondirectory buffer-file-name)) + (gprompt nil) + (case-fold-search t) + + (from-opts (mapcar #'from-name.id (pm--selectors exporter :from))) + (from-id + (cond + ;; A: guess from spec + ((null from) + (or + ;; 1. repeated export; don't ask + pm--export:from-last + + ;; 2. select :from entries which match to current file + (let ((matched (cl-loop for el in (pm--selectors exporter :from) + when (pm--selector-match (cdr el)) + collect (from-name.id el)))) + (when matched + (if (> (length matched) 1) + (cdr (pm--completing-read "Multiple `from' specs matched. Choose one: " matched)) + (cdar matched)))) + + ;; 3. guess from weaver and return a cons (weaver-id . exporter-id) + (let ((weaver (symbol-value (or (oref pm/polymode :weaver) + (progn + (setq gprompt "Choose `from' spec: ") + (polymode-set-weaver)))))) + (when weaver + ;; fixme: weaver was not yet ported to selectors + ;; fixme: currently only first match is returned + (let ((pair (cl-loop for w in (oref weaver :from-to) + ;; weaver input extension matches the filename + if (string-match-p (nth 1 w) fname) + return (cl-loop for el in (pm--selectors exporter :from) + ;; input exporter extensnion matches weaver output extension + when (pm--selector-match (cdr el) (concat "dummy." (nth 2 w))) + return (cons (car w) (car el)))))) + (when pair + (message "Matching weaver found. Weaving to '%s' first." (car pair)) + pair)))) + + ;; 4. nothing matched; ask + (let* ((prompt (or gprompt + (format "No `from' specs matched. Choose one: " + (file-name-nondirectory fname) (eieio-object-name-string exporter)))) + (sel (pm--completing-read prompt from-opts nil t nil 'pm--export:from-hist))) + (cdr sel)))) + + ;; B: C-u, force a :from spec + ((equal from '(4)) + (cdr (if (> (length from-opts) 1) + (pm--completing-read "Input type: " from-opts nil t nil 'pm--export:from-hist) + (car from-opts)))) + + ;; C. string + ((stringp from) + (if (assoc from (oref exporter :from)) + from + (error "Cannot find `from' spec '%s' in %s exporter" + from (eieio-object-name exporter)))) + ;; D. error + (t (error "'from' argument must be nil, universal argument or a string")))) + + (to-opts (mapcar #'to-name.id (pm--selectors exporter :to))) + (to-id + (cond + ;; A. guess from spec + ((null to) + (or + ;; 1. repeated export; don't ask and use first entry in history + (unless (equal from '(4)) + pm--export:to-last) + + ;; 2. First export or C-u + (cdr (pm--completing-read "Export to: " to-opts nil t nil 'pm--export:to-hist)))) + + ;; B. string + ((stringp to) + (if (assoc to (oref exporter :to)) + to + (error "Cannot find output spec '%s' in %s exporter" + to (eieio-object-name exporter)))) + ;; C . Error + (t (error "'to' argument must be nil or a string"))))) + + (setq-local pm--export:from-last from-id) + (setq-local pm--export:to-last to-id) + + (if (consp from-id) + ;; run through weaver + (let ((pm--export-spec (cons (cdr from-id) to-id)) + (pm--output-not-real t)) + (pm-weave (symbol-value (oref pm/polymode :weaver)) (car from-id))) + (pm-export exporter from-id to-id))))) + +(defun polymode-set-exporter () + "Interactively set exporter for the current file." + (interactive) + (unless pm/polymode + (error "No pm/polymode object found. Not in polymode buffer?")) + (let* ((exporters (pm--abrev-names + (delete-dups (pm--oref-with-parents pm/polymode :exporters)) + "pm-exporter/")) + (sel (pm--completing-read "Choose exporter: " exporters nil t nil 'pm--exporter-hist)) + (out (intern (cdr sel)))) + (setq-local pm--export:from-last nil) + (setq-local pm--export:to-last nil) + (oset pm/polymode :exporter out) + out)) + +(defmacro polymode-register-exporter (exporter defaultp &rest configs) + "Add EXPORTER to :exporters slot of all config objects in CONFIGS. +When DEFAULT? is non-nil, also make EXPORTER the default exporter +for each polymode in CONFIGS." + `(dolist (pm ',configs) + (object-add-to-list (symbol-value pm) :exporters ',exporter) + (when ,defaultp (oset (symbol-value pm) :exporter ',exporter)))) + + +;;; GLOBAL EXPORTERS +(defcustom pm-exporter/pandoc + (pm-shell-exporter "pandoc" + :from + '(;; ("json" "\\.json\\'" "JSON native AST" "pandoc %i -f json -t %t -o %o") + ("markdown" "\\.md\\'" "pandoc's markdown" "pandoc %i -f markdown -t %t -o %o") + ("markdown_strict" "\\.md\\'" "original markdown" "pandoc %i -f markdown_strict -t %t -o %o") + ("markdown_phpextra" "\\.md\\'" "PHP markdown" "pandoc %i -f markdown_phpextra -t %t -o %o") + ("markdown_phpextra" "\\.md\\'" "github markdown" "pandoc %i -f markdown_phpextra -t %t -o %o") + ("textile" "\\.textile\\'" "Textile" "pandoc %i -f textile -t %t -o %o") + ("rst" "\\.rst\\'" "reStructuredText" "pandoc %i -f rst -t %t -o %o") + ("html" "\\.x?html?\\'" "HTML" "pandoc %i -f html -t %t -o %o") + ("doocbook" "\\.xml\\'" "DocBook" "pandoc %i -f doocbook -t %t -o %o") + ("mediawiki" "\\.wiki\\'" "MediaWiki" "pandoc %i -f mediawiki -t %t -o %o") + ("latex" "\\.tex\\'" "LaTeX" "pandoc %i -f latex -t %t -o %o") + ) + :to + '(;; ("json" "json" "JSON version of native AST" "json") + ("plain" "txt" "plain text" "plain") + ("markdown" "md" "pandoc's extended markdown" "markdown") + ("markdown_strict" "md" "original markdown" "markdown_strict") + ("markdown_phpextra" "md" "PHP extended markdown" "markdown_phpextra") + ("markdown_github" "md" "github extended markdown" "markdown_github") + ("rst" "rst" "reStructuredText" "rst") + ("html" "html" "XHTML 1" "html") + ("html5" "html" "HTML 5" "html5") + ("latex" "tex" "LaTeX" "latex") + ("beamer" "tex" "LaTeX beamer" "beamer") + ("context" "tex" "ConTeXt" "context") + ("man" "man" "groff man" "man") + ("mediawiki" "wiki" "MediaWiki markup" "mediawiki") + ("textile" "textile" "Textile" "textile") + ("org" "org" "Emacs Org-Mode" "org") + ("texinfo" "info" "GNU Texinfo" "texinfo") + ("docbook" "xml" "DocBook XML" "docbook") + ("opendocument" "xml" "OpenDocument XML" "opendocument") + ("odt" "odt" "OpenOffice text document" "odt") + ("docx" "docx" "Word docx" "docx") + ("epub" "epub" "EPUB book" "epub") + ("epub3" "epub" "EPUB v3" "epub3") + ("fb2" "fb" "FictionBook2 e-book" "fb2") + ("asciidoc" "txt" "AsciiDoc" "asciidoc") + ("slidy" "html" "Slidy HTML slide show" "slidy") + ("slideous" "html" "Slideous HTML slide show" "slideous") + ("dzslides" "html" "HTML5 slide show" "dzslides") + ("s5" "html" "S5 HTML slide show" "s5") + ("rtf" "rtf" "rich text format" "rtf")) + :function 'pm-default-shell-export-function + :sentinel 'pm-default-export-sentinel) + "Pandoc exporter" + :group 'polymode-export + :type 'object) + +(provide 'polymode-export) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-methods.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-methods.el new file mode 100644 index 0000000..fb28a03 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-methods.el @@ -0,0 +1,872 @@ +(require 'polymode-core) +(require 'poly-lock) + + +;;; Initialization + +(defgeneric pm-initialize (config) + "Initialize current buffer with CONFIG.") + +(defmethod pm-initialize ((config pm-polymode)) + ;; fixme: (VS[06-03-2016]: probably not anymore) reinstalation leads to + ;; infloop of poly-lock--fontify-region-original and others ... On startup with local + ;; auto vars emacs reinstals the mode twice .. waf? Temporary fix: don't + ;; install twice + (unless pm/polymode + (let ((chunkmode (clone (symbol-value (oref config :hostmode))))) + (let ((pm-initialization-in-progress t) + ;; Set if nil! This allows unspecified host chunkmodes to be used in + ;; minor modes. + (host-mode (or (oref chunkmode :mode) + (oset chunkmode :mode major-mode)))) + + (pm--mode-setup host-mode) + + ;; maybe: fixme: inconsistencies? + ;; 1) Not calling config's :minor-mode (polymode function). But polymode + ;; function calls pm-initialize, so it's probably ok. + (oset chunkmode -buffer (current-buffer)) + (oset config -hostmode chunkmode) + + (setq pm/polymode config + pm/chunkmode chunkmode + pm/type 'host) + + (pm--common-setup) + (add-hook 'flyspell-incorrect-hook + 'pm--flyspel-dont-highlight-in-chunkmodes nil t)) + (pm--run-init-hooks config 'polymode-init-host-hook) + (pm--run-init-hooks chunkmode)))) + +(defmethod pm-initialize ((config pm-polymode-one)) + (let ((pm-initialization-in-progress t)) + (call-next-method)) + (eval `(oset config -innermodes + (list (clone ,(oref config :innermode))))) + (pm--run-init-hooks config 'polymode-init-host-hook)) + +(defmethod pm-initialize ((config pm-polymode-multi)) + (let ((pm-initialization-in-progress)) + (call-next-method)) + (oset config -innermodes + (mapcar (lambda (sub-name) + (clone (symbol-value sub-name))) + (oref config :innermodes))) + (pm--run-init-hooks config 'polymode-init-host-hook)) + +(defmethod pm-initialize ((chunkmode pm-chunkmode) &optional type mode) + ;; run in chunkmode indirect buffer + (setq mode (or mode (pm--get-chunkmode-mode chunkmode type))) + (let ((pm-initialization-in-progress t) + (new-name (generate-new-buffer-name + (format "%s[%s]" (buffer-name (pm-base-buffer)) + (replace-regexp-in-string "-mode" "" (symbol-name mode)))))) + (rename-buffer new-name) + (pm--mode-setup (pm--get-existent-mode mode)) + (pm--move-vars '(pm/polymode buffer-file-coding-system) (pm-base-buffer)) + (setq pm/chunkmode chunkmode + pm/type type) + (funcall (oref pm/polymode :minor-mode)) + (vc-find-file-hook) + (pm--common-setup) + (pm--run-init-hooks chunkmode 'polymode-init-inner-hook))) + +(defun pm--mode-setup (mode &optional buffer) + ;; General major-mode install. Should work for both indirect and base buffers. + ;; PM objects are not yet initialized (pm/polymode, pm/chunkmode, pm/type) + + (with-current-buffer (or buffer (current-buffer)) + ;; don't re-install if already there; polymodes can be used as minor modes. + (unless (eq major-mode mode) + (let ((polymode-mode t) ;major-modes might check this + ;; (font-lock-fontified t) + ;; Modes often call font-lock functions directly. We prevent that. + (font-lock-function 'ignore) + (font-lock-flush-function 'ignore) + (font-lock-fontify-buffer-function 'ignore) + ;; Mode functions can do arbitrary things. We inhibt all PM hooks + ;; because PM objects have not been setup yet. + (pm-allow-after-change-hook nil) + (pm-allow-fontification nil)) + (condition-case-unless-debug err + (funcall mode) + (error (message "Polymode error (pm--mode-setup '%s): %s" mode (error-message-string err)))))) + + (setq polymode-mode t) + (current-buffer))) + +(defun pm--common-setup (&optional buffer) + ;; General buffer setup. Should work for indirect and base buffers. Assumes + ;; that the buffer was fully prepared and objects like pm/polymode and + ;; pm/chunkmode have been initialised. Return the BUFFER. + + (with-current-buffer (or buffer (current-buffer)) + + ;; INDENTATION + (when (and indent-line-function ; not that it should ever be nil... + (oref pm/chunkmode :protect-indent-line)) + (setq pm--indent-line-function-original indent-line-function) + (setq-local indent-line-function 'pm-indent-line-dispatcher)) + + ;; FONT LOCK + (setq-local font-lock-function 'poly-lock-mode) + (font-lock-mode t) + + ;; SYNTAX + ;; We are executing `syntax-propertize' narrowed to span as per advice in + ;; (polymode-compat.el) + (pm-around-advice syntax-begin-function 'pm-override-output-position) ; obsolete as of 25.1 + (pm-around-advice syntax-propertize-extend-region-functions 'pm-override-output-cons) + ;; flush ppss in all buffers and hook checks + (add-hook 'before-change-functions 'polymode-before-change-setup t t) + + ;; REST + (add-hook 'kill-buffer-hook 'pm--kill-indirect-buffer t t) + (add-hook 'post-command-hook 'polymode-post-command-select-buffer nil t) + (object-add-to-list pm/polymode '-buffers (current-buffer)) + + (current-buffer))) + +(defun pm--run-init-hooks (object &optional emacs-hook) + (unless pm-initialization-in-progress + (when emacs-hook + (run-hooks emacs-hook)) + (pm--run-hooks object :init-functions))) + +(defun pm--run-hooks (object slot &rest args) + "Run hooks from SLOT of OBJECT and its parent instances. +Parents' hooks are run first." + (let ((inst object) + funs) + ;; run hooks, parents first + (while inst + (setq funs (append (and (slot-boundp inst slot) ; don't cascade + (eieio-oref inst slot)) + funs) + inst (and (slot-boundp inst :parent-instance) + (oref inst :parent-instance)))) + (if args + (apply 'run-hook-with-args 'funs args) + (run-hooks 'funs)))) + +(defvar-local pm--killed-once nil) +(defun pm--kill-indirect-buffer () + ;; find-alternate-file breaks (https://github.com/vspinu/polymode/issues/79) + (let ((base (buffer-base-buffer))) + (when (and base (buffer-live-p base)) + ;; 'base' is non-nil in indirect buffers only + (set-buffer-modified-p nil) + (unless (buffer-local-value 'pm--killed-once base) + (with-current-buffer base + (setq pm--killed-once t)) + (kill-buffer base))))) + + +(defgeneric pm-get-buffer-create (chunkmode &optional type) + "Get the indirect buffer associated with SUBMODE and +SPAN-TYPE. Should return nil if buffer has not yet been +installed. Also see `pm-get-span'.") + +(defmethod pm-get-buffer-create ((chunkmode pm-chunkmode) &optional type) + (let ((buff (oref chunkmode -buffer))) + (or (and (buffer-live-p buff) buff) + (oset chunkmode -buffer + (pm--get-chunkmode-buffer-create chunkmode type))))) + +(defmethod pm-get-buffer-create ((chunkmode pm-hbtchunkmode) &optional type) + (let ((buff (cond ((eq 'body type) (oref chunkmode -buffer)) + ((eq 'head type) (oref chunkmode -head-buffer)) + ((eq 'tail type) (oref chunkmode -tail-buffer)) + (t (error "Don't know how to select buffer of type '%s' for chunkmode '%s' of class '%s'" + type (eieio-object-name chunkmode) (class-of chunkmode)))))) + (if (buffer-live-p buff) + buff + (pm--set-chunkmode-buffer chunkmode type + (pm--get-chunkmode-buffer-create chunkmode type))))) + +(defun pm--get-chunkmode-buffer-create (chunkmode type) + (let ((mode (pm--get-existent-mode + (pm--get-chunkmode-mode chunkmode type)))) + (or + ;; 1. look through existent buffer list + (loop for bf in (oref pm/polymode -buffers) + when (and (buffer-live-p bf) + (eq mode (buffer-local-value 'major-mode bf))) + return bf) + ;; 2. create new + (with-current-buffer (pm-base-buffer) + (let* ((new-name (generate-new-buffer-name (buffer-name))) + (new-buffer (make-indirect-buffer (current-buffer) new-name))) + (with-current-buffer new-buffer + (pm-initialize chunkmode type mode)) + new-buffer))))) + +(defun pm--get-chunkmode-mode (obj type) + (with-slots (mode head-mode tail-mode) obj + (cond ((or (eq type 'body) + (and (eq type 'head) + (eq head-mode 'body)) + (and (eq type 'tail) + (or (eq tail-mode 'body) + (and (or (null tail-mode) + (eq tail-mode 'head)) + (eq head-mode 'body))))) + (oref obj :mode)) + ((or (and (eq type 'head) + (eq head-mode 'host)) + (and (eq type 'tail) + (or (eq tail-mode 'host) + (and (or (null tail-mode) + (eq tail-mode 'head)) + (eq head-mode 'host))))) + (oref (oref pm/polymode -hostmode) :mode)) + ((eq type 'head) + (oref obj :head-mode)) + ((eq type 'tail) + (if (or (null tail-mode) + (eq tail-mode 'head)) + (oref obj :head-mode) + (oref obj :tail-mode))) + (t (error "type must be one of 'head 'tail 'body"))))) + +(defun pm--set-chunkmode-buffer (obj type buff) + "Assign BUFF to OBJ's slot(s) corresponding to TYPE." + (with-slots (-buffer head-mode -head-buffer tail-mode -tail-buffer) obj + (pcase (list type head-mode tail-mode) + (`(body body ,(or `nil `body)) + (setq -buffer buff + -head-buffer buff + -tail-buffer buff)) + (`(body ,_ body) + (setq -buffer buff + -tail-buffer buff)) + (`(body ,_ ,_ ) + (setq -buffer buff)) + (`(head ,_ ,(or `nil `head)) + (setq -head-buffer buff + -tail-buffer buff)) + (`(head ,_ ,_) + (setq -head-buffer buff)) + (`(tail ,_ ,(or `nil `head)) + (setq -tail-buffer buff + -head-buffer buff)) + (`(tail ,_ ,_) + (setq -tail-buffer buff)) + (_ (error "type must be one of 'body, 'head or 'tail"))))) + + +(defvar pm-move-vars-from-base '(buffer-file-name) + "Variables transferred from base buffer on buffer switch.") + +(defvar pm-move-vars-from-old-buffer + '(buffer-invisibility-spec + selective-display overwrite-mode + ;; truncation and word-wrap + truncate-lines word-wrap + line-move-visual truncate-partial-width-windows) + "Variables transferred from old buffer on buffer switch.") + +(defgeneric pm-select-buffer (chunkmode span) + "Ask SUBMODE to select (make current) its indirect buffer +corresponding to the type of the SPAN returned by +`pm-get-span'.") + +(defmethod pm-select-buffer ((chunkmode pm-chunkmode) span) + "Select the buffer associated with CHUNKMODE. +Install a new indirect buffer if it is not already installed. For +this method to work correctly, SUBMODE's class should define +`pm-get-buffer-create' methods." + (let* ((type (car span)) + (buff (pm-get-buffer-create chunkmode type))) + (pm--select-existent-buffer buff))) + +;; extracted for debugging purpose +(defun pm--select-existent-buffer (buffer) + (when (and (not (eq buffer (current-buffer))) + (buffer-live-p buffer)) + (pm--move-vars pm-move-vars-from-base (pm-base-buffer) buffer) + (if pm--select-buffer-visibly + ;; slow, visual selection + (pm--select-existent-buffer-visibly buffer) + ;; fast set-buffer + (set-buffer buffer)))) + +;; extracted for debugging purpose +(defun pm--select-existent-buffer-visibly (new-buffer) + (let ((old-buffer (current-buffer)) + (point (point)) + (window-start (window-start)) + (visible (pos-visible-in-window-p)) + (vlm visual-line-mode) + (ractive (region-active-p)) + ;; text-scale-mode + (scale (and (boundp 'text-scale-mode) text-scale-mode)) + (scale-amount (and (boundp 'text-scale-mode-amount) text-scale-mode-amount)) + (hl-line (and (boundp 'hl-line-mode) hl-line-mode)) + (mkt (mark t)) + (bro buffer-read-only)) + + (when hl-line + (hl-line-mode -1)) + + (pm--move-vars pm-move-vars-from-old-buffer old-buffer new-buffer) + (pm--move-overlays old-buffer new-buffer) + + (switch-to-buffer new-buffer) + (bury-buffer-internal old-buffer) + + (unless (eq bro buffer-read-only) + (read-only-mode (if bro 1 -1))) + (pm--adjust-visual-line-mode vlm) + + (when (and (boundp 'text-scale-mode-amount) + (not (and (eq scale text-scale-mode) + (= scale-amount text-scale-mode-amount)))) + (if scale + (text-scale-set scale-amount) + (text-scale-set 0))) + + ;; fixme: what is the right way to do this ... activate-mark-hook? + (if (not ractive) + (deactivate-mark) + (set-mark mkt) + (activate-mark)) + + ;; avoid display jumps + (goto-char point) + (when visible + (set-window-start (get-buffer-window buffer t) window-start)) + + (when hl-line + (hl-line-mode 1)) + + (run-hook-with-args 'polymode-switch-buffer-hook old-buffer new-buffer) + (pm--run-hooks pm/polymode :switch-buffer-functions old-buffer new-buffer) + (pm--run-hooks pm/chunkmode :switch-buffer-functions old-buffer new-buffer))) + +(defun pm--move-overlays (from-buffer to-buffer) + (with-current-buffer from-buffer + (mapc (lambda (o) + (unless (eq 'linum-str (car (overlay-properties o))) + (move-overlay o (overlay-start o) (overlay-end o) to-buffer))) + (overlays-in 1 (1+ (buffer-size)))))) + +(defun pm--move-vars (vars from-buffer &optional to-buffer) + (let ((to-buffer (or to-buffer (current-buffer)))) + (unless (eq to-buffer from-buffer) + (with-current-buffer to-buffer + (dolist (var vars) + (and (boundp var) + (set var (buffer-local-value var from-buffer)))))))) + +(defun pm--adjust-visual-line-mode (vlm) + (unless (eq visual-line-mode vlm) + (if (null vlm) + (visual-line-mode -1) + (visual-line-mode 1)))) + +(defmethod pm-select-buffer ((config pm-polymode-multi-auto) &optional span) + ;; :fixme: pm-get-span on multi configs returns config as last object of + ;; span. This unnatural and confusing. Same problem with pm-indent-line + (pm-select-buffer (pm--get-multi-chunk config span) span)) + +(defun pm--get-multi-chunk (config span) + ;; fixme: cache somehow? + (if (null (car span)) + (oref config -hostmode) + (let ((type (car span)) + (proto (symbol-value (oref config :auto-innermode)))) + (save-excursion + (goto-char (cadr span)) + (unless (eq type 'head) + (let ((matcher (oref proto :head-reg))) + (if (functionp matcher) + (goto-char (car (funcall matcher -1))) + (re-search-backward matcher nil 'noerr)))) + (let* ((str (or + ;; a. try regexp matcher + (and (oref proto :retriever-regexp) + (re-search-forward (oref proto :retriever-regexp) nil t) + (match-string-no-properties (oref proto :retriever-num))) + ;; b. otherwise function (fixme: these should be merged) + (and (oref proto :retriever-function) + (funcall (oref proto :retriever-function))))) + (mode (pm--get-mode-symbol-from-name str 'no-fallback))) + (if mode + ;; Inferred body MODE serves as ID; this not need be the + ;; case in the future and a generic id getter might replace + ;; it. Currently head/tail/body indirect buffers are shared + ;; across chunkmodes. This currently works ok. A more + ;; general approach would be to track head/tails/body with + ;; associated chunks. Then for example r hbt-chunk and elisp + ;; hbt-chunk will not share head/tail buffers. There could + ;; be even two r hbt-chunks with providing different + ;; functionality and thus not even sharing body buffer. + (let ((name (concat (object-name-string proto) ":" (symbol-name mode)))) + (or + ;; a. loop through installed inner modes + (loop for obj in (oref config -auto-innermodes) + when (equal name (object-name-string obj)) + return obj) + ;; b. create new + (let ((innermode (clone proto name :mode mode))) + (object-add-to-list config '-auto-innermodes innermode) + innermode))) + ;; else, use hostmode + (oref pm/polymode -hostmode))))))) + + +;;; SPAN MANIPULATION + +(defgeneric pm-get-span (chunkmode &optional pos) + "Ask the CHUNKMODE for the span at point. +Return a list of three elements (TYPE BEG END OBJECT) where TYPE +is a symbol representing the type of the span surrounding +POS (head, tail, body). BEG and END are the coordinates of the +span. OBJECT is a sutable object which is 'responsable' for this +span. This is an object that could be dispached upon with +`pm-select-buffer', .. (fixme: complete this list). + +Should return nil if there is no SUBMODE specific span around POS.") + +(defmethod pm-get-span (chunkmode &optional pos) + "Return nil. +Base mode usually do not compute the span." + (unless chunkmode + (error "Dispatching `pm-get-span' on a nil object")) + nil) + +(defmethod pm-get-span ((config pm-polymode) &optional pos) + "Apply pm-get-span on every element of chunkmodes slot of config object. +Return a cons (chunkmode . span), for which START is closest to +POS (and before it); i.e. the innermost span. POS defaults to +point." + (save-restriction + (widen) + ;; fixme: host should be last, to take advantage of the chunkmodes computation + (let* ((smodes (cons (oref config -hostmode) + (oref config -innermodes))) + (start (point-min)) + (end (point-max)) + (pos (or pos (point))) + (span (list nil start end nil)) + val) + + (dolist (sm smodes) + (setq val (pm-get-span sm pos)) + (when (and val + (or (> (nth 1 val) start) + (< (nth 2 val) end))) + (if (or (car val) + (null span)) + (setq span val + start (nth 1 val) + end (nth 2 val)) + ;; nil car means outer chunkmode (usually host). And it can be an + ;; intersection of spans returned by 2 different neighbour inner + ;; chunkmodes. See rapport mode for an example + (setq start (max (nth 1 val) + (nth 1 span)) + end (min (nth 2 val) + (nth 2 span))) + (setcar (cdr span) start) + (setcar (cddr span) end)))) + + (unless (and (<= start end) (<= pos end) (>= pos start)) + (error "Bad polymode selection: span:%s pos:%s" + (list start end) pos)) + (when (null (car span)) ; chunkmodes can compute the host span by returning nil + (setcar (last span) (oref config -hostmode))) + span))) + +;; No need for this one so far. Basic method iterates through -innermodes +;; anyhow. +;; (defmethod pm-get-span ((config pm-polymode-multi) &optional pos)) + +(defmethod pm-get-span ((config pm-polymode-multi-auto) &optional pos) + (let ((span-other (call-next-method)) + (proto (symbol-value (oref config :auto-innermode)))) + (if (oref proto :head-reg) + (let ((span (pm--span-at-point (oref proto :head-reg) + (oref proto :tail-reg) + pos))) + (if (and span-other + (or (> (nth 1 span-other) (nth 1 span)) + (< (nth 2 span-other) (nth 2 span)))) + ;; treat intersections with the host mode + (if (car span-other) + span-other ;not host + ;; here, car span should better be nil; no explicit check + (setcar (cdr span-other) (max (nth 1 span-other) (nth 1 span))) + (setcar (cddr span-other) (min (nth 2 span-other) (nth 2 span))) + span-other) + (append span (list config)))) ;fixme: this returns config as last object + span-other))) + +(defmethod pm-get-span ((chunkmode pm-hbtchunkmode) &optional pos) + "Return a list of the form (TYPE POS-START POS-END SELF). +TYPE can be 'body, 'head or 'tail. SELF is just a chunkmode object +in this case." + (with-slots (head-reg tail-reg head-mode tail-mode) chunkmode + (let* ((span (pm--span-at-point head-reg tail-reg pos)) + (type (car span))) + (when (or (and (eq type 'head) (eq head-mode 'host)) + (and (eq type 'tail) (or (eq tail-mode 'host) + (and (null tail-mode) + (eq head-mode 'host))))) + (setcar span nil)) + (append span (list chunkmode))))) + +(defmacro pm-create-indented-block-matchers (name regex) + "Defines 2 functions, each return a list of the start and end points of the +HEAD and TAIL portions of an indented block of interest, via some regex. +You can then use these functions in the defcustom pm-inner modes. + +e.g. +(pm-create-indented-block-matchers 'slim-coffee' \"^[^ ]*\\(.*:? *coffee: *\\)$\") + +creates the functions + +pm-slim-coffee-head-matcher +pm-slim-coffee-tail-matcher + +In the example below, + +The head matcher will match against 'coffee:', returning the positions of the +start and end of 'coffee:' +The tail matcher will return a list (n, n) of the final characters is the block. + + |<----- Uses this indentation to define the left edge of the 'block' + | + |<--->| This region is higlighted by the :head-mode in the block-matchers + | | + | |<----- the head matcher uses this column as the end of the head + | | +----:-----:-------------- example file ----------------------------------------- +1| : : +2| coffee: +3| myCoffeeCode() +4| moreCode -> +5| do things +6| : +7| This is no longer in the block +8| : +----------------:--------------------------------------------------------------- + --->|<----- this region of 0 width is highlighted by the :tail-mode + the 'block' ends after this column on line 5 + + +All the stuff after the -end- of the head and before the start of the tail is +sent to the new mode for syntax highlighting." + (let* ((head-name (intern (format "pm-%s-head-matcher" name))) + (tail-name (intern (format "pm-%s-tail-matcher" name)))) + `(progn + (defun ,head-name (ahead) + (when (re-search-forward ,regex nil t ahead) + (cons (match-beginning 1) (match-end 1)))) + + (defun ,tail-name (ahead) + (save-excursion + ;; (cons (point-max) (point-max))))))) + (goto-char (car (,head-name 1))) + (let* ((block-col (current-indentation)) + (posn (catch 'break + (while (not (eobp)) + (forward-line 1) + (when (and (<= (current-indentation) block-col) + (not (progn + (beginning-of-line) + (looking-at "^[[:space:]]*$")))) + (throw 'break (point-at-bol)))) + (throw 'break (point-max))))) + (cons posn posn))))))) + +(defun pm--default-matcher (reg ahead) + (if (< ahead 0) + (if (re-search-backward reg nil t) + (cons (match-beginning 0) (match-end 0))) + (if (re-search-forward reg nil t) + (cons (match-beginning 0) (match-end 0))))) + +;; fixme: there should be a simpler way... check the code and document +(defun pm--span-at-point-fun-fun (hd-matcher tl-matcher) + (save-excursion + (let ((pos (point)) + (posh (funcall hd-matcher -1))) + (if (null posh) + ;; special first chunk + (let ((posh1 (progn (goto-char (point-min)) + (funcall hd-matcher 1)))) + (if (and posh1 + (<= (car posh1) pos) + (< pos (cdr posh1))) + (list 'head (car posh1) (cdr posh1)) + (list nil (point-min) (or (car posh1) + (point-max))))) + (let ((post (progn (goto-char (car posh)) + (or (funcall tl-matcher 1) + (cons (point-max) (point-max)))))) + (if (and (<= (cdr posh) pos) + (< pos (car post))) + (list 'body (cdr posh) (car post)) + (if (and (<= (car post) pos) + (< pos (cdr post))) + (list 'tail (car post) (cdr post)) + (if (< pos (cdr post)) + ;; might be in the head + (progn + (goto-char (car post)) + (let ((posh1 (funcall hd-matcher -1))) + (if (and (<= (car posh1) pos) + (< pos (cdr posh1))) + (list 'head (car posh1) (cdr posh1)) + (list nil (cdr posh) (car posh1))))) ;; posh is point min, fixme: not true anymore? + (goto-char (cdr post)) + (let ((posh1 (or (funcall hd-matcher 1) + (cons (point-max) (point-max))))) + (if (and posh + (<= (car posh1) pos ) + (< pos (cdr posh1))) + (list 'head (car posh1) (cdr posh1)) + (list nil (cdr post) (car posh1)))))))))))) + +(defun pm--span-at-point-reg-reg (head-matcher tail-matcher) + ;; Guaranteed to produce non-0 length spans. If no span has been found + ;; (head-matcher didn't match) return (nil (point-min) (point-max)). + + ;; xxx1 relate to the first ascending search + ;; xxx2 relate to the second descending search + (save-excursion + (let* ((pos (point)) + + (head1-beg (and (re-search-backward head-matcher nil t) + (match-beginning 0))) + (head1-end (and head1-beg (match-end 0)))) + + (if head1-end + ;; we know that (>= pos head1-end) + ;; ----------------------- + ;; host](head)[body](tail)[host](head) + (let* ((tail1-beg (and (goto-char head1-end) + (re-search-forward tail-matcher nil t) + (match-beginning 0))) + (tail1-end (and tail1-beg (match-end 0))) + (tail1-beg (or tail1-beg (point-max))) + (tail1-end (or tail1-end (point-max)))) + + (if (or (< pos tail1-end) + (= tail1-end (point-max))) + (if (<= pos tail1-beg) + ;; ------ + ;; host](head)[body](tail)[host](head)) + (list 'body head1-end tail1-beg) + ;; ----- + ;; host](head](body](tail)[host](head) + (list 'tail tail1-beg tail1-end)) + + ;; ------------ + ;; host](head](body](tail)[host](head) + (let* ((head2-beg (or (and (re-search-forward head-matcher nil t) + (match-beginning 0)) + (point-max)))) + (if (<= pos head2-beg) + ;; ------ + ;; host](head](body](tail)[host](head) + (list nil tail1-end head2-beg) + ;; ------ + ;; host](head](body](tail)[host](head) + (list 'head head2-beg (match-end 0)))))) + + ;; ----------- + ;; host](head)[body](tail)[host + (let ((head2-beg (and (goto-char (point-min)) + (re-search-forward head-matcher nil t) + (match-beginning 0)))) + + (if (null head2-beg) + ;; no span found + (list nil (point-min) (point-max)) + + (if (<= pos head2-beg) + ;; ----- + ;; host](head)[body](tail)[host + (list nil (point-min) head2-beg) + ;; ------ + ;; host](head)[body](tail)[host + (list 'head head2-beg (match-end 0))))))))) + +(defun pm--span-at-point (head-matcher tail-matcher &optional pos) + "Basic span detector with head/tail. + +Either of HEAD-MATCHER and TAIL-MATCHER can be a regexp or a +function. When a function the matcher must accept one argument +that can take either values 1 (forwards search) or -1 (backward +search). This function must return either nil (no match) or +a (cons BEG END) representing the span of the head or tail +respectively. See `pm--default-matcher' for an example. + +Return (type span-start span-end) where type is one of the +follwoing symbols: + +nil - pos is between point-min and head-reg, or between tail-reg and point-max +body - pos is between head-reg and tail-reg (exclusively) +head - head span +tail - tail span" + ;; ! start of the span is part of the span ! + (save-restriction + (widen) + (goto-char (or pos (point))) + (cond ((and (stringp head-matcher) + (stringp tail-matcher)) + (pm--span-at-point-reg-reg head-matcher tail-matcher)) + ((and (stringp head-matcher) + (functionp tail-matcher)) + (pm--span-at-point-fun-fun + (lambda (ahead) (pm--default-matcher head-matcher ahead)) + tail-matcher)) + ((and (functionp head-matcher) + (stringp tail-matcher)) + (pm--span-at-point-fun-fun + head-matcher + (lambda (ahead) (pm--default-matcher tail-matcher ahead)))) + ((and (functionp head-matcher) + (functionp tail-matcher)) + (pm--span-at-point-fun-fun head-matcher tail-matcher)) + (t (error "head and tail matchers should be either regexp strings or functions"))))) + + +;;; INDENT +(defun pm-indent-line-dispatcher () + "Dispatch methods indent methods on current span." + (let ((span (pm-get-innermost-span)) + (inhibit-read-only t)) + (pm-indent-line (car (last span)) span))) + +(defgeneric pm-indent-line (&optional chunkmode span) + "Indent current line. +Protect and call original indentation function associated with +the chunkmode.") + +(defun pm--indent-line (span) + (let (point) + (save-current-buffer + (pm-set-buffer span) + (pm-with-narrowed-to-span span + (funcall pm--indent-line-function-original) + (setq point (point)))) + (goto-char point))) + +(defmethod pm-indent-line ((chunkmode pm-chunkmode) &optional span) + (pm--indent-line span)) + +(defmethod pm-indent-line ((chunkmode pm-hbtchunkmode) &optional span) + "Indent line in inner chunkmodes. +When point is at the beginning of head or tail, use parent chunk +to indent." + (let ((pos (point)) + (span (or span (pm-get-innermost-span))) + delta) + (unwind-protect + (cond + + ;; 1. in head or tail (we assume head or tail fit in one line for now) + ((or (eq 'head (car span)) + (eq 'tail (car span))) + (goto-char (nth 1 span)) + (setq delta (- pos (point))) + (when (not (bobp)) + (let ((prev-span (pm-get-innermost-span (1- pos)))) + (if (and (eq 'tail (car span)) + (eq (point) (save-excursion (back-to-indentation) (point)))) + ;; if tail is first on the line, indent as head + (indent-to (pm--head-indent prev-span)) + (pm--indent-line prev-span))))) + + ;; 2. body + (t + (back-to-indentation) + (if (> (nth 1 span) (point)) + ;; first body line in the same line with header (re-indent at indentation) + (pm-indent-line-dispatcher) + (setq delta (- pos (point))) + (pm--indent-line span) + (let ((fl-indent (pm--first-line-indent span))) + (if fl-indent + (when (bolp) + ;; Not first line. Indent only when original indent is at + ;; 0. Otherwise it's a continuation indentation and we assume + ;; the original function did it correctly with respect to + ;; previous lines. + (indent-to fl-indent)) + ;; First line. Indent with respect to header line. + (indent-to + (+ (- (point) (point-at-bol)) ;; non-0 if code in header line + (pm--head-indent span) ;; indent with respect to header line + (oref chunkmode :indent-offset)))))))) + ;; keep point on same characters + (when (and delta (> delta 0)) + (goto-char (+ (point) delta)))))) + +(defun pm--first-line-indent (&optional span) + (save-excursion + (let ((pos (point))) + (goto-char (nth 1 (or span (pm-get-innermost-span)))) + (goto-char (point-at-eol)) + (skip-chars-forward " \t\n") + (let ((indent (- (point) (point-at-bol)))) + (when (< (point-at-eol) pos) + indent))))) + +(defun pm--head-indent (&optional span) + (save-excursion + (goto-char (nth 1 (or span (pm-get-innermost-span)))) + (back-to-indentation) + (- (point) (point-at-bol)))) + +(defmethod pm-indent-line ((config pm-polymode-multi-auto) &optional span) + ;; fixme: pm-polymode-multi-auto is not a chunk, pm-get-innermost-span should + ;; not return it in the first place + ;; (pm-set-buffer span) + ;; (pm-indent-line pm/chunkmode span)) + (pm-indent-line (pm--get-multi-chunk config span) span)) + + +;;; FACES +(defgeneric pm-get-adjust-face (chunkmode &optional type)) +(defmethod pm-get-adjust-face ((chunkmode pm-chunkmode) &optional type) + (oref chunkmode :adjust-face)) +(defmethod pm-get-adjust-face ((chunkmode pm-hbtchunkmode) &optional type) + (setq type (or type pm/type)) + (cond ((eq type 'head) + (oref chunkmode :head-adjust-face)) + ((eq type 'tail) + (if (eq 'head (oref pm/chunkmode :tail-adjust-face)) + (oref pm/chunkmode :head-adjust-face) + (oref pm/chunkmode :tail-adjust-face))) + (t (oref pm/chunkmode :adjust-face)))) + +(defun pm--get-adjusted-background (prop) + ;; if > lighten on dark backgroun. Oposite on light. + (color-lighten-name (face-background 'default) + (if (eq (frame-parameter nil 'background-mode) 'light) + (- prop) ;; darken + prop))) + +(defun pm--adjust-chunk-face (beg end face) + ;; propertize 'face of the region by adding chunk specific configuration + (interactive "r") + (when face + (with-current-buffer (current-buffer) + (let ((face (or (and (numberp face) + (list (cons 'background-color + (pm--get-adjusted-background face)))) + face)) + (pchange nil)) + ;; (while (not (eq pchange end)) + ;; (setq pchange (next-single-property-change beg 'face nil end)) + ;; (put-text-property beg pchange 'face + ;; `(,face ,@(get-text-property beg 'face))) + ;; (setq beg pchange)) + (font-lock-prepend-text-property beg end 'face face))))) + +(provide 'polymode-methods) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-tangle.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-tangle.el new file mode 100644 index 0000000..c9b1b71 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-tangle.el @@ -0,0 +1,3 @@ +(defgroup polymode-tangle nil + "Polymode Tanglers" + :group 'polymode) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode-weave.el b/layers.personal/misctools/my-polymode/local/polymode/polymode-weave.el new file mode 100644 index 0000000..9140a63 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode-weave.el @@ -0,0 +1,252 @@ +;; -*- lexical-binding: t -*- +(require 'polymode-core) +(require 'polymode-classes) + +(defgroup polymode-weave nil + "Polymode Weavers" + :group 'polymode) + +(defcustom polymode-weave-output-file-format "%s[woven]" + "Format of the weaved files. +%s is substituted with the current file name sans extension." + :group 'polymode-weave + :type 'string) + +(defclass pm-weaver (pm-root) + ((from-to + :initarg :from-to + :initform '() + :type list + :custom list + :documentation + "Input-output specifications. An alist with elements of the + form (id reg-from ext-to doc command) or (id . selector). + + In both cases ID is the unique identifier of the spec. In + the former case REG-FROM is a regexp used to identify if + current file can be weaved with the spec. EXT-TO is the + extension of the output file. DOC is a short help string + used for interactive completion and messages. COMMAND is a + weaver specific specific command. It can contain the + following format specs: + + %i - input file (no dir) + %I - input file (full path) + %o - output file (no dir) + %O - output file (full path) + %b - output file (base name only) + %t - 4th element of the :to spec + + When specification is of the form (id . selector), SELECTOR + is a function of variable arguments that accepts at least + one argument ACTION. This function is called in a buffer + visiting input file. ACTION is a symbol and can one of the + following: + + match - must return non-nil if this specification + applies to the file that current buffer is visiting, + or :nomatch if specification does not apply. + + regexp - return a string which is used to match input + file name. If nil, `match' selector must return + non-nil value. This selector is ignored if `match' + returned non-nil. + + output-file - return an output file name or a list of + file names. Receives input-file as argument. If this + command returns nil, the output is built from the + input file name and value of 'output-ext command. + + This selector can also return a function. This + function will be called in the callback or sentinel of + the weaving process after the weaving was + completed. This function should sniff the output of + the process for errors or file names. It must return a + file name, a list of file names or nil if no such + files have been detected. + + ext - extension of output file. If nil and + `output' also returned nil, the exporter won't be able + to identify the output file and no automatic display + or preview will be available. + + doc - return documentation string + + command - return a string to be used instead of + the :from command. If nil, :from spec command is used.") + (function + :initarg :function + :initform (lambda (command id) + (error "No weaving function declared for this weaver")) + :type (or symbol function) + :documentation + "Function to perform the weaving. Must take 2 arguments + COMMAND and ID. COMMAND is the 5th argument of :from-to spec + with all the formats substituted. ID is the id the + corresponding element in :from-to spec. + + If this function returns a filename that file will be + displayed to the user.")) + "Root weaver class.") + +(defclass pm-callback-weaver (pm-weaver) + ((callback + :initarg :callback + :initform (lambda (&optional rest) + (error "No callback defined for this weaver.")) + :type (or symbol function) + :documentation + "Callback function to be called by :function. There is no + default callback. Callbacks must return the output file.")) + "Class to represent weavers that call processes spanned by + Emacs.") + +(defclass pm-shell-weaver (pm-weaver) + ((function + :initform 'pm-default-shell-weave-function) + (sentinel + :initarg :sentinel + :initform 'pm-default-shell-weave-sentinel + :type (or symbol function) + :documentation + "Sentinel function to be called by :function when a shell + call is involved. Sentinel must return the output file + name.") + (quote + :initarg :quote + :initform nil + :type boolean + :documentation "Non-nil when file arguments must be quoted + with `shell-quote-argument'.")) + "Class for weavers that call external processes.") + +(defun pm-default-shell-weave-function (command sentinel from-to-id &rest args) + "Run weaving command interactively. +Run command in a buffer (in comint-shell-mode) so that it accepts +user interaction. This is a default function in all weavers +that call a shell command" + (pm--run-shell-command command sentinel "*polymode weave*" + (concat "weaving " from-to-id " with command:\n\n " + command "\n\n"))) + + +;;; METHODS + +(declare-function pm-export "polymode-export") + +(defgeneric pm-weave (weaver from-to-id &optional ifile) + "Weave current FILE with WEAVER. +WEAVER is an object of class `pm-weaver'. EXPORT is a list of the +form (FROM TO) suitable to be passed to `polymode-export'. If +EXPORT is provided, corresponding exporter's (from to) +specification will be called.") + +(defmethod pm-weave ((weaver pm-weaver) from-to-id &optional ifile) + (pm--weave-internal weaver from-to-id ifile)) + +(defmethod pm-weave ((weaver pm-callback-weaver) fromto-id &optional ifile) + (let ((cb (pm--wrap-callback weaver :callback ifile)) + ;; with transitory output, callback might not run + (pm--export-spec (and pm--output-not-real pm--export-spec))) + (pm--process-internal weaver fromto-id nil ifile cb))) + +(defmethod pm-weave ((weaver pm-shell-weaver) fromto-id &optional ifile) + (let ((cb (pm--wrap-callback weaver :sentinel ifile)) + ;; with transitory output, callback might not run + (pm--export-spec (and pm--output-not-real pm--export-spec))) + (pm--process-internal weaver fromto-id nil ifile cb (oref weaver :quote)))) + + +;; UI + +(defvar pm--weaver-hist nil) +(defvar pm--weave:fromto-hist nil) +(defvar pm--weave:fromto-last nil) + +(defun polymode-weave (&optional from-to) + "Weave current file. +First time this command is called in a buffer the user is asked +for the weaver to use from a list of known weavers. + +FROM-TO is the id of the specification declared in :from-to slot +of the current weaver. If the weaver hasn't been set yet, set the +weaver with `polymode-set-weaver'. You can always change the +weaver manually by invoking `polymode-set-weaver'. + +If `from-to' dismissing detect automatically based on current +weaver :from-to specifications. If this detection is ambiguous +ask the user. + +When `from-to' is universal argument ask user for specification +for the specification. See also `pm-weaveer' for the complete +specification." + (interactive "P") + (cl-flet ((name.id (el) (cons (funcall (cdr el) 'doc) (car el)))) + (let* ((weaver (symbol-value (or (oref pm/polymode :weaver) + (polymode-set-weaver)))) + (fname (file-name-nondirectory buffer-file-name)) + (case-fold-search t) + + (opts (mapcar #'name.id (pm--selectors weaver :from-to))) + (ft-id + (cond + ;; A. guess from-to spec + ((null from-to) + (or + ;; 1. repeated weaving; don't ask + pm--weave:fromto-last + + ;; 2. select :from entries which match to current file + (let ((matched (cl-loop for el in (pm--selectors weaver :from-to) + when (pm--selector-match (cdr el)) + collect (name.id el)))) + (when matched + (if (> (length matched) 1) + (cdr (pm--completing-read "Multiple `from-to' specs matched. Choose one: " matched)) + (cdar matched)))) + + ;; 3. nothing matched, ask + (let* ((prompt (format "No `from-to' specs matched. Choose one: " + (file-name-extension fname) (eieio-object-name weaver))) + (sel (pm--completing-read prompt opts nil t nil 'pm--weave:fromto-hist))) + (cdr sel)))) + + ;; B. C-u, force a :from-to spec + ((equal from-to '(4)) + (cdr (if (> (length opts) 1) + (pm--completing-read "Weaver type: " opts nil t nil 'pm--weave:fromto-hist) + (car opts)))) + ;; C. string + ((stringp from-to) + (if (assoc from-to (oref weaver :from-to)) + from-to + (error "Cannot find `from-to' spec '%s' in %s weaver" + from-to (eieio-object-name weaver)))) + (t (error "'from-to' argument must be nil, universal argument or a string"))))) + + (setq-local pm--weave:fromto-last ft-id) + (pm-weave weaver ft-id)))) + +(defmacro polymode-register-weaver (weaver defaultp &rest configs) + "Add WEAVER to :weavers slot of all config objects in CONFIGS. +When DEFAULT? is non-nil, also make weaver the default WEAVER for +each polymode in CONFIGS." + `(dolist (pm ',configs) + (object-add-to-list (symbol-value pm) :weavers ',weaver) + (when ,defaultp (oset (symbol-value pm) :weaver ',weaver)))) + +(defun polymode-set-weaver () + (interactive) + (unless pm/polymode + (error "No pm/polymode object found. Not in polymode buffer?")) + (let* ((weavers (pm--abrev-names + (delete-dups (pm--oref-with-parents pm/polymode :weavers)) + "pm-weaver/")) + (sel (pm--completing-read "Choose weaver: " weavers nil t nil 'pm--weaver-hist)) + (out (intern (cdr sel)))) + (setq-local pm--weaver:from-last nil) + (setq-local pm--weaver:to-last nil) + (oset pm/polymode :weaver out) + out)) + +(provide 'polymode-weave) diff --git a/layers.personal/misctools/my-polymode/local/polymode/polymode.el b/layers.personal/misctools/my-polymode/local/polymode/polymode.el new file mode 100644 index 0000000..64823a3 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/polymode.el @@ -0,0 +1,449 @@ +;;; polymode.el --- Versatile multiple modes with extensive literate programming support +;; +;; Filename: polymode.el +;; Author: Spinu Vitalie +;; Maintainer: Spinu Vitalie +;; Copyright (C) 2013-2014, Spinu Vitalie, all rights reserved. +;; Version: 1.0 +;; Package-Requires: ((emacs "24")) +;; URL: https://github.com/vitoshka/polymode + ;; Keywords: emacs +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Extensible, fast, objected-oriented multimode specifically designed for +;; literate programming. Extensible support for weaving, tangling and export. +;; +;; Usage: https://github.com/vspinu/polymode +;; +;; Design new polymodes: https://github.com/vspinu/polymode/tree/master/modes +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(require 'polymode-core) +(require 'polymode-classes) +(require 'polymode-methods) +(require 'polymode-compat) +(require 'polymode-debug) +(require 'polymode-export) +(require 'polymode-weave) +(require 'poly-lock) +(require 'poly-base) + +(defcustom polymode-prefix-key "\M-n" + "Prefix key for the polymode mode keymap. +Not effective after loading the polymode library." + :group 'polymode + :type '(choice string vector)) + +(defvar polymode-mode-map + (let ((map (make-sparse-keymap))) + (define-key map polymode-prefix-key + (let ((map (make-sparse-keymap))) + ;; navigation + (define-key map "\C-n" 'polymode-next-chunk) + (define-key map "\C-p" 'polymode-previous-chunk) + (define-key map "\C-\M-n" 'polymode-next-chunk-same-type) + (define-key map "\C-\M-p" 'polymode-previous-chunk-same-type) + ;; chunk manipulation + (define-key map "\M-k" 'polymode-kill-chunk) + (define-key map "\M-m" 'polymode-mark-or-extend-chunk) + (define-key map "\C-t" 'polymode-toggle-chunk-narrowing) + (define-key map "\M-i" 'polymode-insert-new-chunk) + ;; backends + (define-key map "e" 'polymode-export) + (define-key map "E" 'polymode-set-exporter) + (define-key map "w" 'polymode-weave) + (define-key map "W" 'polymode-set-weaver) + (define-key map "t" 'polymode-tangle) + (define-key map "T" 'polymode-set-tangler) + (define-key map "$" 'polymode-show-process-buffer) + ;; todo: add polymode-goto-process-buffer + map)) + (define-key map [menu-bar Polymode] + (cons "Polymode" + (let ((map (make-sparse-keymap "Polymode"))) + (define-key-after map [next] + '(menu-item "Next chunk" polymode-next-chunk)) + (define-key-after map [previous] + '(menu-item "Previous chunk" polymode-previous-chunk)) + (define-key-after map [next-same] + '(menu-item "Next chunk same type" polymode-next-chunk-same-type)) + (define-key-after map [previous-same] + '(menu-item "Previous chunk same type" polymode-previous-chunk-same-type)) + (define-key-after map [mark] + '(menu-item "Mark or extend chunk" polymode-mark-or-extend-chunk)) + (define-key-after map [kill] + '(menu-item "Kill chunk" polymode-kill-chunk)) + (define-key-after map [insert] + '(menu-item "Insert new chunk" polymode-insert-new-chunk)) + map))) + map) + "The default minor mode keymap that is active in all polymode + modes.") + + +;;; COMMANDS +(defvar *span*) +(defun polymode-next-chunk (&optional N) + "Go COUNT chunks forwards. +Return, how many chucks actually jumped over." + (interactive "p") + (let* ((sofar 0) + (back (< N 0)) + (beg (if back (point-min) (point))) + (end (if back (point) (point-max))) + (N (if back (- N) N))) + (condition-case nil + (pm-map-over-spans + (lambda () + (unless (memq (car *span*) '(head tail)) + (when (>= sofar N) + (signal 'quit nil)) + (setq sofar (1+ sofar)))) + beg end nil back) + (quit (when (looking-at "\\s *$") + (forward-line))) + (pm-switch-to-buffer)) + sofar)) + +;;fixme: problme with long chunks .. point is recentered +;;todo: merge into next-chunk +(defun polymode-previous-chunk (&optional N) + "Go COUNT chunks backwards . +Return, how many chucks actually jumped over." + (interactive "p") + (polymode-next-chunk (- N))) + +(defun polymode-next-chunk-same-type (&optional N) + "Go to next COUNT chunk. +Return, how many chucks actually jumped over." + (interactive "p") + (let* ((sofar 0) + (back (< N 0)) + (beg (if back (point-min) (point))) + (end (if back (point) (point-max))) + (N (if back (- N) N)) + this-type this-class) + (condition-case nil + (pm-map-over-spans + (lambda () + (unless (memq (car *span*) '(head tail)) + (when (and (equal this-class + (eieio-object-name (car (last *span*)))) + (eq this-type (car *span*))) + (setq sofar (1+ sofar))) + (unless this-class + (setq this-class (eieio-object-name (car (last *span*))) + this-type (car *span*))) + (when (>= sofar N) + (signal 'quit nil)))) + beg end nil back) + (quit (when (looking-at "\\s *$") + (forward-line))) + (pm-switch-to-buffer)) + sofar)) + +(defun polymode-previous-chunk-same-type (&optional N) + "Go to previus COUNT chunk. +Return, how many chucks actually jumped over." + (interactive "p") + (polymode-next-chunk-same-type (- N))) + +(defun pm--kill-span (types) + (let ((span (pm-get-innermost-span))) + (when (memq (car span) types) + (delete-region (nth 1 span) (nth 2 span))))) + +(defun polymode-kill-chunk () + "Kill current chunk" + (interactive) + (pcase (pm-get-innermost-span) + (`(,(or `nil `host) ,beg ,end ,_) (delete-region beg end)) + (`(body ,beg ,end ,_) + (goto-char beg) + (pm--kill-span '(body)) + (pm--kill-span '(head tail)) + (pm--kill-span '(head tail))) + (`(tail ,beg ,end ,_) + (if (eq beg (point-min)) + (delete-region beg end) + (goto-char (1- beg)) + (polymode-kill-chunk))) + (`(head ,_ ,end ,_) + (goto-char end) + (polymode-kill-chunk)) + (_ (error "canoot find chunk to kill")))) + +(defun polymode-toggle-chunk-narrowing () + "Toggle narrowing of the current chunk." + (interactive) + (if (buffer-narrowed-p) + (progn (widen) (recenter)) + (pcase (pm-get-innermost-span) + (`(head ,_ ,end ,_) + (goto-char end) + (pm-narrow-to-span)) + (`(tail ,beg ,end ,_) + (if (eq beg (point-min)) + (error "Invalid chunk") + (goto-char (1- beg)) + (pm-narrow-to-span))) + (_ (pm-narrow-to-span))))) + + +(defun polymode-mark-or-extend-chunk () + (interactive) + (error "Not implemented yet")) + +(defun polymode-insert-new-chunk () + (interactive) + (error "Not implemented yet")) + +(defun polymode-show-process-buffer () + (interactive) + (let ((buf (cl-loop for b being the buffers + if (buffer-local-value 'pm--process-buffer b) + return b))) + (if buf + (pop-to-buffer buf `(nil . ((inhibit-same-window . ,pop-up-windows)))) + (message "No polymode process buffers found.")))) + + +;;; HOOKS +;; In addition to these hooks there is poly-lock-after-change which is placed in +;; after-change-functions. See poly-lock.el + +(defun polymode-post-command-select-buffer () + "Select the appropriate (indirect) buffer corresponding to point's context. +This funciton is placed in local `post-command-hook'." + (when (and pm-allow-post-command-hook + polymode-mode + pm/chunkmode) + (condition-case err + (pm-switch-to-buffer) + (error (message "(pm-switch-to-buffer %s): %s" + (point) (error-message-string err)))))) + +(defun polymode-before-change-setup (beg end) + "Run `syntax-ppss-flush-cache' in all polymode buffers. +This function is placed in `before-change-functions' hook." + ;; Modification hooks are run only in current buffer and not in other (base or + ;; indirect) buffers. Thus some actions like flush of ppss cache must be taken + ;; care explicitly. We run some safety hooks checks here as well. + (dolist (buff (oref pm/polymode -buffers)) + ;; The following two checks are unnecessary by poly-lock design, but we are + ;; checking them here, just in case. + ;; VS[06-03-2016]: `fontification-functions' probably should be checked as well. + (when (memq 'font-lock-after-change-function after-change-functions) + (remove-hook 'after-change-functions 'font-lock-after-change-function t)) + (when (memq 'jit-lock-after-change after-change-functions) + (remove-hook 'after-change-functions 'jit-lock-after-change t)) + + (with-current-buffer buff + ;; now `syntax-ppss-flush-cache is harmless, but who knows in the future. + (when (memq 'syntax-ppss-flush-cache before-change-functions) + (remove-hook 'before-change-functions 'syntax-ppss-flush-cache t)) + (syntax-ppss-flush-cache beg end)))) + + +;;; DEFINE +;;;###autoload +(defmacro define-polymode (mode config &optional keymap &rest body) + "Define a new polymode MODE. +This macro defines command MODE and an indicator variable MODE +which becomes t when MODE is active and nil otherwise. + +MODE command is similar to standard emacs major modes and it can +be used in `auto-mode-alist'. Standard hook MODE-hook is run at +the end of the initialization of each polymode buffer (both +indirect and base buffers). Additionally MODE-map is created +based on the CONFIG's :map slot and the value of the :keymap +argument; see below. + +CONFIG is a name of a config object representing the mode. + +MODE command can also be use as a minor mode. Current major mode +is not reinitialized if it coincides with the :mode slot of +CONFIG object or if the :mode slot is nil. + +BODY contains code to be executed after the complete + initialization of the polymode (`pm-initialize') and before + running MODE-hook. Before the BODY code, you can write keyword + arguments, i.e. alternating keywords and values. The following + special keywords are supported: + +:lighter SPEC Optional LIGHTER is displayed in the mode line when + the mode is on. If omitted, it defaults to + the :lighter slot of CONFIG object. + +:keymap MAP Same as the KEYMAP argument. + + If nil, a new MODE-map keymap is created what + directly inherits from the keymap defined by + the :map slot of CONFIG object. In most cases it + is a simple map inheriting form + `polymode-mode-map'. If t or an alist (of + bindings suitable to be passed to + `easy-mmode-define-keymap') a keymap MODE-MAP is + build by mergin this alist with the :map + specification of the CONFIG object. If a symbol, + it should be a variable whose value is a + keymap. No MODE-MAP is automatically created in + the latter case and :map slot of the CONFIG + object is ignored. + +:after-hook A single lisp form which is evaluated after the mode hooks + have been run. It should not be quoted." + (declare + (debug (&define name name + [&optional [¬ keywordp] sexp] + [&rest [keywordp sexp]] + def-body))) + + + (when (keywordp keymap) + (push keymap body) + (setq keymap nil)) + + (let* ((last-message (make-symbol "last-message")) + (mode-name (symbol-name mode)) + (pretty-name (concat + (replace-regexp-in-string "poly-\\|-mode" "" mode-name) + " polymode")) + (keymap-sym (intern (concat mode-name "-map"))) + (hook (intern (concat mode-name "-hook"))) + (extra-keywords nil) + (after-hook nil) + keyw lighter) + + ;; Check keys. + (while (keywordp (setq keyw (car body))) + (setq body (cdr body)) + (pcase keyw + (`:lighter (setq lighter (purecopy (pop body)))) + (`:keymap (setq keymap (pop body))) + (`:after-hook (setq after-hook (pop body))) + (_ (push keyw extra-keywords) (push (pop body) extra-keywords)))) + + `(progn + :autoload-end + + ;; Define the variable to enable or disable the mode. + (defvar ,mode nil ,(format "Non-nil if %s mode is enabled." pretty-name)) + (make-variable-buffer-local ',mode) + + (let* ((keymap ,keymap) + (config ',config) + (lighter (or ,lighter + (oref (symbol-value config) :lighter))) + key-alist) + + (unless (keymapp keymap) + ;; keymap is either nil or list. Iterate through parents' :map slot + ;; and gather keys. + (setq key-alist keymap) + (let* ((pi (symbol-value config)) + map mm-name) + (while pi + (setq map (and (slot-boundp pi :map) + (oref pi :map))) + (if (and (symbolp map) + (keymapp (symbol-value map))) + ;; If one of the parent's :map is a keymap, use it as our + ;; keymap and stop further descent. + (setq keymap (symbol-value map) + pi nil) + ;; Descend to next parent and append the key list to key-alist + (setq pi (and (slot-boundp pi :parent-instance) + (oref pi :parent-instance)) + key-alist (append key-alist map)))))) + + (unless keymap + ;; If we couldn't figure out the original keymap: + (setq keymap polymode-mode-map)) + + ;; Define the minor-mode keymap: + (defvar ,keymap-sym + (easy-mmode-define-keymap key-alist nil nil `(:inherit ,keymap)) + ,(format "Keymap for %s." pretty-name)) + + ;; The actual mode function: + (defun ,mode (&optional arg) ,(format "%s.\n\n\\{%s}" pretty-name keymap-sym) + (interactive) + (unless ,mode + (let ((,last-message (current-message))) + (unless pm/polymode ;; don't reinstall for time being + (let ((config (clone ,config))) + (oset config :minor-mode ',mode) + (pm-initialize config))) + ;; set our "minor" mode + (setq ,mode t) + ,@body + (run-hooks ',hook) + ;; Avoid overwriting a message shown by the body, + ;; but do overwrite previous messages. + (when (and (called-interactively-p 'any) + (or (null (current-message)) + (not (equal ,last-message + (current-message))))) + (message ,(format "%s enabled" pretty-name))) + ,@(when after-hook `(,after-hook)) + (force-mode-line-update))) + ;; Return the new setting. + ,mode) + + (add-minor-mode ',mode lighter ,keymap-sym))))) + +(define-minor-mode polymode-minor-mode + "Polymode minor mode, used to make everything work." + nil " PM" polymode-mode-map) + +(define-derived-mode poly-head-tail-mode prog-mode "HeadTail" + "Default major mode for polymode head and tail spans.") + +(define-derived-mode poly-fallback-mode prog-mode "FallBack" + ;; fixme: + ;; 1. doesn't work as fallback for hostmode + ;; 2. highlighting is lost (Rnw with inner fallback) + "Default major mode for modes which were not found. +This is better than fundamental-mode because it allows running +globalized minor modes and can run user hooks.") + + + +;;; FONT-LOCK +;; indulge elisp font-lock :) +(dolist (mode '(emacs-lisp-mode lisp-interaction-mode)) + (font-lock-add-keywords + mode + '(("(\\(define-polymode\\)\\s +\\(\\(\\w\\|\\s_\\)+\\)" + (1 font-lock-keyword-face) + (2 font-lock-variable-name-face))))) + + +(provide 'polymode) +;;; polymode.el ends here diff --git a/layers.personal/misctools/my-polymode/local/polymode/readme.md b/layers.personal/misctools/my-polymode/local/polymode/readme.md new file mode 100644 index 0000000..25f8e04 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/readme.md @@ -0,0 +1,164 @@ +[![unstable](http://badges.github.io/stability-badges/dist/unstable.svg)](http://github.com/badges/stability-badges) + +## Overview + +Polymode is an emacs package that offers generic support for multiple major +modes inside a single emacs buffer. It is lightweight, object oriented and +highly extensible. Creating new polymodes typically takes a +[few](modes#multiple-automatically-detected-innermodes) lines of code. + +Polymode also provides extensible facilities for external literate programming +tools for exporting, weaving and tangling. + +- [Installation](#installation) +- [Polymodes Activation](#activation-of-polymodes) +- [Basic Usage](#basic-usage) +- [Warnings](#warnings) +- [Development](modes) +- [Screenshots](#screenshots) + +## Installation + +*Note: Oldest supported Emacs version is 24.4* + +### From [MELPA](https://github.com/milkypostman/melpa) + +M-x `package-install` `polymode`. + +### Manually + +```sh +git clone https://github.com/vitoshka/polymode.git +``` + +Add "polymode" directory and "polymode/modes" to your emacs path: + +```lisp +(setq load-path + (append '("path/to/polymode/" "path/to/polymode/modes") + load-path)) +``` + +Require any polymode bundles that you are interested in. For example: + +```lisp +(require 'poly-R) +(require 'poly-markdown) +``` + +## Activation of Polymodes + +Polymodes are functions, just like ordinary emacs modes. The can be used in +place of emacs major or minor modes alike. There are two main ways to +automatically activate emacs (poly)modes: + + 1. _By registering a file extension by adding modes to `auto-mode-alist`_: + + ```lisp + ;;; MARKDOWN + (add-to-list 'auto-mode-alist '("\\.md" . poly-markdown-mode)) + + ;;; R modes + (add-to-list 'auto-mode-alist '("\\.Snw" . poly-noweb+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rnw" . poly-noweb+r-mode)) + (add-to-list 'auto-mode-alist '("\\.Rmd" . poly-markdown+r-mode)) + ``` + See [polymode-configuration.el](polymode-configuration.el) for more + examples. + + 2. _By setting local mode variable in you file_: + + ```c++ + // -*- mode: poly-C++R -*- + ``` + or + + ```sh + ## -*- mode: poly-brew+R; -*- + ``` + +## Basic Usage + +All polymode keys start with the prefix defined by `polymode-prefix-key`, +default is M-n. The `polymode-mode-map` is the parent of all +polymodes' maps: + +* BACKENDS + + e `polymode-export` + + E `polymode-set-exporter` + + w `polymode-weave` + + W `polymode-set-weaver` + + t `polymode-tangle` ;; not implemented yet + + T `polymode-set-tangler` ;; not implemented yet + + $ `polymode-show-process-buffer` + +* NAVIGATION + + C-n `polymode-next-chunk` + + C-p `polymode-previous-chunk` + + C-M-n `polymode-next-chunk-same-type` + + C-M-p `polymode-previous-chunk-same-type` + +* MANIPULATION + + M-k `polymode-kill-chunk` + + M-m `polymode-mark-or-extend-chunk` + + C-t `polymode-toggle-chunk-narrowing` + + M-i `polymode-insert-new-chunk` + + +## Warnings + + * Tested with Emacs 24.3.1 and 24.4.5. + +Some things still don't work as expected. For example: + + * To kill a polymode buffer you will have position the cursor in the host + mode buffer. + * Customization interface is not working as expected (an eieio bug) and is + not even tested. + * Indentation and font-lock is not always right and requires some more + tweaking. This is especially true for complex modes like `c-mode`. + +## Developing with Polymode + +For the relevant terminology and development info see these [docs](modes). + +## Screenshots + +### slim + + + +### markdown+R + + + +### markdown+R+YAML + + + +### org mode + + + +### Ess-help buffer + + + +### C++R + + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/ANOVA.rapport b/layers.personal/misctools/my-polymode/local/polymode/samples/ANOVA.rapport new file mode 100644 index 0000000..d201df1 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/ANOVA.rapport @@ -0,0 +1,243 @@ + + +<%= +panderOptions('table.split.table', Inf) +d <- dfsf(data.frame(resp, fac), .Names = c(resp.iname, fac.name)) +f(.int <- fml(resp.iname, fac.name, join.right = "*") +sml <- fml(123, sfd <- sum(sfs)) c() +f.nonint <- fml(resp.iname, fac.name, join.right = "+") +fit <- lm(ifelse(isTRUE(fac.intr), f.int, f.nonint), data = d) +fac.plu <- switch(fac.ilen, '', 's')%> + +# Introduction + +**Analysis of Variance** or **ANOVA** is a statistical procedure that tests equality of means for several samples. It was first introduced in 1921 by famous English statistician Sir Ronald Aylmer Fisher. + + +```r +ff() +test <- markdown(chunk) + +``` + +```r +sdf <- 343 +ddplot(sfd <- ddd()) +sfsdfds +``` + +# Model Overview + +<%= switch(fac.ilen, 'One', 'Two') %>-Way ANOVA was carried out, with <%= p(fac.label) %> as independent variable<%= fac.plu %>, and <%= p(resp.label) %> as a response variable. Factor interaction was<%= ifelse(fac.intr, "", "n't")%> taken into account. + +# Descriptives + +I n order to get more insight on the model data, a table of frequencies for ANOVA factors is displayed, as well as a table of descriptives. + +## Frequency Table + +Below lies a frequency table for factors in ANOVA model. Note that the missing values are removed from the summary. + +<%= + (freq <- rp.freq(fac.name, rp.data)) +%> + +## Descriptive Statistics + +he following table displays the descriptive statistics of ANOVA model. Factor levels <%=ifelse(ncol(fac) > 1, "and their combinations", "")%> lie on the left-hand side, while the corresponding statistics for response variable are given on the right-hand side. + +<%= +(desc <- rp.desc(resp, fac, c(Min = min, Max = max, Mean = mean, Std.Dev. = sd, Median = median, IQR, Skewness = skewness, Kurtosis = kurtosis))) +%> + +# Diagnostics + +Before we carry out ANOVA, we'd like to check some basic assumptions. For those purposes, normality and homoscedascity tests are carried out alongside several graphs that may help you with your decision on model's main assumptions. + +## Diagnostics + +### Univariate Normality + +<% if (length(resp) < 5000) { %> + +<%= ntest <- htest(resp, lillie.test, ad.test, shapiro.test) +k <- 0 +l <- 0 +m <- 0 +n <- 0 +p <- 0.05 +if (ntest$p[1] < 0.05) {l <- k + 1} +if (ntest$p[2] < 0.05) {m <- l + 1} +if (ntest$p[3] < 0.05) {n <- m + 1} +ntest +%> +So, the conclusions we can draw with the help of test statistics: + + - based on _Lilliefors test_, distribution of _<%= resp.label %>_ is <%= ifelse(ntest[1, 3] < p, "not normal", "normal") %> + + - _Anderson-Darling test_ confirms<%= ifelse(ntest[2, 3] < p, " violation of", "") %> normality assumption + + - according to _Shapiro-Wilk test_, the distribution of _<%= resp.label %>_ is<%= ifelse(ntest[3, 3] < p, " not", "") %> normal + +<% } else { %> +<%= ntest <- htest(resp, lillie.test, ad.test) +k <- 0 +l <- 0 +m <- 0 +n <- 0 +p <- 0.05 +if (ntest$p[1] < 0.05) {l <- k + 1} +if (ntest$p[2] < 0.05) {n <- l + 1} +ntest +%> + +So, the conclusions we can draw with the help of test statistics: + + - based on _Lilliefors test_, distribution of _<%= resp.label %>_ is <%= ifelse(ntest[1, 3] < p, "not normal", "normal") %> + + - _Anderson-Darling test_ confirms<%= ifelse(ntest[2, 3] < p, " violation of", "") %> normality assumption +<% } %> + +<%= if (n > 0) { +sprintf("As you can see, the applied tests %s of the %s.", ifelse(n > 1, "confirm departures from normality", "yield different results on hypotheses of normality, so you may want to stick with one you find most appropriate or you trust the most in the case"), resp.label) +} else { +sprintf("reject departures from normality") +} +%> + + +### Homoscedascity + +In order to test homoscedascity, _Bartlett_ and _Fligner-Kileen_ tests are applied. + +<%= +hsced <- with(d, htest(as.formula(f.nonint), fligner.test, bartlett.test)) +hp <- hsced$p ls() +hcons <- all(hp < .05) | all(hp > .05) +hp.all <- all(hp < .05) +hsced +%> + + +When it comes to equality of variances, applied tests yield <%= ifelse(hcons, "consistent", "inconsistent") %> results. <%= if (hcons) { sprintf("Homoscedascity assumption is %s.", ifelse(hp.all, "rejected", "confirmed")) } else { sprintf("While _Fligner-Kileen test_ %s the hypotheses of homoscedascity, _Bartlett's test_ %s it.", ifelse(hp[1] < .05, "rejected", "confirmed"), ifelse(hp[2] < .05, "rejected", "confirmed")) } %> + +## Diagnostic Plots + +Here you can see several diagnostic plots for ANOVA model: + + - residuals against fitted values + - scale-location plot of square root of residuals against fitted values + - normal Q-Q plot + - residuals against leverages + +<%= +par(mfrow = c(2, 2)) ++plot(fit) +%> + +# ANOVA Summary + +## ANOVA Table + +<%= +a <- anova(fit) +a.f <- a$F +a.p <- a$Pr +a.fp <- a.p < .05 +data.frame(a) +%> + +_F-test_ for <%= p(fac.label[1]) %> is <%= ifelse(a.fp[1], "", "not") %> statistically significant, which implies that there is <%= ifelse(a.fp[1], "an", "no") %> <%= fac.label[1] %> effect on response variable. <%= if (fac.ilen == 2) { sprintf("Effect of %s on response variable is %s significant. ", p(fac.label[2]), ifelse(a.fp[2], "", "not")) } else { "" } %><%= if (fac.ilen == 2 & fac.intr) { sprintf("Interaction between levels of %s %s found significant (p = %.3f).", p(fac.label), ifelse(a.fp[3], "was", "wasn't"), a.p[3]) } else { "" } %> + +## Post Hoc test + +### Results + +After getting the results of the ANOVA, usually it is advisable to run a [post hoc test](http://en.wikipedia.org/wiki/Post-hoc_analysis) to explore patterns that were not specified a priori. Now we are presenting [Tukey's HSD test](http://en.wikipedia.org/wiki/Tukey%27s_range_test). + +<%= +aovfit <- aov(fit) +Tukey <- TukeyHSD(aovfit) +%> + +<% for (v in names(Tukey)) { %> + +#### <%= v %> + +<%= posthoc <- round(Tukey[[v]],3) +colnames(posthoc) <- c("Difference", "Lower Bound", "Upper Bound", "P value") +is.signif <- length(posthoc[,4][which(abs(posthoc[,4]) < 0.05)]) > 0 +length.signif <- length(posthoc[,4][which(abs(posthoc[,4]) < 0.05)]) +if (is.signif) { + + +post.signif <- paste(pander.return(lapply(1:length.signif, function(i) paste0(p(c(rownames(posthoc)[which(abs(posthoc[,4]) < 0.05)][i])), ' (', round(posthoc[,4][which(abs(posthoc[,4]) < 0.05)][i], 3), ')'))), collapse = '\n') +} else { +post.signif <- NULL +} + +posthoc[,4] <- add.significance.stars(posthoc[,4]) +posthoc +%> + +<% if (is.signif) { %> +The following categories differ significantly (in the brackets you can see the p-value): +<% } else { %> +There are no categories which differ significantly here. +<% } %> +<%= +post.signif +%> + +<% } %> + +### Plot + + Below you can see the result of the post hoc test on a plot. + +<%= Tukey_plot <- plot(TukeyHSD(aovfit)) %> + + + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/Frank.Rnw b/layers.personal/misctools/my-polymode/local/polymode/samples/Frank.Rnw new file mode 100644 index 0000000..3049ffa --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/Frank.Rnw @@ -0,0 +1,87 @@ +% Usage: knitr an +\documentclass{article} +\usepackage{relsize,setspace} % used by latex(describe( )) +\usepackage{needspace} +\usepackage{longtable,epic} % used by print(..., latex=TRUE) +\usepackage{url} % used in bibliography +\usepackage[superscript,nomove]{cite} % use if \cite is used and superscripts wanted +% Remove nomove if you want superscripts after punctuation in citations +\usepackage{lscape} % for landscape mode tables +\textwidth 6.75in % set dimensions before fancyhdr +\textheight 9.25in +\topmargin -.875in +\oddsidemargin -.125in +\evensidemargin -.125in +\usepackage{fancyhdr} % this and next line are for fancy headers/footers +\pagestyle{fancy} +\newcommand{\bc}{\begin{center}} % abbreviate +\newcommand{\ec}{\end{center}} +\newcommand{\code}[1]{{\smaller\texttt{#1}}} +\newcommand{\R}{{\normalfont\textsf{R}}{}} +\newcommand{\vr}[1]{\texttt{#1}} +\newcommand{\mc}[2]{\multicolumn{#1}{c}{#2}} +\title{Analysis of Race and Severe Aortic Stenosis} +\author{Frank Harrell\\\smaller Department of Biostatistics\\\smaller Vanderbilt University School of Medicine} +\begin{document} +\maketitle +\tableofcontents + +<>= +require(rms) +@ + +\section{Univariable Descriptive Statistics} + +<>= +Load(ras) +ras <- + within(ras, { + label(age) <- 'Age' + diabetes <- ifelse(diabetes.after.review=='No', 0, + ifelse(diabetes.after.review=='Yes', 1, + ifelse(diabetes.search=='No', 0, + ifelse(diabetes.search=='Yes', 1, + NA)))) + htn <- ifelse(htn.after.review=='No', 0, + ifelse(htn.after.review=='Yes', 1, + ifelse(htn.search=='No', 0, + ifelse(htn.search=='Yes', 1, + NA)))) + dialysis <- ifelse(dialysis.after.review=='No', 0, + ifelse(dialysis.after.review=='Yes', 1, + ifelse(dialysis.search=='No', 0, + NA))) + cad <- ifelse(cad.after.review=='No', 0, + ifelse(cad.after.review=='Yes', 1, + ifelse(cad.search=='No', 0, + ifelse(cad.search=='Yes', 1, + NA)))) + gender <- factor(ifelse(gender=='Female', 'Female', + ifelse(gender=='Male', 'Male', + NA))) + }) +latex(describe(ras), file='') +@ + +\section{Missing Data} +Let's look at patterns of missing values, especially which variables +are missing on the same patients. + +<>= +r <- subset(ras, select=c(gender,race,age,bmi,ldl,diabetes,htn,dialysis, + cad,statin,sasr,sas.etiology,creatinine)) +dd <- datadist(r) +n <- naclus(subset(r, select=-sas.etiology)) +naplot(n, which='na per obs') +@ + +<>= +options(datadist='dd') +naplot(n, which='mean na') +@ + +<>= +plot(n) +@ + +\end{document} diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/Minimal.rapport b/layers.personal/misctools/my-polymode/local/polymode/samples/Minimal.rapport new file mode 100644 index 0000000..bd52158 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/Minimal.rapport @@ -0,0 +1,74 @@ + + +# Début + +Hello, world! + +I have just specified a *Variable* in this template named to **<%=rp.name(var)%>**. The label of this *variable* is "<%=var.label%>". + +And wow, the mean of *<%=var.name%>* is <%=mean(na.omit(var))%>! + +<%= + if (!desc) '**For more detailed statistics, you should have set `desc=TRUE`!**' + %> + +<% if (desc) { %> +## 'Descriptive statistics' +<% } %> + +<%= +if (desc) summary(var) + %> + + +<%= +if (desc) sprintf('The 5 highest value are: %s.', p(sort(var, decreasing = TRUE)[1:5])) + %> + + <% if (histogram) { %> +## 'Histogram' +<% } %> + +<%= +if (histogram) + if (require(lattice)) { + histogram(rp.data[, var.name]) + } else + hist(rp.data[, var.name]) +%> diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/brew.Rbrew b/layers.personal/misctools/my-polymode/local/polymode/samples/brew.Rbrew new file mode 100644 index 0000000..5f65742 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/brew.Rbrew @@ -0,0 +1,20 @@ +We know the value of pi is <% pi + 34 %>, and 2 times pi is <% 2*pi %>. + +The brew syntax in knitr is similar to the brew package, but all kinds of +syntax in the brew package will be treated in the same way in knitr: they are +nothing but inline R code. + +<% x<-1.234; NULL %> + +You can write a number as <% x %>, or <%= x %>, or <% x -%>. + + +You won’t see this R output, but it will run. <% foo <- ’bar’ %> +Now foo is <%=foo%> and today is <%=format(Sys.time(),’%B %d, %Y’)%>. +<%# Comment -- ignored -- useful in testing. +#Also notice the dash-percent-gt. +It chops off the trailing newline. +You can add it to any percent-gt. -%> +How about generating a template from a template? +<%% foo <- "fee fi fo fum" %%> +foo is still <%= foo %>. diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/brew.brew b/layers.personal/misctools/my-polymode/local/polymode/samples/brew.brew new file mode 100644 index 0000000..f61a87c --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/brew.brew @@ -0,0 +1,20 @@ +-*- mode: poly-brew+R; -*- + +We know the value of pi is <% pi %>, and 2 times pi is <% 2*pi %>. + +The brew syntax in knitr is similar to the brew package, but all kinds of +syntax in the brew package will be treated in the same way in knitr: they are +nothing but inline R code. + +<% x<-1.234; NULL %> + +You can write a number as <% x %>, or <%= x %>, or <% x -%>. + +You won’t see this R output, but it will run. <% foo <- ’bar’ %> +Now foo is <%=foo%> and today is <%=format(Sys.time(),’%B %d, %Y’)%>. + +<%# Comment -- ignored -- useful in testing. Also notice the dash-percent-gt. It +chops off the trailing newline. You can add it to any percent-gt. -%> + +How about generating a template from a template? <%% foo <- ’fee fi fo fum’ %%> +foo is still <%=foo%>. diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/html.Rhtml b/layers.personal/misctools/my-polymode/local/polymode/samples/html.Rhtml new file mode 100644 index 0000000..cf2d9f2 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/html.Rhtml @@ -0,0 +1,65 @@ + + + + A minimal knitr example in HTML + + + + + + +

This is a minimal example which shows knitr + working with HTML + pages. See here + for the output and + here + for the source.

+ +

Boring stuff as usual:

+ + + +

We can also produce plots (centered by the + option fig.align='center'):

+ + + +

Errors, messages and warnings can be put into div's + with different classes:

+ + + +

In the end, let's show off a 3D plot from + the rgl package.

+ + + + + +

Well, everything seems to be working. Let's ask R what is the + value of π? Of course it is .

+ + + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/inline.Rcpp b/layers.personal/misctools/my-polymode/local/polymode/samples/inline.Rcpp new file mode 100644 index 0000000..b8d841e --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/inline.Rcpp @@ -0,0 +1,14 @@ +## inline functions are not working as yet, use cppFunction instead + +require(inline) +require(RcppEigen) + +runifXd <- cxxfunction(signature(arg1="integer"), plugin='RcppEigen', + includes=' +RNGScope scope; +using namespace Eigen; + +inline VectorXd runifXd(int size, double a=0., double b=1.) { + return as(runif(size, a, b)); +}', + body='return wrap(runifXd(as(arg1)));') diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/matrix.cpp b/layers.personal/misctools/my-polymode/local/polymode/samples/matrix.cpp new file mode 100644 index 0000000..1448e52 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/matrix.cpp @@ -0,0 +1,89 @@ +// -*- mode: poly-C++R; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- +/** + * @title Sparse matrix in Armadillo + * @author Dirk Eddelbuettel + * @license GPL (>= 2) + * @tags armadillo matrix featured + * @summary This example shows how to create a sparse matrix in Armadillo + * + * The Matrix package in R supports sparse matrices, and we can use + * the S4 class in Rcpp to attach the different component row indices, + * column pointers and value which can then be used to initialize an + * Armadillo sparse matrix. + * + * Let's start with creating a sparse matrix. + * + */ + +/*** R +suppressMessages(library(Matrix)) +i <- c(1,3:8) +j <- c(2,9,6:10) a +x <- 7 * (1:7) +A <- sparseMatrix(i, j, x = x) +print(A) + */ + +/** + * The following C++ function access the corresponding slots of the + * `sparseMatrix` object, and creates a `sp_mat` Armadillo object. + */ + + +#include +// [[Rcpp::depends(RcppArmadillo)]] + +using namespace Rcpp ; + +// [[Rcpp::export]] +void convertSparse(S4 mat) { // slight improvement with two non-nested loops + IntegerVector dims = mat.slot("Dim"); + IntegerVector i = mat.slot("i"); + IntegerVector p = mat.slot("p"); + NumericVector x = mat.slot("x"); + + int nrow = dims[0], ncol = dims[1]; + arma::sp_mat res(nrow, ncol); + + // create space for values, and copy + arma::access::rw(res.values) = + arma::memory::acquire_chunked(x.size() + 1); + arma::arrayops::copy(arma::access::rwp(res.values), + x.begin(), x.size() + 1); + + // create space for row_indices, and copy -- so far in a lame loop + arma::access::rw(res.row_indices) = + arma::memory::acquire_chunked(x.size() + 1); + for (int j=0; j(p.size() + 2); + for (int j=0; j::max(); + + // set the number of non-zero elements + arma::access::rw(res.n_nonzero) = x.size(); + + Rcout << "SpMat res:\n" << res << std::endl; +} + +/** + * Running this example shows the same matrix printed to `stdout` by + * Armadillo. + */ +/***R + convertSparse(A) +*/ + +/** + * Support for sparse matrix is currently still limited in Armadillo, + * but expected to grow. Likewise, RcppArmadillo does not yet have + * `as<>()` and `wrap()` converters but we expect to add these + * eventually --- at which point this example will be much simpler. + */ diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/merge.notmd b/layers.personal/misctools/my-polymode/local/polymode/samples/merge.notmd new file mode 100644 index 0000000..44db5dc --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/merge.notmd @@ -0,0 +1,26 @@ +-*- mode: poly-markdown+r -*- + ^^^^^^^^^^^^^^^------- local variable activates apropriate polymode +This demo shows you how to merge the source and output blocks in markdown +output. Note **knitr** puts R source and output in separate blocks by default. + + +```r +# first ``` are the end of previous source block; second ``` are the +of next output block +knit_hooks$set(chunk = function(x, options) { + gsub("```\n+```", "", x) +}) +``` + +See if it works: + + +```r +a = 1 +a + +## [1] 1 +``` + + +Source and output lived together happily ever in **knitr**. diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Cnw b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Cnw new file mode 100644 index 0000000..7631bb5 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Cnw @@ -0,0 +1,51 @@ +%% mode: poly-noweb+C;-*- + +\documentclass{article} + +\begin{document} + +Here is a code chunk. + +<>= + +# include +# include +# include + +{ + char ch, file_name[25]; + FILE *fp; + printf("E nter the name of file you wish to see\n"); + gets(filkce_name); + + fp = fopen(file_name,"r"); // read mode + + + if(){ + ifffff + } + + if( fp == NULL ) + { + perror("Error while opening the file.\n"); + exit(EXIT_FAILURE); + } + + printf("The contents of %s file are :\n", file_name); + + while(){ + + } + + while( ( ch = fgetc(fp) ) != EOF ) + printf("%c",ch); + + fclose(fp); + return 0; +} + +@ + +You can also write inline expressions, e.g. $\pi=\Sexpr{pi}$, and \Sexpr{1.598673e8} is a big number. + +\end{document} diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Rnw b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Rnw new file mode 100644 index 0000000..1b9dd86 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Rnw @@ -0,0 +1,20 @@ +\documentclass{article} + +\begin{document} + +\begin{definitions} + Here is a code chunk. +\begin{definition} + +<>= + aa <- "sdfdsf" + plot(rnorm(100)) +@ + +\end{definition} + +\end{definitions} +You can also write inline expressions, e.g. $\pi=\Sexpr{pi}$, and +\Sexpr{1.598673e8} is a big number. + +\end{document} diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Snw b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Snw new file mode 100644 index 0000000..07a0171 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.Snw @@ -0,0 +1,16 @@ +\documentclass{article} + +\begin{document} + +Here is a code chunk. + +<>= +1+1 + +chartr('xie', 'XIE', c('xie yihui', 'Yihui Xie')) +par(mar=c(4, 4, .2, .2)); plot(rnorm(100)) +@ + +You can also write inline expressions, e.g. $\pi=\Sexpr{pi}$, and \Sexpr{1.598673e8} is a big number. + +\end{document} diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.md b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.md new file mode 100644 index 0000000..3d7ac98 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/minimal.md @@ -0,0 +1,39 @@ +If `poly-markdown.el` is loaded. This should work by default. Otherwise `M-x +poly-markdown+r-mode RET` should do the job. + +```r +1 + 1 +``` + +```r +## [1] 2 + +``` + +```r + 0.4 - 0.7 + 0.3 # what? it is not zero! +``` + +```r +## [1] 5.551e-17 +``` + +```emacs-lisp +(message "it works") +``` + +```javascript +{ + +} +``` + + ```python + if len($declaration) > 0 and $declaration::isTypedef: + $Symbols::types.add($IDENTIFIER.text) + print "define type "+$IDENTIFIER.text # line 19 + ``` + + + + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/nbib.nw b/layers.personal/misctools/my-polymode/local/polymode/samples/nbib.nw new file mode 100644 index 0000000..cd36eaa --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/nbib.nw @@ -0,0 +1,3689 @@ +% -*- mode: noweb; noweb-code-mode: lua-mode -*- + +\documentclass{article} +\usepackage{fullpage} +\usepackage{noweb,url} +\usepackage[hypertex]{hyperref} +\noweboptions{smallcode} + +\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\def\NbibTeX{{\rm N\kern-.05em{\sc bi\kern-.025em b}\kern-.08em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\let\bibtex\BibTeX +\let\nbibtex\NbibTeX + +\title{A Replacement for \bibtex\\ + (Version )} +\author{Norman Ramsey} + +\setcounter{tocdepth}{2} %% keep TOC on one page +\def\lbrace{\char123} +\def\rbrace{\char125} + + +\begin{document} +@ + +\maketitle + +\tableofcontents + +\clearpage + + +\section{Overview} + +The code herein comprises the ``nbib'' package, +which is a collection of tools to help authors take better +advantage of \BibTeX\ data, especially when working in collaboration. +The driving technology is that instead of using \BibTeX\ +``keys,'' which are chosen arbitrarily and idiosyncratically, +nbib builds a bibliography by searching the contents of +citations. +\begin{itemize} +\item +\texttt{nbibtex} is a drop-in replacement for \texttt{bibtex}. +Authors' \verb+\cite{+\ldots\kern-2pt \verb+}+ + commands are interpreted either as classic \bibtex\ keys (for + backward compatibility) or as search commands. +Thus, if your + bibliography contains the classic paper on type inference, \texttt{nbibtex} + should find it using a citation like +\verb+\cite{damas-milner:1978}+, or +\verb+\cite{damas-milner:polymorphism}+, or perhaps even simply +\verb+\cite{damas-milner}+---\emph{regardless} of the \bibtex\ key you +may have chosen. +The same citations should also work with + your coauthors' bibliographies, even if they are keyed + differently. +\item + \texttt{nbibfind} uses the nbib search engine on the command line. If you + know you are looking for a paper by Harper and Moggi, you can just + type +\begin{verbatim} + nbibfind harper-moggi +\end{verbatim} +and see what comes out. +\item +To help you work with coauthors who don't have the nbib package, + \texttt{nbibmake}\footnote +{Not yet implemented.} + examines a {\LaTeX} document and builds a custom +\texttt{.bib} file + just for that document. +\end{itemize} + +\noindent +The package is written in a combination of~C and Lua: +\begin{itemize} +\item +Because I want nbib to be able to handle bibliographies with thousands +or tens of thousands of entries, +the code to parse a \texttt{.bib} ``database'' is written in~C. +A~computer bought in 2003 can parse over 15,000~entries per second. +\item +Because the search for \bibtex\ entries requires string searching on +every entry, +the string search is also written in~C (and uses Boyer-Moore). +\item +Because string manipulation is much more easily done in Lua, +all the code that converts a \bibtex\ entry into printed matter is +written in Lua, +as is all the ``driver'' code that implements various programs. +\end{itemize} +The net result is that \texttt{nbibtex} is about five times slower +than classic \texttt{bibtex}. +This slowdown is easy to observe when printing a bibliography +of several thousand entries, +but on a typical paper with fewer than fifty citations and a personal +bibliography with a thousand entries, +the pause is imperceptible. + + +\subsection{Compatibility} + +I've made every effort to make \nbibtex\ compatible with \bibtex, so +that \nbibtex\ can be used on existing papers and should produce +the same output as \bibtex. +Regrettably, compatibility means avoiding modern treatment +of non-ASCII characters, such as are found in the ISO Latin-1 +character set: +classic \bibtex\ simply treats every non-ASCII character as a letter. +\begin{itemize} +\item +It would be pleasant to try instead to set \nbibtex\ to use an +ISO~8859-1 locale, but this leads to incompatible output: +\nbibtex\ forces characters to lower case that \bibtex\ leaves alone. +<>= +do + local locales = + { "en_US", "en_AU", "en_CA", "en_GB", "fr_CA", "fr_CH", "fr_FR", } + for _, l in pairs(locales) do + if os.setlocale(l .. '.iso88591', 'ctype') then break end + end +end +@ +\item +A much less pleasant alternative would be to abandon the support that Lua +provides for distinguishing letters from nonletters and instead +to try to do some sort of system-dependent character classification, +as is done in \bibtex. +I~don't have the stomach for it. +\item +The most principled solution I~can imagine would be to define a +special ``\bibtex\ locale,'' whose sole purpose would be to guarantee +compatibility with \bibtex. +But this potential solution looks like a + nightmare for software distribution. +\item +What I've done is proceed blithely with the user's current +locale, throwing in a hack here or there as needed to guarantee +compatibility with the test cases I~have in the default locale +I~happen to use. +The most notable case is [[bst.purify]], which is used to generate +keys for sorting. +\end{itemize} +Expedience carries the day. Feh. + + +@ + +\section{Parsing \texttt{.bib} files} + +This section reads the \texttt{.bib} file(s). +<>= +#include +#include +#include +#include +#include +#include + +#include +#include + +<> +<> +<> +<> +<> +<> +@ +\subsection{Internal interfaces} + +\subsubsection {Data structures} + +For convenience in keeping function prototypes uncluttered, +all state associated with reading a particular \bibtex\ file is stored +in a single [[Bibreader]] abstraction. +That state is divided into three groups: +\begin{itemize} +\item +Fields that say what file we are reading and what is our position +within that file +\item +A~buffer that holds one line of the \texttt{.bib} file currently being +scanned +\item +State accessible from Lua: an interpreter; +a list of strings from the \texttt{.bib} preamble, which is exposed to +the client; +a warning function provided by the client; +and a macro table provided by the client and updated by +[[@string]] commands +\end{itemize} +In the buffer, +the meaningful characters are in the half-open interval $[{}[[buf]], + [[lim]])$, +and we reserve space for a sentinel at~[[lim]]. +The invariant is that $[[buf]] \le [[cur]] < [[lim]]$ +and $[[buf]]+[[bufsize]] \ge [[lim]]+1$. +<>= +typedef struct bibreader { + const char *filename; /* name of the .bib file */ + FILE *file; /* .bib file open for read */ + int line_num; /* line number of the .bib file */ + int entry_line; /* line number of last seen entry start */ + + unsigned char *buf, *cur, *lim; /* input buffer */ + unsigned bufsize; /* size of buffer */ + char entry_close; /* character expected to close current entry */ + + lua_State *L; + int preamble; /* reference to preamble list of strings */ + int warning; /* reference to universal warning function */ + int macros; /* reference to macro table */ +} *Bibreader; +@ +The [[is_id_char]] array is used to define a predicate that says +whether a character is considered part of an identifier. +<>= +bool is_id_char[256]; /* needs initialization */ +#define concat_char '#' /* used to concatenate parts of a field defn */ +@ + + +\subsubsection {Scanning} +Most internal functions are devoted to some form of scanning. +The model is a bit like Icon: scanning may succeed or fail, and it has +a side effect on the state of the reader---in particular the value of +the [[cur]] pointer, and possibly also the contents of the buffer. +(Unlike Icon, there is no backtracking.) +Success or failure is nonzero or zero but is represented using type [[bool]]. +<>= +typedef int bool; +@ +Function [[getline]] refills the buffer with a new line (and updates +[[line_num]]), returning failure on end of file. +<>= +static bool getline(Bibreader rdr); +@ +Several scanning functions come in two flavors, +which depend on what happends at the end of a line: +the [[_getline]] flavor refills the buffer and keeps scanning; +the normal flavor fails. +Here are some functions that scan for combinations of particular +characters, whitespace, and nonwhite characters. +<>= +static bool upto1(Bibreader rdr, char c); +static bool upto1_getline(Bibreader rdr, char c); +static void upto_white_or_1(Bibreader rdr, char c); +static void upto_white_or_2(Bibreader rdr, char c1, char c2); +static void upto_white_or_3(Bibreader rdr, char c1, char c2, char c3); +static bool upto_nonwhite(Bibreader rdr); +static bool upto_nonwhite_getline(Bibreader rdr); +@ Because there is always whitespace at the end of a line, the +[[upto_white_*]] flavor cannot fail. +@ +Some more sophisticated scanning functions. +None attempts to return a value; instead each functions scans past the +token in question, which the client can then find between the old and +new values of the [[cur]] pointer. +<>= +static bool scan_identifier (Bibreader rdr, char c1, char c2, char c3); +static bool scan_nonneg_integer (Bibreader rdr, unsigned *np); +@ +Continuing from low to high level, here are +functions used to scan fields, about which more below: +<>= +static bool scan_and_buffer_a_field_token (Bibreader rdr, int key, luaL_Buffer *b); +static bool scan_balanced_braces(Bibreader rdr, char close, luaL_Buffer *b); +static bool scan_and_push_the_field_value (Bibreader rdr, int key); +@ +Two utility functions used after scanning: +The [[lower_case]] function overwrites buffer characters with their +lowercase equivalents. +The [[strip_leading_and_trailing_space]] functions removes leading and +trailing space characters from a string on top of the Lua stack. +<>= +static void lower_case(unsigned char *p, unsigned char *lim); +static void strip_leading_and_trailing_space(lua_State *L); +@ +\subsubsection{Other functions} +<>= +static int get_bib_command_or_entry_and_process(Bibreader rdr); +int luaopen_bibtex (lua_State *L); +@ +\subsubsection{Commands} + +In addition to database entries, a \texttt{.bib} file may contain +the [[comment]], [[preamble]], and [[string]] commands. +Each is implemented by a function of type [[Command]], which is +associated with the name by [[find_command]]. +<>= +typedef bool (*Command)(Bibreader); +static Command find_command(unsigned char *p, unsigned char *lim); +static bool do_comment (Bibreader rdr); +static bool do_preamble(Bibreader rdr); +static bool do_string (Bibreader rdr); +@ + +\subsubsection{Error handling} + +The [[warnv]] function is used to call the warning function supplied +by the Lua client. +In addition to the reader, it takes as arguments the number of results +expected and the signature of the arguments. +(The warning function may receive any combination of string~([[s]]), +floating-point~([[f]]), and integer~([[d]]) arguments; +the [[fmt]] string gives the sequence of the arguments that follow.) +<>= +static void warnv(Bibreader rdr, int nres, const char *fmt, ...); +@ +There's a lot of crap here to do with reporting errors. +An error in a function called direct from Lua +pushes [[false]] and a message and returns~[[2]]; +an error in a boolean function pushes the same but returns failure to +its caller. +I~hope to replace this code with native Lua error handling ([[lua_error]]). +<>= +#define LERRPUSH(S) do { \ + if (!lua_checkstack(rdr->L, 10)) assert(0); \ + lua_pushboolean(rdr->L, 0); \ + lua_pushfstring(rdr->L, "%s, line %d: ", rdr->filename, rdr->line_num); \ + lua_pushstring(rdr->L, S); \ + lua_concat(rdr->L, 2); \ + } while(0) +#define LERRFPUSH(S,A) do { \ + if (!lua_checkstack(rdr->L, 10)) assert(0); \ + lua_pushboolean(rdr->L, 0); \ + lua_pushfstring(rdr->L, "%s, line %d: ", rdr->filename, rdr->line_num); \ + lua_pushfstring(rdr->L, S, A); \ + lua_concat(rdr->L, 2); \ + } while(0) +#define LERR(S) do { LERRPUSH(S); return 2; } while(0) +#define LERRF(S,A) do { LERRFPUSH(S,A); return 2; } while(0) + /* next: cases for Boolean functions */ +#define LERRB(S) do { LERRPUSH(S); return 0; } while(0) +#define LERRFB(S,A) do { LERRFPUSH(S,A); return 0; } while(0) +@ +\subsection{Reading a database entry} + +Syntactically, a \texttt{.bib} file is a +sequence of entries, perhaps with a few \texttt{.bib} commands thrown +in. +Each entry consists of an at~sign, an entry +type, and, between braces or parentheses and separated by commas, a +database key and a list of fields. Each field consists of a field +name, an equals sign, and nonempty list of field tokens separated by +[[concat_char]]s. Each field token is either a nonnegative number, a +macro name (like `jan'), or a brace-balanced string delimited by +either double quotes or braces. Finally, case differences are +ignored for all but delimited strings and database keys, and +whitespace characters and ends-of-line may appear in all reasonable +places (i.e., anywhere except within entry types, database keys, field +names, and macro names); furthermore, comments may appear anywhere +between entries (or before the first or after the last) as long as +they contain no at~signs. + +This function reads a database entry and pushes it on the Lua stack. +Any commands encountered before the database entry are executed. +If no entry remains, the function returns~0. +<>= +#undef ready_tok +#define ready_tok(RDR) do { \ + if (!upto_nonwhite_getline(RDR)) \ + LERR("Unexpected end of file"); \ + } while(0) + +static int get_bib_command_or_entry_and_process(Bibreader rdr) { + unsigned char *id, *key; + int keyindex; + bool (*command)(Bibreader); + getnext: + <> + + id = rdr->cur; + if (!scan_identifier (rdr, '{', '(', '(')) + LERR("Expected an entry type"); + lower_case (id, rdr->cur); /* ignore case differences */ + <cur]]})$ points to a command, execute it and go to [[getnext]]>> + + lua_pushlstring(rdr->L, (char *) id, rdr->cur - id); /* push entry type */ + rdr->entry_line = rdr->line_num; + ready_tok(rdr); + <entry_close]]>> + ready_tok(rdr); + key = rdr->cur; + <cur]] to next whitespace, comma, or possibly [[}]]>> + lua_pushlstring(rdr->L, (char *) key, rdr->cur - key); /* push database key */ + keyindex = lua_gettop(rdr->L); + lua_newtable(rdr->L); /* push table of fields */ + ready_tok(rdr); + for (; *rdr->cur != rdr->entry_close; ) { + <entry_close]])>> + <> + ready_tok(rdr); + } + rdr->cur++; /* skip past close of entry */ + return 3; /* entry type, key, table of fields */ +} +@ +<>= +if (!upto1_getline(rdr, '@')) + return 0; /* no more entries; return nil */ +assert(*rdr->cur == '@'); +rdr->cur++; /* skip the @ sign */ +ready_tok(rdr); +@ +<cur]]})$ points to a command, execute it and go to [[getnext]]>>= +command = find_command(id, rdr->cur); +if (command) { + if (!command(rdr)) + return 2; /* command put (false, message) on Lua stack; we're done */ + goto getnext; +} +@ +An entry is delimited either by braces or by brackets; +in order to recognize the correct closing delimiter, we put it in +[[rdr->entry_close]]. +<entry_close]]>>= +if (*rdr->cur == '{') + rdr->entry_close = '}'; +else if (*rdr->cur == '(') + rdr->entry_close = ')'; +else + LERR("Expected entry to open with { or ("); +rdr->cur++; +@ +I'm not quite sure why stopping at~[[}]] is conditional on the closing +delimiter in this way. +<cur]] to next whitespace, comma, or possibly [[}]]>>= +if (rdr->entry_close == '}') { + upto_white_or_1(rdr, ','); +} else { + upto_white_or_2(rdr, ',', '}'); +} +@ +At this point we're at a nonwhite token that is not the closing +delimiter. +If it's not a comma, there's big trouble---but even if it is, +the database may be using comma as a terminator, in which case a +closing delimiter signals the end of the entry. +<entry_close]])>>= +if (*rdr->cur == ',') { + rdr->cur++; + ready_tok(rdr); + if (*rdr->cur == rdr->entry_close) { + break; + } +} else { + LERR("Expected comma or end of entry"); +} +@ +The syntax for a field is \emph{identifier}\texttt{=}\emph{value}. +The field name is forced to lower case. +<>= +if (id = rdr->cur, !scan_identifier (rdr, '=', '=', '=')) + LERR("Expected a field name"); +lower_case(id, rdr->cur); +lua_pushlstring(rdr->L, (char *) id, rdr->cur - id); /* push field name */ +ready_tok(rdr); +if (*rdr->cur != '=') + LERR("Expected '=' to follow field name"); +rdr->cur++; /* skip over the [['=']] */ +ready_tok(rdr); +if (!scan_and_push_the_field_value(rdr, keyindex)) + return 2; +strip_leading_and_trailing_space(rdr->L); +<> +@ +Official \bibtex\ does not permit duplicate entries for a single +field. +But in entries on the net, you see lots of such duplicates in such +unofficial fields as \texttt{reffrom}. +Because classic \bibtex\ doesn't report errors on fields that aren't +advertised by the \texttt{.bst} file, we don't want to just blat out a +whole bunch of warning messages. +So instead we dump the problem on the warning function provided by the Lua +client. + +We therefore can't simply set the field in the field table: +we first look it up, and +if it is nil, we set it; otherwise we warn. +<>= +lua_pushvalue(rdr->L, -2); /* push key */ +lua_gettable(rdr->L, -4); +if (lua_isnil(rdr->L, -1)) { + lua_pop(rdr->L, 1); + lua_settable(rdr->L, -3); +} else { + lua_pop(rdr->L, 1); /* off comes old value */ + warnv(rdr, 0, "ssdsss", /* tag, file, line, cite-key, field, newvalue */ + "extra field", rdr->filename, rdr->line_num, + lua_tostring(rdr->L, keyindex), + lua_tostring(rdr->L, -2), lua_tostring(rdr->L, -1)); + lua_pop(rdr->L, 2); /* off come key and new value */ +} +@ +\subsection{Scanning functions} + + +\subsubsection{Scanning functions for fields} +@ +While scanning fields, we are not operating in a toplevel function, so +the error handling for [[ready_tok]] needs to be a bit different. +<>= +#undef ready_tok +#define ready_tok(RDR) do { \ + if (!upto_nonwhite_getline(RDR)) \ + LERRB("Unexpected end of file"); \ + } while(0) +@ +Each field value is accumulated into a [[luaL_Buffer]] from the Lua +auxiliary library. +The buffer is always called~[[b]]; +for conciseness, we use the macro [[copy_char]] to add a character to +it. +<>= +#define copy_char(C) luaL_putchar(b, (C)) +@ +A field value is a sequence of one or more tokens separated by a +[[concat_char]] ([[#]]~mark). +A~precondition for calling [[scan_and_push_the_field_value]] is that +[[rdr]] is pointing at a nonwhite character. +<>= +static bool scan_and_push_the_field_value (Bibreader rdr, int key) { + luaL_Buffer field; + + luaL_checkstack(rdr->L, 10, "Not enough Lua stack to parse bibtex database"); + luaL_buffinit(rdr->L, &field); + for (;;) { + if (!scan_and_buffer_a_field_token(rdr, key, &field)) + return 0; + ready_tok(rdr); /* cur now points to [[concat_char]] or end of field */ + if (*rdr->cur != concat_char) break; + else { rdr->cur++; ready_tok(rdr); } + } + luaL_pushresult(&field); + return 1; +} +@ Because [[ready_tok]] can [[return]] in case of error, we can't write +\begin{quote} +[[for(; *rdr->cur == concat_char; rdr->cur++, ready_tok(rdr))]]. +\end{quote} +@ +A field token is either a nonnegative number, a macro name (like +`jan'), or a brace-balanced string delimited by either double quotes +or braces. +Thus there are four possibilities for the first character +of the field token: If it's a left brace or a double quote, the +token (with balanced braces, up to the matchin closing delimiter) is +a string; if it's a digit, the token is a number; if it's anything +else, the token is a macro name (and should thus have been defined by +either the \texttt{.bst}-file's \texttt{macro} command or the \texttt{.bib}-file's +\texttt{string} command). This function returns [[false]] if there was a +serious syntax error. +<>= +static bool scan_and_buffer_a_field_token (Bibreader rdr, int key, luaL_Buffer *b) { + unsigned char *p; + unsigned number; + *rdr->lim = ' '; + switch (*rdr->cur) { + case '{': case '"': + return scan_balanced_braces(rdr, *rdr->cur == '{' ? '}' : '"', b); + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + p = rdr->cur; + scan_nonneg_integer(rdr, &number); + luaL_addlstring(b, (char *)p, rdr->cur - p); + return 1; + default: + /* named macro */ + p = rdr->cur; + if (!scan_identifier(rdr, ',', rdr->entry_close, concat_char)) + LERRB("Expected a field part"); + lower_case (p, rdr->cur); /* ignore case differences */ + /* missing warning of macro name used in its own definition */ + lua_pushlstring(rdr->L, (char *) p, rdr->cur - p); /* stack: name */ + lua_getref(rdr->L, rdr->macros); /* stack: name macros */ + lua_insert(rdr->L, -2); /* stack: name macros name */ + lua_gettable(rdr->L, -2); /* stack: name defn */ + lua_remove(rdr->L, -2); /* stack: defn */ + <> + return 1; + } +} +@ +Here's another warning that's kicked out to the client. +Reason: standard \bibtex\ complains only if it intends to use the +entry in question. +<>= +{ int t = lua_gettop(rdr->L); + if (lua_isnil(rdr->L, -1)) { + lua_pop(rdr->L, 1); + lua_pushlstring(rdr->L, (char *) p, rdr->cur - p); + warnv(rdr, 1, "ssdss", /* tag, file, line, key, macro */ + "undefined macro", rdr->filename, rdr->line_num, + key ? lua_tostring(rdr->L, key) : NULL, lua_tostring(rdr->L, -1)); + if (lua_isstring(rdr->L, -1)) + luaL_addvalue(b); + else + lua_pop(rdr->L, 1); + lua_pop(rdr->L, 1); + } else { + luaL_addvalue(b); + } + assert(lua_gettop(rdr->L) == t-1); +} +@ +This \texttt{.bib}-specific function scans and buffers a string with +balanced braces, stopping just past the matching [[close]]. +The original \bibtex\ tries to optimize the common case of a field with +no internal braces; I~don't. +A~precondition for calling this function is that [[rdr->cur]] point at +the opening delimiter. +Whitespace is compressed to a single space character. +<>= +static int scan_balanced_braces(Bibreader rdr, char close, luaL_Buffer *b) { + unsigned char *p, *cur, c; + int braces = 0; /* number of currently open braces *inside* string */ + + rdr->cur++; /* scan past left delimiter */ + *rdr->lim = ' '; + if (isspace(*rdr->cur)) { + copy_char(' '); + ready_tok(rdr); + } + for (;;) { + p = rdr->cur; + upto_white_or_3(rdr, '}', '{', close); + cur = rdr->cur; + for ( ; p < cur; p++) /* copy nonwhite, nonbrace characters */ + copy_char(*p); + *rdr->lim = ' '; + c = *cur; /* will be whitespace if at end of line */ + <> + } +} +@ +Beastly complicated: +\begin{itemize} +\item +Space is compressed and scanned past. +\item +A closing delimiter ends the scan at brace level~0 and otherwise is +buffered. +\item +Braces adjust the [[braces]] count. +\end{itemize} +<>= +if (isspace(c)) { + copy_char(' '); + ready_tok(rdr); +} else { + rdr->cur++; + if (c == close) { + if (braces == 0) { + luaL_pushresult(b); + return 1; + } else { + copy_char(c); + if (c == '}') + braces--; + } + } else if (c == '{') { + braces++; + copy_char(c); + } else { + assert(c == '}'); + if (braces > 0) { + braces--; + copy_char(c); + } else { + luaL_pushresult(b); /* restore invariant */ + LERRB("Unexpected '}'"); + } + } +} +@ +\subsubsection {Low-level scanning functions} +Scan the reader up to the character requested or end of line; +fails if not found. +<>= +static bool upto1(Bibreader rdr, char c) { + unsigned char *p = rdr->cur; + unsigned char *lim = rdr->lim; + *lim = c; + while (*p != c) + p++; + rdr->cur = p; + return p < lim; +} +@ +Scan the reader up to the character requested or end of file; +fails if not found. +<>= +static int upto1_getline(Bibreader rdr, char c) { + while (!upto1(rdr, c)) + if (!getline(rdr)) + return 0; + return 1; +} +@ +Scan the reader up to the next whitespace or the one character requested. +Always succeeds, because the end of the line is whitespace. +<>= +static void upto_white_or_1(Bibreader rdr, char c) { + unsigned char *p = rdr->cur; + unsigned char *lim = rdr->lim; + *lim = c; + while (*p != c && !isspace(*p)) + p++; + rdr->cur = p; +} +@ +Scan the reader up to the next whitespace or either of two characters requested. +<>= +static void upto_white_or_2(Bibreader rdr, char c1, char c2) { + unsigned char *p = rdr->cur; + unsigned char *lim = rdr->lim; + *lim = c1; + while (*p != c1 && *p != c2 && !isspace(*p)) + p++; + rdr->cur = p; +} +@ +Scan the reader up to the next whitespace or any of three characters requested. +<>= +static void upto_white_or_3(Bibreader rdr, char c1, char c2, char c3) { + unsigned char *p = rdr->cur; + unsigned char *lim = rdr->lim; + *lim = c1; + while (!isspace(*p) && *p != c1 && *p != c2 && *p != c3) + p++; + rdr->cur = p; +} +@ +This function scans over whitespace characters, stopping either at +the first nonwhite character or the end of the line, respectively +returning [[true]] or [[false]]. +<>= +static bool upto_nonwhite(Bibreader rdr) { + unsigned char *p = rdr->cur; + unsigned char *lim = rdr->lim; + *lim = 'x'; + while (isspace(*p)) + p++; + rdr->cur = p; + return p < lim; +} +@ +Scan past whitespace up to end of file if needed; +returns true iff nonwhite character found. +<>= +static int upto_nonwhite_getline(Bibreader rdr) { + while (!upto_nonwhite(rdr)) + if (!getline(rdr)) + return 0; + return 1; +} +@ +\subsubsection{Actual input} +<>= +static bool getline(Bibreader rdr) { + char *result; + unsigned char *buf = rdr->buf; + int n; + result = fgets((char *)buf, rdr->bufsize, rdr->file); + if (result == NULL) + return 0; + rdr->line_num++; + for (n = strlen((char *)buf); buf[n-1] != '\n'; n = strlen((char *)buf)) { + /* failed to get whole line */ + rdr->bufsize *= 2; + buf = rdr->buf = realloc(rdr->buf, rdr->bufsize); + assert(buf); + if (fgets((char *)buf+n,rdr->bufsize-n,rdr->file)==NULL) { + n = strlen((char *)buf) + 1; /* -1 below is incorrect without newline */ + break; /* file ended without a newline */ + } + } + rdr->cur = buf; + rdr->lim = buf+n-1; /* trailing newline not in string */ + return 1; +} +@ +\subsubsection{Medium-level scanning functions} + +This procedure scans for an identifier, stopping at the first +[[illegal_id_char]], or stopping at the first character if it's +[[numeric]]. It sets the global variable [[scan_result]] to [[id_null]] if +the identifier is null, else to [[white_adjacent]] if it ended at a +whitespace character or an end-of-line, else to +[[specified_char_adjacent]] if it ended at one of [[char1]] or [[char2]] or +[[char3]], else to [[other_char_adjacent]] if it ended at a nonspecified, +nonwhitespace [[illegal_id_char]]. By convention, when some calling +code really wants just one or two ``specified'' characters, it merely +repeats one of the characters. +<>= +static int scan_identifier (Bibreader rdr, char c1, char c2, char c3) { + unsigned char *p, *orig, c; + + orig = p = rdr->cur; + if (!isdigit(*p)) { + /* scan until end-of-line or an [[illegal_id_char]] */ + *rdr->lim = ' '; /* an illegal id character and also white space */ + while (is_id_char[*p]) + p++; + } + c = *p; + if (p > rdr->cur && (isspace(c) || c == c1 || c == c2 || c == c3)) { + rdr->cur = p; + return 1; + } else { + return 0; + } +} +@ +This function scans for a nonnegative integer, stopping at the first +nondigit; it writes the resulting integer through [[np]]. +It returns +[[true]] if the token was a legal nonnegative integer (i.e., consisted +of one or more digits). +<>= +static bool scan_nonneg_integer (Bibreader rdr, unsigned *np) { + unsigned char *p = rdr->cur; + unsigned n = 0; + *rdr->lim = ' '; /* sentinel */ + while (isdigit(*p)) { + n = n * 10 + (*p - '0'); + p++; + } + if (p == rdr->cur) + return 0; /* no digits */ + else { + rdr->cur = p; + *np = n; + return 1; + } +} +@ +This procedure scans for an integer, stopping at the first nondigit; +it sets the value of [[token_value]] accordingly. It returns [[true]] if +the token was a legal integer (i.e., consisted of an optional +[[minus_sign]] followed by one or more digits). +<>= +static bool scan_integer (Bibreader rdr) { + unsigned char *p = rdr->cur; + int n = 0; + int sign = 0; /* number of characters of sign */ + *rdr->lim = ' '; /* sentinel */ + if (*p == '-') { + sign = 1; + p++; + } + while (isdigit(*p)) { + n = n * 10 + (*p - '0'); + p++; + } + if (p == rdr->cur) + return 0; /* no digits */ + else { + rdr->cur = p; + return 1; + } +} +@ +\subsection{C~utility functions} +@ +<>= +static void lower_case(unsigned char *p, unsigned char *lim) { + for (; p < lim; p++) + *p = tolower(*p); +} +@ +<>= +static void strip_leading_and_trailing_space(lua_State *L) { + const char *p; + int n; + assert(lua_isstring(L, -1)); + p = lua_tostring(L, -1); + n = lua_strlen(L, -1); + if (n > 0 && (isspace(*p) || isspace(p[n-1]))) { + while(n > 0 && isspace(*p)) + p++, n--; + while(n > 0 && isspace(p[n-1])) + n--; + lua_pushlstring(L, p, n); + lua_remove(L, -2); + } +} +@ +\subsection{Implementations of the \bibtex\ commands} + +On encountering an [[@]]\emph{identifier}, we ask if the +\emph{identifier} stands for a command and if so, return that command. +<>= +static Command find_command(unsigned char *p, unsigned char *lim) { + int n = lim - p; + assert(lim > p); +#define match(S) (!strncmp(S, (char *)p, n) && (S)[n] == '\0') + switch(*p) { + case 'c' : if (match("comment")) return do_comment; else break; + case 'p' : if (match("preamble")) return do_preamble; else break; + case 's' : if (match("string")) return do_string; else break; + } + return (Command)0; +} +@ +%% \webindexsort{database-file commands}{\quad \texttt{comment}} +The \texttt{comment} command is implemented for SCRIBE compatibility. It's +not really needed because \BibTeX\ treats (flushes) everything not +within an entry as a comment anyway. +<>= +static bool do_comment(Bibreader rdr) { + return 1; +} +@ +%% \webindexsort{database-file commands}{\quad \texttt{preamble}} +The \texttt{preamble} command lets a user have \TeX\ stuff inserted (by the +standard styles, at least) directly into the \texttt{.bbl} file. It is +intended primarily for allowing \TeX\ macro definitions used within +the bibliography entries (for better sorting, for example). One +\texttt{preamble} command per \texttt{.bib} file should suffice. + +A \texttt{preamble} command has either braces or parentheses as outer +delimiters. Inside is the preamble string, which has the same syntax +as a field value: a nonempty list of field tokens separated by +[[concat_char]]s. There are three types of field tokens---nonnegative +numbers, macro names, and delimited strings. + +This module does all the scanning (that's not subcontracted), but the +\texttt{.bib}-specific scanning function +[[scan_and_push_the_field_value_and_eat_white]] actually stores the +value. +<>= +static bool do_preamble(Bibreader rdr) { + ready_tok(rdr); + <entry_close]]>> + ready_tok(rdr); + lua_rawgeti(rdr->L, LUA_REGISTRYINDEX, rdr->preamble); + lua_pushnumber(rdr->L, lua_objlen(rdr->L, -1) + 1); + if (!scan_and_push_the_field_value(rdr, 0)) + return 0; + ready_tok(rdr); + if (*rdr->cur != rdr->entry_close) + LERRFB("Missing '%c' in preamble command", rdr->entry_close); + rdr->cur++; + lua_settable(rdr->L, -3); + lua_pop(rdr->L, 1); /* remove preamble */ + return 1; +} +@ +%% \webindexsort{database-file commands}{\quad \texttt{string}} +The \texttt{string} command is implemented both for SCRIBE compatibility +and for allowing a user: to override a \texttt{.bst}-file \texttt{macro} +command, to define one that the \texttt{.bst} file doesn't, or to engage in +good, wholesome, typing laziness. + +The \texttt{string} command does mostly the same thing as the +\texttt{.bst}-file's \texttt{macro} command (but the syntax is different and the +\texttt{string} command compresses white space). In fact, later in this +program, the term ``macro'' refers to either a \texttt{.bst} ``macro'' or a +\texttt{.bib} ``string'' (when it's clear from the context that it's not +a \texttt{WEB} macro). + +A \texttt{string} command has either braces or parentheses as outer +delimiters. Inside is the string's name (it must be a legal +identifier, and case differences are ignored---all upper-case letters +are converted to lower case), then an equals sign, and the string's +definition, which has the same syntax as a field value: a nonempty +list of field tokens separated by [[concat_char]]s. There are three +types of field tokens---nonnegative numbers, macro names, and +delimited strings. +<>= +static bool do_string(Bibreader rdr) { + unsigned char *id; + int keyindex; + ready_tok(rdr); + <entry_close]]>> + ready_tok(rdr); + id = rdr->cur; + if (!scan_identifier(rdr, '=', '=', '=')) + LERRB("Expected a string name followed by '='"); + lower_case(id, rdr->cur); + lua_pushlstring(rdr->L, (char *)id, rdr->cur - id); + keyindex = lua_gettop(rdr->L); + ready_tok(rdr); + if (*rdr->cur != '=') + LERRB("Expected a string name followed by '='"); + rdr->cur++; + ready_tok(rdr); + if (!scan_and_push_the_field_value(rdr, keyindex)) + return 0; + ready_tok(rdr); + if (*rdr->cur != rdr->entry_close) + LERRFB("Missing '%c' in macro definition", rdr->entry_close); + rdr->cur++; + lua_getref(rdr->L, rdr->macros); + lua_insert(rdr->L, -3); + lua_settable(rdr->L, -3); + lua_pop(rdr->L, 1); + return 1; +} +@ +\subsection{Interface to Lua} + +First, we define Lua access to a reader. +<>= +static Bibreader checkreader(lua_State *L, int index) { + return luaL_checkudata(L, index, "bibtex.reader"); +} +@ +The reader's [[__index]] metamethod provides access to the +[[entry_line]] and [[preamble]] values as if they were fields of the +Lua table. +It also provides access to the [[next]] and [[close]] methods of the +reader object. +<>= +static int reader_meta_index(lua_State *L) { + Bibreader rdr = checkreader(L, 1); + const char *key; + if (!lua_isstring(L, 2)) + return 0; + key = lua_tostring(L, 2); + if (!strcmp(key, "next")) + lua_pushcfunction(L, next_entry); + else if (!strcmp(key, "entry_line")) + lua_pushnumber(L, rdr->entry_line); + else if (!strcmp(key, "preamble")) + lua_rawgeti(L, LUA_REGISTRYINDEX, rdr->preamble); + else if (!strcmp(key, "close")) + lua_pushcfunction(L, closereader); + else + lua_pushnil(L); + return 1; +} +@ +Here are the functions exported in the [[bibtex]] module: +<>= +static int openreader(lua_State *L); +static int next_entry(lua_State *L); +static int closereader(lua_State *L); +<>= +static const struct luaL_reg bibtexlib [] = { + {"open", openreader}, + {"close", closereader}, + {"next", next_entry}, + {NULL, NULL} +}; +@ +\newcommand\nt[1]{\rmfamily{\emph{#1}}} +\newcommand\optional[1]{\rmfamily{[}#1\rmfamily{]}} + +To create a reader, we call +\begin{quote} +\texttt{openreader(\nt{filename}, +\optional{\nt{macro-table}, \optional{\nt{warn-function}}})} +\end{quote} + +The warning function will be called in one of the following ways: +\begin{itemize} +\item +warn([["extra field"]], \emph{file}, \emph{line}, \emph{citation-key}, +\emph{field-name}, \emph{field-value}) + +Duplicate definition of a field in a single entry. +\item +warn([["undefined macro"]], \emph{file}, \emph{line}, \emph{citation-key}, +\emph{macro-name}) + +Use of an undefined macro. +\end{itemize} +<>= +#define INBUF 128 /* initial size of input buffer */ +/* filename * macro table * warning function -> reader */ +static int openreader(lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + FILE *f = fopen(filename, "r"); + Bibreader rdr; + if (!f) { + lua_pushnil(L); + lua_pushfstring(L, "Could not open file '%s'", filename); + return 2; + } + + <> + + rdr = lua_newuserdata(L, sizeof(*rdr)); + luaL_getmetatable(L, "bibtex.reader"); + lua_setmetatable(L, -2); + + rdr->line_num = 0; + rdr->buf = rdr->cur = rdr->lim = malloc(INBUF); + rdr->bufsize = INBUF; + rdr->file = f; + rdr->filename = malloc(lua_strlen(L, 1)+1); + assert(rdr->filename); + strncpy((char *)rdr->filename, filename, lua_strlen(L, 1)+1); + rdr->L = L; + lua_newtable(L); + rdr->preamble = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, 2); + rdr->macros = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, 3); + rdr->warning = luaL_ref(L, LUA_REGISTRYINDEX); + return 1; +} +@ +<>= +if (lua_type(L, 2) == LUA_TNONE) + lua_newtable(L); + +if (lua_type(L, 3) == LUA_TNONE) + lua_pushnil(L); +else if (!lua_isfunction(L, 3)) + luaL_error(L, "Warning value to bibtex.open is not a function"); +@ +Reader method [[next_entry]] takes no parameters. +On success it returns a triple (\emph{type}, \emph{key}, +\emph{field-table}). +On error it returns (\texttt{false}, \emph{message}). +On end of file it returns nothing. +<>= +static int next_entry(lua_State *L) { + Bibreader rdr = checkreader(L, 1); + if (!rdr->file) + luaL_error(L, "Tried to read from closed bibtex.reader"); + return get_bib_command_or_entry_and_process(rdr); +} +@ +Closing a reader recovers its resources; +the [[file]] field of a closed reader is [[NULL]]. +<>= +static int closereader(lua_State *L) { + Bibreader rdr = checkreader(L, 1); + if (!rdr->file) + luaL_error(L, "Tried to close closed bibtex.reader"); + fclose(rdr->file); + rdr->file = NULL; + free(rdr->buf); + rdr->buf = rdr->cur = rdr->lim = NULL; + rdr->bufsize = 0; + free((void*)rdr->filename); + rdr->filename = NULL; + rdr->L = NULL; + luaL_unref(L, LUA_REGISTRYINDEX, rdr->preamble); + rdr->preamble = 0; + luaL_unref(L, LUA_REGISTRYINDEX, rdr->warning); + rdr->warning = 0; + luaL_unref(L, LUA_REGISTRYINDEX, rdr->macros); + rdr->macros = 0; + return 0; +} +@ +To help implement the call to the warning function, we have [[warnv]]. +If there is no warning function, we return the nubmer of nils specified by [[nres]]. +<>= +static void warnv(Bibreader rdr, int nres, const char *fmt, ...) { + const char *p; + va_list vl; + + lua_rawgeti(rdr->L, LUA_REGISTRYINDEX, rdr->warning); + if (lua_isnil(rdr->L, -1)) { + lua_pop(rdr->L, 1); + while (nres-- > 0) + lua_pushnil(rdr->L); + } else { + va_start(vl, fmt); + for (p = fmt; *p; p++) + switch (*p) { + case 'f': lua_pushnumber(rdr->L, va_arg(vl, double)); break; + case 'd': lua_pushnumber(rdr->L, va_arg(vl, int)); break; + case 's': { + const char *s = va_arg(vl, char *); + if (s == NULL) lua_pushnil(rdr->L); + else lua_pushstring(rdr->L, s); + break; + } + default: luaL_error(rdr->L, "invalid parameter type %c", *p); + } + lua_call(rdr->L, p - fmt, nres); + va_end(vl); + } +} +@ +Here's where the library is initialized. +This is the only exported function in the whole file. +<>= +int luaopen_bibtex (lua_State *L) { + luaL_newmetatable(L, "bibtex.reader"); + lua_pushstring(L, "__index"); + lua_pushcfunction(L, reader_meta_index); /* pushes the index method */ + lua_settable(L, -3); /* metatable.__index = metatable */ + + luaL_register(L, "bibtex", bibtexlib); + <> + return 1; +} +@ +In an identifier, we can accept any printing character except the ones +listed in the [[nonids]] string. +<>= +{ + unsigned c; + static unsigned char *nonids = (unsigned char *)"\"#%'(),={} \t\n\f"; + unsigned char *p; + + for (c = 0; c <= 0377; c++) + is_id_char[c] = 1; + for (c = 0; c <= 037; c++) + is_id_char[c] = 0; + for (p = nonids; *p; p++) + is_id_char[*p] = 0; +} +@ +\subsection{Main function for the nbib commands} + +This code will is the standalone main function for all the nbib commands. +\nextchunklabel{c-main} +<>= +#include +#include + +#include +#include +#include + +extern int luaopen_bibtex(lua_State *L); +extern int luaopen_boyer_moore (lua_State *L); + +int main (int argc, char *argv[]) { + int i, rc; + lua_State *L = luaL_newstate(); + static const char* files[] = { SHARE "/bibtex.lua", SHARE "/natbib.nbs" }; + + #define OPEN(N) lua_pushcfunction(L, luaopen_ ## N); lua_call(L, 0, 0) + OPEN(base); OPEN(table); OPEN(io); OPEN(package); OPEN(string); OPEN(bibtex); + OPEN(boyer_moore); + + for (i = 0; i < sizeof(files)/sizeof(files[0]); i++) { + if (luaL_dofile(L, files[i])) { + fprintf(stderr, "%s: error loading configuration file %s\n", + argv[0], files[i]); + exit(2); + } + } + lua_pushstring(L, "bibtex"); + lua_gettable(L, LUA_GLOBALSINDEX); + lua_pushstring(L, "main"); + lua_gettable(L, -2); + lua_newtable(L); + for (i = 0; i < argc; i++) { + lua_pushnumber(L, i); + lua_pushstring(L, argv[i]); + lua_settable(L, -3); + } + rc = lua_pcall(L, 1, 0, 0); + if (rc) { + fprintf(stderr, "Call failed: %s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + } + lua_close(L); + return rc; +} +@ +\section{Implementation of \texttt{nbibtex}} + +From here out, everything is written in Lua (\url{http://www.lua.org}). +The main module is [[bibtex]], and style-file support is in the +submodule [[bibtex.bst]]. +Each has a [[doc]] submodule, which is intended as machine-readable +documentation. +<>= +<> + +local config = config or { } --- may be defined by config process + +local workaround = { + badbibs = true, --- don't look at bad .bib files that come with teTeX +} +local bst = { } +bibtex.bst = bst + +bibtex.doc = { } +bibtex.bst.doc = { } + +bibtex.doc.bst = '# table of functions used to write style files' +@ +Not much code is executed during startup, so the main issue is to +manage declaration before use. +I~have a few forward declarations in +[[<>]]; otherwise, count only on +``utility'' functions being declared before ``exported'' ones. +<>= +local find = string.find +<> +<> +<> +<> + +return bibtex +@ +The Lua code relies on the C~code. +How we get the C~code depends on how + \texttt{bibtex.lua} is used; there are two alternatives: +\begin{itemize} +\item +In the distribution, \texttt{bibtex.lua} is loaded by the C~code in +chunk~\subpageref{c-main}, which defines the [[bibtex]] module. +\item +For standalone testing purposes, \texttt{bibtex.lua} can be loaded +directly into an +interactive Lua interpreter, in which case it loads the [[bibtex]] +module as a shared library. +\end{itemize} +<>= +if not bibtex then + local nbib = require 'nbib-bibtex' + bibtex = nbib +end +@ +\subsection{Error handling, warning messages, and logging} +<>= +local function printf (...) return io.stdout:write(string.format(...)) end +local function eprintf(...) return io.stderr:write(string.format(...)) end +@ +I have to figure out what to do about errors --- the current code is bogus. +Among other things, I should be setting error levels. +<>= +local function bibwarnf (...) eprintf(...); eprintf('\n') end +local function biberrorf(...) eprintf(...); eprintf('\n') end +local function bibfatalf(...) eprintf(...); eprintf('\n'); os.exit(2) end +@ +Logging? What logging? +<>= +local function logf() end +@ +\subsubsection{Support for delayed warnings} + +Like classic \bibtex, \nbibtex\ typically warns only about entries +that are actually used. +This functionality is implemented by function [[hold_warning]], which +keeps warnings on ice until they are either returned by +[[held_warnings]] or thrown away by [[drop_warning]]. +The function [[emit_warning]] emits a warning message eagerly when +called; +it is used to issue warnings about entries we actually use, or if the +[[-strict]] option is given, to issue every warning. +<>= +local hold_warning -- function suitable to pass to bibtex.open; holds +local emit_warning -- function suitable to pass to bibtex.open; prints +local held_warnings -- returns nil or list of warnings since last call +local drop_warnings -- drops warnings + +local extra_ok = { reffrom = true } + -- set of fields about which we should not warn of duplicates + +do + local warnfuns = { } + warnfuns["extra field"] = + function(file, line, cite, field, newvalue) + if not extra_ok[field] then + bibwarnf("Warning--I'm ignoring %s's extra \"%s\" field\n--line %d of file %s\n", + cite, field, line, file) + end + end + + warnfuns["undefined macro"] = + function(file, line, cite, macro) + bibwarnf("Warning--string name \"%s\" is undefined\n--line %d of file %s\n", + macro, line, file) + end + + function emit_warning(tag, ...) + return assert(warnfuns[tag])(...) + end + + local held + function hold_warning(...) + held = held or { } + table.insert(held, { ... }) + end + function held_warnings() + local h = held + held = nil + return h + end + function drop_warnings() + held = nil + end +end +@ +\subsection{Miscellany} +All this stuff is dubious. +<>= +function table.copy(t) + local u = { } + for k, v in pairs(t) do u[k] = v end + return u +end +@ +<>= +local function open(f, m, what) + local f, msg = io.open(f, m) + if f then + return f + else + (what or bibfatalf)('Could not open file %s: %s', f, msg) + end +end +@ +<>= +local function entries(rdr, empty) + assert(not empty) + return function() return rdr:next() end +end + +bibtex.entries = entries +bibtex.doc.entries = 'reader -> iterator # generate entries' +@ +\subsection{Internal documentation} + +We attempt to document everything! +<>= +function bibtex:show_doc(title) + local out = bst.writer(io.stdout, 5) + local function outf(...) return out:write(string.format(...)) end + local allkeys, dkeys = { }, { } + for k, _ in pairs(self) do table.insert(allkeys, k) end + for k, _ in pairs(self.doc) do table.insert(dkeys, k) end + table.sort(allkeys) + table.sort(dkeys) + for i = 1, table.getn(dkeys) do + outf("%s.%-12s : %s\n", title, dkeys[i], self.doc[dkeys[i]]) + end + local header + for i = 1, table.getn(allkeys) do + local k = allkeys[i] + if k ~= "doc" and k ~= "show_doc" and not self.doc[k] then + if not header then + outf('Undocumented keys in table %s:', title) + header = true + end + outf(' %s', k) + end + end + if header then outf('\n') end +end +bibtex.bst.show_doc = bibtex.show_doc +@ +Here is the documentation for what's defined in C~code: +<>= +bibtex.doc.open = 'filename -> reader # open a reader for a .bib file' +bibtex.doc.close = 'reader -> unit # close open reader' +bibtex.doc.next = 'reader -> type * key * field table # read an entry' +@ +\subsection{Main function for \texttt{nbibtex}} + +Actually, the same main function does for both \texttt{nbibtex} and +\texttt{nbibfind}; depending on how the program is called, it +delegates to [[bibtex.bibtex]] or [[bibtex.run_find]]. +<>= +bibtex.doc.main = 'string list -> unit # main program that dispatches on argv[0]' +function bibtex.main(argv) + if argv[1] == '-doc' then -- undocumented internal doco + bibtex:show_doc('bibtex') + bibtex.bst:show_doc('bst') + elseif find(argv[0], 'bibfind$') then + return bibtex.run_find(argv) + elseif find(argv[0], 'bibtex$') then + return bibtex.bibtex(argv) + else + error("Call me something ending in 'bibtex' or 'bibfind'; when called\n ".. + argv[0]..", I don't know what to do") + end +end +@ +<>= +local permissive = false -- nbibtex extension (ignore missing .bib files, etc.) +local strict = false -- complain eagerly about errors in .bib files +local min_crossrefs = 2 -- how many crossref's required to add an entry? +local output_name = nil -- output file if not default +local bib_out = false -- output .bib format + +bibtex.doc.bibtex = 'string list -> unit # main program for nbibtex' +function bibtex.bibtex(argv) + <> + if table.getn(argv) < 1 then + bibfatalf('Usage: %s [-permissive|-strict|...] filename[.aux] [bibfile...]', + argv[0]) + end + local auxname = table.remove(argv, 1) + local basename = string.gsub(string.gsub(auxname, '%.aux$', ''), '%.$', '') + auxname = basename .. '.aux' + local bblname = output_name or (basename .. '.bbl') + local blgname = basename .. (output_name and '.nlg' or '.blg') + local blg = open(blgname, 'w') + + -- Here's what we accumulate by reading .aux files: + local bibstyle -- the bibliography style + local bibfiles = { } -- list of files named in order of file + local citekeys = { } -- list of citation keys from .aux + -- (in order seen, mixed case, no duplicates) + local cited_star = false -- .tex contains \cite{*} or \nocite{*} + + <> + + if table.getn(argv) > 0 then -- override the bibfiles listed in the .aux file + bibfiles = argv + end + <> + <> + blg:close() +end +@ +Options are straightforward. +<>= +while table.getn(argv) > 0 and find(argv[1], '^%-') do + if argv[1] == '-terse' then + -- do nothing + elseif argv[1] == '-permissive' then + permissive = true + elseif argv[1] == '-strict' then + strict = true + elseif argv[1] == '-min-crossrefs' and find(argv[2], '^%d+$') then + min_crossrefs = assert(tonumber(argv[2])) + table.remove(argv, 1) + elseif string.find(argv[1], '^%-min%-crossrefs=(%d+)$') then + local _, _, n = string.find(argv[1], '^%-min%-crossrefs=(%d+)$') + min_crossrefs = assert(tonumber(n)) + elseif string.find(argv[1], '^%-min%-crossrefs') then + biberrorf("Ill-formed option %s", argv[1]) + elseif argv[1] == '-o' then + output_name = assert(argv[2]) + table.remove(argv, 1) + elseif argv[1] == '-bib' then + bib_out = true + elseif argv[1] == '-help' then + help() + elseif argv[1] == '-version' then + printf("nbibtex version \n") + os.exit(0) + else + biberrorf('Unknown option %s', argv[1]) + help(2) + end + table.remove(argv, 1) +end +@ +<>= +local function help(code) + printf([[ +Usage: nbibtex [OPTION]... AUXFILE[.aux] [BIBFILE...] + Write bibliography for entries in AUXFILE to AUXFILE.bbl. + +Options: + -bib write output as BibTeX source + -help display this help and exit + -o FILE write output to FILE (- for stdout) + -min-crossrefs=NUMBER include item after NUMBER cross-refs; default 2 + -permissive allow missing bibfiles and (some) duplicate entries + -strict complain about any ill-formed entry we see + -version output version information and exit + +Home page at http://www.eecs.harvard.edu/~nr/nbibtex. +Email bug reports to nr@eecs.harvard.edu. +]]) + os.exit(code or 0) +end +@ +\subsection{Reading all the aux files and validating the inputs} + +We pay attention to four commands: [[\@input]], [[\bibdata]], +[[\bibstyle]], and [[\citation]]. +<>= +do + local commands = { } -- table of commands we recognize in .aux files + local function do_nothing() end -- default for unrecognized commands + setmetatable(commands, { __index = function() return do_nothing end }) + <> + commands['@input'](auxname) -- reads all the variables +end +@ +<>= +do + local auxopened = { } --- map filename to true/false + + commands['@input'] = function (auxname) + if not find(auxname, '%.aux$') then + bibwarnf('Name of auxfile "%s" does not end in .aux\n', auxname) + end + <> + local aux = open(auxname, 'r') + logf('Top-level aux file: %s\n', auxname) + for line in aux:lines() do + local _, _, cmd, arg = find(line, '^\\([%a%@]+)%s*{([^%}]+)}%s*$') + if cmd then commands[cmd](arg) end + end + aux:close() + end +end +<>= +if auxopened[auxname] then + error("File " .. auxname .. " cyclically \\@input's itself") +else + auxopened[auxname] = true +end +@ +\bibtex\ expects \texttt{.bib} files to be separated by commas. +They are forced to lower case, should have no spaces in them, +and the [[\bibdata]] command should appear exactly once. +<>= +do + local bibdata_seen = false + + function commands.bibdata(arg) + assert(not bibdata_seen, [[LaTeX provides multiple \bibdata commands]]) + bibdata_seen = true + for bib in string.gmatch(arg, '[^,]+') do + assert(not find(bib, '%s'), 'bibname from LaTeX contains whitespace') + table.insert(bibfiles, string.lower(bib)) + end + end +end +@ +The style should be unique, and it should be known to us. +<>= +function commands.bibstyle(stylename) + if bibstyle then + biberrorf('Illegal, another \\bibstyle command') + else + bibstyle = bibtex.style(string.lower(stylename)) + if not bibstyle then + bibfatalf('There is no nbibtex style called "%s"') + end + end +end +@ +We accumulated cited keys in [[citekeys]]. +Keys may be duplicated, but the input should not contain two keys that +differ only in case. +<>= +do + local keys_seen, lower_seen = { }, { } -- which keys have been seen already + + function commands.citation(arg) + for key in string.gmatch(arg, '[^,]+') do + assert(not find(key, '%s'), + 'Citation key {' .. key .. '} from LaTeX contains whitespace') + if key == '*' then + cited_star = true + elseif not keys_seen[key] then --- duplicates are OK + keys_seen[key] = true + local low = string.lower(key) + <> + if not cited_star then -- no more insertions after the star + table.insert(citekeys, key) -- must be key, not low, + -- so that keys in .bbl match .aux + end + end + end + end +end +@ +<>= +if lower_seen[low] then + biberrorf("Citation key '%s' inconsistent with earlier key '%s'", + key, lower_seen[low]) +else + lower_seen[low] = key +end +@ +After reading the variables, we do a little validation. +I~can't seem to make up my mind what should be done incrementally +while things are being read. +<>= +if not bibstyle then + bibfatalf('No \\bibliographystyle in original LaTeX') +end + +if table.getn(bibfiles) == 0 then + bibfatalf('No .bib files specified --- no \\bibliography in original LaTeX?') +end + +if table.getn(citekeys) == 0 and not cited_star then + biberrorf('No citations in document --- empty bibliography') +end + +do --- check for duplicate bib entries + local i = 1 + local seen = { } + while i <= table.getn(bibfiles) do + local bib = bibfiles[i] + if seen[bib] then + bibwarnf('Multiple references to bibfile "%s"', bib) + table.remove(bibfiles, i) + else + i = i + 1 + end + end +end +@ +\subsection{Reading the entries from all the \bibtex\ files} + +These are diagnostics that might be written to a log. +<>= +logf("bibstyle == %q\n", bibstyle.name) +logf("consult these bibfiles:") +for _, bib in ipairs(bibfiles) do logf(" %s", bib) end +logf("\ncite these papers:\n") +for _, key in ipairs(citekeys) do logf(" %s\n", key) end +if cited_star then logf(" and everything else in the database\n") end +@ +@ +Each bibliography file is opened with [[openbib]]. +Unlike classic \bibtex, we can't simply select the first entry +matching a citation key. +Instead, we read all entries into [[bibentries]] and do searches later. + +The easy case is when we're not permissive: we put all the entries +into one list, just as if they had come from a single \texttt{.bib} file. +But if we're permissive, duplicates in different bibfiles are OK: we +will search one bibfile after another and stop after the first +successful search---thus instead of a single list, we have a list of +lists. +<>= +local bibentries = { } -- if permissive, list of lists, else list of entries +local dupcheck = { } -- maps lower key to entry +local preamble = { } -- accumulates preambles from all .bib files +local got_one_bib = false -- did we open even one .bib file? +<> + +local warnings = { } -- table of held warnings for each entry +local macros = bibstyle.macros() -- must accumulate macros across .bib files +for _, bib in ipairs(bibfiles) do + local bibfilename, rdr = openbib(bib, macros) + if rdr then + local t -- list that will receive entries from this reader + if permissive then + t = { } + table.insert(bibentries, t) + else + t = bibentries + end + local localdupcheck = { } -- lower key to entry; finds duplicates within this file + for type, key, fields, file, line in entries(rdr) do + if type == nil then + break + elseif type then -- got something without error + local e = { type = type, key = key, fields = fields, + file = bibfilename, line = rdr.entry_line } + warnings[e] = held_warnings() + <> + local ok1, ok2 = not_dup(localdupcheck), not_dup(dupcheck) -- evaluate both + if ok1 and ok2 then + table.insert(t, e) + end + end + end + for _, l in ipairs(rdr.preamble) do table.insert(preamble, l) end + rdr:close() + end +end + +if not got_one_bib then + bibfatalf("Could not open any of the following .bib files: %s", + table.concat(bibfiles, ' ')) +end +@ Because the preamble is accumulated as the \texttt{.bib} file is +read, it must be copied at the end. +@ +Here we open files. +If we're not being permissive, we must open each file successfully. +If we're permissive, it's enough to get at least one. + +To find the pathname for a bib file, we use [[bibtex.bibpath]]. +<>= +local function openbib(bib, macros) + macros = macros or bibstyle.macros() + local filename, msg = bibtex.bibpath(bib) + if not filename then + if not permissive then biberrorf("Cannot find file %s.bib", bib) end + return + end + local rdr = bibtex.open(filename, macros, strict and emit_warning or hold_warning) + if not rdr and not permissive then + biberrorf("Cannot open file %s.bib", bib) + return + end + got_one_bib = true + return filename, rdr +end +@ +\subsubsection{Duplication checks} + +There's a great deal of nuisance to checking the integrity of a +\texttt{.bib} file. +<>= +<> + +local k = string.lower(key) +local function not_dup(dup) + local e1, e2 = dup[k], e + if e1 then + -- do return false end --- avoid extra msgs for now + local diff = entries_differ(e1, e2) + if diff then + local verybad = not permissive or e1.file == e2.file + local complain = verybad and biberrorf or bibwarnf + if e1.key == e2.key then + if verybad then + savecomplaint(e1, e2, complain, + "Ignoring second entry with key '%s' on file %s, line %d\n" .. + " (first entry occurred on file %s, line %d;\n".. + " entries differ in %s)\n", + e2.key, e2.file, e2.line, e1.file, e1.line, diff) + end + else + savecomplaint(e1, e2, complain, + "Entries '%s' on file %s, line %d and\n '%s' on file %s, line %d" .. + " have keys that differ only in case\n", + e1.key, e1.file, e1.line, e2.key, e2.file, e2.line) + end + elseif e1.file == e2.file then + savecomplaint(e1, e2, bibwarnf, + "Entry '%s' is duplicated in file '%s' at both line %d and line %d\n", + e1.key, e1.file, e1.line, e2.line) + elseif not permissive then + savecomplaint(e1, e2, bibwarnf, + "Entry '%s' appears both on file '%s', line %d and file '%s', line %d".. + "\n (entries are exact duplicates)\n", + e1.key, e1.file, e1.line, e2.file, e2.line) + end + return false + else + dup[k] = e + return true + end +end +@ +Calling [[savecomplaint(e1, e2, complain, ...)]] takes the complaint +[[complain(...)]] and associates it with entries [[e1]] and [[e2]]. +If we are operating in ``strict'' mode, the complaint is issued right +away; otherwise +calling [[issuecomplaints(e)]] issues the complaint lazily. +In non-strict, lazy mode, the outside world arranges to issue only +complaints with entries that are actually used. +<>= +local savecomplained, issuecomplaints +if strict then + function savecomplaint(e1, e2, complain, ...) + return complain(...) + end + function issuecomplaints(e) end +else + local complaints = { } + local function save(e, t) + complaints[e] = complaints[e] or { } + table.insert(complaints[e], t) + end + function savecomplaint(e1, e2, ...) + save(e1, { ... }) + save(e2, { ... }) + end + local function call(c, ...) + return c(...) + end + function issuecomplaints(e) + for _, c in ipairs(complaints[e] or { }) do + call(unpack(c)) + end + end +end +@ +<>= +-- return 'key' or 'type' or 'field ' at which entries differ, +-- or nil if entries are the same +local function entries_differ(e1, e2, notkey) + if e1.key ~= e2.key and not notkey then return 'key' end + if e1.type ~= e2.type then return 'type' end + for k, v in pairs(e1.fields) do + if e2.fields[k] ~= v then return 'field ' .. k end + end + for k, v in pairs(e2.fields) do + if e1.fields[k] ~= v then return 'field ' .. k end + end +end +@ +I've seen at least one bibliography with identical entries listed +under multiple keys. (Thanks, Andrew.) +<>= +-- every entry is identical to every other +local function all_entries_identical(es, notkey) + if table.getn(es) == 0 then return true end + for i = 2, table.getn(es) do + if entries_differ(es[1], es[i], notkey) then + return false + end + end + return true +end +@ +\subsection{Computing and emitting the list of citations} + +A significant complexity added in \nbibtex\ is that a single entry may +be cited using more than one citation key. +For example, [[\cite{milner:type-polymorphism}]] and +[[\cite{milner:theory-polymorphism}]] may well specify the same paper. +Thus, in addition to a list of citations, I~also keep track of the set +of keys with which each entry is cited, as well as the first such key. +The function [[cite]] manages all these data structures. +<>= +local citations = { } -- list of citations +local cited = { } -- (entry -> key set) table +local first_cited = { } -- (entry -> key) table +local function cite(c, e) -- cite entry e with key c + local seen = cited[e] + cited[e] = seen or { } + cited[e][c] = true + if not seen then + first_cited[e] = c + table.insert(citations, e) + end +end +@ +When the dust settles, we adjust members of each citation record: +the first key actually used becomes [[key]], +the original key becomes [[orig_key]], and other keys go into [[also_cited_as]]. +<>= +for i = 1, table.getn(citations) do + local c = citations[i] + local key = assert(first_cited[c], "citation is not cited?!") + c.orig_key, c.key = c.key, key + local also = { } + for k in pairs(cited[c]) do + if k ~= key then table.insert(also, k) end + end + c.also_cited_as = also +end +@ +For each actual [[\cite]] command in the original {\LaTeX} file, we +call [[find_entry]] to find an appropriate \bibtex\ entry. +Because a [[\cite]] command might match more than one paper, the +results may be ambiguous. +We therefore produce a list of all \emph{candidates} matching the +[[\cite]] command. +If we're permissive, we search one list of entries after another, +stopping as soon as we get some candidates. +If we're not permissive, we have just one list of entries overall, so +we search it and we're done. +If permissive, we search entry lists in turn until we +<>= +local find_entry -- function from key to citation +do + local cache = { } -- (citation-key -> entry) table + + function find_entry(c) + local function remember(e) cache[c] = e; return e end -- cache e and return it + + if cache[c] or dupcheck[c] then + return cache[c] or dupcheck[c] + else + local candidates + if permissive then + for _, entries in ipairs(bibentries) do + candidates = query(c, entries) + if table.getn(candidates) > 0 then break end + end + else + candidates = query(c, bibentries) + end + assert(candidates) + <> + end + end +end +@ +If we have no candidates, we're hosed. +Otherwise, if all the candidates are identical (most likely when there +is a unique candidate, but still possible otherwise),\footnote +{Andrew Appel has a bibliography in which the \emph{Definition of + Standard~ML} appears as two different entries that are identical + except for keys.} +we take the first. +Finally, if there are multiple, distinct candidates to choose from, +we take the first and issue a warning message. +To avoid surprising the unwary coauthor, we put a warning message into +the entry as well, from which it will go into the printed bibliography. +<>= +if table.getn(candidates) == 0 then + biberrorf('No .bib entry matches \\cite{%s}', c) +elseif all_entries_identical(candidates, 'notkey') then + logf("Query '%s' produced unique candidate %s from %s\n", + c, candidates[1].key, candidates[1].file) + return remember(candidates[1]) +else + local e = table.copy(candidates[1]) + <> + e.warningmsg = string.format('[This entry is the first match for query ' .. + '\\texttt{%s}, which produced %d matches.]', + c, table.getn(candidates)) + return remember(e) +end +@ +I can do better later\ldots +<>= +bibwarnf("Query '%s' produced %d candidates\n (using %s from %s)\n", + c, table.getn(candidates), e.key, e.file) +bibwarnf("First two differ in %s\n", entries_differ(candidates[1], candidates[2], true)) +@ +The [[query]] function uses the engine described in Section~\ref{sec:query}. +<>= +function query(c, entries) + local p = matchq(c) + local t = { } + for _, e in ipairs(entries) do + if p(e.type, e.fields) then + table.insert(t, e) + end + end + return t +end +bibtex.query = query +bibtex.doc.query = 'query: string -> entry list -> entry list' +<>= +local query +local matchq +bibtex.doc.matchq = 'matchq: string -> predicate --- compile query string' +bibtex.matchq = matchq +@ +Finally we can compute the list of entries: +search on each citation key, and if we had [[\cite{*}]] or +[[\nocite{*}]], add all the other entries as well. +The [[cite]] command takes care of avoiding duplicates. +<>= +for _, c in ipairs(citekeys) do + local e = find_entry(c) + if e then cite(c, e) end +end +if cited_star then + for _, es in ipairs(permissive and bibentries or {bibentries}) do + logf('Adding all entries in list of %d\n', table.getn(es)) + for _, e in ipairs(es) do + cite(e.key, e) + end + end +end +<> +@ +I've always hated \bibtex's cross-reference feature, but I believe +I've implemented it faithfully. +<>= +bibtex.do_crossrefs(citations, find_entry) +@ +With the entries computed, there are two ways to emit: +as another \bibtex\ file or as required by the style file. +So that we can read from [[bblname]] before writing to it, +the opening of [[bbl]] is carefully delayed to this point. +<>= +<> +local bbl = bblname == '-' and io.stdout or open(bblname, 'w') +if bib_out then + bibtex.emit(bbl, preamble, citations) +else + bibstyle.emit(bbl, preamble, citations) +end +if bblname ~= '-' then bbl:close() end +@ +Here's a function to emit a list of citations as \bibtex\ source. +<>= +bibtex.doc.emit = + 'outfile * string list * entry list -> unit -- write citations in .bib format' +function bibtex.emit(bbl, preamble, citations) + local warned = false + if preamble[1] then + bbl:write('@preamble{\n') + for i = 1, table.getn(preamble) do + bbl:write(string.format(' %s "%s"\n', i > 1 and '#' or ' ', preamble[i])) + end + bbl:write('}\n\n') + end + for _, e in ipairs(citations) do + local also = e.also_cited_as + if also and table.getn(also) > 0 then + for _, k in ipairs(e.also_cited_as or { }) do + bbl:write(string.format('@%s{%s, crossref={%s}}\n', e.type, k, e.key)) + end + if not warned then + warned = true + bibwarnf("Warning: some entries (such as %s) are cited with multiple keys;\n".. + " in the emitted .bib file, these entries are duplicated (using crossref)\n", + e.key) + end + end + emit_tkf.bib(bbl, e.type, e.key, e.fields) + end +end +@ +<>= +for _, e in ipairs(citations) do + if warnings[e] then + for _, w in ipairs(warnings[e]) do emit_warning(unpack(w)) end + end +end +@ +\subsection{Cross-reference} + +If an entry contains a [[crossref]] field, +that field is used as a key to find the parent, and the entry inherits +missing fields from the parent. + +If the parent is cross-referenced sufficiently often (i.e., more than +[[min_crossref]] times), it may be added +to the citation list, in which case the style file knows what to do +with the [[crossref]] field. +But if the parent is not cited sufficiently often, +it disappears, and do does the [[crossref]] field. +<>= +bibtex.doc.do_crossrefs = "citation list -> unit # add crossref'ed fields in place" +function bibtex.do_crossrefs(citations, find_entry) + local map = { } --- key to entry (on citation list) + local xmap = { } --- key to entry (xref'd only) + local xref_count = { } -- entry -> number of times xref'd + <> + for i = 1, table.getn(citations) do + local c = citations[i] + if c.fields.crossref then + local lowref = string.lower(c.fields.crossref) + local parent = map[lowref] or xmap[lowref] + if not parent and find_entry then + parent = find_entry(lowref) + xmap[lowref] = parent + end + if not parent then + biberrorf("Entry %s cross-references to %s, but I can't find %s", + c.key, c.fields.crossref, c.fields.crossref) + c.fields.crossref = nil + else + xref_count[parent] = (xref_count[parent] or 0) + 1 + local fields = c.fields + fields.crossref = parent.key -- force a case match! + for k, v in pairs(parent.fields) do -- inherit field if missing + fields[k] = fields[k] or v + end + end + end + end + <> + <> +end +<>= +for i = 1, table.getn(citations) do + local c = citations[i] + local key = string.lower(c.key) + map[key] = map[key] or c +end +<>= +for _, e in pairs(xmap) do -- includes only missing entries + if xref_count[e] >= min_crossrefs then + table.insert(citations, e) + end +end +<>= +for i = 1, table.getn(citations) do + local c = citations[i] + if c.fields.crossref then + local parent = xmap[string.lower(c.fields.crossref)] + if parent and xref_count[parent] < min_crossrefs then + c.fields.crossref = nil + end + end +end +@ +\subsection{The query engine (i.e., the point of it all)} + +\label{sec:query} + +The query language is described in the man page for [[nbibtex]]. +Its implementation is divided into two parts: +the internal predicates which are composed to form a query predicate, +and the parser that takes a string and produces a query predicate. +Function [[matchq]] is declared [[local]] above and is the only +function visible outside this block. +<>= +do + if not boyer_moore then + require 'boyer-moore' + end + local bm = boyer_moore + local compile = bm.compilenc + local search = bm.matchnc + + -- type predicate = type * field table -> bool + -- val match : field * string -> predicate + -- val author : string -> predicate + -- val matchty : string -> predicate + -- val andp : predicate option * predicate option -> predicate option + -- val orp : predicate option * predicate option -> predicate option + -- val matchq : string -> predicate --- compile query string + + <> + + <> + <> +end +@ +\subsubsection{Query predicates} + +The common case is a predicate for a named field. +We also have some special syntax for ``all fields'' and the \bibtex\ +``type,'' which is not a field. +<>= +local matchty +local function match(field, string) + if string == '' then return nil end + local pat = compile(string) + if field == '*' then + return function (t, fields) + for _, v in pairs(fields) do if search(pat, v) then return true end end + end + elseif field == '[type]' then + return matchty(string) + else + return function (t, fields) return search(pat, fields[field] or '') end + end +end +@ +Here's a type matcher. +<>= +function matchty(string) + if string == '' then return nil end + local pat = compile(string) + return function (t, fields) return search(pat, t) end +end +@ +We make a special case of [[author]] because it really means ``author +or editor.'' +<>= +local function author(string) + if string == '' then return nil end + local pat = compile(string) + return function (t, fields) + return search(pat, fields.author or fields.editor or '') + end +end +@ +We conjoin and disjoin predicates, being careful to use tail calls +(not [[and]] and [[or]]) in order to save stack space. +<>= +local function andp(p, q) + -- associate to right for constant stack space + if not p then + return q + elseif not q then + return p + else + return function (t,f) if p(t,f) then return q(t,f) end end + end +end +<>= +local function orp(p, q) + -- associate to right for constant stack space + if not p then + return q + elseif not q then + return p + else + return function (t,f) if p(t,f) then return true else return q(t,f) end end + end +end +@ +\subsubsection{The query compiler} + +The function [[matchq]] takes the syntax explained in the man page and +produces a predicate. +<>= +function matchq(query) + local find = string.find + local parts = split(query, '%:') + local p = nil + if parts[1] and not find(parts[1], '=') then + <> + table.remove(parts, 1) + if parts[1] and not find(parts[1], '=') then + <> + table.remove(parts, 1) + if parts[1] and not find(parts[1], '=') then + <> + table.remove(parts, 1) + end + end + end + for _, part in ipairs(parts) do + if not find(part, '=') then + biberrorf('bad query %q --- late specs need = sign', query) + else + local _, _, field, words = find(part, '^(.*)=(.*)$') + assert(field and words, 'bug in query parsing') + <> + end + end + if not p then + bibwarnf('empty query---matches everything\n') + return function() return true end + else + return p + end +end +@ +Here's where an unnamed key defaults to author or editor. +<>= +for _, word in ipairs(split(parts[1], '-')) do + p = andp(author(word), p) +end +<>= +local field, words = find(parts[1], '%D') and 'title' or 'year', parts[1] +<> +<>= +if find(parts[1], '%D') then + local ty = nil + for _, word in ipairs(split(parts[1], '-')) do + ty = orp(matchty(word), ty) + end + p = andp(p, ty) --- check type last for efficiency +else + for _, word in ipairs(split(parts[1], '-')) do + p = andp(p, match('year', word)) -- check year last for efficiency + end +end +@ +There could be lots of matches on a year, so we check years last. +<>= +for _, word in ipairs(split(words, '-')) do + if field == 'year' then + p = andp(p, match(field, word)) + else + p = andp(match(field, word), p) + end +end +@ +\subsection{Path search and other system-dependent stuff} + +To find a bib file, I rely on the \texttt{kpsewhich} program, +which is typically found on Unix {\TeX} installations, and which +should guarantee to find the same bib files as normal bibtex. +<>= +assert(io.popen) +local function capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + assert(f:close()) --- can't get an exit code + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +@ +Function [[bibpath]] is normally called on a bibname in a {\LaTeX} +file, but because a bibname may also be given on the command line, +we add \texttt{.bib} only if not already present. +Also, because we can +<>= +bibtex.doc.bibpath = 'string -> string # from \\bibliography name, find pathname of file' +function bibtex.bibpath(bib) + if find(bib, '/') then + local f, msg = io.open(bib) + if not f then + return nil, msg + else + f:close() + return bib + end + else + if not find(bib, '%.bib$') then + bib = bib .. '.bib' + end + local pathname = capture('kpsewhich ' .. bib) + if string.len(pathname) > 1 then + return pathname + else + return nil, 'kpsewhich cannot find ' .. bib + end + end +end +@ +\section{Implementation of \texttt{nbibfind}} + + +\subsection{Output formats for \bibtex\ entries} + +We can emit a \bibtex\ entry in any of three formats: +[[bib]], [[terse]], and [[full]]. +An emitter takes as arguments the type, key, and fields of the entry, +and optionally the name of the file the entry came from. +<>= +local emit_tkf = { } +@ +The simplest entry is legitimate \bibtex\ source: +<>= +function emit_tkf.bib(outfile, type, key, fields) + outfile:write('@', type, '{', key, ',\n') + for k, v in pairs(fields) do + outfile:write(' ', k, ' = {', v, '},\n') + end + outfile:write('}\n\n') +end +@ +For the other two entries, we devise a string format. +In principle, we could go with an ASCII form of a full-blown style, +but since the purpose is to identify the entry in relatively few +characters, it seems sufficient to spit out the author, year, title, +and possibly the source. +``Full'' output shows the whole string; ``terse'' is just the first line. +<>= +do + local function bibstring(type, key, fields, bib) + <> + local names = format_lab_names(fields.author) or + format_lab_names(fields.editor) or + fields.key or fields.organization or '????' + local year = fields.year + local lbl = names .. (year and ' ' .. year or '') + local title = fields.title or '????' + if bib then + key = string.gsub(bib, '.*/', '') .. ': ' .. key + end + local answer = + bib and + string.format('%-25s = %s: %s', key, lbl, title) or + string.format('%-21s = %s: %s', key, lbl, title) + local where = fields.booktitle or fields.journal + if where then answer = answer .. ', in ' .. where end + answer = string.gsub(answer, '%~', ' ') + for _, cs in ipairs { 'texttt', 'emph', 'textrm', 'textup' } do + answer = string.gsub(answer, '\\' .. cs .. '%A', '') + end + answer = string.gsub(answer, '[%{%}]', '') + return answer + end + + function emit_tkf.terse(outfile, type, key, fields, bib) + outfile:write(truncate(bibstring(type, key, fields, bib), 80), '\n') + end + + function emit_tkf.full(outfile, type, key, fields, bib) + local w = bst.writer(outfile) + w:write(bibstring(type, key, fields, bib), '\n') + end +end +@ +<>= +local format_lab_names +do + local fmt = '{vv }{ll}' + local function format_names(s) + local s = bst.commafy(bst.format_names(fmt, bst.namesplit(s))) + return (string.gsub(s, ' and others$', ' et al.')) + end + function format_lab_names(s) + if not s then return s end + local t = bst.namesplit(s) + if table.getn(t) > 3 then + return bst.format_name(fmt, t[1]) .. ' et al.' + else + return format_names(s) + end + end +end +@ +Function [[truncate]] +returns enough of a string to fit in [[n]] columns, with ellipses as +needed. +<>= +local function truncate(s, n) + local l = string.len(s) + if l <= n then + return s + else + return string.sub(s, 1, n-3) .. '...' + end +end +@ +@ +\subsection{Main functions for \texttt{nbibfind}} +<>= +bibtex.doc.run_find = 'string list -> unit # main program for nbibfind' +bibtex.doc.find = 'string * string list -> entry list' + +function bibtex.find(pattern, bibs) + local es = { } + local p = matchq(pattern) + for _, bib in ipairs(bibs) do + local rdr = bibtex.open(bib, bst.months(), hold_warning) + for type, key, fields in entries(rdr) do + if type == nil then + break + elseif not type then + io.stderr:write('Something disastrous happened with entry ', key, '\n') + elseif key == pattern or p(type, fields) then + <> + table.insert(es, { type = type, key = key, fields = fields, + bib = table.getn(bibs) > 1 and bib }) + else + drop_warnings() + end + end + rdr:close() + end + return es +end + +function bibtex.run_find(argv) + local emit = emit_tkf.terse + while argv[1] and find(argv[1], '^-') do + if emit_tkf[string.sub(argv[1], 2)] then + emit = emit_tkf[string.sub(argv[1], 2)] + else + biberrorf('Unrecognized option %s', argv[1]) + end + table.remove(argv, 1) + end + if table.getn(argv) == 0 then + io.stderr:write(string.format('Usage: %s [-bib|-terse|-full] pattern [bibs]\n', + string.gsub(argv[0], '.*/', ''))) + os.exit(1) + end + local pattern = table.remove(argv, 1) + local bibs = { } + <> + + local entries = bibtex.find(pattern, bibs) + for _, e in ipairs(entries) do + emit(io.stdout, e.type, e.key, e.fields, e.bib) + end +end +@ +If we have no arguments, search all available bibfiles. +Otherwise, an argument with a~[[/]] is a pathname, and +an argument without~[[/]] is a name as it would appear in +[[\bibliography]]. +<>= +if table.getn(argv) == 0 then + bibs = all_bibs() +else + for _, a in ipairs(argv) do + if find(a, '/') then + table.insert(bibs, a) + else + table.insert(bibs, assert(bibtex.bibpath(a))) + end + end +end +@ +<>= +local ws = held_warnings() +if ws then + for _, w in ipairs(ws) do + emit_warning(unpack(w)) + end +end +@ +To search all bib files, we lean heavily on \texttt{kpsewhich}, which is +distributed with the Web2C version of {\TeX}, and which knows exactly +which directories to search. +<>= +local function all_bibs() + local pre_path = assert(capture('kpsewhich -show-path bib')) + local path = assert(capture('kpsewhich -expand-path ' .. pre_path)) + local bibs = { } -- list of results + local inserted = { } -- set of inserted bibs, to avoid duplicates + for _, dir in ipairs(split(path, ':')) do + local files = assert(capture('echo ' .. dir .. '/*.bib')) + for _, file in ipairs(split(files, '%s')) do + if readable(file) then + if not (workaround.badbibs and (find(file, 'amsxport%-options') or + find(file, '/plbib%.bib$'))) + then + if not inserted[file] then + table.insert(bibs, file) + inserted[file] = true + end + end + end + end + end + return bibs +end +bibtex.all_bibs = all_bibs +@ Notice the [[workaround.badbibs]], which prevents us from searching +some bogus bibfiles that come with Thomas Esser's te{\TeX}. +@ +It's a pity there's no more efficient way to see if a file is readable +than to try to read it, but that's portability for you. +<>= +local function readable(file) + local f, msg = io.open(file, 'r') + if f then + f:close() + return true + else + return false, msg + end +end +@ + +\section{Support for style files} + +A \bibtex\ style file is used to turn a \bibtex\ entry into {\TeX} or +{\LaTeX} code suitable for inclusion in a bibliography. +It can also be used for many other wondrous purposes, such as +generating HTML for web pages. +In classes \bibtex, each style file is written in a rudimentary, +unnamed, stack-based language, +which is described in a document called ``Designing \bibtex\ Styles,'' +which is often called \texttt{btxhak.dvi}. +One of the benefits of \nbibtex\ is that styles can instead be written +in Lua, which is a much more powerful language---and perhaps even +easier to read. + +But while Lua has amply powerful string-processing primitives, it +lacks some of the primitives that are specific to \bibtex. +Most notable among these primitives is the machinery for parsing and +formatting names (of authors, editors and so on). +That machinery is re-implemented here. +If documentation seems scanty, consult the original \texttt{btxhak}. + +@ +In classic \bibtex, each style is its own separate file. +Here, we share code by allowing a single file to register multiple +styles. +<>= +bibtex.doc.register_style = + [[string * style -> unit # remember style with given name +type style = { emit : outfile * string list * citation list -> unit + , style : table of formatting functions # defined document types + , macros : unit -> macro table + }]] +bibtex.doc.style = 'name -> style # return style with given name, loading on demand' + +do + local styles = { } + + function bibtex.register_style(name, s) + assert(not styles[name], "Duplicate registration of style " .. name) + styles[name] = s + s.name = s.name or name + end + + function bibtex.style(name) + if not styles[name] then + local loaded + if config.nbs then + local loaded = loadfile(config.nbs .. '/' .. name .. '.nbs') + if loaded then loaded() end + end + if not loaded then + require ('nbib-' .. name) + end + if not styles[name] then + bibfatalf('Tried to load a file, but it did not register style %s\n', name) + end + end + return styles[name] + end +end +@ +\subsection{Special string-processing support} + +A great deal of \bibtex's processing depends on giving a special +status to substrings inside braces; +indeed, when such a substring begins with a backslash, it is called a +``special character.'' +Accordingly, we provide a function to search for a pattern +\emph{outside} balanced braces. +<>= +local function find_outside_braces(s, pat, i) + local len = string.len(s) + local j, k = string.find(s, pat, i) + if not j then return j, k end + local jb, kb = string.find(s, '%b{}', i) + while jb and jb < j do --- scan past braces + --- braces come first, so we search again after close brace + local i2 = kb + 1 + j, k = string.find(s, pat, i2) + if not j then return j, k end + jb, kb = string.find(s, '%b{}', i2) + end + -- either pat precedes braces or there are no braces + return string.find(s, pat, j) --- 2nd call needed to get captures +end +@ +\subsubsection{String splitting} + +Another common theme in \bibtex\ is the list represented as string. +A~list of names is represented as a string with individual names +separated by ``and.'' +A~name itself is a list of parts separated by whitespace. +So here are some functions to do general splitting. +When we don't care about the separators, we use [[split]]; +when we care only about the separators, we use [[splitters]]; +and +when we care about both, we use [[odd_even_split]]. +<>= +local function split(s, pat, find) --- return list of substrings separated by pat + find = find or string.find -- could be find_outside_braces + local len = string.len(s) + local t = { } + local insert = table.insert + local i, j, k = 1, true + while j and i <= len + 1 do + j, k = find(s, pat, i) + if j then + insert(t, string.sub(s, i, j-1)) + i = k + 1 + else + insert(t, string.sub(s, i)) + end + end + return t +end +@ +Function [[splitters]] returns a table that, when interleaved with the +result of [[split]], reconstructs the original string. +<>= +local function splitters(s, pat, find) --- return list of separators + find = find or string.find -- could be find_outside_braces + local t = { } + local insert = table.insert + local j, k = find(s, pat, 1) + while j do + insert(t, string.sub(s, j, k)) + j, k = find(s, pat, k+1) + end + return t +end +@ +Function [[odd_even_split]] makes odd entries strings between the +sought-for pattern and even entries the strings that match the pattern. +<>= +local function odd_even_split(s, pat) + local len = string.len(s) + local t = { } + local insert = table.insert + local i, j, k = 1, true + while j and i <= len + 1 do + j, k = find(s, pat, i) + if j then + insert(t, string.sub(s, i, j-1)) + insert(t, string.sub(s, j, k)) + i = k + 1 + else + insert(t, string.sub(s, i)) + end + end + return t +end +@ +As a special case, we may want to pull out brace-delimited substrings: +<>= +local function brace_split(s) return odd_even_split(s, '%b{}') end +@ +Some things need splits. +<>= +<> +@ +\subsubsection{String lengths and widths} + +Function [[text_char_count]] counts characters, +but a special counts as one character. +It is based on \bibtex's [[text.length$]] function. +<>= +local function text_char_count(s) + local n = 0 + local i, last = 1, string.len(s) + while i <= last do + local special, splast, sp = find(s, '(%b{})', i) + if not special then + return n + (last - i + 1) + elseif find(sp, '^{\\') then + n = n + (special - i + 1) -- by statute, it's a single character + i = splast + 1 + else + n = n + (splast - i + 1) - 2 -- don't count braces + i = splast + 1 + end + end + return n +end +bst.text_length = text_char_count +bst.doc.text_length = "string -> int # length (with 'special' char == 1)" +@ +Sometimes we want to know not how many characters are in a string, but +how much space we expect it to take when typeset. +(Or rather, we want to compare such widths to find the widest.) +This is original \bibtex's [[width$]] function. + +The code should use the [[char_width]] array, for which +[[space]] is the only whitespace character given a nonzero printing +width. The widths here are taken from Stanford's June~'87 +$cmr10$~font and represent hundredths of a point (rounded), but since +they're used only for relative comparisons, the units have no meaning. +<>= +do + local char_width = { } + local special_widths = { ss = 500, ae = 722, oe = 778, AE = 903, oe = 1014 } + for i = 0, 255 do char_width[i] = 0 end + local char_width_from_32 = { + 278, 278, 500, 833, 500, 833, 778, 278, 389, 389, 500, 778, 278, 333, + 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, + 278, 778, 472, 472, 778, 750, 708, 722, 764, 681, 653, 785, 750, 361, + 514, 778, 625, 917, 750, 778, 681, 778, 736, 556, 722, 750, 750, + 1028, 750, 750, 611, 278, 500, 278, 500, 278, 278, 500, 556, 444, + 556, 444, 306, 500, 556, 278, 306, 528, 278, 833, 556, 500, 556, 528, + 392, 394, 389, 556, 528, 722, 528, 528, 444, 500, 1000, 500, 500, + } + for i = 1, table.getn(char_width_from_32) do + char_width[32+i-1] = char_width_from_32[i] + end + + bst.doc.width = "string -> faux_points # width of string in 1987 cmr10" + function bst.width(s) + assert(false, 'have not implemented width yet') + end +end +@ +\subsection{Parsing names and lists of names} + +Names in a string are separated by \texttt{and} surrounded by nonnull +whitespace. +Case is not significant. +<>= +local function namesplit(s) + local t = split(s, '%s+[aA][nN][dD]%s+', find_outside_braces) + local i = 2 + while i <= table.getn(t) do + while find(t[i], '^[aA][nN][dD]%s+') do + t[i] = string.gsub(t[i], '^[aA][nN][dD]%s+', '') + table.insert(t, i, '') + i = i + 1 + end + i = i + 1 + end + return t +end +bst.namesplit = namesplit +bst.doc.namesplit = 'string -> list of names # split names on "and"' + +@ +<>= +local sep_and_not_tie = '%-' +local sep_chars = sep_and_not_tie .. '%~' +@ +To parse an individual name, we want to count commas. +We first remove leading white space (and [[sep_char]]s), and trailing +white space (and [[sep_char]]s) and commas, complaining for each +trailing comma. + +We then represent the name as two sequences: [[tokens]] and +[[trailers]]. +The [[tokens]] are the names themselves, and the [[trailers]] are the +separator characters between tokens. +(A~separator is white space, a dash, or a tie, and multiple separators +in sequence are frowned upon.) +The [[commas]] table becomes an array mapping the comma number to the +index of the token that follows it. +<>= +local parse_name +do + local white_sep = '[' .. sep_chars .. '%s]+' + local white_comma_sep = '[' .. sep_chars .. '%s%,]+' + local trailing_commas = '(,[' .. sep_chars .. '%s%,]*)$' + local sep_char = '[' .. sep_chars .. ']' + local leading_white_sep = '^' .. white_sep + + <> + + function parse_name(s, inter_token) + if string.find(s, trailing_commas) then + biberrorf("Name '%s' has one or more commas at the end", s) + end + s = string.gsub(s, trailing_commas, '') + s = string.gsub(s, leading_white_sep, '') + local tokens = split(s, white_comma_sep, find_outside_braces) + local trailers = splitters(s, white_comma_sep, find_outside_braces) + <> + local commas = { } --- maps each comma to index of token the follows it + for i, t in ipairs(trailers) do + string.gsub(t, ',', function() table.insert(commas, i+1) end) + end + local name = { } + <> + return name + end +end +bst.parse_name = parse_name +bst.doc.parse_name = 'string * string option -> name table' +@ +A~name has up to four parts: the most general form is either +``First von Last, Junior'' or +``von Last, First, Junior'', but various vons and Juniors can be +omitted. +The name-parsing algorithm is baroque and is transliterated from the +original \bibtex\ source, but the principle is clear: +assign the full version of each part to the four fields +[[ff]], [[vv]], [[ll]], and [[jj]]; +and +assign an abbreviated version of each part to the fields +[[f]], [[v]], [[l]], and [[j]]. +<>= +local first_start, first_lim, last_lim, von_start, von_lim, jr_lim + -- variables mark subsequences; if start == lim, sequence is empty +local n = table.getn(tokens) +<> + +local commacount = table.getn(commas) +if commacount == 0 then -- first von last jr + von_start, first_start, last_lim, jr_lim = 1, 1, n+1, n+1 + <> +elseif commacount == 1 then -- von last jr, first + von_start, last_lim, jr_lim, first_start, first_lim = + 1, commas[1], commas[1], commas[1], n+1 + divide_von_from_last() +elseif commacount == 2 then -- von last, jr, first + von_start, last_lim, jr_lim, first_start, first_lim = + 1, commas[1], commas[2], commas[2], n+1 + divide_von_from_last() +else + biberrorf("Too many commas in name '%s'") +end +<> +@ +The von name, if any, goes from the first von token to the last von +token, except the last name is entitled to at least one token. +So to find the limit of the von name, we start just before the last +token and wind down until we find a von token or we hit the von start +(in which latter case there is no von name). +<>= +function divide_von_from_last() + von_lim = last_lim - 1; + while von_lim > von_start and not isVon(tokens[von_lim-1]) do + von_lim = von_lim - 1 + end +end +@ +OK, here's one form. +<>= +local got_von = false +while von_start < last_lim-1 do + if isVon(tokens[von_start]) then + divide_von_from_last() + got_von = true + break + else + von_start = von_start + 1 + end +end +if not got_von then -- there is no von name + while von_start > 1 and find(trailers[von_start - 1], sep_and_not_tie) do + von_start = von_start - 1 + end + von_lim = von_start +end +first_lim = von_start +@ +The last name starts just past the last token, before the first +comma (if there is no comma, there is deemed to be one at the end +of the string), for which there exists a first brace-level-0 letter +(or brace-level-1 special character), and it's in lower case, unless +this last token is also the last token before the comma, in which +case the last name starts with this token (unless this last token is +connected by a [[sep_char]] other than a [[tie]] to the previous token, in +which case the last name starts with as many tokens earlier as are +connected by non[[tie]]s to this last one (except on Tuesdays +$\ldots\,$), although this module never sees such a case). Note that +if there are any tokens in either the von or last names, then the last +name has at least one, even if it starts with a lower-case letter. +@ +The string separating tokens is reduced to a single ``separator +character.'' +A~comma always trumps other separator characters. +Otherwise, if there's no comma, we take the first character, be it a +separator or a space. +(Patashnik considers that multiple such characters constitute +``silliness'' on the user's part.) +<>= +for i = 1, table.getn(trailers) do + local s = trailers[i] + assert(string.len(s) > 0) + if find(s, ',') then + trailers[i] = ',' + else + trailers[i] = string.sub(s, 1, 1) + end +end +@ +<>= +<> +set_name(first_start, first_lim, 'ff', 'f') +set_name(von_start, von_lim, 'vv', 'v') +set_name(von_lim, last_lim, 'll', 'l') +set_name(last_lim, jr_lim, 'jj', 'j') +@ +We set long and short forms together; [[ss]]~is the long form and +[[s]]~is the short form. +<>= +local function set_name(start, lim, long, short) + if start < lim then + -- string concatenation is quadratic, but names are short + <> + local ss = tokens[start] + local s = abbrev(tokens[start]) + for i = start + 1, lim - 1 do + if inter_token then + ss = ss .. inter_token .. tokens[i] + s = s .. inter_token .. abbrev(tokens[i]) + else + local ssep, nnext = trailers[i-1], tokens[i] + local sep, next = ssep, abbrev(nnext) + <> + ss = ss .. ssep .. nnext + s = s .. '.' .. sep .. next + end + end + name[long] = ss + name[short] = s + end +end +@ +Here is the default for a character between tokens: +a~tie is the default space character between the last two tokens of +the name part, and between the first two tokens if the first token is +short enough; otherwise, a space is the default. +<>= +if find(sep, sep_char) then + -- do nothing; sep is OK +elseif i == lim-1 then + sep, ssep = '~', '~' +elseif i == start + 1 then + sep = text_char_count(s) < 3 and '~' or ' ' + ssep = text_char_count(ss) < 3 and '~' or ' ' +else + sep, ssep = ' ', ' ' +end +@ +The von name starts with the first token satisfying [[isVon]], +unless that is the last token. +A~``von token'' is simply one that begins with a lower-case +letter---but those damn specials complicate everything. +<>= +local upper_specials = { OE = true, AE = true, AA = true, O = true, L = true } +local lower_specials = { i = true, j = true, oe = true, ae = true, aa = true, + o = true, l = true, ss = true } +<>= +function isVon(s) + local lower = find_outside_braces(s, '%l') -- first nonbrace lowercase + local letter = find_outside_braces(s, '%a') -- first nonbrace letter + local bs, ebs, command = find_outside_braces(s, '%{%\\(%a+)') -- \xxx + if lower and lower <= letter and lower <= (bs or lower) then + return true + elseif letter and letter <= (bs or letter) then + return false + elseif bs then + if upper_specials[command] then + return false + elseif lower_specials[command] then + return true + else + local close_brace = find_outside_braces(s, '%}', ebs+1) + lower = find(s, '%l') -- first nonbrace lowercase + letter = find(s, '%a') -- first nonbrace letter + return lower and lower <= letter + end + else + return false + end +end +@ +An abbreviated token is the first letter of a token, except again we +have to deal with the damned specials. +<>= +local function abbrev(token) + local first_alpha, _, alpha = find(token, '(%a)') + local first_brace = find(token, '%{%\\') + if first_alpha and first_alpha <= (first_brace or first_alpha) then + return alpha + elseif first_brace then + local i, j, special = find(token, '(%b{})', first_brace) + if i then + return special + else -- unbalanced braces + return string.sub(token, first_brace) + end + else + return '' + end +end +@ +\subsection{Formatting names} + +Lacking Lua's string-processing utilities, classic \bibtex\ defines a +way of converting a ``format string'' and a name into a formatted +name. +I~find this formatting technique painful, but I also wanted to preserve +compatibility with existing bibliography styles, so I've implemented +it as accurately as I~can. + +The interface is not quite identical to classic \bibtex; +a style can use [[namesplit]] to split names and then +[[format_name]] to format a single one, +or it can throw caution to the winds and call [[format_names]] to +format a whole list of names. +<>= +bst.doc.format_names = "format * name list -> string list # format each name in list" +function bst.format_names(fmt, t) + local u = { } + for i = 1, table.getn(t) do + u[i] = bst.format_name(fmt, t[i]) + end + return u +end +@ +A \bibtex\ format string contains its variable elements inside braces. +Thus, we format a name by replacing each braced substring of the +format string. +<>= +do + local good_keys = { ff = true, vv = true, ll = true, jj = true, + f = true, v = true, l = true, j = true, } + + bst.doc.format_name = "format * name -> string # format 1 name as in bibtex" + function bst.format_name(fmt, name) + local t = type(name) == 'table' and name or parse_name(name) + -- at most one of the important letters, perhaps doubled, may appear + local function replace_braced(s) + local i, j, alpha = find_outside_braces(s, '(%a+)', 2) + if not i then + return '' --- can never be printed, but who are we to complain? + elseif not good_keys[alpha] then + biberrorf ('The format string %q has an illegal brace-level-1 letter', s) + elseif find_outside_braces(s, '%a+', j+1) then + biberrorf ('The format string %q has two sets of brace-level-1 letters', s) + elseif t[alpha] then + local k = j + 1 + local t = t + <> + local head, tail = string.sub(s, 2, i-1) .. t[alpha], string.sub(s, k, -2) + <> + return head .. tail + else + return '' + end + end + return (string.gsub(fmt, '%b{}', replace_braced)) + end +end +@ +<>= +local kk, jj = find(s, '%b{}', k) +if kk and kk == k then + k = jj + 1 + if type(name) == 'string' then + t = parse_name(name, string.sub(s, kk+1, jj-1)) + else + error('Style error -- used a pre-parsed name with non-standard inter-token format string') + end +end +@ +<>= +if find(tail, '%~%~$') then + tail = string.sub(tail, 1, -2) -- denotes hard tie +elseif find(tail, '%~$') then + if text_char_count(head) + text_char_count(tail) - 1 >= 3 then + tail = string.gsub(tail, '%~$', ' ') + end +end +@ +\subsection{Line-wrapping output} + +EXPLAIN THIS INTERFACE!!! + +My [[max_print_line]] appears to be off by one from Oren Patashnik's. +<>= +local min_print_line, max_print_line = 3, 79 +bibtex.hard_max = max_print_line +bibtex.doc.hard_max = 'int # largest line that avoids a forced line break (for wizards)' +bst.doc.writer = "io-handle * int option -> object # result:write(s) buffers and breaks lines" +function bst.writer(out, indent) + indent = indent or 2 + assert(indent + 10 < max_print_line) + indent = string.rep(' ', indent) + local gsub = string.gsub + local buf = '' + local function write(self, ...) + local s = table.concat { ... } + local lines = split(s, '\n') + lines[1] = buf .. lines[1] + buf = table.remove(lines) + for i = 1, table.getn(lines) do + local line = lines[i] + if not find(line, '^%s+$') then -- no line of just whitespace + line = gsub(line, '%s+$', '') + while string.len(line) > max_print_line do + <> + end + out:write(line, '\n') + end + end + end + assert(out.write, "object passed to bst.writer does not have a write method") + return { write = write } +end +<>= +local last_pre_white, post_white +local i, j, n = 1, 1, string.len(line) +while i and i <= n and i <= max_print_line do + i, j = find(line, '%s+', i) + if i and i <= max_print_line + 1 then + if i > min_print_line then last_pre_white, post_white = i - 1, j + 1 end + i = j + 1 + end +end +if last_pre_white then + out:write(string.sub(line, 1, last_pre_white), '\n') + if post_white > max_print_line + 2 then + post_white = max_print_line + 2 -- bug-for-bug compatibility with bibtex + end + line = indent .. string.sub(line, post_white) +elseif n < bibtex.hard_max then + out:write(line, '\n') + line = '' +else -- ``unbreakable'' + out:write(string.sub(line, 1, bibtex.hard_max-1), '%\n') + line = string.sub(line, bibtex.hard_max) +end +@ +<>= +assert(min_print_line >= 3) +assert(max_print_line > min_print_line) +@ +\subsection{Functions copied from classic \bibtex} + +\paragraph{Adding a period} +Find the last non-[[}]] character, and if it is not a sentence +terminator, add a period. +<>= +do + local terminates_sentence = { ["."] = true, ["?"] = true, ["!"] = true } + + bst.doc.add_period = "string -> string # add period unless already .?!" + function bst.add_period(s) + local _, _, last = find(s, '([^%}])%}*$') + if last and not terminates_sentence[last] then + return s .. '.' + else + return s + end + end +end +@ +\paragraph{Case-changing} + +Classic \bibtex\ has a [[change.case$]] function, which takes an +argument telling whether to change to lower case, upper case, or +``title'' case (which has initial letters capitalized). +Because Lua supports first-class functions, it makes more sense just +to export three functions: [[lower]], [[title]], and [[upper]]. +<>= +do + bst.doc.lower = "string -> string # lower case according to bibtex rules" + bst.doc.upper = "string -> string # upper case according to bibtex rules" + bst.doc.title = "string -> string # title case according to bibtex rules" + + <> + + <> +end +@ +Case conversion is complicated by the presence of brace-delimited +sequences, especially since there is one set of conventions for a ``special +character'' (brace-delimited sequence beginning with {\TeX} control +sequence) and +another set of conventions for other brace-delimited sequences. +To deal with them, we typically do an ``odd-even split'' on balanced +braces, +then apply a ``normal'' conversion function to the odd elements and a +``special'' conversion function to the even elements. +The application is done by [[oeapp]]. +<>= +local function oeapp(f, g, t) + for i = 1, table.getn(t), 2 do + t[i] = f(t[i]) + end + for i = 2, table.getn(t), 2 do + t[i] = g(t[i]) + end + return t +end +@ +Upper- and lower-case conversion are easiest. +Non-specials are hit directly with [[string.lower]] or +[[string.upper]]; +for special characters, we use utility called [[convert_special]]. +<>= +local lower_special = convert_special(string.lower) +local upper_special = convert_special(string.upper) + +function bst.lower(s) + return table.concat(oeapp(string.lower, lower_special, brace_split(s))) +end + +function bst.upper(s) + return table.concat(oeapp(string.upper, upper_special, brace_split(s))) +end +@ +Here is [[convert_special]]. +If a special begins with an alphabetic control sequence, we convert +only elements between control sequences. +If a special begins with a nonalphabetic control sequence, we convert +the whole special as usual. +Finally, if a special does not begin with a control sequence, we leave +it the hell alone. +(This is the convention that allows us to put [[{FORTRAN}]] in a +\bibtex\ entry and be assured that capitalization is not lost.) +<>= +function convert_special(cvt) + return function(s) + if find(s, '^{\\(%a+)') then + local t = odd_even_split(s, '\\%a+') + for i = 1, table.getn(t), 2 do + t[i] = cvt(t[i]) + end + return table.concat(t) + elseif find(s, '^{\\') then + return cvt(s) + else + return s + end + end +end +@ +Title conversion doesn't fit so nicely into the framework. + +Function [[lower_later]] lowers all but the first letter of a string. +<>= +local function lower_later(s) + return string.sub(s, 1, 1) .. string.lower(string.sub(s, 2)) +end +@ +For title conversion, we don't mess with a token that follows a colon. +Hence, we must maintain [[prev]] and can't use [[convert_special]]. +<>= +local function title_special(s, prev) + if find(prev, ':%s+$') then + return s + else + if find(s, '^{\\(%a+)') then + local t = odd_even_split(s, '\\%a+') + for i = 1, table.getn(t), 2 do + local prev = t[i-1] or prev + if find(prev, ':%s+$') then + assert(false, 'bugrit') + else + t[i] = string.lower(t[i]) + end + end + return table.concat(t) + elseif find(s, '^{\\') then + return string.lower(s) + else + return s + end + end +end +@ +Internal function [[recap]] deals with the damn colons. +<>= +function bst.title(s) + local function recap(s, first) + local parts = odd_even_split(s, '%:%s+') + parts[1] = first and lower_later(parts[1]) or string.lower(parts[1]) + for i = (first and 3 or 1), table.getn(parts), 2 do + parts[i] = lower_later(parts[i]) + end + return table.concat(parts) + end + local t = brace_split(s) + for i = 1, table.getn(t), 2 do -- elements outside specials get recapped + t[i] = recap(t[i], i == 1) + end + for i = 2, table.getn(t), 2 do -- specials are, well, special + local prev = t[i-1] + if i == 2 and not find(prev, '%S') then prev = ': ' end + t[i] = title_special(t[i], prev) + end + return table.concat(t) +end +@ +\paragraph{Purification} + +Purification (classic [[purify$]]) involves removing non-alphanumeric +characters. +Each sequence of ``separator'' characters becomes a single space. +<>= +do + bst.doc.purify = "string -> string # remove nonalphanumeric, non-sep chars" + local high_alpha = string.char(128) .. '-' .. string.char(255) + local sep_white_char = '[' .. sep_chars .. '%s]' + local disappears = '[^' .. sep_chars .. high_alpha .. '%s%w]' + local gsub = string.gsub + local function purify(s) + return gsub(gsub(s, sep_white_char, ' '), disappears, '') + end + -- special characters are purified by removing all non-alphanumerics, + -- including white space and sep-chars + local function spurify(s) + return gsub(s, '[^%w' .. high_alpha .. ']+', '') + end + local purify_all_chars = { oe = true, OE = true, ae = true, AE = true, ss = true } + + function bst.purify(s) + local t = brace_split(s) + for i = 1, table.getn(t) do + local _, k, cmd = find(t[i], '^{\\(%a+)%s*') + if k then + if lower_specials[cmd] or upper_specials[cmd] then + if not purify_all_chars[cmd] then + cmd = string.sub(cmd, 1, 1) + end + t[i] = cmd .. spurify(string.sub(t[i], k+1)) + else + t[i] = spurify(string.sub(t[i], k+1)) + end + elseif find(t[i], '^{\\') then + t[i] = spurify(t[i]) + else + t[i] = purify(t[i]) + end + end + return table.concat(t) + end +end +@ +\paragraph{Text prefix} + +Function [[text_prefix]] (classic [[text.prefix$]]) takes an initial +substring of a string, with the proviso that a \bibtex\ ``special +character'' sequence counts as a single character. +<>= +bst.doc.text_prefix = "string * int -> string # take first n chars with special == 1" +function bst.text_prefix(s, n) + local t = brace_split(s) + local answer, rem = '', n + for i = 1, table.getn(t), 2 do + answer = answer .. string.sub(t[i], 1, rem) + rem = rem - string.len(t[i]) + if rem <= 0 then return answer end + if find(t[i+1], '^{\\') then + answer = answer .. t[i+1] + rem = rem - 1 + else + <> + end + end + return answer +end +<>= +local s = t[i+1] +local braces = 0 +local sub = string.sub +for i = 1, string.len(s) do + local c = sub(s, i, i) + if c == '{' then + braces = braces + 1 + elseif c == '}' then + braces = braces + 1 + else + rem = rem - 1 + if rem == 0 then + return answer .. string.sub(s, 1, i) .. string.rep('}', braces) + end + end +end +answer = answer .. s +@ +\paragraph{Emptiness test} + +Function [[empty]] (classic [[empty$]]) tells if a value is empty; +i.e., it is missing (nil) or it is only white space. +<>= +bst.doc.empty = "string option -> bool # is string there and holding nonspace?" +function bst.empty(s) + return s == nil or not find(s, '%S') +end +@ +@ +\subsection{Other utilities} + +\paragraph{A stable sort} + +Function [[bst.sort]] is like [[table.sort]] only stable. +It is needed because classic \bibtex\ uses a stable sort. +Its interface is the same as [[table.sort]]. +<>= +bst.doc.sort = 'value list * compare option # like table.sort, but stable' +function bst.sort(t, lt) + lt = lt or function(x, y) return x < y end + local pos = { } --- position of each element in original table + for i = 1, table.getn(t) do pos[t[i]] = i end + local function nlt(x, y) + if lt(x, y) then + return true + elseif lt(y, x) then + return false + else -- elements look equal + return pos[x] < pos[y] + end + end + return table.sort(t, nlt) +end +bst.doc.sort = 'value list * compare option -> unit # stable sort' +@ +\paragraph{The standard months} + +Every style is required to recognize the months, so we make it easy to +create a fresh table with either full or abbreviated months. +<>= +bst.doc.months = "string option -> table # macros table containing months" +function bst.months(what) + local m = { + jan = "January", feb = "February", mar = "March", apr = "April", + may = "May", jun = "June", jul = "July", aug = "August", + sep = "September", oct = "October", nov = "November", dec = "December" } + if what == 'short' or what == 3 then + for k, v in pairs(m) do + m[k] = string.sub(v, 1, 3) + end + end + return m +end +@ +\paragraph{Comma-separated lists} + +The function [[commafy]] takes a list and inserts commas and +[[and]] (or [[or]]) using American conventions. +For example, +\begin{quote} +[[commafy { 'Graham', 'Knuth', 'Patashnik' }]] +\end{quote} +returns [['Graham, Knuth, and Patashnik']], +but +\begin{quote} +[[commafy { 'Knuth', 'Plass' }]] +\end{quote} +returns [['Knuth and Plass']]. +<>= +bst.doc.commafy = "string list -> string # concat separated by commas, and" +function bst.commafy(t, andword) + andword = andword or 'and' + local n = table.getn(t) + if n == 1 then + return t[1] + elseif n == 2 then + return t[1] .. ' ' .. andword .. ' ' .. t[2] + else + local last = t[n] + t[n] = andword .. ' ' .. t[n] + local answer = table.concat(t, ', ') + t[n] = last + return answer + end +end +@ +\section{Testing and so on} + +Here are a couple of test functions I used during development that I +thought might be worth keeping around. +<>= +bibtex.doc.cat = 'string -> unit # emit the named bib file in bib format' +function bibtex.cat(bib) + local rdr = bibtex.open(bib, bst.months()) + if not rdr then + rdr = assert(bibtex.open(assert(bibtex.bibpath(bib)), bst.months())) + end + for type, key, fields in entries(rdr) do + if type == nil then + break + elseif not type then + io.stderr:write('Error on key ', key, '\n') + else + emit_tkf.bib(io.stdout, type, key, fields) + end + end + bibtex.close(rdr) +end +@ +<>= +bibtex.doc.count = 'string list -> unit # take list of bibs and print number of entries' +function bibtex.count(argv) + local bibs = { } + local macros = { } + local n = 0 + <> + local function warn() end + for _, bib in ipairs(bibs) do + local rdr = bibtex.open(bib, macros) + for type, key, fields in entries(rdr) do + if type == nil then + break + elseif type then + n = n + 1 + end + end + rdr:close() + end + printf("%d\n", n) +end +@ +<>= +bibtex.doc.all_entries = "bibname * macro-table -> preamble * citation list" +function bibtex.all_entries(bib, macros) + macros = macros or bst.months() + warn = warn or emit_warning + local rdr = bibtex.open(bib, macros, warn) + if not rdr then + rdr = assert(bibtex.open(assert(bibtex.bibpath(bib)), macros, warn), + "could not open bib file " .. bib) + end + local cs = { } + local seen = { } + for type, key, fields in entries(rdr) do + if type == nil then + break + elseif not type then + io.stderr:write(key, '\n') + elseif not seen[key] then + seen[key] = true + table.insert(cs, { type = type, key = key, fields = fields, file = bib, + line = rdr.entry_line }) + end + end + local p = assert(rdr.preamble) + rdr:close() + return p, cs +end +@ +\section{Laundry list} + +THINGS TO DO: +\begin{itemize} +\item TRANSITION THE C~CODE TO LUA NATIVE ERROR HANDLING ([[luaL_error]] and [[pcall]]) +\item NO WARNING FOR DUPLICATE FIELDS NOT DEFINED IN .BST? +\item STANDARD WARNING FOR REPEATED ENTRY? +\item +NOT ENFORCED: An entry type must be +defined in the \texttt{.bst} file if this entry is to be included in the +reference list. +\item +THE WHOLE BST-SEARCH THING NEEDS MORE CARE. + + BibTeX searches the directories in the path defined by the BSTINPUTS + environment variable for .bst files. If BSTINPUTS is not set, it uses + the system default. For .bib files, it uses the BIBINPUTS environment + variable if that is set, otherwise the default. See tex(1) for the + details of the searching. + + If the environment variable TEXMFOUTPUT is set, BibTeX attempts to put + its output files in it, if they cannot be put in the current directory. + Again, see tex(1). No special searching is done for the .aux file. +\item +RATIONALIZE ERROR MACHINERY WITH WARNING, ERROR, AND FATAL CASES -- +AND COUNTS. +\item +Here are some things that \bibtex\ does that \nbibtex\ should do: +\begin{enumerate} +\item +Writes a log file +\item +Counts warnings, or if there is an error, counts errors instead +\end{enumerate} +\end{itemize} + + +\end{document} +@ diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/pairs.Rd b/layers.personal/misctools/my-polymode/local/polymode/samples/pairs.Rd new file mode 100644 index 0000000..da831a2 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/pairs.Rd @@ -0,0 +1,102 @@ +% File src/library/graphics/man/pairs.Rd +% Part of the R package, http://www.R-project.org +% Copyright 1995-2007 R Core Team +% Distributed under GPL 2 or later + +\name{pairs} +\alias{pairs} +\alias{pairs.default} +\alias{pairs.formula} + +\title{Scatterplot Matrices} +\description{ + A matrix of scatterplots is produced. +} +\usage{ +pairs(x, \dots) + +\method{pairs}{formula}(formula, data = NULL, \dots, subset, + na.action = stats::na.pass) + +\method{pairs}{default}(x, labels, panel = points, \dots, + lower.panel = panel, upper.panel = panel, + diag.panel = NULL, text.panel = textPanel, + label.pos = 0.5 + has.diag/3, + cex.labels = NULL, font.labels = 1, + row1attop = TRUE, gap = 1) +} +\arguments{ + \item{x}{the coordinates of points given as numeric columns of a + matrix or dataframe. Logical and factor columns are converted to + numeric in the same way that \code{\link{data.matrix}} does. + } + \item{formula}{a formula, such as \code{~ x + y + z}. Each term will + give a separate variable in the pairs plot, so terms should be + numeric vectors. (A response will be interpreted as another + variable, but not treated specially, so it is confusing to use one.)} + \item{data}{a data.frame (or list) from which the variables in + \code{formula} should be taken.} + \item{subset}{an optional vector specifying a subset of observations + to be used for plotting.} + ..... +} +\details{ + The \eqn{ij}th scatterplot contains \code{x[,i]} plotted against + \code{x[,j]}. The scatterplot can be customised by setting panel + functions to appear as something completely different. The + off-diagonal panel functions are passed the appropriate columns of + \code{x} as \code{x} and \code{y}: the diagonal panel function (if + any) is passed a single column, and the \code{text.panel} function is + passed a single \code{(x, y)} location and the column name. + + ..... +} +\author{ + Enhancements for \R 1.0.0 contributed by Dr. Jens + Oehlschlaegel-Akiyoshi and R-core members. +} +\references{ + Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) + \emph{The New S Language}. + Wadsworth & Brooks/Cole. +} +\examples{ +pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species", + pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)]) + +## formula method +pairs(~ Fertility + Education + Catholic, data = swiss, + subset = Education < 20, main = "Swiss data, Education < 20") + +pairs(USJudgeRatings) + +## put histograms on the diagonal +panel.hist <- function(x, ...) +{ + usr <- par("usr"); on.exit(par(usr)) + par(usr = c(usr[1:2], 0, 1.5) ) + h <- hist(x, plot = FALSE) + breaks <- h$breaks; nB <- length(breaks) + y <- h$counts; y <- y/max(y) + rect(breaks[-nB], 0, breaks[-1], y, col = "cyan", ...) +} +pairs(USJudgeRatings[1:5], panel = panel.smooth, + cex = 1.5, pch = 24, bg = "light blue", + diag.panel = panel.hist, cex.labels = 2, font.labels = 2) + +## put (absolute) correlations on the upper panels, +## with size proportional to the correlations. +panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...) +{ + usr <- par("usr"); on.exit(par(usr)) + par(usr = c(0, 1, 0, 1)) + r <- abs(cor(x, y)) + txt <- format(c(r, 0.123456789), digits = digits)[1] + txt <- paste(prefix, txt, sep = "") + if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt) + text(0.5, 0.5, txt, cex = cex.cor * r) +} +pairs(USJudgeRatings, lower.panel = panel.smooth, upper.panel = panel.cor) +} + +\keyword{hplot} diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/rcpp.Rcpp b/layers.personal/misctools/my-polymode/local/polymode/samples/rcpp.Rcpp new file mode 100644 index 0000000..17aff02 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/rcpp.Rcpp @@ -0,0 +1,52 @@ +## C ++ R is not working properly. + + +signR <- function(x) { + if (x > 0) { + 1 + } else if (x == 0) { + 0 + } else{ + -1, + } +} + "sdfd" 'sdfd' + < sdfds > + +cppFunction(' + +int signnC(int x) { + if (x > 0) { + n return 1; + } else if (x == 0) { + return 0; + } else { + return -1; + } +} + +') + +sdf <- sfds + +sfdds <- 343 + +sdfd + + + +cppFunction(' + +int signnC(int x) { + if (x > 0) { + n return 1; + } else if (x == 0) { + return 0; + } else { + return -1; + } +} + +') + + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/readme.md b/layers.personal/misctools/my-polymode/local/polymode/samples/readme.md new file mode 100644 index 0000000..987329b --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/readme.md @@ -0,0 +1,6 @@ + +Most of these examples are collected from elsewhere: + + * [knitr-examples](https://github.com/yihui/knitr-examples) + * [rcpp-gallery](https://github.com/jjallaire/rcpp-gallery) + * [nXhtml tests](http://bazaar.launchpad.net/~nxhtml/nxhtml/main/files/835/tests) diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/slim.html.slim b/layers.personal/misctools/my-polymode/local/polymode/samples/slim.html.slim new file mode 100644 index 0000000..75daa3d --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/slim.html.slim @@ -0,0 +1,20 @@ +doctype html +html + head + | Head stuff + + body + .body: markdown: + # An awesome header + ## Subheading one + Awesome Text + [stuff](Other Stuff) + button#clicky + +coffee: + $('#clicky').click -> + elem = $(this) + this.text "Something Fantastic + +ruby: + SomethingUnwise.call_at :the_wrong_place diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/sorting.cppR b/layers.personal/misctools/my-polymode/local/polymode/samples/sorting.cppR new file mode 100644 index 0000000..f15380c --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/sorting.cppR @@ -0,0 +1,124 @@ +/** + * @title Sorting Numeric Vectors in C++ and R + * @author Ross Bennett + * @license GPL (>= 2) + * @tags stl benchmark + * @summary Illustrates the comparison of different sorting algorithms with R + * and the C++ STL. + */ + +/** + * Consider the problem to sort all elements of the given vector in ascending + * order. We can simply use the function `std::sort` from the C++ STL. + */ + +#include +using namespace Rcpp; + +// [[Rcpp::export]] +NumericVector stl_sort(NumericVector x) { + NumericVector y = clone(x); + std::sort(y.begin(), y.end()); + return y; +} + + /*** R + library(rbenchmark) + set.seed(123) + z <- rnorm(100000) + x <- rnorm(100) + + ## check that stl_sort is the same as sort + stopifnot(all.equal(stl_sort(x), sort(x))) + + ## benchmark stl_sort and sort + benchmark(stl_sort(z), sort(z), order="relative")[,1:4] + */ + +/** + * Consider the problem of sorting the first `n` elements of a given vector. + * The function `std::partial_sort` from the C++ STL does just this. + */ + +// [[Rcpp::export]] +NumericVector stl_partial_sort(NumericVector x, int n) { + NumericVector y = clone(x); + std::partial_sort(y.begin(), y.begin()+n, y.end()); + return y; +} + +/** + * An alternate implementation of a partial sort algorithm is to use + * `std::nth_element` to partition the given vector at the nth sorted + * element and then use `std::sort`, both from the STL, to sort the vector + * from the beginning to the nth element. + * + * For an equivalent implementation in R, we can use the `sort` function by + * specifying a vector of `1:n` for the partial argument (i.e. `partial=1:n`). + */ + +// [[Rcpp::export]] +NumericVector nth_partial_sort(NumericVector x, int nth) { + NumericVector y = clone(x); + std::nth_element(y.begin(), y.begin()+nth, y.end()); + std::sort(y.begin(), y.begin()+nth); + return y; +} + +/*** R +n <- 25000 + +# check that stl_partial_sort is equal to nth_partial_sort +stopifnot(all.equal(stl_partial_sort(x, 50)[1:50], + nth_partial_sort(x, 50)[1:50])) + +# benchmark stl_partial_sort, nth_element_sort, and sort +benchmark(stl_partial_sort(z, n), + nth_partial_sort(z, n), + sort(z, partial=1:n), + order="relative")[,1:4] +*/ + +/** + * An interesting result to note is the gain in speed of + * `nth_partial_sort` over `stl_partial_sort`. In this case, for the given + * data, it is faster to use the combination of`std::nth_element` and + * `std::sort` rather than `std::partial_sort` to sort the first `n` elements + * of a vector. + */ + +// [[Rcpp::export]] +NumericVector stl_nth_element(NumericVector x, int n) { + NumericVector y = clone(x); + std::nth_element(y.begin(), y.begin()+n, y.end()); + return y; +} + +/** + * Finally, consider a problem where you only need a single element of a + * sorted vector. The function `std::nth_element` from the C++ STL does just + * this. An example of this type of problem is computing the median of a given + * vector. + * + * For an equivalent implementation in R, we can use the `sort` function by + * specifying a scalar value for the argument partial (i.e. `partial=n`). + */ + +/*** R +# check that the nth sorted elements of the vectors are equal +stopifnot(all.equal(stl_nth_element(x, 43)[43], sort(x, partial=43)[43])) + +# benchmark nth_element and sort +benchmark(stl_nth_element(z, n), + sort(z, partial=n), + order="relative")[,1:4] +*/ + + +/** + * While these are not huge speed improvements over the base R sort function, + * this post demonstrates how to easily access sorting functions in the C++ + * STL and is a good exercise to better understand the differences and + * performance of the sorting algorithms available in C++ and R. + */ + diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/subset.Rmd b/layers.personal/misctools/my-polymode/local/polymode/samples/subset.Rmd new file mode 100644 index 0000000..899159f --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/subset.Rmd @@ -0,0 +1,94 @@ +% Title +% Author +% March 29, 2013 + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad +minim veniam, quis nostrud exercitation ullamco laboris nisi ut +aliquip ex ea commodo consequat. Duis aute irure dolor in +reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla +pariatur. Excepteur sint occaecat cupidatat non proident, sunt in +culpa qui officia deserunt mollit anim id est laborum. + +```{r test1} +1+1 +bla[[i]] +``` + +Sed ut perspiciatis unde omnis iste natus error sit voluptatem +accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae +ab illo inventore veritatis et quasi architecto beatae vitae dicta +sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit +aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos +qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui +dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed +quia non numquam eius modi tempora incidunt ut labore et dolore magnam +aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum +exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex +ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in +ea voluptate velit esse quam nihil molestiae consequatur, vel illum +qui dolorem eum fugiat quo voluptas nulla pariatur? + +```{r test2, include = FALSE} +2+2 +``` + +Non eram nescius, Brute, cum, quae summis ingeniis exquisitaque +doctrina philosophi Graeco sermone tractavissent, ea Latinis litteris +mandaremus, fore ut hic noster labor in varias reprehensiones +incurreret. nam quibusdam, et iis quidem non admodum indoctis, totum +hoc displicet philosophari. quidam autem non tam id reprehendunt, si +remissius agatur, sed tantum studium tamque multam operam ponendam in +eo non arbitrantur. erunt etiam, et ii quidem eruditi Graecis +litteris, contemnentes Latinas, qui se dicant in Graecis legendis +operam malle consumere. postremo aliquos futuros suspicor, qui me ad +alias litteras vocent, genus hoc scribendi, etsi sit elegans, personae +tamen et dignitatis esse negent. + +At vero eos et accusamus et iusto odio dignissimos ducimus qui +blanditiis praesentium voluptatum deleniti atque corrupti quos dolores +et quas molestias excepturi sint occaecati cupiditate non provident, +similique sunt in culpa qui officia deserunt mollitia animi, id est +laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita +distinctio. Nam libero tempore, cum soluta nobis est eligendi optio +cumque nihil impedit quo minus id quod maxime placeat facere possimus, +omnis voluptas assumenda est, omnis dolor repellendus. Temporibus +autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe +eveniet ut et voluptates repudiandae sint et molestiae non +recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut +creiciendis voluptatibus maiores alias consequatur aut perferendis +doloribus asperiores repellat. + +Contra quos omnis dicendum breviter existimo. Quamquam philosophiae +quidem vituperatoribus satis responsum est eo libro, quo a nobis +philosophia defensa et collaudata est, cum esset accusata et +vituperata ab Hortensio. qui liber cum et tibi probatus videretur et +iis, quos ego posse iudicare arbitrarer, plura suscepi veritus ne +movere hominum studia viderer, retinere non posse. Qui autem, si +maxime hoc placeat, moderatius tamen id volunt fieri, difficilem +quandam temperantiam postulant in eo, quod semel admissum coerceri +reprimique non potest, ut propemodum iustioribus utamur illis, qui +omnino avocent a philosophia, quam his, qui rebus infinitis modum +constituant reque eo, quo sit , mediocritatem + +desiderent. + +```R +aa <- function(x){ + x + 3 +} +aa(2) +``` + +```{r test3} +bb <- 3+3 +bb[[1]] +``` + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do +eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad +minim veniam, quis nostrud exercitation ullamco laboris nisi ut +aliquip ex ea commodo consequat. Duis aute irure dolor in +reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla +pariatur. Excepteur sint occaecat cupidatat non proident, sunt in +culpa qui officia deserunt mollit anim id est laborum. diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/test.Rmd b/layers.personal/misctools/my-polymode/local/polymode/samples/test.Rmd new file mode 100644 index 0000000..ed3091b --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/test.Rmd @@ -0,0 +1,42 @@ +# Evaluate and echo different lines + +For demonstration purposes, we may want to show some source code in the output, +but really evaluate different code in the background. + +```{r} +hook_source <- knit_hooks$get('source') +knit_hooks$set(source = function(x, options) { + res <- hook_source(x, options) + gsub("(^|\n)#'#' ", '\\1', res) +}) +``` +The trick is to mask the source code in special comments (e.g. `#'#'`), and +remove the comment markers later. Of course, you have to guarantee these markers +are unique. + +```{r test, echo=-3} +x <- 2 +## 1/sqrt(2 * pi) * exp(-x^2/2) +dnorm(x) +``` + +```{r sdf} + + +dfdfd + + + +``` + +We used `echo=-3` to remove the 3rd expression from the source code, and +`gsub()` to strip `#'#'` off. + +This is completely hack. Use with care. + +Example code: + +```{r} +## Example code: +paggregate(argent[, 2:5], by = list(Transect = argent$Transect, Season = argent$Season), FUN = sum) +``` diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/test.org b/layers.personal/misctools/my-polymode/local/polymode/samples/test.org new file mode 100644 index 0000000..07bbe5a --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/test.org @@ -0,0 +1,34 @@ +* emacs lisp code block + +#+begin_src emacs-lisp :var tbl='() + (defun all-to-string (tbl) + (if (listp tbl) + (mapcar #'all-to-string tbl) + (if (stringp tbl) + tbl + (format "%s" tbl)))) + (all-to-string tbl) +#+end_src + + +* java code block + +#+begin_src java :classname myfirstjavaprog + class myfirstjavaprog + { + public static void main(String args[]) + { + System.out.println("Hello World!"); + } + } +#+end_src + +#+begin_src C++ +class myfirstjavaprog + { + public static void main(String args[]) + { + System.out.println("Hello World!"); + } + } +#+end_src diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/v-pl-test.sv b/layers.personal/misctools/my-polymode/local/polymode/samples/v-pl-test.sv new file mode 100644 index 0000000..e8ee816 --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/v-pl-test.sv @@ -0,0 +1,37 @@ +`ifndef WHATEVER_PKG_SV +`define WHATEVER_PKG_SV + +`cinclude "randoccm_filename.svh" +// my $string = 'hat'; # comment test +package whatever; + + logic www_w<$string> [<% ($random % 10) + 10 %> : <% $random % 10 %>]; + + // if ($define_s) { + function bit s(int x, int y); + return (x < 0 && y > 0) ? 1 : 0; + endfunction: s + // } + + task fin(); + #100ns; + $finish; + endtask: fin + + +use strict; +use warnings; + +our $str1 = "//Some random string...\n"; + +my $a1 = "str1"; # a "symbolic reference" -- contains the name of the variable to reference + +if ($a1 ne "") { + no strict 'refs'; # since we have "use strict" + print $$a1; +} + + +endpackage: whatever + +`endif // WHATEVER_PKG_SV diff --git a/layers.personal/misctools/my-polymode/local/polymode/samples/yaml.Rmd b/layers.personal/misctools/my-polymode/local/polymode/samples/yaml.Rmd new file mode 100644 index 0000000..2c1c07c --- /dev/null +++ b/layers.personal/misctools/my-polymode/local/polymode/samples/yaml.Rmd @@ -0,0 +1,56 @@ +--- +title: "Some very clever title here" +author: "Author 1, Author 2" +date: "February, 2016" +output: html_document +comment: Posted by Fernando Mayer in #87 +--- + +```{r setup, include=FALSE, purl=FALSE, eval=TRUE} +opts_chunk$set( + ## knitr options + cache = TRUE, + tidy = FALSE, + ## comment = NA, + fig.width = 10, + fig.height = 8, + fig.align = "center", + # dpi = 60, ## higher resolution + dev = "png" + # fig.path = "figures/", + ) +``` + +# Packages + +```{r, message=FALSE} +library(lattice) +library(car) +library(Matrix) +# library(INLA) +# library(FishMaps) +## extra functions +# source("script_functions.R") +``` + +# Data + +```{r} +## Some data +dat <- data.frame(col1 = rnorm(100), + col2 = runif(100)) +str(dat) +summary(dat) +``` + +Now we must create a simple plot of the two variables. + +```{r} +plot(col2 ~ col1, data = dat) +``` + +And now we can do some transformation + +```{r} + +``` \ No newline at end of file diff --git a/layers.personal/misctools/my-polymode/packages.el b/layers.personal/misctools/my-polymode/packages.el new file mode 100644 index 0000000..caa2d26 --- /dev/null +++ b/layers.personal/misctools/my-polymode/packages.el @@ -0,0 +1,71 @@ +;;; packages.el --- my-polymode layer packages file for Spacemacs. +;; +;; Copyright (c) 2012-2017 Sylvain Benner & Contributors +;; +;; Author: Rongsong Shen +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;;; Commentary: + +;; See the Spacemacs documentation and FAQs for instructions on how to implement +;; a new layer: +;; +;; SPC h SPC layers RET +;; +;; +;; Briefly, each package to be installed or configured by this layer should be +;; added to `my-polymode-packages'. Then, for each package PACKAGE: +;; +;; - If PACKAGE is not referenced by any other Spacemacs layer, define a +;; function `my-polymode/init-PACKAGE' to load and initialize the package. + +;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so +;; define the functions `my-polymode/pre-init-PACKAGE' and/or +;; `my-polymode/post-init-PACKAGE' to customize the package as it is loaded. + +;;; Code: + +(defconst my-polymode-packages + '((polymode :location local)) + "The list of Lisp packages required by the my-polymode layer. + +Each entry is either: + +1. A symbol, which is interpreted as a package to be installed, or + +2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun my-polymode/init-polymode () + (use-package polymode + :defer t + :init (progn + (require 'polymode-configuration))) + ) + +(defun my-polymode/post-init-polymode () + ) +;;; packages.el ends here diff --git a/layers.personal/misctools/mytools/README.org b/layers.personal/misctools/mytools/README.org new file mode 100644 index 0000000..b1df1f5 --- /dev/null +++ b/layers.personal/misctools/mytools/README.org @@ -0,0 +1,30 @@ +#+TITLE: mytools layer + +# The maximum height of the logo should be 200 pixels. +[[img/mytools.png]] + +# TOC links should be GitHub style anchors. +* Table of Contents :TOC_4_gh:noexport: +- [[#description][Description]] +- [[#install][Install]] +- [[#key-bindings][Key bindings]] + +* Description +This layer does wonderful things: + - thing01 + +* Install +To use this configuration layer, add it to your =~/.spacemacs=. You will need to +add =mytools= to the existing =dotspacemacs-configuration-layers= list in this +file. + +* Key bindings + +| Key Binding | Description | +|-------------+----------------| +| ~SPC x x x~ | Does thing01 | +# Use GitHub URLs if you wish to link a Spacemacs documentation file or its heading. +# Examples: +# [[https://github.com/syl20bnr/spacemacs/blob/master/doc/VIMUSERS.org#sessions]] +# [[https://github.com/syl20bnr/spacemacs/blob/master/layers/%2Bfun/emoji/README.org][Link to Emoji layer README.org]] +# If space-doc-mode is enabled, Spacemacs will open a local copy of the linked file. diff --git a/layers.personal/misctools/mytools/packages.el b/layers.personal/misctools/mytools/packages.el new file mode 100644 index 0000000..7b943db --- /dev/null +++ b/layers.personal/misctools/mytools/packages.el @@ -0,0 +1,72 @@ +;;; packages.el --- mytools layer packages file for Spacemacs. +;; +;; Copyright (c) 2012-2017 Sylvain Benner & Contributors +;; +;; Author: 沈荣松 +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;;; Commentary: + +;; See the Spacemacs documentation and FAQs for instructions on how to implement +;; a new layer: +;; +;; SPC h SPC layers RET +;; +;; +;; Briefly, each package to be installed or configured by this layer should be +;; added to `mytools-packages'. Then, for each package PACKAGE: +;; +;; - If PACKAGE is not referenced by any other Spacemacs layer, define a +;; function `mytools/init-PACKAGE' to load and initialize the package. + +;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so +;; define the functions `mytools/pre-init-PACKAGE' and/or +;; `mytools/post-init-PACKAGE' to customize the package as it is loaded. + +;;; Code: + +(defconst mytools-packages + '((vlfi :location (recipe :fetcher github + :repo "m00natic/vlfi"))) + "The list of Lisp packages required by the mytools layer. + +Each entry is either: + +1. A symbol, which is interpreted as a package to be installed, or + +2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun mytools/init-vlfi () + ;; (use-package vlfi + ;; :defer t + ;; :commands (vlf vlf-mode)) + (require 'vlf-setup) + ) + +(defun mytools/post-init-vlfi () + t) +;;; packages.el ends here diff --git a/layers.personal/mylangs/mycquery/config.el b/layers.personal/mylangs/mycquery/config.el new file mode 100644 index 0000000..eee7b7d --- /dev/null +++ b/layers.personal/mylangs/mycquery/config.el @@ -0,0 +1,31 @@ +;; Configuration for cquery +;;; config.el --- lsp Layer config File for Spacemacs +;; +;; Copyright (c) 2012-2018 Sylvain Benner & Contributors +;; +;; Author: Fangrui Song +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;; ;; These all have toggles bound under 't' in spacemacs/lsp-define-keys-for-mode + + +(defvar mycquery-executable "/usr/local/bin/cquery" + "The executable file for cquery tool") + +(defvar mycquery-extra-init-params + '(:index (:comments 2) + :cacheFormat "msgpack" + :completion (:detailedLabel t)) + "Extra parameters for cquery init") + +(defvar lsp-remap-xref-keybindings nil "When non-nil, xref keybindings remapped to lsp-ui-peek-find-*") +(defvar lsp-ui-peek-expand-by-default nil "Expand lsp-ui-peek by default (may have performance implications)") +(defvar lsp-ui-doc-enable t "Enable/disable lsp-ui-doc overlay") +(defvar lsp-ui-doc-include-signature nil "When non-nil, type signature included in the lsp-ui-doc overlay") +(defvar lsp-ui-sideline-enable t "Enable/disable lsp-ui-sideline overlay") +(defvar lsp-ui-sideline-show-symbol nil "When non-nil, sideline includes symbol info (largely redundant for c modes)") ; don't show symbol on the right of info +(defvar lsp-ui-sideline-ignore-duplicate t "Ignore duplicates") diff --git a/layers.personal/mylangs/mycquery/funcs.el b/layers.personal/mylangs/mycquery/funcs.el new file mode 100644 index 0000000..94f351e --- /dev/null +++ b/layers.personal/mylangs/mycquery/funcs.el @@ -0,0 +1,97 @@ +;;; funcs.el --- lsp Layer funcs File for Spacemacs +;; +;; Copyright (c) 2012-2018 Sylvain Benner & Contributors +;; +;; Author: Fangrui Song +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +(defun spacemacs//lsp-sync-peek-face () + "Synchronize the face used in `lsp-ui' peek window according to the theme." + (set-face-attribute 'lsp-ui-peek-list nil + :background (face-attribute 'hl-line :background nil t)) + (set-face-attribute 'lsp-ui-peek-peek nil + :background (face-attribute 'hl-line :background nil t)) + (set-face-attribute 'lsp-ui-peek-selection nil + :background (face-attribute 'highlight :background nil t) + :foreground (face-attribute 'default :foreground nil t)) + (set-face-attribute 'lsp-ui-peek-filename nil + :foreground (face-attribute 'font-lock-constant-face + :foreground nil t)) + (set-face-attribute 'lsp-ui-peek-highlight nil + :background (face-attribute 'highlight :background nil t) + :foreground (face-attribute 'highlight :foreground nil t) + :distant-foreground (face-attribute 'highlight + :foreground nil t)) + (set-face-attribute 'lsp-ui-peek-header nil + :background (face-attribute 'highlight :background nil t) + :foreground (face-attribute 'default :foreground nil t)) + ) + +(defun spacemacs/lsp-append-jump-handlers (mode) + ;;; Override + (let ((handler (intern (format "spacemacs-jump-handlers-%s" mode)))) + (add-to-list handler 'lsp-ui-peek-find-definitions)) + ;; The notion of 'spacemacs-reference-handlers' is the subject of this PR: + ;; https://github.com/syl20bnr/spacemacs/pull/9911 + ;; Disabling for now... + ;; (let ((handler (intern (format "spacemacs-reference-handlers-%s" mode)))) + ;; (add-to-list handler 'lsp-ui-peek-find-references)) + ) + +(defun spacemacs/lsp-bind-keys-for-mode (mode) + "Define key bindings for the specific MODE." + (spacemacs/declare-prefix-for-mode mode "m=" "format") + (spacemacs/declare-prefix-for-mode mode "mg" "goto") + (spacemacs/declare-prefix-for-mode mode "ml" "lsp") + (spacemacs/declare-prefix-for-mode mode "mr" "refactor") + (spacemacs/declare-prefix-for-mode mode "mT" "toggle") + + (spacemacs/set-leader-keys-for-major-mode mode + ;;Format + "=b" #'spacemacs/lsp-format-buffer + ;;goto + "gi" #'lsp-ui-imenu + "gd" #'lsp-ui-peek-find-definitions + "gr" #'lsp-ui-peek-find-references + "gs" #'lsp-ui-peek-find-workspace-symbol + ;;refactor + "rr" #'lsp-rename + ;;toggles + "Td" #'lsp-ui-doc-mode + "Ts" #'lsp-ui-sideline-mode + "TF" #'spacemacs/lsp-ui-doc-func + "TS" #'spacemacs/lsp-ui-sideline-symb + "TI" #'spacemacs/lsp-ui-sideline-ignore-duplicate + ) + + ) + + +(defun spacemacs/lsp-ui-doc-func () + "Toggle the function signature in the lsp-ui-doc overlay" + (interactive) + (setq lsp-ui-doc-include-signature (not lsp-ui-doc-include-signature))) + +(defun spacemacs/lsp-ui-sideline-symb () + "Toggle the symbol in the lsp-ui-sideline overlay. +(generally redundant in C modes)" + (interactive) + (setq lsp-ui-sideline-show-symbol (not lsp-ui-sideline-show-symbol))) + +(defun spacemacs/lsp-ui-sideline-ignore-duplicate () + "Toggle ignore duplicates for lsp-ui-sideline overlay" + (interactive) + (setq lsp-ui-sideline-ignore-duplicate (not lsp-ui-sideline-ignore-duplicate))) + +;; Used for lsp-ui-peek-mode, but may be able to use some spacemacs fn. instead? +(defun spacemacs/lsp-define-key (keymap key def &rest bindings) + "Define multiple key bindings with KEYMAP KEY DEF BINDINGS." + (interactive) + (while key + (define-key keymap (kbd key) def) + (setq key (pop bindings) + def (pop bindings)))) diff --git a/layers.personal/mylangs/mycquery/packages.el b/layers.personal/mylangs/mycquery/packages.el new file mode 100644 index 0000000..5b98eae --- /dev/null +++ b/layers.personal/mylangs/mycquery/packages.el @@ -0,0 +1,137 @@ + ;;; packages.el --- mycquery layer packages file for Spacemacs. + ;; + ;; Copyright (c) 2012-2016 Sylvain Benner & Contributors + ;; + ;; Author: Rongsong Shen + ;; URL: https://github.com/syl20bnr/spacemacs + ;; + ;; This file is not part of GNU Emacs. + ;; + ;;; License: GPLv3 + + ;;; Commentary: + + ;; See the Spacemacs documentation and FAQs for instructions on how to implement + ;; a new layer: + ;; + ;; SPC h SPC layers RET + ;; + ;; + ;; Briefly, each package to be installed or configured by this layer should be + ;; added to `mycquery-packages'. Then, for each package PACKAGE: + ;; + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a + ;; function `mycquery/init-PACKAGE' to load and initialize the package. + + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so + ;; define the functions `mycquery/pre-init-PACKAGE' and/or + ;; `mycquery/post-init-PACKAGE' to customize the package as it is loaded. + + ;;; Code: + + (defconst mycquery-packages + '((cquery :location (recipe :fetcher github :repo "cquery-project/emacs-cquery")) + (company-lsp :requires company) + (flycheck-lsp :requires flycheck :location built-in) + lsp-mode + lsp-ui + (lsp-imenu :requires imenu :location built-in) + (lsp-ui-imenu :requires lsp-imenu :location built-in) + ) + "The list of Lisp packages required by the mycquery layer. + + Each entry is either: + + 1. A symbol, which is interpreted as a package to be installed, or + + 2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun cquery/enable () + (condition-case nil + (lsp-cquery-enable) + (lsp-ui-imenu) + (user-error nil))) + +(defun mycquery/init-cquery () + (use-package cquery + :defer t + :commands lsp-cquery-enable + :init (add-hook 'c-mode-common-hook #'cquery/enable))) + +(defun mycquery/post-init-cquery () + t) + +(defun mycquery/init-lsp-mode () + (use-package lsp-mode + :defer t + :commands lsp-mode)) + +(defun mycquery/post-init-lsp-mode () + t) + +(defun mycquery/init-lsp-ui () + (use-package lsp-ui + :defer t + :init (add-hook 'lsp-mode-hook 'lsp-ui-mode) + :config (progn + (spacemacs//lsp-sync-peek-face) + (add-hook 'spacemacs-post-theme-change-hook + #'spacemacs//lsp-sync-peek-face) + + (if lsp-ui-peek-expand-by-default + (setq lsp-ui-peek-expand-function (lambda (xs) (mapcar #'car xs)))) + + (if lsp-remap-xref-keybindings + (progn (define-key lsp-ui-mode-map [remap xref-find-definitions] #'lsp-ui-peek-find-definitions) + (define-key lsp-ui-mode-map [remap xref-find-references] #'lsp-ui-peek-find-references))) + + (spacemacs/lsp-define-key + lsp-ui-peek-mode-map + "h" #'lsp-ui-peek--select-prev-file + "j" #'lsp-ui-peek--select-next + "k" #'lsp-ui-peek--select-prev + "l" #'lsp-ui-peek--select-next-file + )))) + +(defun mycquery/post-init-lsp-ui () + ) + +(defun mycquery/init-company-lsp () + (use-package company-lsp + :defer t + :init (setq company-transformers nil + company-lsp-async t + company-lsp-cache-candidates nil))) + +(defun mycquery/post-init-company-lsp ()) + +(defun mycquery/init-flycheck-lsp () + (setq lsp-enable-flycheck nil)) + +(defun mycqury/init-lsp-imenu () + (use-package lsp-imenu :defer t :init (add-hook 'lsp-after-open-hook #'lsp-enable-imenu))) + +(defun mycquery/init-lsp-ui-imenu () + (use-package lsp-ui-imenu :defer t :config (evil-make-overriding-map lsp-ui-imenu-mode-map))) + + ;;; packages.el ends here diff --git a/layers.personal/mylangs/myeiffel/README.org b/layers.personal/mylangs/myeiffel/README.org new file mode 100644 index 0000000..9966608 --- /dev/null +++ b/layers.personal/mylangs/myeiffel/README.org @@ -0,0 +1,29 @@ +#+TITLE: myeiffel layer +#+HTML_HEAD_EXTRA: + +#+CAPTION: logo + +# The maximum height of the logo should be 200 pixels. +[[img/myeiffel.png]] + +* Table of Contents :TOC_4_org:noexport: + - [[Description][Description]] + - [[Install][Install]] + - [[Key bindings][Key bindings]] + +* Description +This layer add the support of Eiffel to Spacemacs: + +* Install +To use this contribution add it to your =~/.spacemacs= + +#+begin_src emacs-lisp + (setq-default dotspacemacs-configuration-layers '(myeiffel)) +#+end_src + +* Key bindings + +| Key Binding | Description | +|-----------------+----------------| +| | | + diff --git a/layers.personal/mylangs/myeiffel/funcs.el b/layers.personal/mylangs/myeiffel/funcs.el new file mode 100644 index 0000000..140bf5c --- /dev/null +++ b/layers.personal/mylangs/myeiffel/funcs.el @@ -0,0 +1,3 @@ +;; add functions here which can be used in myeiffel layer +(defun spacemacs/eiffel-define-keys () + ) diff --git a/layers.personal/mylangs/myeiffel/img/myeiffel.png b/layers.personal/mylangs/myeiffel/img/myeiffel.png new file mode 100644 index 0000000..8b8c4f2 Binary files /dev/null and b/layers.personal/mylangs/myeiffel/img/myeiffel.png differ diff --git a/layers.personal/mylangs/myeiffel/local/eiffel/eiffel.el b/layers.personal/mylangs/myeiffel/local/eiffel/eiffel.el new file mode 100644 index 0000000..1fd4976 --- /dev/null +++ b/layers.personal/mylangs/myeiffel/local/eiffel/eiffel.el @@ -0,0 +1,2776 @@ +;;; eiffel.el --- major mode for editing Eiffel files. + +;; Copyright (C) 1989, 1990, 93, 94, 95, 96, 99, 2000, 01, 02, 03 +;; Tower Technology Corporation, +;; Free Software Foundation, +;; Bob Weiner, +;; C. Adrian + +;; Authors: 1989-1990 Stephen Omohundro, ISE and Bob Weiner +;; 1993-1996 Tower Technology Corporation +;; 1999-2003 Martin Schwenke +;; Maintainer: martin@meltin.net +;; Keywords: eiffel languages oop +;; Requires: font-lock, compile, easymenu, imenu + +;; This file is derived from eiffel4.el from Tower Technology Corporation. +;; +;; Known bugs: +;; +;; * eif-short buffer doesn't get font locked under GNU Emacs 19.34. +;; +;; * eif-debug can hang under (at least) XEmacs 21.4.[89] in the wait +;; loop if there is input pending (that is, if the user hits return +;; an extra time). Not yet tested under XEmacs 21.5. +;; +;; This file is distributed under the same terms as GNU Emacs. + +;; GNU Emacs 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, or (at your option) +;; any later version. + +;; GNU Emacs 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; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +;; Boston, MA 02110-1301, USA + +;;; Commentary: + +;; NEW VERSIONS +;; The latest version of this mode is always available via: +;; http://meltin.net/hacks/emacs/ + +;; INSTALLATION +;; To install, simply copy this file into a directory in your +;; load-path and add the following two commands in your .emacs file: +;; +;; (add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode)) +;; (autoload 'eiffel-mode "eiffel" "Major mode for Eiffel programs" t) +;; +;; Note: to be sure to have always a fresh eiffel.el, you can add the +;; "SmartEiffel/misc" directory in the emacs load-path by adding: +;; +;; (setq load-path (cons ".../SmartEiffel/misc" load-path)) + +;;; History: +;; + +;; Add history stuff here!!! + +;;; Code: + +(require 'font-lock) +(require 'compile) +(require 'easymenu) +(require 'imenu) + +(defconst eiffel-version-string + "$Id: eiffel.el,v 2.67 2003/06/14 10:41:01 martins Exp $" + "Version string to make reporting bugs more meaningful. +Note that if this file becomes part of GNU Emacs then the file might +be changed by the Emacs maintainers without this version number +changing. This means that if you are reporting a bug for a version +that was shipped with Emacs, you should report the Emacs version!") + +(defgroup eiffel nil + "Eiffel mode for Emacs" + :group 'oop) + +(defgroup eiffel-indent nil + "Indentation variables in Eiffel mode" + :prefix "eif-" + :group 'eiffel) + +(defgroup eiffel-compile nil + "Compilation support variables in Eiffel mode" + :prefix "eif-" + :group 'eiffel) + +(defun eif-customize () + "Run \\[customize-group] for the `eiffel' group." + (interactive) + (customize-group 'eiffel)) + +;; Indentation amount variables. +;; +;; The default values correspond to style used in ``Eiffel: The +;; Language''. + +(defcustom eif-indent-increment 3 + "*Default indentation interval (in spaces)." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-class-level-kw-indent 0 + "*Indentation for Class level keywords. +Specified as number of `eif-indent-increments'. See the variable +`eif-class-level-keywords-regexp'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-class-level-kw-indent 0 + "*Number of extra spaces to add to `eif-class-level-kw-indent'. +This results in the actual indentation of a class level keyword. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-class-level-comment-indent 0 + "*Indentation of comments at the beginning of a class. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-class-level-comment-indent 0 + "*Number of spaces to add to `eif-class-level-comment-indent'. +This results in the actual indentation of a class level comment. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-inherit-level-kw-indent 2 + "*Indentation of keywords falling under the Inherit clause. +Specified as number of `eif-indent-increments'. See the variable +`eif-inherit-level-keywords'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-inherit-level-kw-indent 0 + "*Number of spaces to add to `eif-inherit-level-kw-indent'. +This results in the actual indentation of an inherit level keyword. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-indent 1 + "*Indentation amount of features. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-indent 0 + "*Number of spaces to add to `eif-feature-level-indent'. +This results in the indentation of a feature. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-kw-indent 2 + "*Indentation of keywords belonging to individual features. +Specified as number of `eif-indent-increments'. See the variable +`eif-feature-level-keywords-regexp'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-kw-indent 0 + "*Number of spaces to add to `eif-feature-level-kw-indent'. +This results in the actual indentation of a feature level keyword. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-comment-indent 3 + "*Indentation of comments at the beginning of a feature. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-comment-indent 0 + "*Number of spaces to add to `eif-feature-level-comment-indent'. +This results in the actual indentation of a feature level comment. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-body-comment-indent 0 + "*Indentation of comments in the body of a routine. +Specified as number of `eif-indent-increments')" + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-body-comment-indent 0 + "*Number of spaces to add to `eif-body-comment-indent'. +This results in the actual indentation of a routine body comment. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-check-keyword-indent 0 + "*Extra indentation for the check clause as described in ETL. +Specified as number of `eif-indent-increments'. Default is 0, which +is different than in ETL's 1." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-check-keyword-indent 0 + "*Number of spaces to add to `eif-check-keyword-indent'. +This results in the actual indentation of a check keyword. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-rescue-keyword-indent -1 + "*Extra indentation for the rescue clause as described in ETL. +Specified as number of `eif-indent-increments'. Default is -1." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-rescue-keyword-indent 0 + "*Number of spaces to add to `eif-rescue-keyword-indent'. +This results in the actual indentation of a rescue keyword. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-then-indent 0 + "*Indentation for a `then' appearing on a line by itself. +This is as opposed to a `then' on the same line as an `if'. Specified +as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-then-indent 0 + "*Number of spaces to add to `eif-then-indent'. +This results in the actual indentation of a `then' appearing on a line +by itself. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-continuation-indent 1 + "*Extra indentation for a continued statement line. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-continuation-indent 0 + "*Number of spaces to add to `eif-continuation-indent'. +This results in the actual indentation of a continued statement +line. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-string-continuation-indent 0 + "*Extra indentation for a continued string. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-string-continuation-indent -1 + "*Number of spaces to add to `eif-string-continuation-indent'. +This results in the actual indentation of a continued string. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-indent-string-continuations-relatively-flag t + "*Non-nil means string continuations are indented relative to 1st character. +That is, `eif-string-continuation-indent' and +`eif-extra-string-continuation-indent' are added to position of first +character of string. If nil, string continuations are indented +relative to indent of previous line." + :type 'boolean + :group 'eiffel-indent) + +(defcustom eif-set-tab-width-flag t + "*Non-nil means `tab-width' is set to `eif-indent-increment' in `eiffel-mode'." + :type 'boolean + :group 'eiffel-indent) + +(defcustom eif-preprocessor-indent 0 + "*Indentation for lines GOBO preprocessor directives. +Specified as number of `eif-indent-increments' from left margin." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-fill-max-save 4096 + "*Maximum size of a paragraph to save before filling. +Normally \\[eif-fill-paragraph] will mark a buffer as modified even if +the fill operation does not make any changes. If the paragraph being +filled is smaller than the value of this variable then the contents of +the paragraph will be saved for comparison with the paragraph after +the fill operation. If they are the same, the buffer modification +state is restored. Set this to 0 to disable this feature, or a very +big number to enable it for all paragraphs." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-use-gnu-eiffel t + "*If t include support for compilation using GNU Liberty Eiffel." + :type 'boolean + :group 'eiffel-compile) + +(defcustom eif-se-command + "se" + "*Program to use for compiling Eiffel programs. +The default is \"se\"." + :type 'string + :group 'eiffel-compile) + +(defcustom eif-compile-options "" + "*Options to use for compiling Eiffel programs." + :type 'string + :group 'eiffel-compile) + +;; +;; No user-customizable definitions below this point. +;; + +;; +;; Indentation macros. +;; + +(defmacro eif-class-level-kw-indent-m () + "Indentation amount for Class level keywords (in number of spaces)." + '(+ (* eif-class-level-kw-indent eif-indent-increment) + eif-extra-class-level-kw-indent)) + +(defmacro eif-class-level-comment-indent-m () + "Indentation amount for Class level comments (in number of spaces)." + '(+ (* eif-class-level-comment-indent eif-indent-increment) + eif-extra-class-level-comment-indent)) + +(defmacro eif-inherit-level-kw-indent-m () + "Indentation amount for Inherit level keywords (in number of spaces)." + '(+ (* eif-inherit-level-kw-indent eif-indent-increment) + eif-extra-inherit-level-kw-indent)) + +(defmacro eif-feature-level-indent-m () + "Indentation amount for features (in number of spaces)." + '(+ (* eif-feature-level-indent eif-indent-increment) + eif-extra-feature-level-indent)) + +(defmacro eif-feature-level-kw-indent-m () + "Indentation amount for Feature level keywords (in number of spaces)." + '(+ (* eif-feature-level-kw-indent eif-indent-increment) + eif-extra-feature-level-kw-indent)) + +(defmacro eif-body-comment-indent-m () + "Indentation amount for comments in routine bodies (in number of spaces)." + '(+ (* eif-body-comment-indent eif-indent-increment) + eif-extra-body-comment-indent)) + +(defmacro eif-feature-level-comment-indent-m () + "Indentation amount for Feature level comments (in number of spaces)." + '(+ (* eif-feature-level-comment-indent eif-indent-increment) + eif-extra-feature-level-comment-indent)) + +(defmacro eif-check-keyword-indent-m () + "Indentation amount for Check keyword (in number of spaces)." + '(+ (* eif-check-keyword-indent eif-indent-increment) + eif-extra-check-keyword-indent)) + +(defmacro eif-rescue-keyword-indent-m () + "Indentation amount for Rescue keyword (in number of spaces)." + '(+ (* eif-rescue-keyword-indent eif-indent-increment) + eif-extra-rescue-keyword-indent)) + +(defmacro eif-then-indent-m () + "Indentation amount for `then' appearing on a line by itself (in number of spaces)." + '(+ (* eif-then-indent eif-indent-increment) + eif-extra-then-indent)) + +(defmacro eif-continuation-indent-m () + "Indentation amount for a statement continuation line (in number of spaces)." + '(+ (* eif-continuation-indent eif-indent-increment) + eif-extra-continuation-indent)) + +(defmacro eif-string-continuation-indent-m () + "Indentation amount for a statement continuation line (in number of spaces)." + '(+ (* eif-string-continuation-indent eif-indent-increment) + eif-extra-string-continuation-indent)) + +(defmacro eif-preprocessor-indent-m () + "Indentation amount for a preprocessor statement (in number of spaces)." + '(* eif-preprocessor-indent eif-indent-increment)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Keyword Regular Expression Constants. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst eif-non-id-char-regexp "\\S_" ;; "[^a-z0-9_]" + "The characters that are not part of identifiers.") + +(defun eif-post-anchor (regexp) + "Anchor given REGEXP with end-word delimiter and `eif-non-id-char-regexp'." + (concat "\\(" regexp "\\)\\>" eif-non-id-char-regexp)) + +(defun eif-word-anchor (regexp) + "Anchor given REGEXP with word delimiters and `eif-non-id-char-regexp'." + (concat "\\<\\(" regexp "\\)\\>" eif-non-id-char-regexp)) + +(defun eif-anchor (regexp) + "Anchor given REGEXP front and back to match line break or non-symbol char." + (concat "\\(^\\|\\S_\\<\\)\\(" regexp "\\)\\($\\|\\>\\S_\\)")) + +;; Note invariant is handled as a special case since it is both a +;; class-level and a from-level keyword +;; Note obsolete is handled as a special case since it is both a +;; class-level and a feature-level keyword +;; Note create, note, and indexing are also handled as special cases +(defconst eif-class-level-keywords + (concat + "\\(?:" + (regexp-opt '("deferred" "expanded" "reference" "separate")) + "[ \t]+\\)?class" + "\\|" + (regexp-opt '("inherit" "insert" "convert" "creation" "feature"))) + "Keywords introducing class-level clauses. +Note that `invariant', `obsolete', `indexing', `note', and `create' are not included here since can +function as more than one type of keyword.") + +(defconst eif-class-level-keywords-regexp + (eif-word-anchor eif-class-level-keywords) + "Regexp of keywords introducing class level clauses, with some context. +See `eif-class-level-keywords'.") + +(defconst eif-inherit-level-keywords + (regexp-opt '("rename" "redefine" "undefine" "select" "export")) + "Those keywords which introduce subclauses of the inherit clause.") + +(defconst eif-feature-level-keywords + (regexp-opt '("require" "local" "deferred" "separate" "do" "once" "ensure" "alias" "external" "attribute")) + "Those keywords which are internal to features (in particular, routines).") + +(defconst eif-feature-level-keywords-regexp + (eif-word-anchor eif-feature-level-keywords) + "Regexp of keywords internal to features (usually routines). +See `eif-feature-level-keywords'.") + +(defconst eif-end-keyword "end" "The `end' keyword.") + +(defconst eif-end-on-current-line ".*[ \t]end[ \t]*;?[ \t]*\\(--.*\\)?$" + "Regular expression to identify lines ending with the `end' keyword.") + +(defconst eif-control-flow-keywords + (regexp-opt '("if" "inspect" "from" "debug")) + "Keywords which introduce control-flow constructs.") + +(defconst eif-control-flow-matching-keywords + (concat (regexp-opt '("deferred" "do" "once")) "\\|" eif-control-flow-keywords) + "Keywords that may cause the indentation of an `eif-control-flow-keyword'. +If these occur prior to an `eif-control-flow-keyword' then the +`eif-control-flow-keyword' is indented. Note that technically, `end' +is part of this list but it is handled separately in the function +\[eif-matching-kw\].") + +(defconst eif-control-flow-matching-keywords-regexp + (eif-word-anchor eif-control-flow-matching-keywords) + "Regexp of keywords maybe causing indentation of `eif-control-flow-keyword'. +See `eif-control-flow-keywords'.") + +(defconst eif-check-keyword "check" + "The `check' keyword.") + +(defconst eif-check-keywords-regexp + (eif-word-anchor eif-check-keyword) + "The `check' keyword (with trailing context).") + +;; FIXME: Doesn't work if once keyword is followed by a string on next +;; line, but didn't get broken by this attempt at factoring. +(defconst eif-check-matching-keywords-regexp + eif-control-flow-matching-keywords-regexp + "Keywords that may cause the indentation of an `eif-check-keyword'. +If these occur prior to an `eif-check-keyword' then the +`eif-check-keyword' is indented. Note that technically, `end' is part +of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +;; FIXME: This could be fixed or removed. +(defconst eif-end-keyword-regexp "\\" + "The `end' keyword with context.") + +(defconst eif-end-matching-keywords + (concat (regexp-opt '("attribute" "check" "class" "feature" "rename" "redefine" "undefine" + "select" "export" "separate" "external" "alias")) "\\|" + eif-control-flow-matching-keywords) + "Those keywords whose clause is terminated by an `end' keyword.") + +(defconst eif-end-matching-keywords-regexp + (eif-word-anchor eif-end-matching-keywords) + "Regexp of keywords whose clause is terminated by an `end' keyword. +See `eif-end-matching-keywords'.") + +(defconst eif-rescue-keyword "rescue" "The `rescue' keyword.") + +(defconst eif-obsolete-keyword "obsolete" "The `obsolete' keyword.") + +(defconst eif-indexing-keyword + (regexp-opt '("note" "indexing")) + "The `indexing' and `note' keywords.") + +(defconst eif-indexing-keyword-regexp + (eif-post-anchor eif-indexing-keyword) + "Regexp matching `indexing' and `note' keywords, with trailing context.") + +(defconst eif-rescue-keywords-regexp + (eif-word-anchor eif-rescue-keyword) + "The `rescue' keyword (with trailing context).") + +(defconst eif-rescue-matching-keywords-regexp + (eif-word-anchor (regexp-opt '("deferred" "do" "once"))) + "Keywords that may cause the indentation of an `eif-rescue-keyword'. +If these occur prior to an `eif-rescue-keyword' then the +`eif-rescue-keyword' is indented. Note that technically, `end' is +part of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-from-level-keywords + (regexp-opt '("until" "variant" "loop")) + "Keywords occuring inside of a from clause.") + +(defconst eif-from-level-keywords-regexp + (eif-word-anchor eif-from-level-keywords) + "Regexp of keywords occuring inside of a from clause. +See `eif-from-level-keywords'.") + +(defconst eif-from-keyword "from" "The keyword `from'.") + +(defconst eif-if-or-inspect-level-keywords + (regexp-opt '("elseif" "else" "when")) + "Keywords occuring inside of an if or inspect clause.") + +(defconst eif-if-or-inspect-level-keywords-regexp + (eif-word-anchor eif-if-or-inspect-level-keywords) + "Regexp of keywords occuring inside of an if or inspect clause. +See eif-if-or-inspect-level-keywords.") + +(defconst eif-if-or-inspect-keyword-regexp + (eif-word-anchor (regexp-opt '("if" "inspect"))) + "Regexp matching the `if' or `inspect' keywords.") + +(defconst eif-then-keyword ".*[ \t)]then[ \t]*$" + "The keyword `then' with possible leading text.") + +(defconst eif-solitary-then-keyword "then" "The keyword `then'.") + +(defconst eif-then-matching-keywords + (regexp-opt '("if" "elseif" "when") t) + "Keywords that may alter the indentation of an `eif-then-keyword'. +If one of these occur prior to an `eif-then-keyword' then this sets +the indentation of the `eif-then-keyword'. Note that technically, +`end' is part of this list but it is handled separately in the +function \[eif-matching-kw\]. See also +`eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-invariant-keyword "invariant" "The `invariant' keyword.") + +(defconst eif-invariant-matching-keywords + (regexp-opt '("from" "feature")) + "Keywords that may cause the indentation of an `eif-invarient-keyword'. +If one of these occurs prior to an `eif-invariant-keyword' then the +`eif-invariant-keyword' is indented. Note that technically, `end' is +part of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-obsolete-matching-keywords + (regexp-opt '("is" "class") t) + "Keywords that may cause the indentation of an `eif-obsolete-keyword'. +If one of these occurs prior to an `eif-obsolete-keyword' then the +`eif-obsolete-keyword' is indented.") + +(defconst eif-create-keyword + "create" + "Eiffel create keyword. Can be used at class or minor level.") + +(defconst eif-create-keyword-regexp + (eif-post-anchor eif-create-keyword) + "Regexp matching `create' keyword, with trailing context.") + +(defconst eif-indentation-keywords + (concat (regexp-opt '("note" "indexing" "rescue" "inherit" "insert" "convert" "create" "creation" + "invariant" "require" "local" "ensure" "obsolete")) "\\|" + eif-from-level-keywords "\\|" + eif-if-or-inspect-level-keywords "\\|" + eif-end-matching-keywords) + "Keywords that match any eiffel keyword triggering indentation.") + +(defconst eif-indentation-keywords-regexp + (eif-word-anchor eif-indentation-keywords) + "Regexp of keywords that match any eiffel keyword triggering indentation. +See `eif-indentation-keywords'.") + +(defconst eif-once-non-indent-regexp + "\\s-*once\\(\\s-\\|\n\\)+\"" + "Regexp of Eiffel once keyword in context not affecting indentation.") + +(defconst eif-feature-indentation-keywords-regexp + (eif-word-anchor (regexp-opt '("convert" "creation" "feature"))) + "Keywords which denote the presence of features following them.") + +(defconst eif-is-keyword-regexp "\\(.*[ \t)]\\)?is[ \t]*\\(--.*\\)?$" + "The `is' keyword (with some context).") + +(defconst eif-multiline-routine-is-keyword-regexp + ".*([^)]*)\\([ \t\n]*\\|[ \t\n]*:[][ \t\nA-Za-x0-9_,]*\\)is[ \t]*\\(--.*\\)?$" + "The `is' keyword (with some context).") + +(defconst eif-operator-keywords + (regexp-opt '("and" "or" "implies")) + "Eiffel operator keywords.") + +(defconst eif-operator-regexp + (concat "[ \t]*\\([@*/+]\\|-[^-]\\|\\<\\(" + eif-operator-keywords + "\\)[ \t(]\\)") + "Eiffel operators - used to identify continuation lines. +See `eif-operator-keywords'.") + +(defconst eif-operator-eol-regexp + (concat ".*\\([@*/+-]\\|\\<\\(" eif-operator-keywords + "\\)\\|:=\\)[ \t]*\\(--.*\\)?$") + "Eiffel operators - used to identify continuation lines.") + +(defconst eif-all-keywords + (concat eif-indentation-keywords "\\|" + eif-solitary-then-keyword "\\|" + eif-create-keyword "\\|" + eif-end-keyword) + "Regexp matching (nearly) any eiffel keyword in a line. +Does not include `is'.") + +(defconst eif-all-keywords-regexp + (concat "\\(" + (eif-word-anchor eif-all-keywords) "\\)") + "Anchored regexp matching (nearly) any eiffel keyword in a line. +Does not include `is'. See `eif-all-keywords'.") + +(defconst eiffel-comment-start-skip + "--+|?[ \t]*" + "Regexp matching the beginning of an Eiffel comment.") + +(defconst eif-non-source-line + (concat "[ \t]*\\(\\(" "--" "\\).*\\)?$") + "RE matching line with only whitespace and comment or preprocessor keyword.") + +(defconst eif-variable-or-const-regexp "[^()\n]*:[^=].*" + "RE to match a variable or constant declaration.") + +;; Factor out some important important regexps for use in +;; eif-{beginning,end}-of-feature. + +(defun eiffel-feature-re () + "Liberty Eiffel feature declarations" + (let* ((argument-name "\\(?:[A-Za-z]*[a-z0-9_]+[A-Za-z0-9_]*\\)") + (feature-name (concat "\\(?:\\(infix\\|prefix\\)\\s-+\".+?\"\\|" argument-name "\\(?:\\s-+alias\\s-+\".+?\"\\)?\\)")) + (type-name "\\(?:like\\s-+\\sw+\\|[A-Z]\\sw*\\(?:\\[.+?\\]\\)?\\)")) + (concat + "\\(?:" + "\\(?:\\\\)?"))) + +(defconst eif-routine-begin-regexp + ;"\\([a-z][a-zA-Z_0-9]*\\)\\s-*\\(([^)]*)\\)?\\s-*\\(:\\s-*[A-Z][A-Z0-9_]*\\(\\s-*\\[[^\\]]*\\]\\)?\\)?\\s-*\\(assign\\s-*[a-zA-Z0-9_]+\\)?\\s-*\\\\s-*\\(--.*\\)?$" + (eiffel-feature-re) + "Regexp matching the beginning of an Eiffel routine declaration.") + +(message (concat "Liberty Eiffel features: " eif-routine-begin-regexp)) + +(defconst eif-attribute-regexp + (concat "[a-z_][^-:\n]*:\\s-*" + "\\(like\\s-*[a-zA-Z][a-z_0-9]*\\|" + "\\(\\(expanded\\|reference\\)\\s-*\\)?[A-Z][A-Z_0-9]*" + "\\(\\s-*\\[[^-\n]*\\]\\)?\\)" + "\\s-*\\($\\|[;)].*\\|--.*\\)") + "Regexp matching an Eiffel attribute, parameter or local variable.") + +(defconst eif-constant-regexp + "[a-z_][^-:\n]*:[^-\n]*\\\\s-*[^ \t\n]" + "Regexp matching an Eiffel constant declaration.") + +(defconst eif-probably-feature-regexp + (concat "\\(" eif-routine-begin-regexp + "\\|" eif-attribute-regexp + "\\|" eif-constant-regexp "\\)") + "Regexp probably matching an Eiffel feature. +This will also match local variable and parameter declarations.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar eif-matching-indent -1 + "Indentation of the keyword found on the last call to \[eif-matching-kw\]. +-1 if no match was found.") + +(defvar eif-matching-kw-for-end nil) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +;; Font-lock support. +;; +;; Rewritten from scratch by Cyril Adrian +;; Specific to Liberty Eiffel +;; + +(defconst eiffel-keywords-feature + '("agent" "all" "and" "as" "assign" "attribute" "check" "class" + "convert" "create" "debug" "deferred" "do" "else" "elseif" "end" "ensure" + "expanded" "export" "external" "feature" "from" "if" "implies" + "indexing" "inherit" "insert" "inspect" "invariant" "is" "like" + "local" "loop" "not" "note" "obsolete" "old" "once" "only" "or" + "redefine" "rename" "require" "rescue" "retry" "select" "separate" "then" + "undefine" "until" "variant" "when" "xor")) + +(defconst eiffel-keywords + '("agent" "alias" "all" "and" "as" "assign" "attribute" "check" "class" + "convert" "create" "debug" "deferred" "do" "else" "elseif" "end" "ensure" + "expanded" "export" "external" "feature" "from" "frozen" "if" "implies" + "indexing" "infix" "inherit" "insert" "inspect" "invariant" "is" "like" + "local" "loop" "not" "note" "obsolete" "old" "once" "only" "or" "prefix" + "redefine" "rename" "require" "rescue" "retry" "select" "separate" "then" + "undefine" "until" "variant" "when" "xor")) + +(defconst eiffel-constants + '("Current" "False" "Precursor" "Result" "True" "Void")) + +(defun eiffel-string-re () + "Liberty Eiffel strings" + (concat "U?\"\\(?:" + "\\(?:\\(?:[^%\"\n]\\|%[^\n]\\)*?\\)" ; single-line strings + "\\|" + "\\(?:\\(?:[^%\"\n]\\|%[^\n]\\)*?%[ \t]*\n\\(?:[ \t]*%\\(?:[^%\"\n]\\|%[^\n]\\)*?%[ \t]*\n\\)*[ \t]*%\\(?:[^%\"\n]\\|%[^\n]\\)*?\\)" ; older multiline strings + "\\|" + "\\(?:[[{][ \t]*\n\\(?:.*?\n\\)*?[ \t]*[]}]\"\\)" ; newer multiline strings + "\\)\"")) + +(defun eiffel-wordstart-re () + "start of words" + "\\<\\(") + +(defun eiffel-wordend-re () + "end of words" + (concat "\\)\\>")) + +(defun eiffel-keywords-re () + (concat + (eiffel-wordstart-re) + (regexp-opt eiffel-keywords) + (eiffel-wordend-re))) + +(defun eiffel-constants-re () + (concat + (eiffel-wordstart-re) + (regexp-opt eiffel-constants) + (eiffel-wordend-re))) + +(defun eiffel-preprocessor-re () + (concat + (eiffel-wordstart-re) + (regexp-opt '("c_inline_c" "c_inline_h" "not_yet_implemented" "se_breakpoint" "breakpoint" "to_pointer" + "is_expanded_type" "is_basic_expanded_type" + "object_size" "object_id_memory" + "se_guru01" "se_guru02" "se_guru03")) + (eiffel-wordend-re))) + +(defvar eiffel-font-lock-defaults + (append + `( + ("--|\\(.*\\)\n" . font-lock-comment-face) + ("--\\(.*\\)\n" . font-lock-doc-face) + (,(eiffel-string-re) . font-lock-string-face) + ("'\\(?:[^'%]\\|%.\\)'" . font-lock-string-face) + ("\\<\\([A-Z][A-Z0-9_]*\\)\\>" . font-lock-type-face) + (,(eiffel-keywords-re) 1 font-lock-keyword-face) + (,(eiffel-constants-re) 1 font-lock-builtin-face) + (,(eiffel-preprocessor-re) 1 font-lock-preprocessor-face))) + "Default highlighting expressions for Liberty Eiffel mode") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +;; Compilation support for GNU SmartEiffel. +;; + +(defvar eif-compile-dir nil + "Current directory where Eiffel compilations are taking place. +Possibly used for error location.") + +(defvar eif-root-class nil + "Current Eiffel root class being compiled/debugged.") + +(defvar eif-compile-target nil + "Current Eiffel compilation target.") + +(defvar eif-debug-target nil + "Current Eiffel debug target.") + +(defvar eif-root-proc nil + "Current Eiffel root procedure.") + +(defvar eif-run-command nil + "Current command to run after Eiffel compile.") + +(defvar eif-debug-command nil + "Current debug command to run after Eiffel debug compile.") + +(defun eif-compilation-mode-hook () + "Hook function to set local value for `compilation-error-screen-columns'. +This should be nil for SmartEiffel compiles, because column positions are +returned as character positions rather than screen columns." + ;; In Emacs > 20.7 compilation-error-screen-columns is buffer local. + (or (assq 'compilation-error-screen-columns (buffer-local-variables)) + (make-local-variable 'compilation-error-screen-columns)) + (setq compilation-error-screen-columns nil)) + +(defun eif-compile () + "Compile an Eiffel root class." + (interactive) + (eif-compile-prompt) + (eif-compile-internal)) + +(defun eif-set-compile-options () + "Set Eiffel compiler options." + (interactive) + (setq eif-compile-options + (read-string "Eiffel compiler options: " eif-compile-options))) + +;; Taken from Emacs 20.3 subr.el (just in case we're running under Emacs 19). +(defun eif-split-string (string &optional separators) + "Split STRING into substrings separated by SEPARATORS. +Each match for SEPARATORS is a splitting point. The substrings +between the splitting points are made into a list which is returned. +If SEPARATORS is absent, it defaults to \"[ \\f\\t\\n\\r\\v]+\". + +If there is match for SEPARATORS at the beginning of STRING, we do not +include a null substring for that. Likewise, if there is a match +at the end of STRING, we do not include a null substring for that." + (let ((rexp (or separators "[ \f\t\n\r\v]+")) + (start 0) + notfirst + (list nil)) + (while (and (string-match rexp string + (if (and notfirst + (= start (match-beginning 0)) + (< start (length string))) + (1+ start) start)) + (< (match-beginning 0) (length string))) + (setq notfirst t) + (or (eq (match-beginning 0) 0) + (and (eq (match-beginning 0) (match-end 0)) + (eq (match-beginning 0) start)) + (setq list + (cons (substring string start (match-beginning 0)) + list))) + (setq start (match-end 0))) + (or (eq start (length string)) + (setq list + (cons (substring string start) + list))) + (nreverse list))) + +(defun eif-run () + "Run a compiled Eiffel program." + (interactive) + (setq eif-run-command + (read-string "Command to run: " + (or eif-run-command + eif-compile-target + (file-name-sans-extension + (if (or (eq system-type 'windows-nt) (eq system-type 'cygwin)) + buffer-file-name + (file-name-nondirectory (buffer-file-name))))))) + (eif-run-internal)) + +(defun eif-debug () + "Run the SmartEiffel debugger." + (interactive) + + (eif-compile-prompt) + + (setq eif-debug-target + (file-name-sans-extension + (read-string "Debug target name: " + (or eif-debug-target + (concat eif-compile-target "_debug"))))) + + (let* ((eif-compile-options (concat "-sedb " eif-compile-options)) + (eif-compile-target eif-debug-target) + (buff (eif-compile-internal)) + (proc (get-buffer-process buff))) + + ;; This works under GNU Emacs, but hangs under at least some + ;; versions of XEmacs if there is input pending. + (while (eq (process-status proc) 'run) + (sit-for 1)) + + (if (= (process-exit-status proc) 0) + (progn + (setq eif-debug-command + (read-string "Debugger command to run: " + (or eif-debug-command + eif-debug-target + (file-name-sans-extension + (if (eq system-type 'windows-nt) + buffer-file-name + (file-name-nondirectory + (buffer-file-name))))))) + (let ((eif-run-command eif-debug-command)) + (eif-run-internal)))))) + +(defun eif-compile-prompt () + "Prompt for information required to compile an Eiffel root class." + + ;; Do the save first, since the user might still have their hand on + ;; the mouse. + (save-some-buffers (not compilation-ask-about-save) nil) + + (setq eif-compile-dir (file-name-directory (buffer-file-name))) + (setq eif-root-class + (file-name-sans-extension + (read-string "Name of root class: " + (or eif-compile-target + (file-name-sans-extension + (file-name-nondirectory (buffer-file-name))))))) + (setq eif-compile-target eif-root-class) + (setq eif-root-proc + (read-string "Name of root procedure: " + eif-root-proc))) + +(defun eif-compile-internal () + "Compile an Eiffel root class. Internal version. +Returns the same thing as \\[compilation-start] - the compilation buffer." + + (let ((cmd (concat eif-se-command + " compile -flymake_mode " + eif-compile-options + " -o " eif-compile-target + (if (eq system-type 'windows-nt) ".exe") + " " eif-root-class + " " eif-root-proc)) + (buf-name "*Liberty Eiffel Compilation*") + (compilation-mode-hook (cons 'eif-compilation-mode-hook + compilation-mode-hook))) + (if (fboundp 'compilation-start) ; Emacs 22 and above + (compilation-start cmd nil #'(lambda (mode-name) buf-name)) + (compile-internal cmd "No more errors" buf-name)))) + +(defun eif-run-internal () + "Run a compiled Eiffel program. Internal version." + + (let* ((tmp-buf (current-buffer)) + (words (eif-split-string eif-run-command)) + (cmd (expand-file-name (car words)))) + + (apply 'make-comint cmd cmd nil (cdr words)) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window (concat "*" cmd "*")))) + +;; This has been loosened up to spot parts of messages that contain +;; references to multiple locations. Thanks to Andreas +;; . Also, the column number is a character +;; count rather than a screen column, so we need to make sure that +;; compilation-error-screen-columns is nil. Note that in XEmacs this +;; variable doesn't exist, so we end up in the wrong column. Hey, at +;; least we're on the correct line! +(add-to-list 'compilation-error-regexp-alist + '("^Line \\([0-9]+\\) column \\([0-9]+\\) in [^ ]+ (\\([^)]+\\.[Ee]\\))" 3 1 2)) + +(defun eif-find-file (&optional userclass) + "Find and open an Eiffel file given by a class name" + (interactive) + (let* ((cn (or userclass (current-word)))) + (if (string-match "[A-Z][0-9A-Z_]*" cn) + (let ((classname (substring cn (match-beginning 0) (match-end 0)))) + (message "Searching %s..." classname) + (let* ((shellres (shell-command-to-string (concat "se find --raw " classname))) + (filename (substring shellres 0 (string-match "\n" shellres)))) + (find-file filename) + ))) + (message nil))) + +(defun eif-short () + "Display the short form of an Eiffel class." + (interactive) + (let* ((class (read-string + "Class or file: " + (if (buffer-file-name) + (file-name-nondirectory (buffer-file-name))))) + (buf (get-buffer-create (concat "*Eiffel - short " class "*")))) + + (shell-command (concat eif-se-command " short " class) buf) + (with-current-buffer buf + (let ((font-lock-defaults eiffel-font-lock-defaults)) + (font-lock-fontify-buffer)) + (read-only-mode 1)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Utility Functions. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun eif-feature-quote () + "Put a `' around the current feature name." + (interactive) + (save-excursion + ;; Only try to go back to the beginning of the feature if we're + ;; not already there. + (if (/= (point) + (save-excursion + (forward-sexp) + (backward-sexp) + (point))) + (backward-sexp)) + (insert "`") + (forward-sexp) + (insert "'")) + (if (looking-at "'") + (forward-char 1))) + +(defun eif-peeking-backwards-at (regexp) + "Return non-nil is previous character exists and is matched by REGEXP. +The match is actually an unbounded match starting at the previous character." + (save-excursion + (save-match-data + (and (not (bobp)) + (or (backward-char) t) + (looking-at regexp))))) + +(defsubst eif-in-comment-p () + "Return t if point is in a comment." + (interactive) + (save-excursion + (nth 4 (parse-partial-sexp + (save-excursion (beginning-of-line) (point)) + (point))))) + +(defun eif-in-comment-or-quoted-string-p () + "Return t if point is in a comment or quoted string." + (or (eif-in-comment-p) + (eif-in-quoted-string-p))) + +(defun eif-not-in-comment-or-quoted-string-p () + "Return t if point is not in a comment or quoted string." + (not (eif-in-comment-or-quoted-string-p))) + +(defun eif-near-comment-p () + "Return t if point is close enough to a comment for filling purposes." + (or (eif-in-comment-p) + (and (or (looking-at comment-start-skip) + (eif-peeking-backwards-at comment-start-skip)) + (not (eif-in-quoted-string-p))) + (looking-at (concat "[ \t]*" comment-start-skip)))) + +(defun eif-re-search-forward (regexp &optional limit noerror) + "Search forward from point for REGEXP not in comment or string. +`case-fold-search' is set to nil when searching. For details on other +arguments see \\[re-search-forward]." + + (interactive "sRE search: ") + (let ((start (point)) + found case-fold-search) + (while (and (setq found (re-search-forward regexp limit noerror)) + (eif-in-comment-or-quoted-string-p))) + (if (and found + (eif-not-in-comment-or-quoted-string-p)) + found + (if (eq noerror t) + (goto-char start)) + nil))) + +(defun eif-re-search-backward (regexp &optional limit noerror) + "Search backward from point for REGEXP not in comment or string. +`case-fold-search' is set to nil when searching. For details on other +arguments see \\[re-search-forward]." + (interactive "sRE search: ") + (let ((start (point)) + found case-fold-search) + (while (and (setq found (re-search-backward regexp limit noerror)) + (eif-in-comment-or-quoted-string-p))) + (if (and found + (eif-not-in-comment-or-quoted-string-p)) + found + (if (eq noerror t) + (goto-char start)) + nil))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Indentation Functions. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun eif-skip-leading-whitespace () + "Move to the first non-whitespace character on the current line." + (end-of-line) + (let ((line-end (point))) + (beginning-of-line) + (skip-syntax-forward "-" line-end))) + +(defun eif-calc-indent () + "Calculate the indentation of the current line of eiffel code. +This function handles the case where there is a keyword that affects +indentation at the beginning of the current line. For lines that +don't start with a relevant keyword, the calculation is handed off to +\\[eif-calc-non-keyword-indent]." + (let ((indent 0) + kw-match) + + (save-excursion + (eif-skip-leading-whitespace) + + ;; Look for a keyword on the current line. + (if (looking-at eif-all-keywords-regexp) + + (cond ((looking-at eif-create-keyword-regexp) + ;; Class-level or minor occurence? + (if (save-excursion (eif-find-beginning-of-feature)) + ;; Minor. + (setq indent (eif-calc-indent-non-keyword)) + ;; Class-level. + (setq indent (eif-class-level-kw-indent-m)))) + ;; There's possibly a better way of coding this exception. + ((looking-at eif-once-non-indent-regexp) + (setq indent (eif-calc-indent-non-keyword))) + ((looking-at eif-indexing-keyword-regexp) + ;; Class-level or minor occurence? + (if (string-match eif-check-keyword (eif-matching-kw eif-check-keywords-regexp)) + ;; In check. + (setq indent (+ eif-matching-indent (eif-check-keyword-indent-m))) + (if (save-excursion (eif-find-beginning-of-feature)) + ;; Minor. (BUG: "note" can also be at the END of the class!!!) + (setq indent (eif-calc-indent-non-keyword)) + ;; Class-level. + (setq indent (eif-class-level-kw-indent-m))))) + ((looking-at eif-class-level-keywords-regexp) + ;; File level keywords (indent defaults to 0) + (setq indent (eif-class-level-kw-indent-m))) + ((looking-at eif-inherit-level-keywords) + ;; Inherit level keywords (indent defaults to + ;; 2*eif-indent-increment) + (setq indent (eif-inherit-level-kw-indent-m))) + ((looking-at eif-feature-level-keywords-regexp) + ;; Feature level keywords (indent defaults to + ;; (eif-feature-level-indent-m) + eif-indent-increment) + (setq indent (eif-feature-level-kw-indent-m))) + ((looking-at eif-end-keyword) + ;; End keyword (indent to level of matching keyword) + (if (string-match "end" + (eif-matching-kw + eif-end-matching-keywords-regexp)) + ;; Then + (if (= eif-matching-indent + (eif-feature-level-kw-indent-m)) + ;; Then + (setq indent (eif-class-level-kw-indent-m)) + ;; Else + (setq indent + (- eif-matching-indent eif-indent-increment))) + ;; Else + (setq indent eif-matching-indent)) + ;; FIXME: This is broken!!! + (if (<= indent (eif-feature-level-indent-m)) + (save-excursion + (end-of-line) + (while (and (< (point) (point-max)) + (or (forward-char 1) t) + (looking-at eif-non-source-line)) + (end-of-line)) + (if (not (looking-at eif-non-source-line)) + (setq indent (eif-inherit-level-kw-indent-m)) + (setq indent (eif-class-level-kw-indent-m)))))) + ((looking-at eif-control-flow-keywords) + ;; Control flow keywords + ;; Indent to same level as a preceding "end" or + ;; if no preceding "end" is found, indent to the level + ;; of the preceding "do" plus the value of + ;; eif-indent-increment + (setq kw-match + (eif-matching-kw + eif-control-flow-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent eif-matching-indent)) + (t + (setq indent + (+ eif-matching-indent eif-indent-increment))))) + ((looking-at eif-check-keywords-regexp) + ;; Check keyword + ;; Indent to level of preceding "end"+eif-indent-increment or + ;; if no preceding "end" is found, indent to the level of + ;; the preceding eif-check-matching-keywords-regexp plus the + ;; value (eif-indent-increment + eif-check-keyword-indent). + + (setq kw-match (eif-matching-kw + eif-check-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent (+ eif-matching-indent + (eif-check-keyword-indent-m)))) + (t + (setq indent + (+ eif-matching-indent + (+ eif-indent-increment + (eif-check-keyword-indent-m))))))) + ((looking-at eif-rescue-keywords-regexp) + ;; Rescue keyword + ;; Indent to level of preceding "end"+eif-indent-increment or + ;; if no preceding "end" is found, indent to the level of + ;; the preceding eif-rescue-matching-keywords-regexp plus the + ;; value (eif-indent-increment + eif-rescue-keyword-indent). + (setq kw-match (eif-matching-kw + eif-rescue-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent (+ eif-matching-indent + (eif-rescue-keyword-indent-m)))) + (t + (setq indent eif-matching-indent)))) + ((looking-at eif-from-level-keywords-regexp) + ;; From level keywords (indent to level of matching "From") + (if (string-match "end" (eif-matching-kw eif-from-keyword)) + ;; Closest matching KW is `end'. + (setq indent (- eif-matching-indent eif-indent-increment)) + ;; Closest matching KW is one of `eif-from-keyword'. + (setq indent eif-matching-indent))) + ((looking-at eif-if-or-inspect-level-keywords-regexp) + ;; If level keywords (indent to level of matching + ;; "If" or "Inspect") + (if (string-match "end" + (eif-matching-kw + eif-if-or-inspect-keyword-regexp)) + ;; Closest matching KW is `end'. + (setq indent (- eif-matching-indent eif-indent-increment)) + ;; Closest matching KW is one of `eif-if-or-inspect-keyword-regexp'. + (setq indent eif-matching-indent))) + ((looking-at eif-solitary-then-keyword) + ;; Handles case where "then" appears on a line by itself + (if (eif-matching-kw eif-then-matching-keywords t) + ;; (Indented to level of the matching if, elseif or when) + (setq indent (+ eif-matching-indent (eif-then-indent-m))) + (if (save-excursion (eif-find-beginning-of-feature)) + ;; (Feature-level "then") + (setq indent (eif-feature-level-kw-indent-m)) + (message "Non-matching 'then'") + (setq indent (eif-calc-indent-non-keyword))))) + ((looking-at eif-invariant-keyword) + ;; Invariant keyword + ;; (Indented to level of the matching from or feature) + (if (string-match "from" + (eif-matching-kw eif-invariant-matching-keywords)) + ;; Then - loop invariant + (setq indent eif-matching-indent) + ;; Else - class invariant + (setq indent (eif-class-level-kw-indent-m)))) + ((looking-at eif-obsolete-keyword) + ;; Obsolete keyword + ;; (Indented to the level of the matching from or feature) + (if (string-match "class" + (eif-matching-kw eif-obsolete-matching-keywords)) + ;; Then - class obsolete + (setq indent (eif-class-level-kw-indent-m)) + ;; Else - feature obsolete + (setq indent (eif-feature-level-kw-indent-m))))) + ;; No keyword. Hand off... + (setq indent (eif-calc-indent-non-keyword)))) + indent)) + +(defun eif-calc-indent-non-keyword () + "Calculate indentation of current Eiffel code line, without leading keyword. +This function generally assumes that the preceding line of code is +indented properly, and usually bases the indentation of the current +line on that preceding line." + (let ((indent 0) + originally-looking-at-comment originally-looking-at-lone-string + continuation id-colon) + + (save-excursion + (eif-skip-leading-whitespace) + + ;; Is the line we are trying to indent a comment line? + (setq originally-looking-at-comment (looking-at comment-start-skip)) + + ;; Is the line we are trying to indent a lone string? + (setq originally-looking-at-lone-string (looking-at "\"[^\"]*\"[ \t]*$")) + + ;; Are we in a multi-line parenthesis expression? + (if (or (and (> (eif-in-paren-expression) 0) + (> (setq indent (eif-indent-multi-line)) -1)) + (setq indent (eif-manifest-array-indent))) + + ;; Multi-line parenthesis expression. + ;; Move string continuation lines as per configuration. + (if (looking-at "%") + (setq indent (+ indent (eif-string-continuation-indent-m)))) + + ;; Else Find the first preceding line with non-comment source on it + ;; that is not a continuation line of a multi-line parenthesized + ;; expression (and isn't a preprocessor line :-). + + ;; Record whether this line begins with an operator. We assume + ;; that the line is a continuation line if it begins with an operator + (beginning-of-line) + (setq continuation (looking-at eif-operator-regexp)) + + ;; Record whether the line being indented begins with an " :" + ;; This is used in indenting assertion tag expressions. + (setq id-colon (looking-at "[ \t]*[a-zA-Z0-9_]+[ \t]*:")) + + (forward-line -1) + (beginning-of-line) + (while (and (looking-at eif-non-source-line) + (not (= (point) 1))) + (forward-line -1) + (beginning-of-line)) + (if (eif-line-contains-close-paren) + (backward-sexp)) + (eif-skip-leading-whitespace) + + (cond ((and (= (point) 1) + originally-looking-at-comment + (setq indent (eif-class-level-comment-indent-m)))) + ;; 'eif-is-keyword-regexp' case must precede + ;; '(not eif-all-keywords-regexp)' case since "is" is not + ;; part of 'eif-all-keywords-regexp' + ((or (looking-at eif-is-keyword-regexp) + (looking-at eif-multiline-routine-is-keyword-regexp) + (looking-at eif-obsolete-keyword)) + (if originally-looking-at-comment + ;; Then the line we are trying to indent is a comment + (setq indent (eif-feature-level-comment-indent-m)) + ;; Else the line being indented is not a comment + (setq indent (eif-feature-level-kw-indent-m)))) + ;; Feature indentation keyword or class-level `create'. + ((or (looking-at eif-feature-indentation-keywords-regexp) + (and (looking-at eif-create-keyword-regexp) + (not (save-excursion + (eif-find-beginning-of-feature))))) + (setq indent (eif-feature-level-indent-m))) + ((looking-at eif-create-keyword-regexp) + (setq indent (eif-current-line-indent))) + ((and (looking-at eif-indentation-keywords-regexp) + (not (looking-at eif-once-non-indent-regexp))) + (if (looking-at eif-end-on-current-line) + (setq indent (eif-current-line-indent)) + (setq indent + (+ (eif-current-line-indent) eif-indent-increment)))) + ((looking-at eif-solitary-then-keyword) + (setq indent (- (+ (eif-current-line-indent) eif-indent-increment) + (eif-then-indent-m)))) + ((looking-at eif-then-keyword) + (setq indent (eif-current-line-indent))) + ((looking-at (concat eif-end-keyword eif-non-id-char-regexp)) + (if (= (setq indent (eif-current-line-indent)) + (eif-feature-level-kw-indent-m)) + (setq indent (eif-feature-level-indent-m)) + (eif-matching-line) + (if (string-match eif-check-keyword eif-matching-kw-for-end) + (setq indent (- indent (eif-check-keyword-indent-m)))))) + ((looking-at eif-variable-or-const-regexp) + ;;Either a variable declaration or a pre or post condition tag + (if originally-looking-at-comment + ;; Then the line we are trying to indent is a comment + (if (= (setq indent (eif-current-line-indent)) + (eif-feature-level-indent-m)) + ;; Then - a feature level comment + (setq indent (eif-feature-level-comment-indent-m)) + ;; Else - some other kind of comment + (setq indent (+ indent (eif-body-comment-indent-m)))) + ;; Else the line being indented is not a comment + (if (setq indent (eif-indent-assertion-continuation id-colon)) + indent + ;; One of the ways of getting here is when we're + ;; in a split line in an indexing clause. + ;; Strings on their own need to be given some + ;; extra indent. + (if originally-looking-at-lone-string + (if (looking-at "[ \t]*\"[^\"]*\"[ \t]*$") + (setq indent (eif-current-line-indent)) + (setq indent (+ (eif-current-line-indent) + eif-indent-increment))) + (setq indent (eif-current-line-indent)))))) + ((setq indent (eif-manifest-array-start)) + indent) + ;; OK, this is a sanity check, but it kills a minor + ;; instance of `create', so we need to code the corner + ;; case. As for minor instance of `once'. + ((or (not (looking-at eif-all-keywords-regexp)) + (looking-at eif-create-keyword-regexp) + (looking-at eif-once-non-indent-regexp)) + (if originally-looking-at-comment + ;; Then the line we are trying to indent is a comment + (cond ((eif-continuation-line) + (setq indent + (+ (- (eif-current-line-indent) + eif-indent-increment) + (eif-body-comment-indent-m)))) + ;; preceding line is at eif-feature-level-indent - + ;; assume that the preceding line is a parent + ;; class in an inherit clause + ((= (eif-current-line-indent) + (eif-feature-level-indent-m)) + (setq indent + (+ (eif-inherit-level-kw-indent-m) + (eif-body-comment-indent-m)))) + (t + (setq indent + (+ (eif-current-line-indent) + (eif-body-comment-indent-m))))) + ;; Else line being indented is not a comment + + ;; The line the point is on is the one above the line being + ;; indented + (beginning-of-line) + (if (or continuation (looking-at eif-operator-eol-regexp)) + ;; Then the line being indented is a continuation line + (if (eif-continuation-line) + ;; The line preceding the line being indented is + ;; also a continuation line. Indent to the current + ;; line indentation. + (setq indent (eif-current-line-indent)) + ;; Else The line preceding the line being indented is + ;; not a continuation line. Indent an extra + ;; eif-continuation-indent + (setq indent (+ (eif-current-line-indent) + (eif-continuation-indent-m)))) + ;; Else the line being indented is not a continuation line. + (if (eif-continuation-line) + (if id-colon + ;; Then the line preceding the one being indented + ;; is an assertion continuation. Indent the current + ;; line to the same level as the preceding assertion + ;; tag. + (setq indent (eif-indent-assertion-tag)) + ;; Then the line preceding the one being indented is + ;; a continuation line. Un-indent by an + ;; eif-continuation-indent. + (setq indent (- (eif-current-line-indent) + eif-indent-increment))) + ;; Else the line preceding the line being indented is + ;; also not a continuation line. + + (if (and (looking-at "[ \t]*\"[^\"]*\"[ \t]*$") + (not originally-looking-at-lone-string)) + (setq indent (- (eif-current-line-indent) + eif-indent-increment)) + ;; Else use the current indent. + (setq indent (eif-current-line-indent)))))))))) + indent)) + +(defun eif-continuation-line () + "Return non-nil if the current line is a continuation line." + (or (looking-at eif-operator-regexp) + (save-excursion + (forward-line -1) + (beginning-of-line) + (looking-at eif-operator-eol-regexp)))) + +(defun eif-indent-assertion-continuation (id-colon) + "Generally, are we in line that is a continuation of an assertion? +More precisely, are we inside a pre or a post condition clause on a +line that is a continuation of a multi-line assertion beginning with a +tag? If so, return the indentation of the continuation line. The +argument ID-COLON is t if the line we are indenting begins with +\" :\", and nil otherwise." + (let ((limit (point))) + (if (save-excursion + (if (re-search-backward + (concat eif-feature-level-keywords-regexp "\\|" + eif-end-keyword-regexp) nil t) + (if (looking-at "ensure\\|require") + (setq limit (point))))) + (save-excursion + (end-of-line) + (if (and (not id-colon) (re-search-backward ": *" limit t)) + (progn + (goto-char (match-end 0)) + (current-column))))))) + +(defun eif-indent-assertion-tag () + "Return indentation for part of a multi-line assertion. +That is, the current line is assumed to be a continuation of a +multi-line assertion, and we return the required indentation." + (save-excursion + (if (re-search-backward "ensure\\|require\\|variant\\|invariant" nil t) + (+ (eif-current-line-indent) eif-indent-increment) + ;; This option should not occur + (error "Could not find assertion tag")))) + +(defun eif-matching-kw (matching-keyword-regexp &optional noerror) + "Search backwards and return a keyword in MATCHING-KEYWORD-REGEXP. +Also set the value of variable `eif-matching-indent' to the +indentation of the keyword found. If an `end' keyword occurs prior to +finding one of the keywords in MATCHING-KEYWORD-REGEXP and it +terminates a check clause, set the value of variable +`eif-matching-indent' to the indentation of the `end' minus the value +of `eif-check-keyword-indent'." + (let ((search-regexp (concat "[^a-z0-9A-Z_.]" + eif-end-keyword + "[^a-z0-9A-Z_.]\\|[^a-z0-9A-Z_.]" + matching-keyword-regexp + "\\|" eif-once-non-indent-regexp)) + (keyword nil)) + (save-excursion + ;; Search backward for a matching keyword. + ;; Note that eif-once-non-indent-regexp indicates we haven't + ;; found a match so should keep going. + (while (and (eif-re-search-backward search-regexp 1 t) + (looking-at eif-once-non-indent-regexp) + (not (= (point) 1)))) + (if (looking-at search-regexp) + ;; Then - a keyword was found + (progn + (setq keyword + (buffer-substring (match-beginning 0) (match-end 0))) + (if (and (looking-at eif-end-keyword-regexp) + (eif-matching-line) + (string-match eif-check-keyword eif-matching-kw-for-end)) + ;; Then + (setq eif-matching-indent (- (eif-current-line-indent) + (eif-check-keyword-indent-m))) + ;; Else + (setq eif-matching-indent (eif-current-line-indent)))) + ;; Else no keyword was found. I think this is an error + (setq eif-matching-indent 0) + (if noerror + nil + (message "No matching indent keyword was found"))) + keyword))) + +(defun eif-line-contains-close-paren () + "Return t if the current line contains a close paren, nil otherwise. +If a close paren is found, the point is placed immediately after the +last close paren on the line. If no paren is found, the point is +placed at the beginning of the line." + (let ((search-min 0)) + (beginning-of-line) + (setq search-min (point)) + (end-of-line) + (if (search-backward ")" search-min t) + ;; Then + (progn + (forward-char 1) + t) + ;; Else + (beginning-of-line) + nil))) + +;; Not Currently Used +;;(defun eif-quoted-string-on-line-p () +;; "t if an Eiffel quoted string begins, ends, or is continued +;; on current line." +;; (save-excursion +;; (beginning-of-line) +;; ;; Line must either start with optional whitespace immediately followed +;; ;; by a '%' or include a '\"'. It must either end with a '%' character +;; ;; or must include a second '\"' character. +;; (looking-at "^\\([ \t]*%\\|[^\"\n]*\"\\)[^\"\n]*\\(%$\\|\"\\)"))) + +(defconst eif-opening-regexp + "\\<\\(external\\|check\\|deferred\\|do\\|once\\|from\\|if\\|inspect\\|debug\\)\\>" + "Keywords that open eiffel nesting constructs.") +;; OK, this is a horrible hack in all of this to handle "once" as a +;; special case because it has been overloaded. The search for the +;; opening keyword on the current line is quite reasonably limited to +;; the current line. Therefore, the standard hacky way that we avoid +;; matching once strings, by making sure they're followed by +;; whitespace and a non-double-quote, doesn't work here. +(defconst eif-non-opening-regexp + "\\" + "Keywords that close eiffel nesting constructs.") +(defconst eif-do-regexp "^[[:space:]]*\\(do\\|once\\|external\\|attribute\\)\\>" + "Keyword that opens eiffel routine body.") +(defconst eif-opening-or-closing-regexp + (concat "\\(" eif-opening-regexp "\\|" eif-closing-regexp "\\)") + "Keywords that open or close eiffel nesting constructs.") + +;; +;; Code to allow indenting whole eiffel blocks +;; + +(defun eif-matching-line (&optional return-line-break direction) + "Return the position of the keyword matching the one on the current line. +For example, a line containing the keyword `do' is matched by a line +containing the keyword `end' and a line containing `end' may be +matched by a number of opening keywords. If the optional parameter +RETURN-LINE-BREAK is non-nil, the character position returned is the +beginning (or end) of the line containing the matching keyword instead +of the position of the keyword itself. If the second optional +parameter, DIRECTION, is non-nil, the current line is not searched for +a keyword. Instead, if the value of direction is 'forward, the +function acts as if an `eif-opening-regexp' is on the current line. +If the value of direction is 'backward, the function acts as if a +`eif-closing-regexp' is on the current line. The effect of using the +direction parameter is to locate either the opening or closing keyword +of the syntactic construct containing the point." + (let ((nesting-level 0) + (search-end 0) + matching-point opening-keyword match-start match-end + success start-point) + (unwind-protect + (save-excursion + (setq eif-matching-kw-for-end "");; public variable set by this function + (setq start-point (point)) + (end-of-line) + (setq search-end (point)) + (beginning-of-line) + ;; Set starting state: If direction was specified use it. + ;; If direction is nil, search for a keyword on the current line + ;; If the keyword is in eif-opening-regexp, set the search + ;; direction to 'forward, if the keyword on the current line is `end' + ;; set the search direction to 'backward. + (cond ((eq direction 'forward) + (end-of-line) ;; So we wont see keywords on this line. + (setq nesting-level 1)) + ((eq direction 'backward) + (beginning-of-line) ;; So we wont see keywords on this line. + (setq nesting-level -1)) + ((and (re-search-forward eif-opening-regexp search-end t) + (eif-not-in-comment-or-quoted-string-p)) + (setq match-start (match-beginning 0)) + (setq match-end (match-end 0)) + (goto-char match-start) + (if (and (not (looking-at eif-non-opening-regexp)) + (eif-not-in-comment-or-quoted-string-p)) + (setq nesting-level 1)) + (setq opening-keyword + (cons (buffer-substring match-start match-end) + opening-keyword)) + (goto-char match-end)) + ((and (progn (beginning-of-line) t) + (re-search-forward eif-closing-regexp search-end t) + (eif-not-in-comment-or-quoted-string-p)) + (goto-char (match-beginning 0)) + (if (eif-not-in-comment-or-quoted-string-p) + (setq nesting-level -1)))) + ;; Perform the search + (while (not (= nesting-level 0)) + (if (> nesting-level 0) + ;; Then search forward for the next keyword not in a comment + (while (and (re-search-forward eif-opening-or-closing-regexp nil 1) + (goto-char (setq match-start (match-beginning 0))) + (setq match-end (match-end 0)) + (setq success t) + (or (looking-at eif-non-opening-regexp) + (eif-in-comment-or-quoted-string-p))) + (goto-char match-end) + (setq success nil)) + ;; Else search backward for the next keyword not in a comment + (while (and (re-search-backward eif-opening-or-closing-regexp nil 1) + (goto-char (setq match-start (match-beginning 0))) + (setq success t) + (or (looking-at eif-non-opening-regexp) + (eif-in-comment-or-quoted-string-p))) + (setq success nil))) + (cond ((and (not (looking-at eif-non-opening-regexp)) + (looking-at eif-opening-regexp) + success) + ;; Found an opening keyword + (if (> nesting-level 0) + ;; Then + (if (looking-at eif-do-regexp) + ;; Then + (setq nesting-level -1) + ;; Else + (setq opening-keyword + (cons (buffer-substring match-start + (match-end 0)) + opening-keyword)) + (goto-char (match-end 0))) + ;; Else + (if (= nesting-level -1) + ;; Then + (progn + (setq eif-matching-kw-for-end + (buffer-substring match-start (match-end 0))) + (if (looking-at "[ \t\n]+") + (goto-char (match-end 0)))) + ;; Else + (if (looking-at eif-do-regexp) + ;; Then + (progn + (goto-char (eif-matching-line nil 'forward)) + (setq nesting-level -1)))) + (setq opening-keyword (cdr opening-keyword)) + (if return-line-break + (beginning-of-line))) + (setq nesting-level (1+ nesting-level))) + ((and (looking-at eif-closing-regexp) success) + ;; Found an opening keyword + (if (> nesting-level 0) + ;; Then + (progn + (setq opening-keyword (cdr opening-keyword)) + (if return-line-break + (end-of-line)) + (goto-char (match-end 0))) + ;; Else + (setq opening-keyword + (cons (buffer-substring (match-beginning 0) + (match-end 0)) + opening-keyword))) + (setq nesting-level (1- nesting-level))) + (t (message (concat "Could not find match" + (if (car opening-keyword) + (concat " for: " + (car opening-keyword))))) + (goto-char start-point) + (setq nesting-level 0)))) + (setq matching-point (point)))) + (set-mark matching-point))) + +;; ENHANCEME: Make this function correctly indent more than just routine +;; bodies and their sub-constructs. At the least it should +;; handle whole routines also. +(defun eif-indent-construct () + "Indent an entire eiffel syntactic construct. +It is assumed that the point is within a nesting construct ('do', +`once', 'check', 'if', 'from', or 'inspect'). The whole construct is +indented up to the matching end. If the point is not within such a +construct, then only that line is indented" + (interactive) + (let ((end-point 0)) + (save-excursion + (end-of-line) + (if (not (= (point) (point-max))) (forward-char 1)) + (goto-char (eif-matching-line t 'backward)) + (setq end-point (eif-matching-line t 'forward)) + (while (< (point) end-point) + (eif-indent-line) + (forward-line 1) + (beginning-of-line))))) + +(defun eif-indent-region (&optional start end) + "Indent the lines in the current region. +The region may be specified using optional arguments START and END." + (interactive) + (let ((start-point (or start (region-beginning))) + (end-point (copy-marker (or end (region-end))))) + (save-excursion + (goto-char start-point) + (cond ((eq major-mode 'eiffel-mode) + (while (< (point) end-point) + (if (not (looking-at "[ \t]*$")) + (eif-indent-line)) + (forward-line 1) + (beginning-of-line))) + (t (error "Buffer must be in eiffel mode")))))) + +(defadvice isearch-yank-word (around eif-isearch-yank-word activate) + "isearch-yank-word, with the underscore not being a letter" + (interactive) + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice isearch-yank-word-or-char (around eif-isearch-yank-word-or-char activate) + "isearch-yank-word-or-char, with the underscore not being a letter" + (interactive) + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice forward-word (around eif-forward-word activate) + "forward-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice backward-word (around eif-backward-word activate) + "backward-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice right-word (around eif-forward-word activate) + "right-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice left-word (around eif-backward-word activate) + "left-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice backward-kill-word (around eif-backward-kill-word activate) + "backward-kill-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defadvice kill-word (around eif-kill-word activate) + "kill-word, with the underscore not being a letter" + (interactive "p") + (modify-syntax-entry ?_ "_ ") + ad-do-it + (modify-syntax-entry ?_ "w ")) + +(defun eif-local-indent (amount) + "Set the value of `eif-indent-increment' to AMOUNT buffer-locally." + (interactive "NNumber of spaces for eif-indent-increment: ") + (make-local-variable 'eif-indent-increment) + (setq eif-indent-increment amount)) + +;; ---------------------------------------------------------------------- +;; This next portion of the file is derived from "eiffel.el" +;; Copyright (C) 1989, 1990 Free Software Foundation, Inc. and Bob Weiner +;; Available for use and distribution under the same terms as GNU Emacs. +;; ---------------------------------------------------------------------- + +(defvar eiffel-mode-map nil + "Keymap for Eiffel mode.") + +(if eiffel-mode-map + nil + (let ((map (make-sparse-keymap))) + (define-key map [(control j)] 'newline-and-indent) + (define-key map [(return)] 'reindent-then-newline-and-indent) + (define-key map [(meta control q)] 'eif-indent-construct) + (define-key map [(meta \')] 'eif-feature-quote) + (define-key map [(meta q)] 'eif-fill-paragraph) + (define-key map [(meta control a)] 'eif-beginning-of-feature) + (define-key map [(meta control e)] 'eif-end-of-feature) + (define-key map [(control x) ?n ?d] 'eif-narrow-to-feature) + (define-key map [(control c) ?c] 'eif-class) + (define-key map [(control c) ?f] 'eif-function) + (define-key map [(control c) ?p] 'eif-procedure) + (define-key map [(control c) ?a] 'eif-attribute) + (define-key map [(control c) ?i] 'eif-if) + (define-key map [(control c) ?l] 'eif-loop) + (define-key map [(control c) ?s] 'eif-set) + (define-key map [(control c) ?n] 'eif-inspect) + (define-key map [(control c) ?w] 'eif-when) + (define-key map [(control c) ?e] 'eif-elseif) + (define-key map [(meta control a)] 'eif-beginning-of-feature) + (define-key map [(meta control e)] 'eif-end-of-feature) + (define-key map [(meta control h)] 'eif-mark-feature) + (setq eiffel-mode-map map))) + +(defvar eiffel-mode-syntax-table nil + "Syntax table in use in Eiffel-mode buffers.") + +(if eiffel-mode-syntax-table + nil + (let ((table (make-syntax-table)) + (i 0)) + (while (< i ?0) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?9)) + (while (< i ?A) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?Z)) + (while (< i ?a) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?z)) + (while (< i 128) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (modify-syntax-entry ? " " table) + (modify-syntax-entry ?- ". 12" table) + (modify-syntax-entry ?_ "w " table) + (modify-syntax-entry ?\t " " table) + (modify-syntax-entry ?\n "> " table) + (modify-syntax-entry ?\f "> " table) + (modify-syntax-entry ?\" "\" " table) + (modify-syntax-entry ?\\ "." table) + (modify-syntax-entry ?\( "() " table) + (modify-syntax-entry ?\) ")( " table) + (modify-syntax-entry ?\[ "(] " table) + (modify-syntax-entry ?\] ")[ " table) + (modify-syntax-entry ?\{ "(} " table) + (modify-syntax-entry ?\} "){ " table) + (modify-syntax-entry ?' "\"" table) + (modify-syntax-entry ?` "." table) + (modify-syntax-entry ?/ "." table) + (modify-syntax-entry ?* "." table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "\\" table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?\; "." table) + (modify-syntax-entry ?: "." table) + (modify-syntax-entry ?! "." table) + (modify-syntax-entry ?. "." table) + (modify-syntax-entry ?, "." table) + (setq eiffel-mode-syntax-table table))) + +(defun eif-add-menu () + "Add the \"Eiffel\" menu to the menu bar." + + (easy-menu-define + eiffel-mode-menu + eiffel-mode-map + "Menu for eiffel-mode." + (append (list "LibertyEiffel") + (if eif-use-gnu-eiffel + (list + ["Compile..." eif-compile t] + ["Compiler Options..." eif-set-compile-options t] + ["Next Compile Error..." next-error t] + ["Run..." eif-run t] + ["Debug..." eif-debug t] + ["Short..." eif-short t] + ["----------" nil nil])) + (list + ["Indent Construct" eif-indent-construct t] + (list "Insert" + ["Class" eif-class t] + ["Command" eif-procedure t] + ["Query" eif-function t] + ["Attribute" eif-attribute t] + ["Attribute setter" eif-set t] + ["If" eif-if t] + ["Loop" eif-loop t] + ["Inspect" eif-inspect t] + ["When" eif-when t] + ["Elseif" eif-elseif t]) + ["----------" nil nil] + (list "Imenu" + ["By position" eif-imenu-add-menubar-by-position t] + ["By name" eif-imenu-add-menubar-by-name t]) + (list "Comments" + ["Feature Quote" eif-feature-quote (eif-in-comment-p)] + ["Fill " eif-fill-paragraph (eif-near-comment-p)]) + ["----------" nil nil] + ["Customize" eif-customize t]))) + (easy-menu-add eiffel-mode-menu)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode)) +(add-to-list 'auto-mode-alist '("\\.se\\'" . eiffel-mode)) + +(defun eiffel-mode () + "Major mode for editing Eiffel programs. +\\[indent-for-tab-command] indents the current Eiffel line correctly and +\\[reindent-then-newline-and-indent] causes the current and next line to be +properly indented. + +Key definitions: +\\{eiffel-mode-map} + +If variable `eif-use-gnu-eiffel' is non-nil (default t) then support +for using GNU SmartEiffel is enabled. Run \\[eif-customize] to see +compilation and indentation variables that can be customized." + + (interactive) + + (kill-all-local-variables) + + (setq major-mode 'eiffel-mode) + (setq mode-name "Eiffel") + + (if eif-use-gnu-eiffel + (progn + (define-key eiffel-mode-map "\C-c\C-c" 'eif-compile) + (define-key eiffel-mode-map "\C-c\C-o" 'eif-set-compile-options) + (define-key eiffel-mode-map "\C-c\C-r" 'eif-run) + (define-key eiffel-mode-map "\C-c\C-d" 'eif-debug) + (define-key eiffel-mode-map "\C-c\C-s" 'eif-short) + (define-key eiffel-mode-map "\C-c\C-f" 'eif-find-file)) + (define-key eiffel-mode-map "\C-c\C-c" nil) + (define-key eiffel-mode-map "\C-c\C-o" nil) + (define-key eiffel-mode-map "\C-c\C-r" nil) + (define-key eiffel-mode-map "\C-c\C-s" nil)) + + (use-local-map eiffel-mode-map) + (eif-add-menu) + (set-syntax-table eiffel-mode-syntax-table) + + ;; Make local variables. + (make-local-variable 'paragraph-start) + (make-local-variable 'paragraph-separate) + (make-local-variable 'paragraph-ignore-fill-prefix) + (make-local-variable 'require-final-newline) + (make-local-variable 'parse-sexp-ignore-comments) + (make-local-variable 'indent-line-function) + (make-local-variable 'indent-region-function) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-column) + (make-local-variable 'comment-start-skip) + (make-local-variable 'imenu-create-index-function) + ;; Now set their values. + (setq paragraph-start (concat "^$\\|" page-delimiter) + paragraph-separate "[ \t ]*$" + paragraph-ignore-fill-prefix t + require-final-newline t + parse-sexp-ignore-comments t + indent-line-function 'eif-indent-line + indent-region-function 'eif-indent-region + comment-start "-- " + comment-end "" + comment-column 32 + comment-start-skip eiffel-comment-start-skip + font-lock-multiline t) + + (set (make-local-variable 'font-lock-defaults) #'(eiffel-font-lock-defaults t)) + + (if eif-set-tab-width-flag + (setq tab-width eif-indent-increment)) + + (setq auto-fill-function 'eif-auto-fill) + (run-hooks 'eiffel-mode-hook)) + +(defconst eif-prefeature-regexp + (concat "\\(" eif-non-source-line "\\|\n\\)*" "[ \t]*") + "Regexp matching whitespace-equivalent content, possibly before a feature.") + +(defun eif-find-end-of-feature () + "Find the `end' of the current feature definition. +Assumes point is at the beginning of the feature, not in a comment or +quoted string." + (let (ret) + (cond ((looking-at (concat eif-prefeature-regexp + eif-routine-begin-regexp)) + ;; At the start of a routine, find matching end. + (and (eif-re-search-forward eif-do-regexp nil t) + (goto-char (match-beginning 0)) + (goto-char (setq ret (eif-matching-line))))) + ((looking-at (concat eif-prefeature-regexp + eif-probably-feature-regexp)) + ;; Not a routine, find end of attribute or constant. + (goto-char (setq ret (match-end 0))))) + ret)) + +;; OK, this works well, but it doesn't work for the following cases: +;; * In the middle of the feature regexp that need to be matched. +;; However, it doesn't need to since eif-beginning-of-feature adds +;; some smarts around it... +(defun eif-find-beginning-of-feature () + "Find the beginning of the most recent feature definition. +This will always move backward, if possible." + (interactive) + + (let ((start (point)) + candidate routine-begin) + (if (eif-re-search-backward (concat "\\s-" eif-probably-feature-regexp) + nil t) + (progn + (forward-char) ;; Skip the whitespace character matched above. + (if (looking-at (regexp-opt eiffel-keywords-feature)) + (eif-find-beginning-of-feature) + (if (not (or (looking-at (concat + "\\(" eif-attribute-regexp + "\\|" eif-constant-regexp "\\)")))) + ;; This is a routine. Done. + (point) + ;; Variable/attribute or constant declaration matched. + ;; Now we go back and find the previous routine start, the + ;; following end, and see if the current position + ;; (candidate) is between. If it is, then candidate is a + ;; variable or constant declaration within a routine, so + ;; we're interested in the routine start. If it isn't, + ;; then it must be a class attribute or constant, so it is + ;; what we're looking for. + (setq candidate (point)) + (goto-char start) + (if (eif-re-search-backward + (concat "\\s-" eif-routine-begin-regexp) nil t) + (progn + (forward-char) + (setq routine-begin (point)) + (eif-find-end-of-feature) + (if (and (< routine-begin candidate) + (< candidate (point))) + (goto-char routine-begin) + (goto-char candidate))) + (goto-char candidate)))))))) + +(defun eif-beginning-of-feature (&optional arg) + "Move backward to next feature beginning. +With ARG, do it that many times. Negative arg -N +means move forward to Nth following beginning of feature. +Returns t unless search stops due to beginning or end of buffer." + (interactive "p") + + (or arg + (setq arg 1)) + + (let ((start (point)) + (success t)) + (cond ((> arg 0) + ;; Going backward. + + ;; We have to move forward to make sure we find any feature + ;; that we might be in the middle of the beginning of. How + ;; far? How about this far? + (eif-re-search-forward eif-probably-feature-regexp nil 'move) + + ;; Change arg towards zero as we search, failing if we hit + ;; edge of buffer. + (while (and (> arg 0) + (or (eif-find-beginning-of-feature) + (setq success nil))) + ;; If we've gone backwards from the original start, then + ;; this counts. + (if (< (point) start) + (setq arg (1- arg)))) + (or success + (goto-char (point-min)))) + + ((< arg 0) + ;; Going forward. + + ;; Similar to above, let's go back to the beginning of the + ;; current feature, and then skip over features and find + ;; the beginning of the next repeatedly. + (eif-find-beginning-of-feature) + + (while (and (< arg 0) + (or (not (eobp)) (setq success nil))) + (eif-find-end-of-feature) + (if (eif-re-search-forward eif-probably-feature-regexp + nil 'move) + (progn + (goto-char (match-beginning 0)) + (if (> (point) start) + (setq arg (1+ arg)))))))) + success)) + +(defun eif-end-of-feature (&optional arg) + "Move forward to end of feature. +With argument, do it that many times. Negative argument means move +back ARG preceding ends of features." + (interactive "p") + + ;; Default is to find the first feature's end. + ;; Huh? Even if they specify 0? - martin@meltin.net + ;; Hmmm, it is what end-of-defun does... + (if (or (null arg) + (= arg 0)) + (setq arg 1)) + + ;; This is a bad way of trying to get into position. Happily, it + ;; seems to work. Hmmm, not sure if the comment skip is needed. + (if (eif-in-comment-p) + (end-of-line)) + (cond ((let ((curr (point))) + (save-excursion + (and (eif-beginning-of-feature) + (eif-find-end-of-feature) + (forward-line) + (or (< curr (point)) + (and (< arg 0) + (= curr (point))))))) + ;; Within a feature. Go to its beginning. + (eif-beginning-of-feature)) + ((eif-peeking-backwards-at (concat "\\s-" + eif-probably-feature-regexp)) + ;; Sitting at beginning of feature. Don't move! + t) + (t + ;; Not within a feature or at beginning, go to beginning of + ;; next feature. + (eif-beginning-of-feature -1))) + + ;; This part is correct. + (if (eif-beginning-of-feature (+ (if (< arg 0) 0 1) (- arg))) + (progn + (eif-find-end-of-feature) + (forward-line)))) + +(defun eif-narrow-to-feature () + "Make text outside current feature invisible. +The feature visible is the one that contains point or follows point." + (interactive) + (save-excursion + (widen) + (eif-end-of-feature) + (let ((end (point))) + (eif-beginning-of-feature) + (narrow-to-region (point) end)))) + +(defun eif-current-line-indent () + "Return the indentation of the line containing the point." + (save-excursion + (eif-skip-leading-whitespace) + (current-column))) + +(defun eif-in-quoted-string-p (&optional non-strict-p) + "Return t if point is in a quoted string. +Optional argument NON-STRICT-P if true causes the function to return +true even if the point is located in leading white space on a +continuation line. Normally leading white space is not considered part +of the string." + (let ((initial-regexp "^[ \t]*%\\|[^%]U?\"\\|%[ \t]*$") + (search-limit (point)) + (count 0)) + (save-excursion + ;; Line must either start with optional whitespace immediately followed + ;; by a '%' or include a '\"' before the search-limit. + (beginning-of-line) + (while (re-search-forward initial-regexp search-limit t) + (setq count (1+ count)) + (if (= count 1) (setq search-limit (1+ search-limit)))) + ;; If the number of quotes (including continuation line markers) + ;; is odd, then we are inside of a string. Also if non-strict-p + ;; and we are in the leading white space of a continuation line, + ;; then we are in a quote. + (or (= (% count 2) 1) + (progn + (beginning-of-line) + (and non-strict-p + (looking-at "^[ \t]*%"))))))) + +;; ---------------------------------------------------------------------- +;; End of portion derived from "eiffel.el" +;; ---------------------------------------------------------------------- + +(defun eif-comment-prefix () + "Return the prefix starting a comment that begins a line. +Comments that are not the only thing on a line return nil as their prefix." + (save-excursion + (end-of-line) + (let ((limit (point)) len + (in-string (eif-in-quoted-string-p))) + (beginning-of-line) + (cond ((re-search-forward "^[ \t]*--|?[ \t]*" limit t) + (buffer-substring (match-beginning 0) (match-end 0))) + ;; Handle string-literal continuation lines + (in-string + (end-of-line) + (re-search-backward "^[ \t]*%\\|[^%]\"" nil t) + (re-search-forward "%\\|\"" nil t) + (setq len (1- (current-column))) + (concat (make-string len ? ) "%")))))) + +(defun eif-auto-fill () + "Auto-fill an Eiffel comment." + (let ((fill-prefix (eif-comment-prefix)) + (pm (point-marker))) + (if (and (> (current-column) fill-column) + fill-prefix) + (if (string-match "^[ \t]*%" fill-prefix) + (progn + (backward-char 1) + (re-search-backward "[^][a-zA-Z0-9]" nil t) + (forward-char 1) + (insert "%\n") + (insert fill-prefix) + (goto-char pm)) + ;; (do-auto-fill) + (backward-char 1) + (re-search-backward "\\s-" nil t) + (forward-char 1) + (insert "\n") + (insert fill-prefix) + (goto-char pm))))) + +(defun eif-fill-paragraph () + "Textually fills Eiffel comments ala \\[fill-paragraph]." + (interactive) + (save-excursion + (let ((current-point (point)) + (fill-prefix (eif-comment-prefix)) + last-point para-begin para-end) + (if fill-prefix + (progn + (setq last-point (point)) + (forward-line -1) + (end-of-line) + (while (and (not (= (point) last-point)) + (eif-comment-prefix)) + (setq last-point (point)) + (forward-line -1) + (end-of-line)) + (if (= (point) last-point) + (setq para-begin (save-excursion (beginning-of-line) (point))) + (setq para-begin (1+ (point)))) + (goto-char current-point) + (setq last-point (point)) + (forward-line 1) + (end-of-line) + (while (and (not (= (point) last-point)) + (eif-comment-prefix)) + (setq last-point (point)) + (forward-line 1) + (end-of-line)) + (if (= (point) last-point) + (setq para-end (point)) + (beginning-of-line) + (setq para-end (point))) + ;; Avert eyes now - gross hack follows... how big can an + ;; Eiffel comment be anyway? :-) + (let ((orig-region (and (<= (- para-end para-begin) + eif-fill-max-save) + (buffer-substring para-begin para-end))) + (orig-state (buffer-modified-p)) + (ret (fill-region para-begin para-end))) + (and orig-region + (<= para-end (point-max)) + (string-equal + orig-region (buffer-substring para-begin para-end)) + (set-buffer-modified-p orig-state)) + ret)))))) + +(defun eif-indent-line (&optional whole-exp) + "Indent the current line as Eiffel code. +With optional argument WHOLE-EXP, indent any additional lines of the +same clause rigidly along with this one (not implemented yet)." + (interactive "p") + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (let ((indent (eif-calc-indent))) + (if (not (= indent (current-column))) + (progn + (delete-horizontal-space) + (indent-to indent))))) + (skip-chars-forward " \t")) + +(defun eif-move-to-prev-non-blank () + "Move point to previous line excluding blank lines. +Return t if successful, nil if not." + (beginning-of-line) + (re-search-backward "^[ \t]*[^ \t\n]" nil t)) + +(defvar eif-last-feature-level-indent -1) +(defvar eif-feature-level-indent-regexp nil) +(defun eif-in-paren-expression () + "Determine if we are inside of a parenthesized expression." + (interactive) + (let ((paren-count 0) (limit 0)) + (save-excursion + (if (= eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq limit + (re-search-backward eif-feature-level-indent-regexp nil t)) + (setq eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq eif-feature-level-indent-regexp + (concat "^" (make-string eif-last-feature-level-indent ? ) + "[^ \t\n]")) + (setq limit + (or (re-search-backward eif-feature-level-indent-regexp nil t) + 0)))) + (save-excursion + (while (re-search-backward "[][()]" limit t) + (if (looking-at "[[(]") + (setq paren-count (1+ paren-count)) + (setq paren-count (1- paren-count))))) + paren-count)) + +(defun eif-manifest-array-common () + "Common code for handling indentation/presence of Eiffel manifest arrays." + (let ((paren-count 0)) + (if (= eif-last-feature-level-indent (eif-feature-level-indent-m)) + nil + (setq eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq eif-feature-level-indent-regexp + (concat "^" (make-string eif-last-feature-level-indent ? ) + "[^ \t\n]"))) + (while (and (<= paren-count 0) (re-search-backward "<<\\|>>" nil t)) + (if (not (eif-peeking-backwards-at "|\\|@")) + (if (looking-at "<<") + (setq paren-count (1+ paren-count)) + (setq paren-count (1- paren-count))))) + paren-count)) + +(defun eif-manifest-array-indent () + "Determine if we are inside of a manifest array." + (interactive) + (let (indent) + (save-excursion + (if (> (eif-manifest-array-common) 0) + (let ((eol (save-excursion (end-of-line) (point)))) + (setq indent + (or (and (re-search-forward "[^< \t]" eol t) + (1- (current-column))) + (+ (current-column) 2)))))) + indent)) + +(defun eif-manifest-array-start () + "Determine the indentation of the statement containing a manifest array." + (interactive) + (let (indent) + (save-excursion + (if (> (eif-manifest-array-common) 0) + (let ((limit (progn (end-of-line) (point)))) + (beginning-of-line) + (if (re-search-forward "^[ \t]*<<" limit t) + (setq indent (- (current-column) 2 eif-indent-increment)) + (re-search-forward "^[ \t]*" limit t) + (setq indent (current-column)))))) + indent)) + +;; ---------------------------------------------------------------------- +;; The function below is derived from "eif-mult-fmt.el" +;; Copyright (C) 1985 Free Software Foundation, Inc. +;; Copyright (C) 1990 Bob Weiner, Motorola Inc. +;; Available for use and distribution under the same terms as GNU Emacs. +;; ---------------------------------------------------------------------- + +(defun eif-indent-multi-line (&optional parse-start) + "Return indentation for line within parentheses or double quotes. +That is, we are in a multi-line parenthesised or double-quoted +expression, and want to know the suggested indentation for the current +line. If we are not within such an expression then return -1. +Optional argument PARSE-START is buffer position at which to begin +parsing, default is to begin at the feature enclosing or preceding +point." + (let ((eif-opoint (point)) + (indent-point (progn (beginning-of-line) (point))) + (eif-ind-val -1) + (eif-in-str nil) + (eif-paren-depth 0) + (retry t) + state + ;; setting this to a number inhibits calling hook + last-sexp containing-sexp) + (if parse-start + (goto-char parse-start) + (eif-beginning-of-feature)) + ;; Find outermost containing sexp + (while (< (point) indent-point) + (setq state (parse-partial-sexp (point) indent-point 0))) + ;; Find innermost containing sexp + (while (and retry + state + (> (setq eif-paren-depth (elt state 0)) 0)) + (setq retry nil) + (setq last-sexp (elt state 2)) + (setq containing-sexp (elt state 1)) + ;; Position following last unclosed open. + (goto-char (1+ containing-sexp)) + ;; Is there a complete sexp since then? + (if (and last-sexp (> last-sexp (point))) + ;; Yes, but is there a containing sexp after that? + (let ((peek (parse-partial-sexp last-sexp indent-point 0))) + (if (setq retry (car (cdr peek))) (setq state peek))))) + (if retry + nil + ;; Innermost containing sexp found + (goto-char (1+ containing-sexp)) + (if (not last-sexp) + ;; indent-point immediately follows open paren. + nil + ;; Find the start of first element of containing sexp. + (parse-partial-sexp (point) last-sexp 0 t) + (cond ((looking-at "\\s(") + ;; First element of containing sexp is a list. + ;; Indent under that list. + ) + ((> (save-excursion (forward-line 1) (point)) + last-sexp) + ;; This is the first line to start within the containing sexp. + (backward-prefix-chars)) + (t + ;; Indent beneath first sexp on same line as last-sexp. + ;; Again, it's almost certainly a routine call. + (goto-char last-sexp) + (beginning-of-line) + (parse-partial-sexp (point) last-sexp 0 t) + (backward-prefix-chars)))) + (setq eif-ind-val (current-column))) + ;; Point is at the point to indent under unless we are inside a string. + (setq eif-in-str (elt state 3)) + (goto-char eif-opoint) + (if (not eif-in-str) + nil + ;; Inside a string, indent 1 past string start + (setq eif-paren-depth 1);; To account for being inside string + (save-excursion + (if (re-search-backward "\"" nil t) + (if eif-indent-string-continuations-relatively-flag + (setq eif-ind-val (1+ (current-column))) + (setq eif-ind-val (eif-current-line-indent))) + (goto-char indent-point) + (if (looking-at "^[ \t]*[^ \t\n]") + (eif-move-to-prev-non-blank)) + (skip-chars-forward " \t") + (setq eif-ind-val (current-column))))) + (if (> eif-paren-depth 0) eif-ind-val -1))) + +;; ---------------------------------------------------------------------- +;; imenu support, great for browsing foreign code. +;; Originally contributed by Berend de Boer . +;; ---------------------------------------------------------------------- + +(defun eif-imenu-add-menubar-by-position () + "Add menu of features of a class, sorted in order of occurence." + (interactive) + (setq imenu-create-index-function 'eif-imenu-create-index-by-position) + (imenu-add-to-menubar "Eiffel features") + ) + +(defun eif-imenu-add-menubar-by-name () + "Add menu of features of a class, sorted by name." + (interactive) + (setq imenu-create-index-function 'eif-imenu-create-index-by-name) + (imenu-add-to-menubar "Eiffel names")) + +(defun eif-imenu-create-index-by-position () + "Generate index of features of a class, sorted in order of occurence." + (eif-imenu-create-index 0)) + +(defun eif-imenu-create-index-by-name () + "Generate index of features of a class, sorted by name." + (eif-imenu-create-index 1)) + +(defun eif-imenu-create-index (sort-method) + "Generate an index of all features of a class. +Sort by position if sort-method is 0. Sort by name if sort-method is 1." + + (let (menu prevpos) + + (imenu-progress-message prevpos 0 t) + + ;; scan for features + (goto-char (point-max)) + (while (eif-find-beginning-of-feature) + (imenu-progress-message prevpos nil t) + (if (looking-at "\\(\\sw\\|\\s_\\)+") + (add-to-list 'menu (cons (buffer-substring-no-properties + (match-beginning 0) + (match-end 0)) (point))))) + + (imenu-progress-message prevpos 100) + + ;; sort in increasing buffer position order or by name + (if (= sort-method 0) + (sort menu (function (lambda (a b) (< (cdr a) (cdr b))))) + (sort menu (function (lambda (a b) (string< (car a) (car b)))))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; C. Adrian: added good old features for code templating + +(defun eif-class () + "Insert a 'class' template." + (interactive) + (let ((cname (if (and buffer-file-name + (string-match "/\\([^/]+\\)\\.e$" buffer-file-name)) + (substring buffer-file-name (match-beginning 1) (match-end 1)) + (read-string "Class: ")))) + (if (not (e-empty-line-p)) + (progn (end-of-line)(newline))) + (indent-to 0) + (insert "class " (upcase cname) "\n\n" + "create {ANY}\n" + "make\n" + "\nfeature {ANY}\n\n" + "\nfeature {}\n" + "\n\ninvariant\n\n" + "end -- class " (upcase cname) "\n")) + (re-search-backward "create {ANY}" nil t) + (forward-line 1) + (eif-indent-line) + (re-search-forward "feature {ANY}" nil t) + (forward-line 1) + (eif-indent-line)) + +(defun eif-procedure () + "Insert a 'procedure' template." + (interactive) + (let ((pname (read-string "Procedure name: "))) + (if (not (e-empty-line-p)) + (progn + (end-of-line) + (newline))) + (indent-to eif-indent-increment) + (insert pname " is\n") + (indent-to (* 3 eif-indent-increment)) + (insert "-- \n") + (mapc #'(lambda (keyword) + (indent-to (* 2 eif-indent-increment)) + (insert keyword "\n")) + '("require" "local" "do" "ensure" "end")) + (search-backward " is" nil t))) + +(defun eif-function () + "Insert a 'function' template." + (interactive) + (let ((fname (read-string "Function name: ")) + (type (upcase (read-string "Return type: ")))) + (if (not (e-empty-line-p)) + (progn (end-of-line)(newline))) + (indent-to eif-indent-increment) + (insert fname ": " type " is\n") + (indent-to (* 3 eif-indent-increment)) + (insert "-- \n") + (mapc #'(lambda (keyword) + (indent-to (* 2 eif-indent-increment)) + (insert keyword "\n")) + '("require" "local" "do" "ensure" "end")) + (search-backward ":" nil t))) + +(defun eif-attribute () + "Insert an 'attribute' template." + (interactive) + (if (not (e-empty-line-p)) + (progn (end-of-line)(newline))) + (indent-to eif-indent-increment) + (let ((aname (read-string "Attribute name: ")) + (type (upcase (read-string "Attribute type: ")))) + (insert aname ": " type "\n") + (indent-to (* 3 eif-indent-increment)) + (insert "-- \n") + (eif-indent-line) + (end-of-line))) + +(defun e-empty-line-p () + "True if current line is empty." + (save-excursion + (beginning-of-line) + (looking-at "^[ \t]*$"))) + +(defun eif-if () + "Insert an 'if' statement template." + (interactive) + (mapc #'(lambda (s) + (insert s)) + '("if then" "\n\nelse" "\n\nend" "\n")) + (re-search-backward " then" nil t) + (eif-indent-construct)) + +(defun eif-loop () + "Insert a 'loop' statement template." + (interactive) + (let ( + (varname (read-string "Loop variable name: ") + ) + ) + (if (not (string= varname "")) + + ;; THEN -- A variable is named: insert it + ( + let ((lower (read-string "Lower bound: ")) + (upper (read-string "Upper bound: ")) + (incr (read-string "Increment: ")) + ) + (insert "from\n" varname " := ") + (insert lower) + (insert "\ninvariant") + (insert "\nvariant\n") + (if (>= (string-to-number incr) 0) + (insert "(" upper " - " lower " + " incr ") - " varname) + (insert varname " - (" upper " - " lower " + " (abs incr) ")") + ) + (insert "\nuntil\n" varname) + (if (>= (string-to-number incr) 0) + (insert " > " upper) + (insert " < " upper) + ) + (insert "\nloop\n\n" varname " := " varname) + (if (>= (string-to-number incr) 0) + (insert " + " incr) + (insert " - " (abs incr)) + ) + (insert "\nend\n") + + (re-search-backward "from" nil t) + (eif-indent-construct) + (re-search-forward "loop" nil t) + (forward-line) + (eif-indent-line) + ) + + ;; ELSE -- No variable: general loop + (let () + (mapc #'(lambda (s) + (insert s)) + '("from" "\n\ninvariant" "\n\nvariant" + "\n\nuntil" "\n\nloop\n" "\nend") + ) + (re-search-backward "from" nil t) + (eif-indent-construct) + (forward-line) + (eif-indent-line) + ) + ) + ) + ) + +(defun eif-set () + "Inserts a function to set the value of the given variable." + (interactive) + (let ((aname (read-string "Attribute name: "))) + (insert "set_" aname " (v: like " aname ") is") + (eif-indent-line) + (insert "\n-- ") + (mapc #'(lambda (s) + (insert s) + (eif-indent-line)) + (list (concat "Set value of `" aname "'.") + "\nrequire" + "\nv /= Void" + "\ndo" + (concat "\n" aname " := v") + "\nensure" + (concat "\n" aname " = v") + (concat "\nend;"))) + (insert "\n"))) + +(defun eif-inspect () + "Insert an 'inspect-when' statement template." + (interactive) + (mapc #'(lambda (s) + (insert s) + (eif-indent-line)) + '("inspect " "\n\nwhen then" "\n\nelse" "\n\nend" "\n")) + (beginning-of-line) + (re-search-backward "inspect" nil t) + (forward-line) + (eif-indent-construct) + (eif-indent-line)) + +(defun eif-when () + "Insert another 'when-then' clause." + ;; Obvious improvement -- have this check to see it this is a valid + ;; location for this construct, before inserting it. + (interactive) + (insert "\nwhen then") + (eif-indent-line) + (insert "\n\n") + (re-search-backward " then" nil t)) + +(defun eif-elseif () + "Insert an 'elseif-then' clause." + ;; Obvious improvement -- have this check to see it this is a valid + ;; location for this construct, before inserting it. + (interactive) + (insert "\nelseif then") + (eif-indent-line) + (insert "\n\n") + (re-search-backward " then" nil t)) + +(defun eif-mark-feature () + "Put mark at end of feature, point at beginning." + (interactive) + (push-mark (point)) + (eif-end-of-feature) + (push-mark (point)) + (eif-beginning-of-feature) + (re-search-backward "^\n" (- (point) 1) t)) + +(defun e-comment-line-p () + "t if current line is just a comment." + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (looking-at "--"))) + +(defun e-comment-on-line-p () + "t if current line contains a comment." + (save-excursion + (beginning-of-line) + (looking-at "[^\n]*--"))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; XEmacs addition +;;;###autoload(add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode)) + +(provide 'eiffel) +;;; eiffel.el ends here diff --git a/layers.personal/mylangs/myeiffel/local/evil-eiffel/evil-eiffel.el b/layers.personal/mylangs/myeiffel/local/evil-eiffel/evil-eiffel.el new file mode 100644 index 0000000..a6ff119 --- /dev/null +++ b/layers.personal/mylangs/myeiffel/local/evil-eiffel/evil-eiffel.el @@ -0,0 +1,24 @@ +(require 'evil) +(require 'eiffel) + +(define-minor-mode evil-eiffel-mode + "Buffer local minor mode for evil-eiffel" + :init-value nil + :lighter "EvilEiffel" + :keymap (make-sparse-keymap) + :group 'evil-eiffel) + +(add-hook 'eiffel-mode-hook 'evil-eiffel-mode) + +(mapc #'(lambda (state) + (evil-define-key state evil-eiffel-mode-map + (kbd "M-c") 'eif-compile + (kbd "M-r") 'eif-run + (kbd "M-d") 'eif-debug + (kbd "M-o") 'eif-set-compile-options + (kbd "M-s") 'eif-short + (kbd "M-e") 'eif-next-error + )) + '(normal insert)) + +(provide 'evil-eiffel) diff --git a/layers.personal/mylangs/myeiffel/packages.el b/layers.personal/mylangs/myeiffel/packages.el new file mode 100644 index 0000000..fe77c90 --- /dev/null +++ b/layers.personal/mylangs/myeiffel/packages.el @@ -0,0 +1,83 @@ + ;;; packages.el --- myeiffel layer packages file for Spacemacs. + ;; + ;; Copyright (c) 2012-2016 Sylvain Benner & Contributors + ;; + ;; Author: Rongsong Shen + ;; URL: https://github.com/syl20bnr/spacemacs + ;; + ;; This file is not part of GNU Emacs. + ;; + ;;; License: GPLv3 + + ;;; Commentary: + + ;; See the Spacemacs documentation and FAQs for instructions on how to implement + ;; a new layer: + ;; + ;; SPC h SPC layers RET + ;; + ;; + ;; Briefly, each package to be installed or configured by this layer should be + ;; added to `myeiffel-packages'. Then, for each package PACKAGE: + ;; + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a + ;; function `myeiffel/init-PACKAGE' to load and initialize the package. + + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so + ;; define the functions `myeiffel/pre-init-PACKAGE' and/or + ;; `myeiffel/post-init-PACKAGE' to customize the package as it is loaded. + + ;;; Code: + + (defconst myeiffel-packages + '((eiffel :location local) + (evil-eiffel :location local)) + "The list of Lisp packages required by the myeiffel layer. + + Each entry is either: + + 1. A symbol, which is interpreted as a package to be installed, or + + 2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun myeiffel/init-eiffel () + (use-package eiffel + :defer t + :mode ("\\.e$" . eiffel-mode))) + +(defun myeiffel/init-evil-eiffel () + (use-package evil-eiffel + :commands evil-eiffel-mode + :init (add-hook 'eiffel-mode-hook 'evil-eiffel-mode) + :config (progn + (spacemacs/set-leader-keys-for-major-mode 'eiffel-mode + "c" 'eif-compile + "r" 'eif-run + "o" 'eif-set-compile-options + "d" 'eif-debug + "s" 'eif-short + "e" 'next-error)))) + +(defun myeiffel/post-init-eiffel () + ) + ;;; packages.el ends here diff --git a/layers.personal/mylangs/mymermaid/README.org b/layers.personal/mylangs/mymermaid/README.org new file mode 100644 index 0000000..c4f6e78 --- /dev/null +++ b/layers.personal/mylangs/mymermaid/README.org @@ -0,0 +1,29 @@ +#+TITLE: mymermaid layer +#+HTML_HEAD_EXTRA: + +#+CAPTION: logo + +# The maximum height of the logo should be 200 pixels. +[[img/mymermaid.png]] + +* Table of Contents :TOC_4_org:noexport: + - [[Description][Description]] + - [[Install][Install]] + - [[Key bindings][Key bindings]] + +* Description +This layer does wonderful things: + - thing01 + +* Install +To use this contribution add it to your =~/.spacemacs= + +#+begin_src emacs-lisp + (setq-default dotspacemacs-configuration-layers '(mymermaid)) +#+end_src + +* Key bindings + +| Key Binding | Description | +|-----------------+----------------| +| ~ x x x~ | Does thing01 | diff --git a/layers.personal/mylangs/mymermaid/local/evil-mermaid/evil-mermaid.el b/layers.personal/mylangs/mymermaid/local/evil-mermaid/evil-mermaid.el new file mode 100644 index 0000000..67fa739 --- /dev/null +++ b/layers.personal/mylangs/mymermaid/local/evil-mermaid/evil-mermaid.el @@ -0,0 +1,20 @@ +(require 'evil) +(require 'mermaid-mode) + +(define-minor-mode evil-mermaid-mode + "Buffer local minor mode for evil-mermaid" + :init-value nil + :lighter "EvilMermaid" + :keymap (make-sparse-keymap) + :group 'evil-mermaid) + +(add-hook 'mermaid-mode-hook 'evil-mermaid-mode) + +(mapc #'(lambda (state) + (evil-define-key state evil-mermaid-mode-map + (kbd "M-c") 'mermaid-compile + (kbd "M-v") 'mermaid-view + )) + '(normal insert)) + +(provide 'evil-mermaid) diff --git a/layers.personal/mylangs/mymermaid/local/mermaid/mermaid.el b/layers.personal/mylangs/mymermaid/local/mermaid/mermaid.el new file mode 100644 index 0000000..958c55d --- /dev/null +++ b/layers.personal/mylangs/mymermaid/local/mermaid/mermaid.el @@ -0,0 +1,239 @@ +;; mermaid mode + +(defvar mermaid-mode-hook nil + "initial hook for mermaid mode" + ) + +(defun mermaid-compilation-mode-hook () + "Hook function to set local value for `compilation-error-screen-columns'." + ;; In Emacs > 20.7 compilation-error-screen-columns is buffer local. + (or (assq 'compilation-error-screen-columns (buffer-local-variables)) + (make-local-variable 'compilation-error-screen-columns)) + (setq compilation-error-screen-columns nil)) + +(defvar mermaid-output-format 'png + "The format of generated file") + +(defvar mermaid-verbose nil + "Show verbose information when run compiler") + +(defvar mermaid-compiler "mermaid" + "The compiler used to generate output") + +(defvar mermaid-mode-map + (let ((map (make-sparse-keymap))) + ;; add key bindings for mermaid mode here + ;; + (define-key map "\C-j" 'newline-and-indent) + (define-key map "\C-c\C-c" 'mermaid-compile) + (define-key map "\C-c\C-v" 'mermaid-view) + map) + "Keymap for mermaid mode") + +(defconst mermaid-font-lock-keywords-1 + '(("^[ \t]*\\(graph\\|subgraph\\|end\\|loop\\|alt\\|gantt\\|title\\|section\\|dateFormat\\|sequenceDiagram\\|opt\\|participant\\|note\\|else\\|gitGraph\\|options\\)" . font-lock-keyword-face) + ("^[ \t]*graph[ \t]+\\(TD|\\TB\\|BT\\RL\\|LR\\)" . font-lock-keyword-face) + ("%%\\(.*$\\)" . font-lock-comment-face) + ("{\\(.*\\)}" . font-lock-string-face) + (":\\([^%\012]*\\)[^%\012]*$" . font-lock-warning-face) + ) + "keyword in mermaid mode" + ) + +(defconst mermaid-new-scope-regexp + "^[ \t]*\\(loop\\|opt\\|subgraph\\|graph\\|sequenceDiagram\\|gantt\\|gitGraph\\|{\\)\\([ \t]*\\|$\\)" + "keyword to start a new scope(indent level)") + +(defconst mermaid-end-scope-regexp + "^[ \t]*\\(end\\|}\\)\\([ \t]*\\|$\\)" + "keyword for end a scope(maybe also start a new scope)") + +(defconst mermaid-section-regexp + "^[ \t]*\\(section\\)[ \t]+" + "section keyword") + +(defconst mermaid-else-regexp + "^[ \t]*\\(else\\)" + "else keyword") + +(defconst mermaid-alt-regexp + "^[ \t]*\\(alt\\)" + "alt keyword") + +(defun mermaid-output-ext () + "get the extendsion of generated file" + (if (eq mermaid-output-format 'svg) + ".svg" + ".png")) + +;;;###autoload +(defun mermaid-compile () + (interactive) + (let ((cmd (concat mermaid-compiler + (if (eq mermaid-output-format 'svg) + " --svg " + " ") + (if mermaid-verbose + " --verbose " + " ") + (buffer-file-name))) + (buf-name "*mermaid compilation") + (compilation-mode-hook (cons 'mermaid-compilation-mode-hook compilation-mode-hook))) + (if (fboundp 'compilation-start) + (compilation-start cmd nil + #'(lambda (mode-name) + buf-name)) + (compile-internal cmd "No more errors" buf-name)))) + +;;;###autoload +(defun mermaid-view () + (interactive) + (let ((dst-file-name (concat (buffer-file-name) + (mermaid-output-ext)))) + (if (file-exists-p dst-file-name) + (find-file-other-window dst-file-name) + (error "Please compile the it first!\n")))) + +;; disable debug in default +;; +(defvar mermaid-debug-enabled nil + "enable/disable debug") + +(defmacro mermaid-debug (fmt &rest args) + `(when mermaid-debug-enabled + (message ,fmt ,@args))) + +(defun mermaid-indent-line () + "indent current line in mermaid mode" + (interactive) + (mermaid-debug "line no @ %d\n" (line-number-at-pos)) + (beginning-of-line) + (if (bobp) + (indent-line-to 0) + (let (cur-indent) + (cond + ((looking-at mermaid-end-scope-regexp) + (progn + (mermaid-debug "found end scope\n") + (save-excursion + (forward-line -1) + (if (or (looking-at mermaid-new-scope-regexp) + (looking-at mermaid-alt-regexp)) + (setq cur-indent (current-indentation)) + (setq cur-indent (- (current-indentation) default-tab-width))) + (if (< cur-indent 0) + (setq cur-indent 0))))) + ((looking-at mermaid-section-regexp) + (let ((found-section nil) + (need-search t)) + (mermaid-debug "found section\n") + (save-excursion + (while need-search + (forward-line -1) + (cond + ((looking-at mermaid-section-regexp) + (progn + (mermaid-debug "found section\n") + (setq found-section t) + (setq cur-indent (current-indentation)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((or (looking-at mermaid-new-scope-regexp) + (looking-at mermaid-alt-regexp)) + (progn + (mermaid-debug "found new scope\n") + (setq cur-indent (+ (current-indentation) default-tab-width)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((looking-at mermaid-end-scope-regexp) + (progn + (mermaid-debug "found end scope\n") + (setq cur-indent (current-indentation)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((bobp) + (progn + (setq cur-indent 0) + (setq need-search nil))) + (t t)))) + (if (< cur-indent 0) + (setq cur-indent 0)))) + ((looking-at mermaid-else-regexp) + (let ((need-search t)) + (mermaid-debug "else\n") + (save-excursion + (while need-search + (forward-line -1) + (cond + ((or (looking-at mermaid-else-regexp) + (looking-at mermaid-alt-regexp)) + (progn + (mermaid-debug "found matched alt/else\n") + (setq cur-indent (current-indentation)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((looking-at mermaid-end-scope-regexp) + (progn + (mermaid-debug "found end\n") + (setq cur-indent (- (current-indentation) default-tab-width)) + (setq need-search nil))) + ((bobp) + (progn + (setq cur-indent 0))) + (t t)))))) + (t + (let ((need-search t) + (start-scope (looking-at mermaid-new-scope-regexp))) + (mermaid-debug "normal indent\n") + (save-excursion + (while need-search + (forward-line -1) + (cond + ((looking-at mermaid-end-scope-regexp) + (progn + (mermaid-debug "found end scope\n") + (setq cur-indent (current-indentation)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((or (looking-at mermaid-new-scope-regexp) + (looking-at mermaid-alt-regexp)) + (progn + (mermaid-debug "found begin scope\n") + (setq cur-indent (+ (current-indentation) default-tab-width)) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((looking-at mermaid-section-regexp) + (progn + (mermaid-debug "found section \n") + (if start-scope + (setq cur-indent (current-indentation)) + (setq cur-indent (+ (current-indentation) default-tab-width))) + (mermaid-debug "cur-indent %d\n" cur-indent) + (setq need-search nil))) + ((bobp) + (progn + (setq cur-indent 0) + (setq need-search nil))))))))) + (if cur-indent + (indent-line-to cur-indent) + (indent-line-to 0))))) + +;;;###autoload +(defun mermaid-mode () + "Major mode for editing mermaid scripts" + (interactive) + (kill-all-local-variables) + (use-local-map mermaid-mode-map) + (set (make-local-variable 'font-lock-defaults) + '(mermaid-font-lock-keywords-1)) + (set (make-local-variable 'indent-line-function) + 'mermaid-indent-line) + (set (make-local-variable 'comment-start) "%%") + (set (make-local-variable 'comment-end) "\n") + (setq font-lock-keywords-case-fold-search t) + (setq major-mode 'mermaid-mode) + (setq mode-name "mermaid") + (run-hooks 'mermaid-mode-hook) + ) + +(provide 'mermaid-mode) diff --git a/layers.personal/mylangs/mymermaid/packages.el b/layers.personal/mylangs/mymermaid/packages.el new file mode 100644 index 0000000..64507f9 --- /dev/null +++ b/layers.personal/mylangs/mymermaid/packages.el @@ -0,0 +1,77 @@ +;;; packages.el --- mymermaid layer packages file for Spacemacs. +;; +;; Copyright (c) 2012-2016 Sylvain Benner & Contributors +;; +;; Author: Rongsong Shen +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;;; Commentary: + +;; See the Spacemacs documentation and FAQs for instructions on how to implement +;; a new layer: +;; +;; SPC h SPC layers RET +;; +;; +;; Briefly, each package to be installed or configured by this layer should be +;; added to `mymermaid-packages'. Then, for each package PACKAGE: +;; +;; - If PACKAGE is not referenced by any other Spacemacs layer, define a +;; function `mymermaid/init-PACKAGE' to load and initialize the package. + +;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so +;; define the functions `mymermaid/pre-init-PACKAGE' and/or +;; `mymermaid/post-init-PACKAGE' to customize the package as it is loaded. + +;;; Code: + +(defconst mymermaid-packages + '((mermaid :location local) + (evil-mermaid :location local)) + "The list of Lisp packages required by the mymermaid layer. + +Each entry is either: + +1. A symbol, which is interpreted as a package to be installed, or + +2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun mymermaid/init-mermaid () + (use-package mermaid + :defer t + :mode ("\\.mmd\\'" . mermaid-mode))) + +(defun mymermaid/init-evil-mermaid () + (use-package evil-mermaid + :commands evil-mermaid-mode + :init (add-hook 'mermaid-mode-hook 'evil-mermaid-mode) + :config (progn + (spacemacs/set-leader-keys-for-major-mode 'mermaid-mode + "c" 'mermaid-compile + "v" 'mermaid-view)))) + +;;; packages.el ends here diff --git a/layers.personal/mylangs/mypollen/config.el b/layers.personal/mylangs/mypollen/config.el new file mode 100644 index 0000000..022a8c5 --- /dev/null +++ b/layers.personal/mylangs/mypollen/config.el @@ -0,0 +1,2 @@ +(defvar pollen-templates-directory "~/workenv/templates.pollen/" + "Default directory for pollen templates") diff --git a/layers.personal/mylangs/mypollen/funcs.el b/layers.personal/mylangs/mypollen/funcs.el new file mode 100644 index 0000000..cb33ab9 --- /dev/null +++ b/layers.personal/mylangs/mypollen/funcs.el @@ -0,0 +1,30 @@ +;; add functions here which can be used in mypollen layer + +(defun generate-pollen-document (name) + (let ((context (concat "#lang pollen\n" + "◊(define-meta title \"Sample Pollen Document\")\n" + "◊(define-meta author \"Rongsong Shen\")\n" + "◊(define-meta publisher \"GNU Publisher\")\n" + "◊(define-meta thanklessauthor \"autherX\")" + "◊(define-meta thankslesspublisher \"GNU Less Publisher\")" + "◊(define-meta doc-publish-date \"2016-10-17\")\n" + "◊;using ◊part{} ◊chapter{} as the top two levels of book\n" + "◊;using ◊section{} and ◊subsection{} in tufte-handout\n" + "\n◊;add document here\n"))) + (append-to-file context nil name))) + +(defun pollen-use-template (template destdir) + (interactive + (let ((template-used (read-directory-name "Choose template:" + (expand-file-name pollen-templates-directory) + nil nil nil)) + (destdir-used (read-string "Destination:"))) + (list template-used destdir-used))) + (when (and template destdir) + (let ((tmp-buf (current-buffer))) + (apply 'make-comint "/bin/sh" "/bin/sh" nil + (list "-c" (concat "cp -Rf " template " " destdir))) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window "* SHELL *") + (let ((name (concat destdir "/doc.poly.pm"))) + (generate-pollen-document name))))) diff --git a/layers.personal/mylangs/mypollen/local/evil-pollen/evil-pollen.el b/layers.personal/mylangs/mypollen/local/evil-pollen/evil-pollen.el new file mode 100644 index 0000000..b602fec --- /dev/null +++ b/layers.personal/mylangs/mypollen/local/evil-pollen/evil-pollen.el @@ -0,0 +1,81 @@ +(require 'evil) +(require 'pollen-mode) +(require 'comint) + +(defun insert-lozenge () + "inserts the lozenge character for use with Pollen" + ;; enables function through M-x + (interactive) + ;; insert the proper character + (insert (make-char + 'mule-unicode-2500-33ff 34 42))) + +(defcustom pollen-target-format "pdf" + "Options to build pollen document" + :type 'string + :group 'pollen-mode) + +(defun pollen-target-file (source) + (replace-regexp-in-string "\\.poly\\.pm" + (concat "." pollen-target-format) + source)) + +(defun pollen-build () + "Build pollen document" + (interactive) + (let* ((tmp-buf (current-buffer)) + (file-name (buffer-file-name)) + (cmd (concat "raco pollen render " + (pollen-target-file file-name))) + (buf-name "*pollen compilation *")) + (if (fboundp 'compilation-start) + (compilation-start cmd nil #'(lambda (mode-name) + buf-name)) + (compile-internal cmd "no more errors" buf-name)))) + +(defun pollen-set-target-format () + (interactive) + (let ((fmt (read-string + "Output format:"))) + (if (or (string= fmt "pdf") + (string= fmt "html") + (string= fmt "txt") + (string= fmt "ltx")) + (setq pollen-target-format fmt) + (message "Unsupported format %s\n" fmt)))) + +(defun pollen-view () + (interactive) + (let* ((file-name (concat (pollen-target-file (buffer-file-name)))) + (cmd "open") + (tmp-buf (current-buffer))) + (apply 'make-comint cmd cmd nil (list file-name)) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window (concat "*" cmd "*")))) + +(defun pollen-reset () + (interactive) + (let ((cmd "raco") + (tmp-buf (current-buffer))) + (apply 'make-comint cmd cmd nil (list "pollen" "reset")) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window (concat "*" cmd "*")))) + +(define-minor-mode evil-pollen-mode + "Buffer local minor mode for evil-pollen " + :init-value nil + :lighter "EvilPollen" + :keymap (make-sparse-keymap) + :group 'evil-pollen) + +(mapc #'(lambda (state) + (evil-define-key state evil-pollen-mode-map + (kbd "M-b") 'pollen-build + (kbd "M-f") 'pollen-set-target-format + (kbd "M-v") 'pollen-view + (kbd "M-c") 'pollen-reset)) + '(normal insert)) + +(global-set-key "\M-\\" 'insert-lozenge) + +(provide 'evil-pollen) diff --git a/layers.personal/mylangs/mypollen/packages.el b/layers.personal/mylangs/mypollen/packages.el new file mode 100644 index 0000000..328ff56 --- /dev/null +++ b/layers.personal/mylangs/mypollen/packages.el @@ -0,0 +1,92 @@ + ;;; packages.el --- pollen layer packages file for Spacemacs. + ;; + ;; Copyright (c) 2012-2016 Sylvain Benner & Contributors + ;; + ;; Author: Rongsong Shen + ;; URL: https://github.com/syl20bnr/spacemacs + ;; + ;; This file is not part of GNU Emacs. + ;; + ;;; License: GPLv3 + + ;;; Commentary: + + ;; See the Spacemacs documentation and FAQs for instructions on how to implement + ;; a new layer: + ;; + ;; SPC h SPC layers RET + ;; + ;; + ;; Briefly, each package to be installed or configured by this layer should be + ;; added to `pollen-packages'. Then, for each package PACKAGE: + ;; + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a + ;; function `pollen/init-PACKAGE' to load and initialize the package. + + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so + ;; define the functions `pollen/pre-init-PACKAGE' and/or + ;; `pollen/post-init-PACKAGE' to customize the package as it is loaded. + + ;;; Code: + + (defconst mypollen-packages + '( + (pollen-mode :location (recipe :fetcher github :repo "shen390s/pollen-mode")) + (evil-pollen :location local)) + "The list of Lisp packages required by the pollen layer. + + Each entry is either: + + 1. A symbol, which is interpreted as a package to be installed, or + + 2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + +(defun mypollen/init-pollen-mode () + (use-package pollen-mode + :defer t + :commands pollen-mode + :mode ("\\.poly\\.pm$" . pollen-mode))) + +(defun mypollen/post-init-pollen-mode () + (add-hook 'pollen-mode-hook + #'(lambda () + (smartparens-mode 1) + (rainbow-delimiters-mode 1) + (auto-fill-mode 1)))) + +(defun mypollen/init-evil-pollen () + (use-package evil-pollen + :defer t + :commands evil-pollen-mode + :init (add-hook 'pollen-mode-hook 'evil-pollen-mode) + :config (progn + (spacemacs/set-leader-keys-for-major-mode 'pollen-mode + "b" 'pollen-build + "f" 'pollen-set-target-format + "v" 'pollen-view + "c" 'pollen-reset + "n" 'next-error)))) + +(defun mypollen/post-init-evil-pollen () + ) + + ;;; packages.el ends here diff --git a/layers.personal/mylangs/myscribble/funcs.el b/layers.personal/mylangs/myscribble/funcs.el new file mode 100644 index 0000000..3d23fed --- /dev/null +++ b/layers.personal/mylangs/myscribble/funcs.el @@ -0,0 +1 @@ +;; add functions here which can be used in myeiffel layer diff --git a/layers.personal/mylangs/myscribble/local/evil-scribble/evil-scribble.el b/layers.personal/mylangs/myscribble/local/evil-scribble/evil-scribble.el new file mode 100644 index 0000000..dbfcb90 --- /dev/null +++ b/layers.personal/mylangs/myscribble/local/evil-scribble/evil-scribble.el @@ -0,0 +1,71 @@ +(require 'evil) +(require 'scribble) +(require 'comint) + +(defun insert-lozenge () + "inserts the lozenge character for use with Pollen" + ;; enables function through M-x + (interactive) + ;; insert the proper character + (insert (make-char + 'mule-unicode-2500-33ff 34 42))) + +(defcustom scribble-target-format "pdf" + "Options to build scribble document" + :type 'string + :group 'scribble-mode) + +(defun scribble-build () + "Build scribble document" + (interactive) + (setq scribble-build-options + (if (string= scribble-target-format "pdf") + "--pdf" + "--html")) + (let* ((tmp-buf (current-buffer)) + (file-name (buffer-file-name)) + (cmd (concat "scribble " + scribble-build-options + " " file-name)) + (buf-name "*scribble compilation *")) + (if (fboundp 'compilation-start) + (compilation-start cmd nil #'(lambda (mode-name) + buf-name)) + (compile-internal cmd "no more errors" buf-name)))) + +(defun scribble-set-target-format () + (interactive) + (let ((fmt (read-string + "Output format:"))) + (if (or (string= fmt "pdf") + (string= fmt "html")) + (setq scribble-target-format fmt) + (message "Unsupported format %s\n" fmt)))) + +(defun scribble-view () + (interactive) + (let* ((file-name (concat (file-name-base (buffer-file-name)) + "." scribble-target-format)) + (cmd "open") + (tmp-buf (current-buffer))) + (apply 'make-comint cmd cmd nil (list file-name)) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window (concat "*" cmd "*")))) + +(define-minor-mode evil-scribble-mode + "Buffer local minor mode for evil-scribble " + :init-value nil + :lighter "EvilScribble" + :keymap (make-sparse-keymap) + :group 'evil-scribble) + +(mapc #'(lambda (state) + (evil-define-key state evil-scribble-mode-map + (kbd "M-b") 'scribble-build + (kbd "M-f") 'scribble-set-target-format + (kbd "M-v") 'scribble-view)) + '(normal insert)) + +(global-set-key "\M-\\" 'insert-lozenge) + +(provide 'evil-scribble) diff --git a/layers.personal/mylangs/myscribble/local/scribble/scribble.el b/layers.personal/mylangs/myscribble/local/scribble/scribble.el new file mode 100644 index 0000000..8b2bc78 --- /dev/null +++ b/layers.personal/mylangs/myscribble/local/scribble/scribble.el @@ -0,0 +1,1143 @@ +;; $Id: scribble.el,v 1.49 2015/11/03 17:54:56 user Exp $ + +(defconst scribble-mode-title "Racket Scribble Emacs Mode") +(defconst scribble-mode-version "0.6") +(defconst scribble-mode-date "2016-02-19") +(defconst scribble-mode-web "http://www.neilvandyke.org/scribble-emacs/") + +(defconst scribble-mode-legal-notices + "Copyright (c) 2011, 2013, 2015, 2016 Neil Van Dyke. This program is Free +Software; you can redistribute it and/or modify it under the terms of the GNU +Lesser General Public License as published by the Free Software Foundation; +either version 3 of the License (LGPL 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 http://www.gnu.org/licenses/ for +details. For other licenses and consulting, please contact the author.") + +;; TODO: !!! 2016-02-19 Recover documentation from old PLaneT package. + +;; Note: Changes to above info must be reflected in "scribble-emacs.scrbl" +;; and "info.rkt". + +;;-------------------------------------------------------------------- Requires + +(require 'eldoc) + +;;---------------------------------------------------------------------- Custom + +(defgroup scribble + nil + "Racket Scribble Emacs Mode" + :group 'wp + :prefix "scribble-") + +(defface scribble-comment-face + '((t :foreground "cyan")) + "Face for Comments in Scribble mode." + :group 'scribble) + +(defface scribble-at-keyword-face + '((t :weight bold :foreground "gray50")) + "Face for `@'-and-name in Scribble mode." + :group 'scribble) + +(defface scribble-square-bracket-face + '((t :weight bold :foreground "#c48080")) + "Face for square brackets in Scribble mode." + :group 'scribble) + +(defface scribble-curly-brace-face + '((t :weight bold :foreground "#c48080")) + "Face for curly braces in Scribble mode." + :group 'scribble) + +(defface scribble-title-face + '((t :family "DejaVu Serif" :height 2.0736 :slant italic)) + "Face for titles in Scribble mode." + :group 'scribble) + +(defface scribble-section-heading-face + '((t :family "DejaVu Serif" :height 2.0736 :weight bold)) + "Face for section headings in Scribble mode." + :group 'scribble) + +(defface scribble-subsection-heading-face + '((t :family "DejaVu Serif" :height 1.728 :weight bold)) + "Face for subsection headings in Scribble mode." + :group 'scribble) + +(defface scribble-subsubsection-heading-face + '((t :family "DejaVu Serif" :height 1.44 :weight bold)) + "Face for subsubsection headings in Scribble mode." + :group 'scribble) + +(defface scribble-sub*section-heading-face + '((t :family "DejaVu Serif" :height 1.2 :weight bold)) + "Face for deep-subsection headings in Scribble mode." + :group 'scribble) + +(defface scribble-bold-face + '((t :weight bold)) + "Face for @bold in Scribble mode." + :group 'scribble) + +(defface scribble-emph-face + '((t :slant italic)) + "Face for @emph in Scribble mode." + :group 'scribble) + +(defface scribble-tt-face + '((t :family "DejaVu Sans Mono")) + "Face for @tt in Scribble mode." + :group 'scribble) + +(defface scribble-link-text-face + '((t :underline t :foreground "blue")) + "Face for link text in Scribble mode." + :group 'scribble) + +(defface scribble-planet-face + '((t)) + "Face for @PLaneT in Scribble mode." + :group 'scribble) + +(defface scribble-racket-result-face + '((t :foreground "blue3")) + "Face for Racket results in Scribble mode." + :group 'scribble) + +(defface scribble-racket-value-face + '((t :foreground "green2")) + "Face for Racket values in Scribble mode." + :group 'scribble) + +(defface scribble-bnf-nonterm-face + '((t :slant italic)) + "Face for @nonterm in Scribble mode." + :group 'scribble) + +(defface scribble-racket-litchar-face + '((t :foreground "#aaaa00" + :background "#f4f4f4" + :slant normal + :weight normal)) + "Face for @litchar in Scribble mode." + :group 'scribble) + +;; Quickref Faces: + +;; (defface scribble-quickref-default-face +;; '((t :family "DejaVu Sans" +;; :foreground "#000000" +;; :background "#e8e8ff" +;; :weight normal +;; :slant normal)) +;; "Face for Quickref in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-meta-face +;; '((t :inherit scribble-quickref-default-face +;; :foreground "#000000")) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-literal-face +;; '((t :family "DejaVu Sans Mono" +;; :inherit scribble-quickref-default-face +;; :foreground "red4" +;; :weight bold)) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-value-face +;; '((t :family "DejaVu Sans Mono" +;; :inherit scribble-quickref-default-face +;; :foreground "green4")) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-at-face +;; '((t :inherit scribble-quickref-literal-face)) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-keyword-face +;; '((t :family "DejaVu Sans" +;; :inherit scribble-quickref-literal-face)) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-form-name-face +;; '((t :inherit scribble-quickref-default-face +;; :foreground "blue4" +;; :weight bold)) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-type-face +;; '((t :inherit scribble-quickref-default-face +;; :foreground "blue")) ;!!! +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; (defface scribble-quickref-arg-face +;; '((t :inherit scribble-quickref-default-face +;; :slant italic +;; :foreground "blue2")) +;; "Face for Quickref !!! in Scribble mode." +;; :group 'scribble) + +;; ElDoc Faces: + +(defface scribble-eldoc-default-face + '((t :family "DejaVu Sans" + :foreground "#000000" + :background "#fffff0" + :weight normal + :slant normal)) + "Face for ElDoc in Scribble mode." + :group 'scribble) + +(defface scribble-eldoc-literal-face + '((t :inherit scribble-eldoc-default-face)) + "Face for ElDoc literals in Scribble mode." + :group 'scribble) + +(defface scribble-eldoc-meta-face + '((t :inherit scribble-eldoc-default-face + :foreground "#4040ff")) + "Face for ElDoc metasyntactic symbols in Scribble mode." + :group 'scribble) + +(defface scribble-eldoc-nonterminal-face + '((t :inherit scribble-eldoc-default-face + :slant italic)) + "Face for ElDoc nonterminals in Scribble mode." + :group 'scribble) + +;;---------------------------------------------------- Customization Procedures + +(defun scribble-customize () + (interactive) + (customize-group 'scribble)) + +;; TODO: Implement making any non-face changes take effect. + +;;-------------------------------------------------------------- Scribble Forms + +(defsubst scribble-get-form-name (form) (aref form 0)) +(defsubst scribble-get-form-args (form) (aref form 1)) +(defsubst scribble-get-form-type (form) (aref form 2)) +(defsubst scribble-get-form-face (form) (aref form 3)) + +;; TODO: Maybe make types be strings. + +(defsubst scribble-get-formarg-kind (arg) (aref arg 0)) +(defsubst scribble-get-formarg-name (arg) (aref arg 1)) +(defsubst scribble-get-formarg-type (arg) (aref arg 2)) +(defsubst scribble-get-formarg-default (arg) (aref arg 3)) + +;; Note: The information is from Racket 5.0.2 Scribble documentation. + +(defconst scribble-style-form-type + '(or/c style? f string? symbol? (listof symbol?))) + +(defconst scribble-optional-style-form-arg + `[k style ,scribble-style-form-type "#f"]) + +(defconst scribble-optional-underline?-form-arg + `[k underline? any/c "#t"]) + +(defconst scribble-optional-tag-form-arg + `[k tag (or/c false/c string? (listof string?)) "#f"]) + +(defconst scribble-heading-form-args + `(,scribble-optional-tag-form-arg + [k tag-prefix (or/c false/c string? module-path?) "#f"] + ,scribble-optional-style-form-arg)) + +;; TODO: Support more than just "scribble/base". + +(defconst scribble-base-forms + `( + ;; scribble/base + ;; file:///usr/local/racket-5.0.2/share/racket/doc/scribble/base.html + + [title (,@scribble-heading-form-args + [k version (or/c string? false/c) "#f"] + [p - pre-content? -] + ...) + title-decl? + scribble-title-face] + [section (,@scribble-heading-form-args + [p - pre-content? -] + ...) + part-start? + scribble-section-heading-face] + [subsection (,@scribble-heading-form-args + [p - pre-content? -] + ...) + part-start? + scribble-subsection-heading-face] + [subsubsection (,@scribble-heading-form-args + [p - pre-content? -] + ...) + part-start? + scribble-subsubsection-heading-face] + [sub*section (,@scribble-heading-form-args + [p - pre-content? -] + ...) + part-start? + scribble-sub*section-heading-face] + [author ([p - content? -]) + block? + nil] + [author+email ([p author elem -] + [p email string? -] + [k obfuscate? any/c "#f"]) + element? + nil] + [para (,scribble-optional-style-form-arg + [p - pre-content? -] + ...) + paragraph? + nil] + [nested (,scribble-optional-style-form-arg + [p - pre-flow? -] + ...) + nested-flow? + nil] + [centered ([p - pre-flow? -] + ...) + nested-flow? + nil] + [margin-note ([p - pre-flow? -] + ...) + block? + nil] + [margin-note* ([p - pre-content? -] + ...) + element? + nil] + [itemlist ([p - item? -] + ... + ,scribble-optional-style-form-arg) + itemization? + nil] + [item ([p - pre-flow? -] + ...) + item? + nil] + [tabular ([p cells (listof (listof (or/c block? content? 'cont))) -] + ,scribble-optional-style-form-arg) + table? + nil] + [verbatim ([p indent exact-nonnegative-integer? "0"] + [p - string? -] + ...) + block? + nil] + [elem ([p - pre-content? -] + ... + ,scribble-optional-style-form-arg) + element? + nil] + [italic ([p - pre-content? -] + ...) + element? + nil] + [bold ([p - pre-content? -] + ...) + element? + scribble-bold-face] + [code ([p - pre-content? -] + ...) + element? + nil] + [codeblock ([p - pre-content? -] + ...) + element? + nil] + [tt ([p - pre-content? -] + ...) + element? + scribble-tt-face] + [subscript ([p - pre-content? -] + ...) + element? + nil] + [superscript ([p - pre-content? -] + ...) + element? + nil] + [smaller ([p - pre-content? -] + ...) + element? + nil] + [larger ([p - pre-content? -] + ...) + element? + nil] + [emph ([p - pre-content? -] + ...) + element? + scribble-emph-face] + [linebreak () + element? + nil] + [hspace ([p - exact-nonnegative-integer? -]) + element? + nil] + [literal ([p - string? -] + ...) + element? + nil] + [image + ([p path (or/c path-string? (cons/c 'collects (listof bytes?))) -] + [k scale real? "1.0"] + [k suffixes (listof (rx "^[.]")) "null"] + [p - pre-content? -] + ...) + element? + nil] + [hyperlink ([p url string? -] + [p - pre-content? -] + ... + ,scribble-optional-underline?-form-arg + [k style + (or/c style? string? symbol? false/c) + "(if underline? #f \"plainlink\")"]) + element? + scribble-link-text-face] + [url ([p dest string? -]) + element? + nil] + [secref ([p tag string -] + [k doc (or/c module-path? false/c) "#f"] + [k tag-prefixes (or/c (listof string?) false/c) "#f"] + ,scribble-optional-underline?-form-arg) + element? + scribble-link-text-face] + [seclink ([p tag string? -] + [k doc (or/c module-path? false/c) "#f"] + [k tag-prefixes (or/c (listof string?) false/c) "#f"] + ,scribble-optional-underline?-form-arg + [p - pre-content? -] + ...) + element? + scribble-link-text-face] + [other-doc ([p module-path module-path? -] + ,scribble-optional-underline?-form-arg) + element? + nil] + [elemtag ([p t (or/c tag? string?) -] + [p - pre-content? -] + ...) + element? + nil] + [elemref ([p t (or/c tag? string?) -] + [p - pre-content? -] + ... + ,scribble-optional-underline?-form-arg) + element? + nil] + [index ([p words (or/c string? (listof string?)) -] + [p - pre-content? -] + ...) + index-element? + nil] + [index* ([p words (listof string?) -] + [p word-contents (listof list?) -] + [p - pre-content? -] + ...) + index-element? + nil] + [as-index ([p - pre-content? -] + ...) + index-element? + nil] + [section-index ([p word string? -] + ...) + part-index-decl? + nil] + [index-section ([k tag (or/c false/c string?) "\"doc-index\""] + ,scribble-optional-tag-form-arg) + part? + nil] + [table-of-contents () + delayed-block? + nil] + [local-table-of-contents (,scribble-optional-style-form-arg) + delayed-block? + nil])) + +(defconst scribble-manual-forms + `( + + [racketblock ([p - datum? -] ...) any/c nil] + [RACKETBLOCK ([p - datum? -] ...) any/c nil] + [racketblock0 ([p - datum? -] ...) any/c nil] + [RACKETBLOCK0 ([p - datum? -] ...) any/c nil] + + [racketresultblock ([p - datum? -] ...) any/c nil] + [RACKETRESULTBLOCK ([p - datum? -] ...) any/c nil] + [racketresultblock0 ([p - datum? -] ...) any/c nil] + [RACKETRESULTBLOCK0 ([p - datum? -] ...) any/c nil] + + [racketinput ([p - datum? -] ...) any/c nil] + [RACKETINPUT ([p - datum? -] ...) any/c nil] + + [racketmod ([k file string? "#f"] + [p - datum? -] + ...) + any/c + nil] + + [racket ([p - datum? -] ...) any/c nil] + [RACKET ([p - datum? -] ...) any/c nil] + + ;; TODO: For "racketresult" and "racketid", maybe override body faces. + [racketresult ([p - datum? -] ...) any/c scribble-racket-result-face] + [racketid ([p - datum? -] ...) any/c nil] + + [racketmodlink ([p - datum? -] + [p - pre-content-expr? -] + ...) + any/c + nil] + + [litchar ([p - string? -] ...) element? scribble-racket-litchar-face] + + [racketfont ([p - pre-content? -] ...) element? nil] + [racketvalfont ([p - pre-content? -] ...) element? scribble-racket-value-face] + [racketresultfont ([p - pre-content? -] ...) element? scribble-racket-result-face] + [racketidfont ([p - pre-content? -] ...) element? nil] + [racketvarfont ([p - pre-content? -] ...) element? nil] + [racketkeywordfont ([p - pre-content? -] ...) element? nil] + [racketparenfont ([p - pre-content? -] ...) element? nil] + [racketmetafont ([p - pre-content? -] ...) element? nil] + [racketerror ([p - pre-content? -] ...) element? nil] + [racketmodfont ([p - pre-content? -] ...) element? nil] + [racketoutputfont ([p - pre-content? -] ...) element? nil] + ;; TODO: Define faces for some of the above? + + ;; TODO: We could use overlays to make "@procedure" content have + ;; "#". + [procedure ([p - pre-content? -] ...) element? nil] + + [var ([p - datum? -] ...) element? nil] + [svar ([p - datum? -] ...) element? nil] + + ;; TODO: Possibly add support for all the "scheme" backword-compatibility + ;; identifiers. + + ;; TODO: !!! CONTINUE ADDING AFTER + ;; file:///usr/local/racket-5.0.2/share/racket/doc/scribble/scribble_manual_code.html + + )) + +(defconst scribble-bnf-forms + `([BNF ([p - (cons element? (listof element?)) -] ...) table? nil] + + [nonterm ([p - pre-content? -] ...) element? scribble-bnf-nonterm-face] + [BNF-seq ([p - element? -] ...) element? nil] + [BNF-group ([p - pre-content? -] ...) element? nil] + + [optional ([p - pre-content? -] ...) element? nil] + [kleenestar ([p - pre-content? -] ...) element? nil] + [kleeneplus ([p - pre-content? -] ...) element? nil] + + [kleenerange ([p n any/c -] + [p m any/c -] + [p - pre-content? -] + ...) + element? + nil] + + [BNF-alt ([p - element? -] ...) element? nil] + [BNF-etc ([p - string? -]) void scribble-comment-face])) + +(defconst scribble-forms + `(,@scribble-base-forms + ,@scribble-manual-forms + ,@scribble-bnf-forms)) + +(defconst scribble-name-string-to-form-hash + (let ((ht (make-hash-table :test 'equal))) + (mapc (lambda (form) + (puthash (symbol-name (scribble-get-form-name form)) form ht)) + scribble-forms) + ht)) + +(defun scribble-minus-to-nil (x) + (if (eq x '-) nil x)) + +(defun scribble-form-type-to-racket (type) + ;; TODO: translate true, false, rx, quote. Or convert types to strings. + (format "%s" type)) + +;;---------------------------------------------------------------- Syntax Table + +(defvar scribble-mode-syntax-table + (let ((st (make-syntax-table))) + + (modify-syntax-entry ? " " st) + (modify-syntax-entry ?\t " " st) + (modify-syntax-entry ?\f " " st) + (modify-syntax-entry ?\n ">" st) + + (modify-syntax-entry ?\" "." st) + + (modify-syntax-entry ?\@ "_ 1" st) + (modify-syntax-entry ?\# "_ 1" st) + (modify-syntax-entry ?\: "_ 1" st) + (modify-syntax-entry ?\; ". 2" st) + + (modify-syntax-entry ?\( "()" st) + (modify-syntax-entry ?\) ")(" st) + (modify-syntax-entry ?\[ "(]" st) + (modify-syntax-entry ?\] ")[" st) + (modify-syntax-entry ?\{ "(}" st) + (modify-syntax-entry ?\} "){" st) + + st)) + +;;------------------------------------------------------------- Forms Reference + +;; (defun scribble-forms-reference () +;; (interactive) +;; (scribble-buffer-display +;; "*Scribble Forms Reference*" +;; (function +;; (lambda () +;; (mapc (lambda (form) +;; (insert (scribble-form-quickref-text form) "\n\n")) +;; scribble-forms))))) + +;;------------------------------------------------------------------- Mode Menu + +(defvar scribble-mode-menu + (let ((km (make-sparse-keymap "Scribble"))) + + (define-key km [scribble-about] + '(menu-item "About Scribble Emacs Mode..." scribble-about + :help "See information about Scribble Emacs mode")) + + (define-key km [scribble-browse-mode-web] + '(menu-item "Browse Scribble Emacs Mode Web..." scribble-browse-mode-web + :help "Browse Web pages for Scribble Emacs mode")) + + ;; TODO: Browse/search scribble docs. + + (define-key km [scribble-separator-2] + `(menu-item "--")) + + ;; TODO: Experiment with this. Use local variable "scribble-modules" to + ;; specify in files, and update it programmatically from this interface. + ;; Can also have operation that scans "#lang" and "@(require" to determine + ;; or update this variable. Unfortunately can't use "-*-" line because + ;; Emacs currently (GNU 23.2) doesn't support it occuring after the "#lang" + ;; line. + (define-key km [scribble-forms-bnf] + '(menu-item "scribble/bnf" nil + :enable nil + :button (:toggle . t) + :help "!!!")) + (define-key km [scribble-forms-manual] + '(menu-item "scribble/manual" nil + :enable nil + :button (:toggle . nil) + :help "!!!")) + (define-key km [scribble-forms-base] + '(menu-item "scribble/base" nil + :enable nil + :button (:toggle . t) + :help "!!!")) + + ;; (define-key km [scribble-forms-reference] + ;; '(menu-item "Forms Reference..." scribble-forms-reference + ;; :help "Show a reference of Scribble forms")) + + (define-key km [scribble-separator-1] + `(menu-item "--")) + + (define-key km [scribble-customize] + '(menu-item "Customize..." scribble-customize + :help "Set Emacs customization options for Scribble")) + ;; TODO: Perhaps wrapping "completion-at-point" with another procedure + ;; that does "call-interactively" will work. + ;; + ;; (define-key km [scribble-completion-at-point] + ;; `(menu-item "Completion at Point" 'completion-at-point)) + + km)) + +;;---------------------------------------------------------------------- Keymap + +(defvar scribble-mode-map + (let ((km (make-sparse-keymap))) + (define-key km (kbd "M-TAB") 'completion-at-point) + (define-key km [menu-bar Scribble] (cons "Scribble" scribble-mode-menu)) + km)) + +;;------------------------------------------------------------------- Font-Lock + +;; TODO: Should probably switch to using something other than font-lock, like +;; handwritten fuzzy parser. + +(defvar scribble-font-lock-keywords + `( + ,@(mapcar (lambda (face-to-namerxs-pair) + (let ((face (car face-to-namerxs-pair))) + `(,(concat "\\(" ; < 1 at-name + "@" + (let ((names (cdr face-to-namerxs-pair))) + (if (cdr names) + (regexp-opt names) + (car names))) + "\\)" ; > 1 at-name + "\\b" + "\\(?:" ; < opt-squares + "\\(\\[\\)" ; = 2 open-square + "[^]]*" ; + "\\(\\]\\)" ; = 3 close-square + "\\)?" ; > opt-squares + "\\(?:" ; < opt-curlies + "\\({\\)" ; ; = 4 open-curly + (if face "\\(" "") + "[^}]*" ; + (if face "\\)" "") + "\\(}\\)" ; = 5,6 close-curly + "\\)?" ; > opt-curlies + ) + (1 'scribble-at-keyword-face) + (2 'scribble-square-bracket-face nil t) + (3 'scribble-square-bracket-face nil t) + (4 'scribble-curly-brace-face nil t) + ,@(if face + `((5 (quote ,face) nil t)) + '()) + (,(if face 6 5) 'scribble-curly-brace-face nil t)))) + (let ((face-to-namerxs-alist '())) + (mapc (lambda (form) + (let* ((namerx (regexp-quote + (symbol-name (scribble-get-form-name + form)))) + (face (scribble-get-form-face form)) + (pair (assq face face-to-namerxs-alist))) + (if pair + (setcdr pair (cons namerx (cdr pair))) + (setq face-to-namerxs-alist + `((,face . (,namerx)) + ,@face-to-namerxs-alist))))) + scribble-forms) + face-to-namerxs-alist)) + + ("\\(@\\)\\(PLaneT\\)" + (1 'scribble-at-keyword-face) + (2 'scribble-planet-face)) + + ;; TODO: Is this right? + ;; + ;; ("\\(@\\)@" + ;; (1 'scribble-at-keyword-face)) + + ("\\(@#reader\\)[ ]+\\([^\r\n]+\\)" + (1 'scribble-at-keyword-face) + (2 'scribble-at-keyword-face)) + + ("\\`\\(#lang\\)[ ]+\\([^\r\n]+\\)" + (1 'scribble-at-keyword-face) + (2 'scribble-at-keyword-face)))) + +(defvar scribble-font-lock-defaults + `(scribble-font-lock-keywords nil)) + +;;----------------------------------------------------------------------- Imenu + +(defvar scribble-imenu-generic-expression + '((nil + "@\\(?:sub\\(?:sub\\)?\\)?section\\(?:\\[[^]]*\\]\\)?{\\([^}]*\\)" + 1))) + +;; TODO: Use one of the lower-level ways of doing this. + +;;------------------------------------------------------------------ Characters + +(defconst scribble-right-arrow-char 8594) + +;;-------------------------------------------------------------------- Quickref + +;; TODO: !!! this needs work since eldoc was forked out of this. +;; +;; (defun scribble-form-type-to-quickref (type) +;; (propertize (scribble-form-type-to-racket type) +;; 'face 'scribble-quickref-type-face)) +;; +;; (defconst scribble-quickref-dotdotdot +;; (propertize "..." 'face 'scribble-quickref-meta-face)) +;; +;; (defconst scribble-quickref-space +;; (propertize " " 'face 'scribble-quickref-default-face)) +;; +;; (defconst scribble-quickref-open-paren +;; (propertize "(" 'face 'scribble-quickref-literal-face)) +;; +;; (defconst scribble-quickref-close-paren +;; (propertize ")" 'face 'scribble-quickref-literal-face)) +;; +;; (defconst scribble-quickref-open-optional +;; (propertize "[" 'face 'scribble-quickref-meta-face)) +;; +;; (defconst scribble-quickref-close-optional +;; (propertize "]" 'face 'scribble-quickref-meta-face)) +;; +;; (defconst scribble-quickref-space-colon-space +;; (concat scribble-quickref-space +;; (propertize ":" 'face 'scribble-quickref-meta-face) +;; scribble-quickref-space)) +;; +;; (defconst scribble-quickref-space-equal-space +;; (concat scribble-quickref-space +;; (propertize "=" 'face 'scribble-quickref-meta-face) +;; scribble-quickref-space)) +;; +;; (defun scribble-form-arg-to-quickref (arg) +;; (if (eq arg '...) +;; scribble-quickref-dotdotdot +;; (let* ((fmt '()) +;; (kind (scribble-get-formarg-kind arg)) +;; (name (scribble-minus-to-nil +;; (scribble-get-formarg-name arg))) +;; (type (scribble-get-formarg-type arg)) +;; (default (scribble-minus-to-nil +;; (scribble-get-formarg-default arg))) +;; (name-str (if name (symbol-name name) nil)) +;; (type-str (scribble-form-type-to-racket type)) +;; (type-ps (propertize type-str +;; 'face 'scribble-quickref-type-face))) +;; (cond ((eq kind 'p) +;; (setq fmt +;; (if name-str +;; `(,type-ps +;; ,scribble-quickref-space-colon-space +;; ,(propertize name-str +;; 'face +;; 'scribble-quickref-arg-face)) +;; `(,type-ps)))) +;; ((eq kind 'k) +;; (or name-str +;; (error "formarg kind k must have name in %s" arg)) +;; (setq fmt +;; `(,type-ps +;; ,scribble-quickref-space-colon-space +;; ,(propertize (concat "#:" name-str) +;; 'face 'scribble-quickref-keyword-face)))) +;; (t (error "invalid formarg kind in %s" arg))) +;; (apply 'concat +;; (if default +;; (reverse +;; `(,(propertize default 'face 'scribble-quickref-value-face) +;; ,scribble-quickref-space-equal-space +;; ,@fmt)) +;; (reverse fmt)))))) +;; +;; (defun scribble-form-quickref-text (form) +;; ;; TODO: !!! working on this +;; (let* ((at (propertize "@" 'face 'scribble-quickref-at-face)) +;; (space-arrow-space +;; (concat scribble-quickref-space +;; (propertize (string scribble-right-arrow-char) +;; 'face +;; 'scribble-quickref-meta-face) +;; scribble-quickref-space))) +;; (apply +;; 'concat +;; `(,at +;; ,(propertize (symbol-name (scribble-get-form-name form)) +;; 'face 'scribble-quickref-form-name-face) +;; ,@(let ((args (scribble-get-form-args form))) +;; (if args +;; (let ((fmt '())) +;; (mapc (lambda (arg) +;; (setq fmt `(,(scribble-form-arg-to-quickref arg) +;; ,scribble-quickref-space +;; ,@fmt))) +;; args) +;; (reverse fmt)) +;; '())) +;; ,closeparen-space-arrow-space +;; ,(scribble-form-type-to-quickref (scribble-get-form-type form)))))) + +;;------------------------------------------------------------------------ ElDoc + +(defconst scribble-eldoc-dotdotdot + (propertize "..." 'face 'scribble-eldoc-meta-face)) + +(defconst scribble-eldoc-space + (propertize " " 'face 'scribble-eldoc-default-face)) + +(defconst scribble-eldoc-open-paren + (propertize "(" 'face 'scribble-eldoc-literal-face)) + +(defconst scribble-eldoc-close-paren + (propertize ")" 'face 'scribble-eldoc-literal-face)) + +(defconst scribble-eldoc-open-optional + (propertize "[" 'face 'scribble-eldoc-meta-face)) + +(defconst scribble-eldoc-close-optional + (propertize "]" 'face 'scribble-eldoc-meta-face)) + +(defconst scribble-eldoc-closeparen-space-arrow-space + (concat scribble-eldoc-close-paren + scribble-eldoc-space + (propertize (string scribble-right-arrow-char) + 'face + 'scribble-eldoc-meta-face) + scribble-eldoc-space)) + +(defun scribble-form-arg-to-eldoc (arg) + (if (eq arg '...) + scribble-eldoc-dotdotdot + (let* ((kind (scribble-get-formarg-kind arg)) + (name (scribble-minus-to-nil (scribble-get-formarg-name arg))) + (name-str (if name (symbol-name name) nil)) + (id-ps + (cond ((eq kind 'p) + (propertize (or name-str + (scribble-form-type-to-racket + (scribble-get-formarg-type arg))) + 'face + 'scribble-eldoc-nonterminal-face)) + ((eq kind 'k) + (propertize + (concat "#:" + (or name-str + (error "formarg kind k must have name in %s" + arg))) + 'face 'scribble-eldoc-literal-face)) + (t (error "invalid formarg kind in %s" arg))))) + (if (eq '- (scribble-get-formarg-default arg)) + id-ps + (concat scribble-eldoc-open-optional + id-ps + scribble-eldoc-close-optional))))) + +(defun scribble-make-form-eldoc-message (form) + (apply + 'concat + `(,scribble-eldoc-open-paren + ,(propertize (symbol-name (scribble-get-form-name form)) + 'face 'scribble-eldoc-literal-face) + ,@(let ((args (scribble-get-form-args form))) + (if args + (let ((fmt '())) + (mapc (lambda (arg) + (setq fmt `(,(scribble-form-arg-to-eldoc arg) + ,scribble-eldoc-space + ,@fmt))) + args) + (reverse fmt)) + '())) + ,scribble-eldoc-closeparen-space-arrow-space + ,(propertize (scribble-form-type-to-racket (scribble-get-form-type form)) + 'face + 'scribble-eldoc-nonterminal-face)))) + +(defconst scribble-name-to-eldoc-message-hash + (let ((ht (make-hash-table :test 'equal))) + (mapc (lambda (form) + (puthash (symbol-name (scribble-get-form-name form)) + (scribble-make-form-eldoc-message form) + ht)) + scribble-forms) + ht)) + +(defun scribble-get-form-eldoc-message (form) + (scribble-make-form-eldoc-message form)) + +(defun scribble-eldoc-documentation-function () + ;; TODO: Implement this properly, figuring out which form we're in. Might + ;; wait until we implement better fontification, using the same parsing + ;; mechanism. + ;; + ;; TODO: !!! Maybe look for "@"-name under point, and if that fails, then + ;; up-sexp, and then look for an @-name to left of point (or left-sexp if + ;; there is a square-bracket to left of point. + (let ((word (let ((c (char-after (point)))) + (and c + (memq (char-syntax c) '(?w ?_)) + (current-word))))) + (and (> (length word) 0) + (equal ?@ (aref word 0)) + (gethash (substring word 1) + scribble-name-to-eldoc-message-hash + nil)))) + +;;------------------------------------------------------------------ Completion + +(defun scribble-build-completion-table () + (sort (let ((kw-seen-hash (make-hash-table :test 'eq)) + (result '("Felleisen"))) + (mapc (lambda (form) + (setq result (cons (symbol-name (scribble-get-form-name form)) + result)) + (mapc (lambda (arg) + (and (vectorp arg) + (eq 'k (scribble-get-formarg-kind arg)) + (let ((sym (scribble-get-formarg-name arg))) + (or (gethash sym kw-seen-hash) + (progn (puthash sym t kw-seen-hash) + (setq result + (cons (concat + "#:" + (symbol-name sym)) + result))))))) + (scribble-get-form-args form))) + scribble-forms) + result) + 'string<)) + +(defconst scribble-completion-table (scribble-build-completion-table)) + +(defconst scribble-completion-at-point-tail + (list scribble-completion-table + ;; :annotation-function 'scribble-completion-annotate-function + )) + +(defun scribble-completion-at-point-function () + (let* ((end (point)) + (start (let ((c (char-before end))) + (if (and c (memq (char-syntax c) '(?w ?_))) + (save-excursion + (backward-sexp 1) + (and (eq ?\@ (char-after (point))) + (forward-char 1)) + (point)) + end)))) + `(,start ,end ,@scribble-completion-at-point-tail))) + +;;-------------------------------------------------------------- Buffer Display + +(defun scribble-buffer-display (name proc) + (save-excursion + (set-buffer (get-buffer-create name)) + (toggle-read-only 0) + (buffer-disable-undo) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) + (funcall proc) + (buffer-enable-undo) + (set-buffer-modified-p nil) + (toggle-read-only 1) + (goto-char (point-min)) + ;; TODO: Maybe make "q" restore window config. + (local-set-key "q" 'scribble-quit-buffer-display) + (pop-to-buffer (current-buffer)) + (message "Press \"q\" to quit the \"%s\" buffer." name))) + +(defun scribble-quit-buffer-display () + (interactive) + (let ((buf (current-buffer))) + (condition-case nil + (delete-window) + (error nil)) + (kill-buffer buf))) + +;;---------------------------------------------------------------- Web Browsing + +(defun scribble-browse-mode-web () + (interactive) + (browse-url scribble-mode-web)) + +;; TODO: Add browsing to Scribble documentation. First try to find URLs to +;; their existing documentation (based "~/.racket" and on dir of "racket" +;; command). Fall back to public Web version. + +;;----------------------------------------------------------------------- About + +(defun scribble-about () + (interactive) + (scribble-buffer-display + "*About Scribble Mode*" + (function + (lambda () + (insert (propertize scribble-mode-title 'face 'bold) + "\n\n" + "Version " + (propertize scribble-mode-version 'face 'bold) + "\n\n" + (propertize scribble-mode-web 'face 'bold) + "\n\n" + scribble-mode-legal-notices + "\n"))))) + +;;--------------------------------------------------------------- Mode Function + +;;;###autoload +(defun scribble-mode () + "!!! `\[COMMAND]', `\{KEYMAP}', and `\'" + (interactive) + + (kill-all-local-variables) + + (use-local-map scribble-mode-map) + + (set-syntax-table scribble-mode-syntax-table) + + (setq fill-column 79) + + ;; Comments: + (set (make-local-variable 'comment-start) "@;") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'comment-padding) 1) + (set (make-local-variable 'comment-multi-line) nil) + (set (make-local-variable 'comment-start-skip) + "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *") + + ;; TODO: comment-indent-function + + ;; TODO: indent-line-function + + ;; TODO: abbrev + + ;; Font-Lock: + (set (make-local-variable 'font-lock-defaults) scribble-font-lock-defaults) + + ;; Imenu: + (set (make-local-variable 'imenu-generic-expression) + scribble-imenu-generic-expression) + (set (make-local-variable 'imenu-case-fold-search) nil) + (imenu-add-to-menubar "Imenu") + + ;; ElDoc: + (set (make-local-variable 'eldoc-documentation-function) + 'scribble-eldoc-documentation-function) + (turn-on-eldoc-mode) + + ;; Completion: + (set (make-local-variable 'completion-at-point-functions) + (list 'scribble-completion-at-point-function)) + + ;; Mode Identification: + (setq mode-name "Scribble") + (setq major-mode 'scribble-mode) + + ;; Hooks: + (run-mode-hooks 'scribble-mode-hook)) + +;;------------------------------------------------------------------- Auto-Mode + +;;;###autoload +(mapc (lambda (pair) + (or (assoc (car pair) auto-mode-alist) + (push pair auto-mode-alist))) + '(("\\.scrbl\\'" . scribble-mode))) + +;;--------------------------------------------------------------------- Provide + +(provide 'scribble) + +;;; scribble.el ends here diff --git a/layers.personal/mylangs/myscribble/packages.el b/layers.personal/mylangs/myscribble/packages.el new file mode 100644 index 0000000..d48e7c7 --- /dev/null +++ b/layers.personal/mylangs/myscribble/packages.el @@ -0,0 +1,87 @@ + ;;; packages.el --- scribble layer packages file for Spacemacs. + ;; + ;; Copyright (c) 2012-2016 Sylvain Benner & Contributors + ;; + ;; Author: Rongsong Shen + ;; URL: https://github.com/syl20bnr/spacemacs + ;; + ;; This file is not part of GNU Emacs. + ;; + ;;; License: GPLv3 + + ;;; Commentary: + + ;; See the Spacemacs documentation and FAQs for instructions on how to implement + ;; a new layer: + ;; + ;; SPC h SPC layers RET + ;; + ;; + ;; Briefly, each package to be installed or configured by this layer should be + ;; added to `scribble-packages'. Then, for each package PACKAGE: + ;; + ;; - If PACKAGE is not referenced by any other Spacemacs layer, define a + ;; function `scribble/init-PACKAGE' to load and initialize the package. + + ;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so + ;; define the functions `scribble/pre-init-PACKAGE' and/or + ;; `scribble/post-init-PACKAGE' to customize the package as it is loaded. + + ;;; Code: + + (defconst myscribble-packages + '((scribble :location local) + (evil-scribble :location local)) + "The list of Lisp packages required by the scribble layer. + + Each entry is either: + + 1. A symbol, which is interpreted as a package to be installed, or + + 2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' directs Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun myscribble/init-scribble () + (use-package scribble + :defer t + :commands scribble-mode + :mode ("\\.scrbl$" . scribble-mode))) + +(defun myscribble/post-init-scribble () + ) + +(defun myscribble/init-evil-scribble () + (use-package evil-scribble + :defer t + :commands evil-scribble-mode + :init (add-hook 'scribble-mode-hook 'evil-scribble-mode) + :config (progn + (spacemacs/set-leader-keys-for-major-mode 'scribble-mode + "b" 'scribble-build + "f" 'scribble-set-target-format + "v" 'scribble-view + "n" 'next-error)))) + +(defun myscribble/post-init-evil-scribble () + ) + + ;;; packages.el ends here diff --git a/layers.personal/orgtools/README.org b/layers.personal/orgtools/README.org new file mode 100644 index 0000000..b0666bd --- /dev/null +++ b/layers.personal/orgtools/README.org @@ -0,0 +1,29 @@ +#+TITLE: orgtools layer +#+HTML_HEAD_EXTRA: + +#+CAPTION: logo + +# The maximum height of the logo should be 200 pixels. +[[img/orgtools.png]] + +* Table of Contents :TOC_4_org:noexport: + - [[Description][Description]] + - [[Install][Install]] + - [[Key bindings][Key bindings]] + +* Description +This layer does wonderful things: + - thing01 + +* Install +To use this contribution add it to your =~/.spacemacs= + +#+begin_src emacs-lisp + (setq-default dotspacemacs-configuration-layers '(orgtools)) +#+end_src + +* Key bindings + +| Key Binding | Description | +|-----------------+----------------| +| ~ x x x~ | Does thing01 | diff --git a/layers.personal/orgtools/funcs.el b/layers.personal/orgtools/funcs.el new file mode 100644 index 0000000..9c9e099 --- /dev/null +++ b/layers.personal/orgtools/funcs.el @@ -0,0 +1,45 @@ +(require 'cl-lib) +(defun my-org-get-docinfo (info) + (interactive) + (save-excursion + (progn + (goto-char (point-min)) + (let ((docinfo (if (re-search-forward "^[ \t]*\\*[ \t]+DOCUMENT[ \t]+METADATA" (point-max) t) + (org-entry-properties (point) nil) + nil))) + (add-to-list 'docinfo + (cons "AUTHOR" + (org-export-data (plist-get info :author) info))) + (add-to-list 'docinfo + (cons "PROJECT" + (org-export-data (plist-get info :title) info))) + docinfo)))) + + +(defun my-org-get-table-name () + (save-excursion + (if (re-search-backward "^[ \t]*#\\+NAME:[ \t]*\\([^ \t]*\\).*$") + (match-string 1) + ""))) + +(defvar orgtools-themes nil + "all themes we supported") + +(defun orgtools-register-theme (name func) + "add a theme to our supported theme list" + (unless orgtools-themes + (advice-add 'org-latex-template :around #'orgtools-latex-template)) + (unless (assoc name orgtools-themes) + (add-to-list 'orgtools-themes (list name func)))) + +(defun orgtools-latex-template (orig-fun &rest args) + (let* ((content (car args)) + (info (car (cdr args))) + (docinfo (my-org-get-docinfo info))) + (let* ((theme (cdr (assoc "THEME" docinfo))) + (func (let ((vx (assoc theme orgtools-themes))) + (if vx + (car (cdr vx)) + #'(lambda (content info docinfo) + (list content info )))))) + (apply orig-fun (apply func (list content info docinfo)))))) diff --git a/layers.personal/orgtools/local/ob-mermaid/ob-mermaid.el b/layers.personal/orgtools/local/ob-mermaid/ob-mermaid.el new file mode 100644 index 0000000..5f79743 --- /dev/null +++ b/layers.personal/orgtools/local/ob-mermaid/ob-mermaid.el @@ -0,0 +1,164 @@ +;;; ob-mermaid.el --- org-babel functions for mermaid evaluation + +;; Copyright (C) 2009-2012 Free Software Foundation, Inc. + +;; Author: Rongsong Shen +;; Keywords: literate programming, mermaid +;; Homepage: http://orgmode.org + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . + +;;; Commentary: + +;; Org-Babel support for evaluating mermaid source code. +;; +;; This differs from most standard languages in that +;; +;; 1) there is no such thing as a "session" in mermaid +;; +;; 2) we are generally only going to return results of type "file" +;; +;; 3) we are adding the "file" and "cmdline" header arguments, if file +;; is omitted then the -V option is passed to the mermaid command for +;; interactive viewing + +;;; Requirements: + +;; +;; - mermaid-mode :: Major mode for editing mermaid files + +;;; Code: +(require 'ob) +(eval-when-compile (require 'cl)) + +(defvar org-babel-default-header-args:mermaid + '((:results . "file") (:exports . "results")) + "Default arguments when evaluating an Mermaid source block.") + +(defcustom org-mermaid-program "mmdc" + "Command of mermaid. The command should use command line `mmc sourcefile'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defcustom org-mermaid-convert "convert" + "Command for convert picture format. The command should use format `convert source destintion'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defun mermaid-shell-command (dir cmd) + (shell-command (concat "/bin/sh -c \" cd " + dir ";" + cmd "\""))) + +(defun org-babel-expand-body:mermaid (body params &optional var-lines) + body) + +(defun mermaid-script (body) + body) + +(defun mermaid-run (fmt in-file out-file) + (cond ((string= fmt "svg") + (copy-file (concat (file-name-nondirectory in-file) ".svg") + out-file)) + (t (mermaid-shell-command org-babel-temporary-directory + (concat org-mermaid-convert " " + (file-name-nondirectory in-file) + ".svg" " " + out-file))))) + +;;;###autoload +(defun org-babel-execute:mermaid (body params) + "Execute a block of Mermaid code. +This function is called by `org-babel-execute-src-block'." + (let* ((result-params (split-string (or (cdr (assoc :results params)) ""))) + (out-file (expand-file-name (cdr (assoc :file params)))) + (format (or (and out-file + (string-match ".+\\.\\(.+\\)" out-file) + (match-string 1 out-file)) + "pdf")) + (cmdline (cdr (assoc :cmdline params))) + (in-file (org-babel-temp-file "mermaid-")) + (cmd (concat org-mermaid-program " -i " + (file-name-nondirectory + (org-babel-process-file-name in-file))))) + (with-temp-file in-file + (insert (mermaid-script + (org-babel-expand-body:mermaid + body params)))) + (mermaid-shell-command org-babel-temporary-directory + cmd) + (mermaid-run format in-file out-file) + nil)) ;; signal that output has already been written to file + +;;;###autoload +(defun org-babel-prep-session:mermaid (session params) + "Return an error if the :session header argument is set. +Mermaid does not support sessions" + (error "Mermaid does not support sessions")) + +;;;###autoload +(defun org-babel-variable-assignments:mermaid (params) + "Return list of mermaid statements assigning the block's variables" + t) + +(defconst mermaid-type-prefix "^[^:]*:") + + +(defun org-babel-mermaid-var-value (val) + (setq mmd-m-end 0) + (setq mmd-m-start (string-match mermaid-type-prefix val)) + (if mmd-m-start + (setq mmd-m-end (match-end 0))) + (setq mmd-var-type "") + (setq mmd-var-value val) + (if (> mmd-m-end 0) + (progn (setq mmd-var-type + (substring val mmd-m-start (- mmd-m-end 1))) + (setq mmd-var-value + (substring val mmd-m-end (length val))))) + (cons mmd-var-type (cons mmd-var-value nil))) + +(defun org-babel-mermaid-var-to-mermaid (pair) + "Convert an elisp value into an Mermaid variable. +The elisp value PAIR is converted into Mermaid code specifying +a variable of the same value." + ) + +(defun org-babel-mermaid-define-type (data) + "Determine type of DATA. + +DATA is a list. Return type as a symbol. + +The type is `string' if any element in DATA is +a string. Otherwise, it is either `numeric', if some elements are +floats, or `numeric'." + (let* ((type 'numeric) + find-type ; for byte-compiler + (find-type + (function + (lambda (row) + (catch 'exit + (mapc (lambda (el) + (cond ((listp el) (funcall find-type el)) + ((stringp el) (throw 'exit (setq type 'string))) + ((floatp el) (setq type 'numeric)))) + row)))))) + (funcall find-type data) type)) + +(provide 'ob-mermaid) +;;; ob-mermaid.el ends here diff --git a/layers.personal/orgtools/local/ob-metapost/ob-metapost.el b/layers.personal/orgtools/local/ob-metapost/ob-metapost.el new file mode 100644 index 0000000..0f78bae --- /dev/null +++ b/layers.personal/orgtools/local/ob-metapost/ob-metapost.el @@ -0,0 +1,207 @@ +;;; ob-metapost.el --- org-babel functions for metapost evaluation + +;; Copyright (C) 2009-2012 Free Software Foundation, Inc. + +;; Author: Rongsong Shen +;; Keywords: literate programming, metapost +;; Homepage: http://orgmode.org + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . + +;;; Commentary: + +;; Org-Babel support for evaluating metapost source code. +;; +;; This differs from most standard languages in that +;; +;; 1) there is no such thing as a "session" in metapost +;; +;; 2) we are generally only going to return results of type "file" +;; +;; 3) we are adding the "file" and "cmdline" header arguments, if file +;; is omitted then the -V option is passed to the metapost command for +;; interactive viewing + +;;; Requirements: + +;; +;; - metapost-mode :: Major mode for editing metapost files + +;;; Code: +(require 'ob) +(eval-when-compile (require 'cl)) + +(defvar org-babel-default-header-args:metapost + '((:results . "file") (:exports . "results")) + "Default arguments when evaluating an Metapost source block.") + +(defcustom org-metapost-program "mpost" + "Command of metapost. The command should use command line `mpost sourcefile'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defcustom org-metapost-convert "convert" + "Command for convert picture format. The command should use format `convert source destintion'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defvar mp-prologues) +(defvar mp-script) +(defvar mp-m-end) +(defvar mp-m-start) +(defvar mp-var-type) +(defvar mp-var-value) +(defvar mp-vpair) + +(defun metapost-shell-command (dir cmd) + (shell-command (concat "/bin/sh -c \" cd " + dir ";" + cmd "\""))) + +(defun metapost-fold (acc fun lst) + (if lst + (metapost-fold (funcall fun acc (car lst)) + fun (cdr lst)) + acc)) + +(defun metapost-script (fmt mp-libs body) + (setq mp-prologues + (cond ((string= fmt "svg") "outputformat:=\"svg\";\n") + (t "prologues:=3;\n"))) + + (setq mp-script (concat "beginfig(1);\n" + body + "\nendfig;\n" + "end\n")) + (message "%s" mp-script) + (concat mp-prologues + (if mp-libs + (metapost-fold "" #'(lambda (a b) + (concat a "input " b ";\n")) + (split-string mp-libs ",")) + "") + mp-script)) + +(defun metapost-post-run (fmt in-file out-file) + (cond ((or (string= fmt "svg") + (string= fmt "eps")) + (copy-file (concat (file-name-nondirectory in-file) ".1") + out-file)) + (t (metapost-shell-command org-babel-temporary-directory + (concat org-metapost-convert " " + (file-name-nondirectory in-file) + ".1" " " + out-file))))) + +;;;###autoload +(defun org-babel-execute:metapost (body params) + "Execute a block of Metapost code. +This function is called by `org-babel-execute-src-block'." + (let* ((result-params (split-string (or (cdr (assoc :results params)) ""))) + (out-file (expand-file-name (cdr (assoc :file params)))) + (format (or (and out-file + (string-match ".+\\.\\(.+\\)" out-file) + (match-string 1 out-file)) + "pdf")) + (cmdline (cdr (assoc :cmdline params))) + (in-file (org-babel-temp-file "metapost-")) + (cmd (concat org-metapost-program " --debug " + (file-name-nondirectory + (org-babel-process-file-name in-file))))) + (with-temp-file in-file + (insert (metapost-script format + (cdr (assoc :mp-libs params)) + (org-babel-expand-body:generic + body params + (org-babel-variable-assignments:metapost params))))) + (metapost-shell-command org-babel-temporary-directory + cmd) + (metapost-post-run format in-file out-file) + nil)) ;; signal that output has already been written to file + +;;;###autoload +(defun org-babel-prep-session:metapost (session params) + "Return an error if the :session header argument is set. +Metapost does not support sessions" + (error "Metapost does not support sessions")) + +;;;###autoload +(defun org-babel-variable-assignments:metapost (params) + "Return list of metapost statements assigning the block's variables" + (mapcar #'org-babel-metapost-var-to-metapost + (mapcar #'cdr (org-babel-get-header params :var)))) + +(defconst metapost-type-prefix "^[^:]*:") + + +(defun org-babel-metapost-var-value (val) + (setq mp-m-end 0) + (setq mp-m-start (string-match metapost-type-prefix val)) + (if mp-m-start + (setq mp-m-end (match-end 0))) + (setq mp-var-type "") + (setq mp-var-value val) + (if (> mp-m-end 0) + (progn (setq mp-var-type + (substring val mp-m-start (- mp-m-end 1))) + (setq mp-var-value + (substring val mp-m-end (length val))))) + (cons mp-var-type (cons mp-var-value nil))) + +(defun org-babel-metapost-var-to-metapost (pair) + "Convert an elisp value into an Metapost variable. +The elisp value PAIR is converted into Metapost code specifying +a variable of the same value." + (let ((var (car pair)) + (val (let ((v (cdr pair))) + (if (symbolp v) (symbol-name v) v)))) + (progn + (setq mp-vpair (org-babel-metapost-var-value val)) + (setq mp-var-type (nth 0 mp-vpair)) + (setq mp-var-value (nth 1 mp-vpair)) + (if (string= mp-var-type "string") + (format "%s %s;\n %s :=\"%s\";\n" + mp-var-type var var mp-var-value + ) + (format "%s %s;\n %s := %s;\n" + mp-var-type var var mp-var-value + ))))) + +(defun org-babel-metapost-define-type (data) + "Determine type of DATA. + +DATA is a list. Return type as a symbol. + +The type is `string' if any element in DATA is +a string. Otherwise, it is either `numeric', if some elements are +floats, or `numeric'." + (let* ((type 'numeric) + find-type ; for byte-compiler + (find-type + (function + (lambda (row) + (catch 'exit + (mapc (lambda (el) + (cond ((listp el) (funcall find-type el)) + ((stringp el) (throw 'exit (setq type 'string))) + ((floatp el) (setq type 'numeric)))) + row)))))) + (funcall find-type data) type)) + +(provide 'ob-metapost) +;;; ob-metapost.el ends here diff --git a/layers.personal/orgtools/local/ob-tikz/ob-tikz.el b/layers.personal/orgtools/local/ob-tikz/ob-tikz.el new file mode 100644 index 0000000..0ad28a6 --- /dev/null +++ b/layers.personal/orgtools/local/ob-tikz/ob-tikz.el @@ -0,0 +1,201 @@ +;;; ob-tikz.el --- org-babel functions for tikz evaluation + +;; Copyright (C) 2009-2012 Free Software Foundation, Inc. + +;; Author: Rongsong Shen +;; Keywords: literate programming, tikz +;; Homepage: http://orgmode.org + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . + +;;; Commentary: + +;; Org-Babel support for evaluating tikz source code. +;; +;; This differs from most standard languages in that +;; +;; 1) there is no such thing as a "session" in tikz +;; +;; 2) we are generally only going to return results of type "file" +;; +;; 3) we are adding the "file" and "cmdline" header arguments, if file +;; is omitted then the -V option is passed to the tikz command for +;; interactive viewing + +;;; Requirements: + +;; +;; - tikz-mode :: Major mode for editing tikz files + +;;; Code: +(require 'ob) +(eval-when-compile (require 'cl)) +(require 'latex) + +;;(add-to-list 'org-babel-tangle-lang-exts '("tikz" . "tikz")) + +(define-derived-mode tikz-mode + latex-mode "tikz/pgf" + "Major mode for tikz/pgf script" + ) + +(font-lock-add-keywords + 'tikz-mode + '(("\\draw" . font-lock-keyword-face) + ("\\filldraw" . font-lock-keyword-face) + ("\\clip" . font-lock-keyword-face) + ("\\shadowdraw" . font-lock-keyword-face) + ("\\path" . font-lock-keyword-face) + ("\\foreach" . font-lock-keyword-face) + ("\\node" . font-lock-keyword-face) + ("\\fill" . font-lock-keyword-face) + )) + +(defvar org-babel-default-header-args:tikz + '((:results . "file") (:exports . "results")) + "Default arguments when evaluating an Tikz source block.") + +(defcustom org-tikz-program "pdflatex" + "Command of tikz. The command should use command line `pdflatex sourcefile'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defcustom org-tikz-convert "convert" + "Command for convert picture format. The command should use format `convert source destintion'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defvar tikz-prologues) +(defvar tikz-script) +(defvar tikz-m-end) +(defvar tikz-m-start) +(defvar tikz-var-type) +(defvar tikz-var-value) +(defvar tikz-vpair) + +(defun tikz-shell-command (dir cmd) + (shell-command (concat "/bin/sh " " -c " + "\" cd " dir ";" + cmd "\""))) + +(defun tikz-script (fmt tikz-libs body) + (setq tikz-prologues + (concat "\\documentclass{article}\n" + "\\usepackage{tikz}\n" + "\\usepackage{pgfplots}\n" + (if tikz-libs + (concat "\\usetikzlibrary{" + tikz-libs + "}\n") + "") + "\\begin{document}\n" + "\\begin{tikzpicture}")) + + (setq tikz-script-data (concat body + "\n\\end{tikzpicture}\n" + "\\end{document}\n")) + (message "%s" (concat tikz-prologues tikz-script-data)) + (concat tikz-prologues tikz-script-data)) + +(defun tikz-post-run (fmt in-file out-file) + (tikz-shell-command "." + (concat org-tikz-convert " " + (concat org-babel-temporary-directory "/" + (file-name-nondirectory in-file) + ".pdf") + " " + out-file))) + +;;;###autoload +(defun org-babel-execute:tikz (body params) + "Execute a block of Tikz code. +This function is called by `org-babel-execute-src-block'." + (let* ((result-params (split-string (or (cdr (assoc :results params)) ""))) + (out-file (cdr (assoc :file params))) + (format (or (and out-file + (string-match ".+\\.\\(.+\\)" out-file) + (match-string 1 out-file)) + "pdf")) + (cmdline (cdr (assoc :cmdline params))) + (in-file (org-babel-temp-file "tikz-")) + (cmd + (concat (concat org-tikz-program " -shell-escape ") + (org-babel-process-file-name in-file) + ))) + (with-temp-file (concat in-file ".tex") + (insert (tikz-script format + (tikz-get-value-by-name 'tikz-libs + (mapcar #'cdr (org-babel-get-header params :var))) + (org-babel-expand-body:generic + body params + (org-babel-variable-assignments:tikz params))))) + (message cmd) + (tikz-shell-command org-babel-temporary-directory cmd) + (tikz-post-run format in-file out-file) + nil)) ;; signal that output has already been written to file + +;;;###autoload +(defun org-babel-prep-session:tikz (session params) + "Return an error if the :session header argument is set. +Tikz does not support sessions" + (error "Tikz does not support sessions")) + +;;;###autoload +(defun org-babel-variable-assignments:tikz (params) + "Return list of tikz statements assigning the block's variables" + (mapcar #'org-babel-tikz-var-to-tikz + (mapcar #'cdr (org-babel-get-header params :var)))) + +(defun tikz-get-value-by-name (name vpairs) + (let ((vp (assoc name vpairs))) + (if vp + (cdr vp) + nil))) + +(defun org-babel-tikz-var-value (val) + val) + +(defun org-babel-tikz-var-to-tikz (pair) + "Convert an elisp value into an Tikz variable. +The elisp value PAIR is converted into Tikz code specifying +a variable of the same value." + nil) + +(defun org-babel-tikz-define-type (data) + "Determine type of DATA. + +DATA is a list. Return type as a symbol. + +The type is `string' if any element in DATA is +a string. Otherwise, it is either `numeric', if some elements are +floats, or `numeric'." + (let* ((type 'numeric) + find-type ; for byte-compiler + (find-type + (function + (lambda (row) + (catch 'exit + (mapc (lambda (el) + (cond ((listp el) (funcall find-type el)) + ((stringp el) (throw 'exit (setq type 'string))) + ((floatp el) (setq type 'numeric)))) + row)))))) + (funcall find-type data) type)) + +(provide 'ob-tikz) +;;; ob-tikz.el ends here diff --git a/layers.personal/orgtools/local/org-lsf-theme/org-lsf-theme.el b/layers.personal/orgtools/local/org-lsf-theme/org-lsf-theme.el new file mode 100644 index 0000000..ada54d9 --- /dev/null +++ b/layers.personal/orgtools/local/org-lsf-theme/org-lsf-theme.el @@ -0,0 +1,61 @@ + +(defun org-lsf-gen-header (docinfo) + (let ((my-org-doc-tags '(("THEME" . nil) + ("REVIEWERS" . "docreviewers") + ("VERSION" . "docversion") + ("STATUS" . "docstatus") + ("CIRCULATION" . "circulation") + ("PROJDESCR" . "docdescription") + ("CONTRIBUTORS" . "contributors") + ("TYPE" . "doctype") + ("PROJID" . "projid") + ("PRODVER" . "productversion") + ("PRODNAME" . "productname") + ("PROJNAME" . "projname") + ("PROJECT" . "docname") + ("AUTHOR" . "docauthor")))) + (concat "\\usepackage{mythemes}\n" + (apply #'concat + (mapcar #'(lambda (tag) + (let ((tagname (car tag)) + (cmd (cdr tag))) + (let ((v (cdr (assoc tagname docinfo)))) + (when cmd + (concat "\\newcommand\\" cmd "{" + (if v v "") "}\n"))))) + my-org-doc-tags)) + "\\newcommand\\docupdate{\\today}\n"))) + +(defun org-lsf-gen-title (docinfo) + (let ((history "")) + (org-table-map-tables #'(lambda () + (let ((tblname (my-org-get-table-name))) + (when (string= tblname "document-history") + (let ((table (buffer-substring-no-properties + (org-table-begin) + (org-table-end)))) + (setq history + (let ((params (list + :tstart "\\begin{dochistory}" + :tend "\\end{dochistory}" + :lstart "" :lend "\\\\" :sep " & " + :efmt "%s\\,(%s)" :hline "\\hline"))) + (orgtbl-to-generic (org-table-to-lisp table) + params))))))) + t) + (concat "\\ibmcoverpage\n\\projectinfo\n" + history "\n\\newpage\n"))) + +(defun org-lsf-put-info (info docinfo) + (plist-put info :latex-header-extra + (org-lsf-gen-header docinfo)) + (plist-put info :latex-title-command + (org-lsf-gen-title docinfo)) + info) + +;;;###autoload +(defun org-lsf-theme-latex-template (content info docinfo) + (list (concat "\\newpage\n" content) + (org-lsf-put-info info docinfo))) + +(provide 'org-lsf-theme) diff --git a/layers.personal/orgtools/local/org-templates/org-templates.el b/layers.personal/orgtools/local/org-templates/org-templates.el new file mode 100644 index 0000000..cf36c83 --- /dev/null +++ b/layers.personal/orgtools/local/org-templates/org-templates.el @@ -0,0 +1,19 @@ +;; +(defcustom org-templates-directory "~/workenv/templates/" + "The directory which org templates have been put" + :type 'string + :group 'orgtools) + +;;;###autoload +(defun org-use-template (template) + (interactive + (let ((templated-used (read-file-name "Choose template:" + (expand-file-name org-templates-directory) + nil nil nil))) + (list templated-used))) + (when template + (insert-file-contents template) + ;; enable file local variables defined in template + (hack-local-variables))) + +(provide 'org-templates) diff --git a/layers.personal/orgtools/local/org-tufte-theme/org-tufte-theme.el b/layers.personal/orgtools/local/org-tufte-theme/org-tufte-theme.el new file mode 100644 index 0000000..4757e60 --- /dev/null +++ b/layers.personal/orgtools/local/org-tufte-theme/org-tufte-theme.el @@ -0,0 +1,97 @@ +(defun org-tufte-get-theme (docinfo) + (let ((theme (cdr (assoc "THEME" docinfo)))) + (cond + ((string= "tufte-handout" theme) theme) + ((string= "tufte-book" theme) theme) + (t "")))) + +(defun org-tufte-have-toc (docinfo) + (let ((toc (assoc "TOC" docinfo))) + (if toc + (let ((toc-value (cdr toc))) + (if toc-value + (cond + ((string= toc-value "no") nil) + ((string= toc-value "NO") nil) + (t t)) + t)) + t))) + +(defun org-tufte-gen-header (docinfo) + (concat "\\usepackage{etex}\n" + "\\reserveinserts{36}\n" + "\\usepackage[maxfloats=48]{morefloats}\n" + "\\usepackage[style=verbose-trad1, backend=bibtex]{biblatex}\n" + "\\addbibresource{local.bib}\n" + "\\usepackage{booktabs,graphicx,microtype,hyphenat,marginfix,amsmath}\n" + "\\geometry{paperheight=10.5in,paperwidth=8.5in,textwidth=4.375in}\n" + "\\titleformat{\\part}[display]{\\relax\\itshape\\huge}{}{0pt}{\\huge\\rmfamily\\itshape}[]\n" + "\\usepackage{xparse}\n" + "\\usepackage{xpatch}\n" + "\\makeatletter\n" + "\\xpatchcmd{\\@footnotetext}%\n" + " {\\color@begingroup}\n" + " {\\colomythemesr@begingroup\\toggletrue{blx@footnote}}\n" + " {}\n" + " {}\n" + "\\makeatother\n" + "\n" + "\\DeclareCiteCommand{\\sidecitehelper}\n" + " {\\usebibmacro{prenote}}\n" + " {\\usebibmacro{citeindex}%\n" + " \\usebibmacro{cite}}\n" + " {\\multicitedelim}\n" + " {\\usebibmacro{cite:postnote}}\n" + "\n" + "\\ExplSyntaxOn\n" + "\\NewDocumentCommand\\sidecite{D<>{}O{}om}{%\n" + " \\iftoggle{blx@footnote}\n" + " {\\cs_set_protected_nopar:Npn \\__sct_wrapper:nn ##1 ##2 {\\mkbibparens{##2}}}\n" + " {\\cs_set_protected_nopar:Npn \\__sct_wrapper:nn ##1 ##2 {\\sidenote[][##1]{##2}}}\n" + " {\\IfNoValueTF{#3}\n" + " {\\__sct_wrapper:nn{#1}{\\sidecitehelper[#2]{#4}}}\n" + " {\\__sct_wrapper:nn{#1}{\\sidecitehelper[#2][#3]{#4}}}}\n" + "}\n" + "\\ExplSyntaxOff\n" + "\n")) + +(defun org-tufte-put-info (info docinfo) + (let ((theme (org-tufte-get-theme docinfo)) + (toc (org-tufte-have-toc docinfo))) + (unless (string= "theme" "") + (plist-put info :latex-class theme)) + (if toc + (plist-put info :latex-toc-command + "\\newpage\\tableofcontents") + (plist-put info :latex-toc-command + "\\relax")) + (plist-put info :latex-header + (concat (org-tufte-gen-header docinfo) + "\n" + (plist-get :latex-header docinfo)))) + info) + +;;;###autoload +(defun org-tufte-register-classes () + (unless (assoc "tufte-handout" org-latex-classes) + (add-to-list 'org-latex-classes + '("tufte-handout" + "\\documentclass[nobib]{tufte-handout} " + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}"))) + (add-to-list 'org-latex-classes + '("tufte-book" + "\\documentclass[twoside,nobib]{tufte-book} " + ("\\part{%s}" . "\\part*{%s}") + ("\\chapter{%s}" . "\\chapter*{%s}") + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}"))))) + +;;;###autoload +(defun org-tufte-theme-latex-template (content info docinfo) + (org-tufte-register-classes) + (list (concat "\\newpage\n" content) + (org-tufte-put-info info docinfo))) + +(provide 'org-tufte-theme) diff --git a/layers.personal/orgtools/local/ox-ravel/ox-ravel.el b/layers.personal/orgtools/local/ox-ravel/ox-ravel.el new file mode 100644 index 0000000..c58153f --- /dev/null +++ b/layers.personal/orgtools/local/ox-ravel/ox-ravel.el @@ -0,0 +1,822 @@ +;;; ox-ravel.el --- Sweave/knit/brew document maker for orgmode +;; Copyright (C) 2012---2016 Charles C. Berry + +;; 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 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 . + +;;; Commentary: +;; +;; Several exporters are provided for translating from +;; Org to formats for reproducible research using +;; document generating engines such as Sweave, brew, +;; knitr, rmarkdown, et cetera. Typically, R src blocks +;; are converted to `code chunks' in the desired format +;; and the rest of the Org document is translated to +;; latex, html, markdown, or some other document format. +;; +;; See ox-ravel.org in the orgmode-accessories archive on +;; github for details. Also see demos.org and other +;; *.org files for examples of usage. + +;;; Code: +;; + +;;; Requisites and Declarations +(eval-when-compile (require 'cl-lib)) +(require 'ox) + +(declare-function org-babel-expand-body:R "ob-R.el" ) + +;; defconst-org-babel-header-args:ravel +;; #+NAME: defconst-org-babel-header-args-ravel + +(defconst org-babel-header-args:ravel + '( + (ravel . :any) + (ravel-style . :any) + (engine . :any)) + "Ravel-specific header arguments.") + +;; org-lint org-lint needs these +(eval-after-load 'ob-core + '(mapc (lambda (x) + (add-to-list + 'org-babel-common-header-args-w-values x)) + org-babel-header-args:ravel)) + +(eval-after-load 'ob-core + '(mapc (lambda (x) + (add-to-list + 'org-babel-header-arg-names (car x))) + org-babel-header-args:ravel)) + +;; defvar-org-ravel-style + +;; #+NAME: defvar-org-ravel-style + +(defvar org-ravel-style nil + "The default style to use for constructing chunks. +Can be buffer-local, and is usually set by the export dispatcher.") + +(make-variable-buffer-local 'org-ravel-style) + +;; defvar-org-ravel-run + +;; #+NAME: defvar-org-ravel-run + +(defvar-local org-ravel-run nil + "If ravel is to be run on src blocks, this will be a list like + + '(\"R\") or '(\"R\" \"python\" \"awk\") + +and usually set (by the export dispatcher) to `org-ravel-engines'. + +Set this as buffer/file local for demos or debugging.") + +;; defcustom-org-ravel-engines + +;; #+NAME: defcustom-org-ravel-engines + +(defcustom org-ravel-engines '(("R")) + "Use these engines in forming ravel chunks. + +Typically, `org-ravel-run' will default to these. It can be +buffer-local. These engines are recognized by `knitr': + +`R' `python' `awk' `ruby' `haskell' `bash' `perl' `dot' + `tikz' `sas' `coffeescript', `c', `Rcpp', and `polyglot'. + +Each alist CONS cell has the language (as a string) for the CAR and +any cdr is cons-ed to the ravel attributes. + +Buffer local values are allowed." + + :group 'org-export-ravel + + :type '(set :greedy t + (const :tag " R" ("R") ) + (const :tag " c" ("c" . "engine='c'")) + (const :tag " rcpp" ("c++" . "engine='Rcpp'")) + (const :tag " C" ("C" . "engine='c'")) + (const :tag " Rcpp" ("C++" . "engine='Rcpp'")) + (const :tag " Python" ("python" . "engine='python'")) + (const :tag " AWK" ("awk" . "engine='awk'")) + (const :tag " Ruby" ("ruby" . "engine='ruby'")) + (const :tag " Haskell" ("haskell" . "engine='haskell'")) + (const :tag " bash" ("bash" . "engine='bash'")) + (const :tag " perl" ("perl" . "engine='perl'")) + (const :tag " dot" ("dot" . "engine='dot'")) + (const :tag " TikZ" ("tikz" . "engine='tikz'")) + (const :tag " SAS" ("sas" . "engine='sas'")) + (const :tag " CoffeeScript" + ("coffeescript" . "engine='coffeescript'")) + (const :tag " Polyglot" ("polyglot" . "engine='polyglot'")) + (cons :tag " Other" string string))) + +(make-variable-buffer-local 'org-ravel-engines) + +;; defvar-org-ravel-style-alist + + +;; #+NAME: defcustom-org-ravel-style-alist + +(defgroup org-export-ravel nil + "Options for exporting Org mode files via Ravel." + :tag "Org Export Ravel" + :group 'org-export) + +(defcustom org-ravel-style-alist + '((rnw . (org-ravel-block-rnw org-ravel-inline-rnw ".Rnw")) + (brew . (org-ravel-block-brew org-ravel-inline-brew ".Rbrew")) + (tex . (org-ravel-block-tex org-ravel-inline-tex ".Rtex")) + (html . (org-ravel-block-html org-ravel-inline-html ".Rhtml")) + (md . (org-ravel-block-md org-ravel-inline-md ".Rmd")) + (braces . (org-ravel-block-braces org-ravel-inline-braces ".Rtmpl")) + (rst . (org-ravel-block-rst org-ravel-inline-rst ".Rrst"))) + "The Chunk Style Alist to use in formatting Ravel output. + +The key of each element is matched by the `:ravel-style' property +of a document, if specified, or by the default `:ravel-style' of +the exporter selected. + +The value of each pair is a list of three elements: + - the function that formats src blocks + - the function that formats inline src blocks + - a string giving the file extension. " + :group 'org-export-ravel + :type '(alist + :key-type (symbol :tag "Ravel Style") + :value--type (list :tag "Chunk Defn" + (function :tag "block coder") + (function :tag "inline coder") + (string :tag "File extension")))) + +;; defvar-org-ravel-backend-parent + + +(defvar org-ravel-backend-parent nil + "If ravel is running, this variable will contain the name of the parent.") + +;; defun-org-babel-expand-body:ravel + + + +(defun org-babel-expand-body:ravel (body params &optional var-lines) + "Use native `org-babel-expand-body' for src-block engine if + there is one to format BODY as per PARAMS." + (let* + ((engine-cdr (cdr (assq :engine params))) + (engine (and engine-cdr + (replace-regexp-in-string + "engine='\\([^']+\\)'" "\\1" engine-cdr))) + (expand-cmd + (intern (concat "org-babel-expand-body:" engine)))) + (cond + ((and engine (fboundp expand-cmd)) + (funcall expand-cmd body params)) + (engine (org-babel-expand-body:generic body params)) + (t (org-babel-expand-body:R body params))))) + +;; defun-org-ravel-rewrap + +;; Wrap the results of `org-babel-execute:ravel' in a +;; :#+BEGIN_EXPORT RAVEL ... #+END_EXPORT block. + +;; #+NAME: defun-org-ravel-rewrap + +(defun org-ravel-rewrap (retval &optional inline engine-cdr) + "(Re)Set `:wrap', `:results', `:exports', amd `:engine' + header args to values ravel uses. INLINE settings + differ. ENGINE-CDR gives the engine string, if any. + +Argument RETVAL is the vslue of `org-babel-get-src-block-info'.. + +The original header args `:exports', `:wrap', `:file', `:file-ext', and +`:results' get suffixed with `-arg'. Block/snippet style +functions can find them in `R-HEADERS-ATTR'. " + (let ((n2r (nth 2 retval))) + (cl-loop + for carname in + '(:exports :results :wrap :file :file-ext) do + (let ((elt (assq carname n2r))) + (if elt + (setcar elt (intern (format "%S-arg" carname)))))) + ;; end do + (setf (nth 2 retval) + (append + `((:results . "replace") + (:wrap . ,(if inline "ravel" "EXPORT RAVEL")) + (:exports . "results") + (:engine . ,engine-cdr)) + n2r)))) + +;; defvar-org-ravel-no-confirm-for-ravel + +;; Confirmation of ravel `execution' is a nuisance --- and no code is +;; actually run --- so disable confirmations for `ravel' src blocks. +;; This can be overridden by `(setq org-ravel-no-confirm-for-ravel t)' if +;; ever needed. + +;; Maybe need to add check if (functionp org-confirm-babel-evaluate) is +;; nil in which case, I do not reset it. + +;; #+NAME: defvar-org-ravel-no-confirm-for-ravel + +(defvar org-ravel-no-confirm-for-ravel + (lambda (language body) + (if (string= language "ravel") nil t)) + "Do not confirm if LANGUAGE is `ravel'.") + +(defun org-ravel-reset-confirm (value) + "Revert `org-confirm-babel-evaluate' as buffer local VALUE." + (when org-confirm-babel-evaluate + (setf org-confirm-babel-evaluate + value))) + +;; defun-org-babel-execute:ravel + +;; `org-babel-execute:ravel' calls formatting functions for the code. No +;; actual code is run. Also need to add some kind of alias for edit modes +;; if Rcpp is to be supported. Like `(defalias 'Rcpp-mode 'c++-mode)' + +;; #+NAME: defun-org-babel-execute-ravel + +(defun org-babel-execute:ravel (body params) + "Format BODY as ravel according to PARAMS." + (save-excursion + (if (string= "none" (cdr (assoc :exports params))) + "" + (let* + ((oec (org-element-context)) + (ravel-attr (org-element-property :attr_ravel oec)) + (type (org-element-type oec)) + ;; Need (org-babel-params-from-properties "ravel") here as + ;; parsing was done on "R" or other language. + (headers (apply #'org-babel-merge-params + (append + (org-babel-params-from-properties "ravel") + (list params)))) + (ravelarg (cdr (assoc :ravel headers))) + (engine (cdr (assoc :engine headers))) + (ravelstyle (cdr (assoc :ravel-style headers))) + (label (org-element-property :name oec)) + (non-ravelargs (assq-delete-all :ravel headers)) + (chunk-style + (org-ravel-get-style ravelstyle)) + (body (org-remove-indentation body)) + (full-body + (org-babel-expand-body:ravel body params))) + (when engine + (setq ravel-attr + (cons engine + ravel-attr))) + (if (memq type '(inline-src-block inline-babel-call)) + (org-ravel-snippetize chunk-style ravelarg non-ravelargs full-body) + (org-ravel-blockify chunk-style label ravelarg ravel-attr + non-ravelargs full-body)))))) + +;; defun-org-ravel-snippetize/blockify + +;; Call the chunk-style functions to format the code. + +;; #+NAME: defun-org-ravel-snippetize + +(defun org-ravel-snippetize (chunk-style ravelarg r-headers-attr body) + "Format an inline src block. + +Use CHUNK-STYLE, RAVELARG, and R-HEADERS-ATTR (often ignored) to +format BODY, then wrap it inside an export snippet." + (funcall (nth 1 chunk-style) + ravelarg r-headers-attr body)) + +(defun org-ravel-blockify + (chunk-style label ravelarg ravel-attr non-ravelargs body) + "Format a src block. + +Use CHUNK-STYLE, LABEL, RAVELARG, RAVEL-ATTR and +NON-RAVELARGS (typically ignored) to format BODY and wrap it +inside an export block." + (funcall (nth 0 chunk-style) label ravelarg + ravel-attr non-ravelargs body)) + +;; defun-org-ravel-get-style +;; #+NAME: defun-org-ravel-get-style + +(defun org-ravel-get-style (style-from-header) + "Return the chunk style for STYLE-FROM-HEADER. + +Possibly find it in properties or use `org-ravel-style' by + default." + (or + (assoc-default + (or style-from-header + (cdr (assoc + :ravel-style + (org-babel-parse-header-arguments + (org-entry-get (point) + "header-args:ravel" + 'inherit)))) + org-ravel-style) + org-ravel-style-alist 'string=) + (user-error "Ravel-style: %S not found -- Consult `org-ravel-style-alist'" + style-from-header))) + +;; defun-org-ravel-attr-plus-header +;; #+NAME: defun-org-ravel-attr-plus-header + +(defun org-ravel-attr-plus-header + (label ravelarg ravel-attr) + "Separate LABEL, RAVELARG, and RAVEL-ATTR by commas." + (mapconcat #'identity + (delete nil + (cons label + (cons ravelarg ravel-attr))) ", ")) + +;; defmacro-org-ravel-style-x +;; #+NAME: defmacro-org-ravel-style-x + +(defmacro org-ravel-style-x (x xblock xinline &optional xcode) + "Make style functions. +The functions are `org-ravel-block-X' and `org-ravel-inline-X' +where X names the style, XBLOCK gives the block format, XINLINE gives the +inline format, and XCODE is an optional line prefix. + + `org-ravel-block-X' defines the Chunk code style. It's arguments are + + LABEL - the chunk name (which will be sanitized by +substituting `_' for any character not allowed as a +chunk label by Sweave), + + RAVEL - header args as a string, + ATTR-RAVEL - attributes to be combined with RAVEL, + R-HEADERS-ATTR - other headers from Babel as a string parseable +by `org-babel-parse-header-arguments', + SRC-CODE is the code from the block. + + `org-ravel-inline-X' defines the inline code style. It's arguments + are RAVEL, R-HEADERS-ATTR, SRC-CODE as above. Note that only SRC-CODE is + used in this macro, but other arguments may be used in hand tooled inline + style functions." + (let ((blk-args + '(label ravel attr-ravel r-headers-attr src-code)) + (inline-args '(ravel r-headers-attr src-code)) + (blk-body + `(let* ((label + (if label + (replace-regexp-in-string "[^[:alnum:]#+-_.]" "_" label))) + (ravel (org-ravel-attr-plus-header label ravel attr-ravel))) + ,(if xcode + `(format ,xblock ravel + (replace-regexp-in-string "^" ,xcode src-code)) + `(format ,xblock ravel src-code)))) + (inline-body `(format ,xinline src-code)) + (bname (concat "org-ravel-block-" x)) + (iname (concat "org-ravel-inline-" x))) + (defalias (intern bname) + (list 'lambda blk-args blk-body) + (concat "Run this:\n\n" (pp-to-string blk-body))) + (defalias (intern iname) + (list 'lambda inline-args inline-body) + (concat "Run this:\n\n" (pp-to-string inline-body))) + (format "Functions: %s and %s" bname iname))) + +;; defun-org-ravel-format-brew-spec +;; #+NAME: defun-org-ravel-format-brew-spec + +(defun org-ravel-format-brew-spec (&optional spec) + "Check a brew SPEC, escape % signs, and add a %s spec." + (let + ((spec (or spec "<% %>"))) + (if (string-match + "<\\(%+\\)\\([=]?\\)\\(.+?\\)\\([{}]?[ ]*-?\\)\\(%+\\)>" + spec) + (let ( + (opct (match-string 1 spec)) + (eqsign (match-string 2 spec)) + (filler (match-string 3 spec)) + (enddash (match-string 4 spec)) + (clpct (match-string 5 spec))) + (if (string= opct clpct) + (concat "<" opct opct eqsign " %s " enddash clpct clpct ">") + (error "Percent signs do not balance:%s" spec))) + (error "Invalid spec:%s" spec)))) + +;; defun-org-ravel-block-brew +;; #+NAME: defun-org-ravel-block-brew + +(defun org-ravel-block-brew (label ravel attr_ravel r-headers-attr src-code) + "Define the chunk style for brew. + +LABEL is the chunk name, RAVEL is the collection of ravel args as +a string, ATTR_RAVEL and R-HEADERS-ATTR are ignored here, +SRC-CODE is the code from the block." + (format (org-ravel-format-brew-spec ravel) src-code)) + +(defun org-ravel-inline-brew (ravel r-headers-attr src-code) + "Define the inline-src style for brew. + +RAVEL is the collection of ravel args as a string, R-HEADERS-ATTR +is the collection of headers from Babel as a string parseable by +`org-babel-parse-header-arguments', SRC-CODE is the code from the +block." + (format (org-ravel-format-brew-spec + (or ravel "<%= code -%>")) + src-code)) + +;; org-ravel-style-x-rnw +;; #+NAME: org-ravel-style-x-rnw + +(org-ravel-style-x "rnw" + "<<%s>>=\n%s\n@ %%def" + "\\Sexpr{ %s }") + +;; org-ravel-style-x-tex +;; #+NAME: org-ravel-style-x-tex + +(org-ravel-style-x "tex" + "%% begin.rcode( %s )\n%s\n%% end.code" + "\\rinline{ %s }" + "%") + +;; org-ravel-style-x-html +;; #+NAME: org-ravel-style-x-html + +(org-ravel-style-x "html" + "" + "") + +;; org-ravel-style-x-md +;; #+NAME: org-ravel-style-x-md + +(org-ravel-style-x "md" + "```{r %s }\n%s \n```" + "`r %s `") + +;; org-ravel-style-x-braces +;; #+NAME: org-ravel-style-x-braces + +(org-ravel-style-x "braces" + "{{%0.0s%s}}" + "{{%s}}") + +;; org-ravel-style-x-rst + +;; #+NAME: org-ravel-style-x-rst + +(org-ravel-style-x "rst" + "..{r %s}\n%s\n.. .." + ":r:`%s`" + "%") + +;; defun-org-ravel-export-block + + +;; #+NAME: defun-org-ravel-export-block + +(defun org-ravel-export-block (export-block contents info) + "Transcode a EXPORT-BLOCK element from Org to ravel. +CONTENTS is nil. INFO is a plist holding contextual information." + (if (equal (org-element-property :type export-block) "RAVEL") + (org-unescape-code-in-string + (org-element-property :value export-block)) + (org-export-with-backend + org-ravel-backend-parent export-block contents info))) + +;; defun-org-ravel-export-snippet + +;; #+NAME: defun-org-ravel-export-snippet + +(defun org-ravel-export-snippet (export-snippet contents info) + "Transcode a EXPORT-SNIPPET element from Org to ravel. +CONTENTS is nil. INFO is a plist holding contextual information." + (if (eq (org-export-snippet-backend export-snippet) 'ravel) + (org-element-property :value export-snippet) + (org-export-with-backend org-ravel-backend-parent export-snippet contents info))) + +;; defun-org-ravel-create-backend + +(defun org-ravel-create-backend (parent &optional style) + "Create a ravel-compliant backend from PARENT using STYLE. +Hence, (org-ravel-create-backend 'ascii \"md\") creates a backend +whose parent is ascii and default style is \"md\"." + (org-export-create-backend + :parent parent + :transcoders '((export-snippet . org-ravel-export-snippet) + (export-block . org-ravel-export-block)) + :options `((:ravel-style "RAVEL_STYLE" nil ,style t)) + :blocks '("RAVEL"))) + +;; defmacro-org-ravel-export-wrapper + +;; See [[*defun-org-ravel-export-string-as][defun-org-ravel-export-string-as]] as an example of how this +;; macro is used. + + +(defmacro org-ravel-export-wrapper (&rest body) + "Set up the preliminaries for the BODY of an export function. + +`org-ravel-export-to-file' and similar actions need to redefine + `org-babel-get-src-block-info' and restore the + function to its original value on exit, set values for + `org-ravel-run' and for `org-ravel-style', force the `backend' + to be ravel compliant and let-bind its parent as + `org-ravel-backend-parent', and (by default) turn off + confirmation for the evaluation of ravel blocks. + +`(org-ravel-export-wrapper BODY)' when used inside a `defun' will +take care of these issues. + +Use of this macro outside of ravel export functions is +discouraged as it can corrupt the cache used by the +`org-element-*' functions. In case of these issues, +`org-element-cache-reset' will straighten things out." + (declare (indent 1) (debug (form body))) + `(let* ((org-ravel-get-s-b-info + ;; avoid recursive redefinition + (or (bound-and-true-p org-ravel-get-s-b-info) + (symbol-function + 'org-babel-get-src-block-info))) + (org-ravel-lob-get-info + ;; avoid recursive redefinition + (or (bound-and-true-p org-ravel-lob-get-info) + (symbol-function + 'org-babel-lob-get-info))) + ;; set ravel variables + (org-ravel-run + (or engines org-ravel-run org-ravel-engines)) + (bk-orig + (if (symbolp backend) + (org-export-get-backend backend) backend)) + (ravel-style-option + (assq :ravel-style + (org-export-backend-options bk-orig))) + (backend (if ravel-style-option bk-orig + (unless style + (message "Non ravel BACKEND might need STYLE.")) + (org-ravel-create-backend + (org-export-backend-name bk-orig) style))) + (org-ravel-backend-parent (org-export-backend-parent backend)) + (org-ravel-style + (or style org-ravel-style + (nth 3 + (assoc :ravel-style + (org-export-backend-options + backend))))) + (org-confirm-babel-evaluate org-confirm-babel-evaluate)) + ;; org-babel-get-src-block-info will modify info for ravel blocks + + (cl-letf + (((symbol-function 'org-babel-get-src-block-info) + (lambda (&optional light datum) + (let* ((dat (or datum (org-element-context))) + (lang (org-element-property :language dat)) + (ravel-it (assoc lang org-ravel-run)) + (inline (eq 'inline-src-block (org-element-type datum))) + (engine-cdr (and ravel-it (cdr ravel-it)))) + (if ravel-it + (setf (nth 1 dat) + (plist-put (nth 1 dat) :language "ravel"))) + (let* ((info (funcall org-ravel-get-s-b-info light dat)) + (nth-2-info (nth 2 info))) + + (unless (or (not ravel-it) + (member '(:exports . "none") (nth 2 info))) + ;; revise headers of RAVEL src-blocks + (org-ravel-rewrap info inline engine-cdr)) + ;; return info for all src-blocks + info)))) + ((symbol-function 'org-babel-lob-get-info) + (lambda (&optional datum) + (let* + ((datum (or datum (org-element-context))) + (info (funcall org-ravel-lob-get-info datum)) + (lang (car info)) + (ravel-it (string= lang "ravel")) + (inline (eq 'inline-babel-call (org-element-type datum)))) + (unless (or (not ravel-it) + (member '(:exports . "none") (nth 2 info))) + ;; revise headers of RAVEL src-blocks + (org-ravel-rewrap info inline)) + info)))) + ,@body))) + +;; defun-org-ravel-export-string-as +;; #+NAME: defun-org-ravel-export-string-as + +(defun org-ravel-export-string-as + (string backend &optional body-only ext-plist engines style) + "Export STRING as a string. + + Use BACKEND with BODY-ONLY and EXT-PLIST, all as per +`org-export-string-as'. If non-nil, ENGINES will set +`org-ravel-run' locally. Otherwise, an attempt will be made to +replace it with `org-ravel-run' or `org-ravel-engines'. STYLE +will set `org-ravel-style' if non-nil, otherwise +`org-ravel-style' or the default for BACKEND will be used. + +This function can be run by Babel to produce a string that is +used in a Babel src block. + +It can run arbitrary backends if STYLE is supplied or if STRING +supplies valid values for src blocks and inline src blocks in it." + + + (org-ravel-export-wrapper + (org-ravel-reset-confirm + org-ravel-no-confirm-for-ravel) + (org-export-string-as string backend body-only ext-plist))) + +;; defun-org-ravel-export-to-file + +;; #+NAME: defun-org-ravel-export-to-file + +(defun org-ravel-export-to-file + (backend &optional file async subtreep visible-only + body-only ext-plist post-process engines style) + "Export invoking ravel with BACKEND to FILE. + +ASYNC must be nil, but SUBTREEP, VISIBLE-ONLY, BODY-ONLY, +EXT-PLIST, and POST-PROCESS are passed to `org-export-to-file'. +ENGINES supplies a value for `org-ravel-run' and STYLE for +`org-ravel-style'. If a backend is used that is not set up for +ravel, it usually best to use, e.g. + + `(org-ravel-export-to-file + (org-ravel-create-backend 'ascii \"md\") ... )' + + to create a ravel-compliant backend. + +Note that `org-babel-confirm-evaluate' is set locally by `let*' +to `org-ravel-no-confirm-for-ravel', which holds a `lambda' +function. To override this, create a variable with that name." + + (org-ravel-export-wrapper + (let ((file (or file + (org-export-output-file-name + (org-ravel-extension org-ravel-style) subtreep)))) + (when async (user-error "ASYNC not allow for ravel")) + (org-ravel-reset-confirm org-ravel-no-confirm-for-ravel) + (org-export-to-file backend file async subtreep visible-only + body-only ext-plist post-process)))) +;; defun-org-ravel-export-to-buffer + +;; #+NAME: defun-org-ravel-export-to-buffer + +(defun org-ravel-export-to-buffer + (backend &optional buffer async subtreep visible-only + body-only ext-plist post-process engines style) + "Export invoking ravel using BACKEND to BUFFER. + +ASYNC must be nil, but SUBTREEP, VISIBLE-ONLY, BODY-ONLY, +EXT-PLIST, and POST-PROCESS are passed to `org-export-to-buffer'. +ENGINES supplies a value for `org-ravel-run' and STYLE for +`org-ravel-style'. If a backend is used that is not set up for +ravel, it usually best to use, e.g. + + `(org-ravel-export-to-buffer + (org-ravel-create-backend 'ascii \"md\") ... )' + +to create a ravel-compliant backend. + +Note that `org-babel-confirm-evaluate' is set locally by `let*' +to `org-ravel-no-confirm-for-ravel', which holds a `lambda' +function. To override this, create a variable with that name." + + (org-ravel-export-wrapper + (let ((buffer (or buffer + (format "* %S Output *" + (org-export-backend-name backend))))) + (when async (user-error "ASYNC not allow for ravel")) + (org-ravel-reset-confirm org-ravel-no-confirm-for-ravel) + (org-export-to-buffer backend buffer async subtreep visible-only + body-only ext-plist post-process)))) + +;; defun-org-ravel-extension +;; #+NAME: defun-org-ravel-extension + +(defun org-ravel-extension (style) + "Get the file extension for STYLE." + (nth 3 (assoc-string style org-ravel-style-alist))) + +;; defmacro-ravel-define-exporter + +;; #+NAME: defmacro-ravel-define-exporter + +(defmacro org-ravel-define-exporter + (ravel-backend parent menu-key menu-label style-default + &optional fileout bufferout post-proc filters) + "Define ravel backends. + +The arguments are: + + RAVEL-BACKEND is a symbol naming the backend derived from + + PARENT is a registered backend, + + MENU-KEY should be an integer code for a lower-case + character like `?a' to refer to file dispatch, + + MENU-LABEL tells how to label the backend in the + dispatch menu, + + STYLE-DEFAULT is the style to use if not specified as a + `:ravel-style' attribute, + + FILEOUT is usually nil which allows + `org-ravel-export-to-file' to assign the file name + + BUFFEROUT is usually `t' - if non-nil create menu + entry `(upcase MENU-KEY)' that will be used for menu + dispatch) or nil for no buffer dispatcher, and + + POST-PROC is a post-export hook function or nil + + FILTERS is an alist of filters that will overwrite or + complete filters defined in PARENT back-end. See + `org-export-filters-alist' for a list of allowed filters." + + `(org-export-define-derived-backend + ,ravel-backend + ,parent + :translate-alist '( + (export-snippet . org-ravel-export-snippet) + (export-block . org-ravel-export-block)) + :options-alist '((:ravel-style "RAVEL_STYLE" + nil ,style-default t)) + :filters-alist ,filters + :menu-entry + '(?r "Ravel" + ,(remq nil + `((,menu-key ,(concat menu-label " file") + (lambda (a s v b) + (org-ravel-export-to-file + ,ravel-backend ,fileout a s v b nil + nil nil ,style-default))) + ,(if bufferout + `(,(upcase menu-key) ,(concat menu-label " buffer") + (lambda (a s v b) + (org-ravel-export-to-buffer + ,ravel-backend nil a s v b nil ,post-proc + nil ,style-default))))))))) + +;; Create Backends + +;; The `(eval-after-load FILE FORM)' forms seems to work. i.e. FORM is +;; executed if the backend specified in FILE (e.g. 'ox-latex) is already loaded. +;; If not, then when FILE is loaded, FORM is run. + +;; The variable `org-export-backends' can be customized to (de-)list +;; parent backends. The `ravel' backends that depend on those parents are +;; (de-)activated when the parent is (de-)listed. + +;; A ravel backend whose parent is not in `org-export-backends' will need +;; to `require' or `load' that parent. + +;; #+NAME: run-org-ravel-define-exporters + +(eval-after-load 'ox-latex + '(org-ravel-define-exporter + 'ravel-latex + 'latex ?l "Ravel-LaTeX" "rnw" nil t (lambda () (LaTeX-mode)))) + +(eval-after-load 'ox-beamer + '(org-ravel-define-exporter + 'ravel-beamer + 'beamer ?b "Ravel-beamer" "rnw" nil t (lambda () (LaTeX-mode))) + ) +(eval-after-load 'ox-html + '(org-ravel-define-exporter + 'ravel-html + 'html ?h "Ravel-html" "html" nil t )) + +(defun org-ravel-filter-cite-as-pandoc (text back-end info) + "Translate citations in latex format (i.e. \cite{id}) into + citations in pandoc format (i.e. [@id]). + + Note, loading `ox-bibtex' transforms all latex/bibtex citations + into html links, so do not load it if this format is desired." + (replace-regexp-in-string ",[\s-]*" "; @" + (replace-regexp-in-string + "\\\\cite{\\(.*\\)}" "[@\\1]" text))) +(eval-after-load 'ox-md + '(org-ravel-define-exporter + 'ravel-markdown + 'md ?m "Ravel-markdown" "md" nil t nil + '((:filter-latex-fragment . org-ravel-filter-cite-as-pandoc)))) + +;; provide ravel :noexport: + + +(provide 'ox-ravel) + +;;; ox-ravel.el ends here diff --git a/layers.personal/orgtools/packages.el b/layers.personal/orgtools/packages.el new file mode 100644 index 0000000..ad07905 --- /dev/null +++ b/layers.personal/orgtools/packages.el @@ -0,0 +1,169 @@ +;;; packages.el --- orgtools layer packages file for Spacemacs. +;; +;; Copyright (c) 2012-2016 Sylvain Benner & Contributors +;; +;; Author: Rongsong Shen +;; URL: https://github.com/syl20bnr/spacemacs +;; +;; This file is not part of GNU Emacs. +;; +;;; License: GPLv3 + +;;; Commentary: + +;; See the Spacemacs documentation and FAQs for instructions on how to implement +;; a new layer: +;; +;; SPC h SPC layers RET +;; +;; +;; Briefly, each package to be installed or configured by this layer should be +;; added to `orgtools-packages'. Then, for each package PACKAGE: +;; +;; - If PACKAGE is not referenced by any other Spacemacs layer, define a +;; function `orgtools/init-PACKAGE'mythemes to load and initialize the package. + +;; - Otherwise, PACKAGE is already referenced by another Spacemacs layer, so +;; define the functions `orgtools/pre-init-PACKAGE' and/or +;; `orgtools/post-init-PACKAGE' to customize the package as it is loaded. + +;;; Code: +(defconst orgtools-packages + '((org-templates :location local) + (org-lsf-theme :location local) + (org-tufte-theme :location local) + (ob-tikz :location local) + (ob-metapost :location local) + (ob-mermaid :location local) + (ox-epub :location (recipe :fetcher github :repo "ofosos/org-epub")) + (ox-tufte :location (recipe :fetcher github :repo "dakrone/ox-tufte")) + (ox-ravel :location local) + cdlatex) + "The list of Lisp packages required by the orgtools layer. + +Each entry is either: + +1. A symbol, which is interpreted as a package to be installed, or + +2. A list of the form (PACKAGE KEYS...), where PACKAGE is the + name of the package to be installed or loaded, and KEYS are + any number of keyword-value-pairs. + + The following keys are accepted: + + - :excluded (t or nil): Prevent the package from being loaded + if value is non-nil + + - :location: Specify a custom installation location. + The following values are legal: + + - The symbol `elpa' (default) means PACKAGE will be + installed using the Emacs package manager. + + - The symbol `local' dilibrary(animation) +rects Spacemacs to load the file at + `./local/PACKAGE/PACKAGE.el' + + - A list beginning with the symbol `recipe' is a melpa + recipe. See: https://github.com/milkypostman/melpa#recipe-format") + + +(defun orgtools/init-org-templates () + (use-package org-templates + :defer t + :if (configuration-layer/package-usedp 'org) + :commands org-use-template)) + +(defun orgtools/init-org-lsf-theme () + (use-package org-lsf-theme + :defer t + :if (configuration-layer/package-usedp 'org) + :commands org-lsf-theme-latex-template + :init (progn + (orgtools-register-theme "mythemes" + #'org-lsf-theme-latex-template)))) + +(defun orgtools/init-org-tufte-theme () + (use-package org-tufte-theme + :defer t + :if (configuration-layer/package-usedp 'org) + :commands (org-tufte-theme-latex-template org-tufte-register-classes) + :init (progn + (add-hook 'org-mode-hook #'org-tufte-register-classes) + (orgtools-register-theme "tufte-handout" + #'org-tufte-theme-latex-template) + (orgtools-register-theme "tufte-book" + #'org-tufte-theme-latex-template)))) + +(defun orgtools/init-ob-tikz () + (use-package ob-tikz + :defer t + :if (configuration-layer/package-usedp 'org) + :init (progn + (autoload 'org-babel-execute:tikz "ob-tikz.el") + (autoload 'org-babel-prep-session:tikz "ob-tikz.el") + (autoload 'org-babel-variable-assignments:tikz "ob-tikz.el")) + :config (progn + (add-to-list 'org-babel-load-languages + '(tikz . t)) + (add-to-list 'org-babel-tangle-lang-exts + '("tikz" . "tikz"))))) + +(defun orgtools/init-ob-metapost () + (use-package ob-metapost + :defer t + :if (configuration-layer/package-usedp 'org) + :init (progn + (autoload 'org-babel-execute:metapost "ob-metapost.el") + (autoload 'org-babel-prep-session:metapost "ob-metapost.el") + (autoload 'org-babel-variable-assignments:metapost "ob-metapost.el")) + :config (progn + (add-to-list 'org-babel-load-languages + '(metapost . t)) + (add-to-list 'org-babel-tangle-lang-exts + '("metapost" . "mp"))))) + +(defun orgtools/init-ox-epub () + (spacemacs|use-package-add-hook org :post-config (require 'ox-epub))) + +(defun orgtools/init-ox-tufte () + (spacemacs|use-package-add-hook org :post-config (require 'ox-tufte))) + +(defun orgtools/init-ox-ravel () + (spacemacs|use-package-add-hook org :post-config (require 'ox-ravel))) + +(defun orgtools/init-org-html-themes () + t) + +(defun orgtools/post-init-org-templates () + t) + +(defun orgtools/post-init-org-lsf-theme () + t) + +(defun orgtools/post-init-ob-tikz () + t) + +(defun orgtools/post-init-ob-metapost () + t) + +(defun orgtools/post-init-org-html-themes () + t) + +(defun orgtools/init-cdlatex () + (use-package cdlatex + :defer t + :commands 'turn-on-cdlatex + :config (progn + (add-hook 'org-mode-hook + 'turn-on-cdlatex)))) + +(defun orgtools/post-init-ox-tufte () + t) + +(defun orgtools/post-init-ox-epub () + t) + +(defun orgtools/init-ob-mermaid () + t) +;;; packages.el ends here diff --git a/old-config/init.el b/old-config/init.el new file mode 100644 index 0000000..040e086 --- /dev/null +++ b/old-config/init.el @@ -0,0 +1,22 @@ +(unless (boundp 'user-emacs-directory) + (setq user-emacs-directory "~/.emacs.d/")) + +(defvar *custom-dir* (expand-file-name "~/.emacs.d")) +(defvar *elpa-dir* (concat *custom-dir* "/elpa")) +(defvar *lisp-dir* (concat *custom-dir* "/lisp")) +(defvar *misc-dir* (concat *custom-dir* "/misc")) + +(setq backup-directory-alist + '(("." . "~/.emacs.d/backups"))) + +(setq custom-file (concat *custom-dir* "/custom.el")) + +(add-to-list 'load-path *lisp-dir*) + +;; load personal package configuration +;; +(let ((mypkgs-loader (concat *lisp-dir* + "/mypkgs.el"))) + (when (file-exists-p mypkgs-loader) + (load-file mypkgs-loader))) + diff --git a/old-config/lisp/eiffel.el b/old-config/lisp/eiffel.el new file mode 100644 index 0000000..3b29cce --- /dev/null +++ b/old-config/lisp/eiffel.el @@ -0,0 +1,2585 @@ +;;; eiffel.el --- major mode for editing Eiffel files. + +;; Copyright (C) 1989, 1990, 93, 94, 95, 96, 99, 2000, 01, 02, 04 +;; Tower Technology Corporation, +;; Free Software Foundation, +;; Bob Weiner, +;; C. Adrian + +;; Authors: 1989-1990 Stephen Omohundro, ISE and Bob Weiner +;; 1993-1996 Tower Technology Corporation +;; 1999-2004 Martin Schwenke +;; 2006- Berend de Boer +;; Maintainer: berend@pobox.com +;; Keywords: eiffel languages oop +;; Requires: font-lock, compile, easymenu, imenu + +;; This file is derived from eiffel4.el from Tower Technology Corporation. +;; +;; Known bugs: +;; +;; * eif-short buffer doesn't get font locked under GNU Emacs 19.34. +;; +;; * eif-debug can hang under (at least) XEmacs 21.4.[89] in the wait +;; loop if there is input pending (that is, if the user hits return +;; an extra time). Not yet tested under XEmacs 21.5. +;; +;; This file is distributed under the same terms as GNU Emacs. + +;; GNU Emacs 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, or (at your option) +;; any later version. + +;; GNU Emacs 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; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; NEW VERSIONS +;; The latest version of this mode is always available via: +;; http://sourceforge.net/projects/eiffel-emacs/ + +;; INSTALLATION +;; To install, simply copy this file into a directory in your +;; load-path and add the following two commands in your .emacs file: +;; +;; (add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode)) +;; (autoload 'eiffel-mode "eiffel" "Major mode for Eiffel programs" t) +;; + +;;; History: +;; + +;; Add history stuff here!!! + +;;; Code: + +(require 'font-lock) +(require 'compile) +(require 'easymenu) +(require 'imenu) + +(defconst eiffel-version-string + "$Id: eiffel.el,v 2.78 2006/11/15 02:07:56 berenddeboer Exp $" + "Version string to make reporting bugs more meaningful. +Note that if this file becomes part of GNU Emacs then the file might +be changed by the Emacs maintainers without this version number +changing. This means that if you are reporting a bug for a version +that was shipped with Emacs, you should report the Emacs version!") + +(defgroup eiffel nil + "Eiffel mode for Emacs" + :group 'oop) + +(defgroup eiffel-indent nil + "Indentation variables in Eiffel mode" + :prefix "eif-" + :group 'eiffel) + +(defgroup eiffel-compile nil + "Compilation support variables in Eiffel mode" + :prefix "eif-" + :group 'eiffel) + +(defun eif-customize () + "Run \\[customize-group] for the `eiffel' group." + (interactive) + (customize-group 'eiffel)) + +;; Indentation amount variables. +;; +;; The default values correspond to style used in ``Eiffel: The +;; Language''. + +(defcustom eif-indent-increment 3 + "*Default indentation interval (in spaces)." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-class-level-kw-indent 0 + "*Indentation for Class level keywords. +Specified as number of `eif-indent-increments'. See the variable +`eif-class-level-keywords-regexp'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-class-level-kw-indent 0 + "*Number of extra spaces to add to `eif-class-level-kw-indent'. +This results in the actual indentation of a class level keyword. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-class-level-comment-indent 0 + "*Indentation of comments at the beginning of a class. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-class-level-comment-indent 0 + "*Number of spaces to add to `eif-class-level-comment-indent'. +This results in the actual indentation of a class level comment. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-inherit-level-kw-indent 2 + "*Indentation of keywords falling under the Inherit clause. +Specified as number of `eif-indent-increments'. See the variable +`eif-inherit-level-keywords'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-inherit-level-kw-indent 0 + "*Number of spaces to add to `eif-inherit-level-kw-indent'. +This results in the actual indentation of an inherit level keyword. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-indent 1 + "*Indentation amount of features. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-indent 0 + "*Number of spaces to add to `eif-feature-level-indent'. +This results in the indentation of a feature. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-kw-indent 2 + "*Indentation of keywords belonging to individual features. +Specified as number of `eif-indent-increments'. See the variable +`eif-feature-level-keywords-regexp'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-kw-indent 0 + "*Number of spaces to add to `eif-feature-level-kw-indent'. +This results in the actual indentation of a feature level keyword. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-feature-level-comment-indent 3 + "*Indentation of comments at the beginning of a feature. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-feature-level-comment-indent 0 + "*Number of spaces to add to `eif-feature-level-comment-indent'. +This results in the actual indentation of a feature level comment. +Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-body-comment-indent 0 + "*Indentation of comments in the body of a routine. +Specified as number of `eif-indent-increments')" + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-body-comment-indent 0 + "*Number of spaces to add to `eif-body-comment-indent'. +This results in the actual indentation of a routine body comment. Can +be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-check-keyword-indent 0 + "*Extra indentation for the check clause as described in ETL. +Specified as number of `eif-indent-increments'. Default is 0, which +is different than in ETL's 1." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-check-keyword-indent 0 + "*Number of spaces to add to `eif-check-keyword-indent'. +This results in the actual indentation of a check keyword. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-rescue-keyword-indent -1 + "*Extra indentation for the rescue clause as described in ETL. +Specified as number of `eif-indent-increments'. Default is -1." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-rescue-keyword-indent 0 + "*Number of spaces to add to `eif-rescue-keyword-indent'. +This results in the actual indentation of a rescue keyword. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-then-indent 0 + "*Indentation for a `then' appearing on a line by itself. +This is as opposed to a `then' on the same line as an `if'. Specified +as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-then-indent 1 + "*Number of spaces to add to `eif-then-indent'. +This results in the actual indentation of a `then' appearing on a line +by itself. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-continuation-indent 1 + "*Extra indentation for a continued statement line. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-continuation-indent 0 + "*Number of spaces to add to `eif-continuation-indent'. +This results in the actual indentation of a continued statement +line. Can be negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-string-continuation-indent 0 + "*Extra indentation for a continued string. +Specified as number of `eif-indent-increments'." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-extra-string-continuation-indent -1 + "*Number of spaces to add to `eif-string-continuation-indent'. +This results in the actual indentation of a continued string. Can be +negative." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-indent-string-continuations-relatively-flag t + "*Non-nil means string continuations are indented relative to 1st character. +That is, `eif-string-continuation-indent' and +`eif-extra-string-continuation-indent' are added to position of first +character of string. If nil, string continuations are indented +relative to indent of previous line." + :type 'boolean + :group 'eiffel-indent) + +(defcustom eif-multi-line-string-indent t + "*Set to nil if multi line strings need indentation or need to be left alone when indenting." + :type 'boolean + :group 'eiffel-indent) + +(defcustom eif-set-tab-width-flag t + "*Non-nil means `tab-width' is set to `eif-indent-increment' in `eiffel-mode'." + :type 'boolean + :group 'eiffel-indent) + +(defcustom eif-preprocessor-indent 0 + "*Indentation for lines GOBO preprocessor directives. +Specified as number of `eif-indent-increments' from left margin." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-fill-max-save 4096 + "*Maximum size of a paragraph to save before filling. +Normally \\[eif-fill-paragraph] will mark a buffer as modified even if +the fill operation does not make any changes. If the paragraph being +filled is smaller than the value of this variable then the contents of +the paragraph will be saved for comparison with the paragraph after +the fill operation. If they are the same, the buffer modification +state is restored. Set this to 0 to disable this feature, or a very +big number to enable it for all paragraphs." + :type 'integer + :group 'eiffel-indent) + +(defcustom eif-use-gnu-eiffel t + "*If t include support for compilation using GNU SmartEiffel." + :type 'boolean + :group 'eiffel-compile) + +(defcustom eif-compile-command + (if (file-executable-p "/usr/bin/se-compile") + "se-compile" + "compile") + "*Program to use for compiling Eiffel programs. +The default is \"compile\", unless \"/usr/bin/se-compile\" exists, as +in Debian GNU/Linux, when the default value is \"se-compile\"." + :type 'string + :group 'eiffel-compile) + +(defcustom eif-short-command "short" + "*Program to use for producing short form of Eiffel classes." + :type 'string + :group 'eiffel-compile) + +(defcustom eif-compile-options "" + "*Options to use for compiling Eiffel programs." + :type 'string + :group 'eiffel-compile) + +;; +;; No user-customizable definitions below this point. +;; + +;; +;; Indentation macros. +;; + +(defmacro eif-class-level-kw-indent-m () + "Indentation amount for Class level keywords (in number of spaces)." + '(+ (* eif-class-level-kw-indent eif-indent-increment) + eif-extra-class-level-kw-indent)) + +(defmacro eif-class-level-comment-indent-m () + "Indentation amount for Class level comments (in number of spaces)." + '(+ (* eif-class-level-comment-indent eif-indent-increment) + eif-extra-class-level-comment-indent)) + +(defmacro eif-inherit-level-kw-indent-m () + "Indentation amount for Inherit level keywords (in number of spaces)." + '(+ (* eif-inherit-level-kw-indent eif-indent-increment) + eif-extra-inherit-level-kw-indent)) + +(defmacro eif-feature-level-indent-m () + "Indentation amount for features (in number of spaces)." + '(+ (* eif-feature-level-indent eif-indent-increment) + eif-extra-feature-level-indent)) + +(defmacro eif-feature-level-kw-indent-m () + "Indentation amount for Feature level keywords (in number of spaces)." + '(+ (* eif-feature-level-kw-indent eif-indent-increment) + eif-extra-feature-level-kw-indent)) + +(defmacro eif-body-comment-indent-m () + "Indentation amount for comments in routine bodies (in number of spaces)." + '(+ (* eif-body-comment-indent eif-indent-increment) + eif-extra-body-comment-indent)) + +(defmacro eif-feature-level-comment-indent-m () + "Indentation amount for Feature level comments (in number of spaces)." + '(+ (* eif-feature-level-comment-indent eif-indent-increment) + eif-extra-feature-level-comment-indent)) + +(defmacro eif-check-keyword-indent-m () + "Indentation amount for Check keyword (in number of spaces)." + '(+ (* eif-check-keyword-indent eif-indent-increment) + eif-extra-check-keyword-indent)) + +(defmacro eif-rescue-keyword-indent-m () + "Indentation amount for Rescue keyword (in number of spaces)." + '(+ (* eif-rescue-keyword-indent eif-indent-increment) + eif-extra-rescue-keyword-indent)) + +(defmacro eif-then-indent-m () + "Indentation amount for `then' appearing on a line by itself (in number of spaces)." + '(+ (* eif-then-indent eif-indent-increment) + eif-extra-then-indent)) + +(defmacro eif-continuation-indent-m () + "Indentation amount for a statement continuation line (in number of spaces)." + '(+ (* eif-continuation-indent eif-indent-increment) + eif-extra-continuation-indent)) + +(defmacro eif-string-continuation-indent-m () + "Indentation amount for a statement continuation line (in number of spaces)." + '(+ (* eif-string-continuation-indent eif-indent-increment) + eif-extra-string-continuation-indent)) + +(defmacro eif-preprocessor-indent-m () + "Indentation amount for a preprocessor statement (in number of spaces)." + '(* eif-preprocessor-indent eif-indent-increment)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Keyword Regular Expression Constants. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst eif-non-id-char-regexp "\\S_" ;; "[^a-z0-9_]" + "The characters that are not part of identifiers.") + +(defun eif-post-word-anchor (regexp) + "Anchor given REGEXP with end-word delimiter and `eif-non-id-char-regexp'." + (concat "\\(" regexp "\\)\\>" eif-non-id-char-regexp)) + +(defun eif-word-anchor (regexp) + "Anchor given REGEXP with word delimiters and `eif-non-id-char-regexp'." + (concat "\\<" (eif-post-word-anchor regexp))) + +(defun eif-post-anchor (regexp) + "Anchor given REGEXP at end to match line break or non-symbol char." + (concat "\\(" regexp "\\)\\($\\|\\>\\S_\\)")) + +(defun eif-anchor (regexp) + "Anchor given REGEXP front and back to match line break or non-symbol char." + (concat "\\(^\\|\\S_\\<\\)" (eif-post-anchor regexp))) + +;; Note invariant is handled as a special case since it is both a +;; class-level and a from-level keyword +;; Note obsolete is handled as a special case since it is both a +;; class-level and a feature-level keyword +(defconst eif-class-level-keywords-regexp + (eif-post-anchor + (concat + "class\\|feature\\|convert" "\\|" + "deferred[ \t]+class\\|expanded[ \t]+class" "\\|" + "reference[ \t]+class\\|separate[ \t]+class" "\\|" + "inherit\\|creation")) + "Regexp of keywords introducing class level clauses, with some context. +Note that `invariant' and `obsolete' are not included here since can +function as more than one type of keyword.") + +(defconst eif-inherit-level-keywords + "rename\\|redefine\\|undefine\\|select\\|export" + "Those keywords that introduce subclauses of the inherit clause.") + +(defconst eif-feature-level-keywords + "require\\|local\\|deferred\\|separate\\|do\\|once\\|ensure\\|alias\\|external" + "Those keywords that are internal to features (in particular, routines).") + +(defconst eif-feature-level-keywords-regexp + (eif-word-anchor eif-feature-level-keywords) + "Regexp of keywords internal to features (usually routines). +See `eif-feature-level-keywords'.") + +(defconst eif-end-keyword "end" "The `end' keyword.") + +(defconst eif-end-on-current-line ".*[ \t]end[ \t]*;?[ \t]*\\(--.*\\)?$" + "Regular expression to identify lines ending with the `end' keyword.") + +(defconst eif-control-flow-keywords + "if\\|inspect\\|from\\|debug" + "Keywords that introduce control-flow constructs.") + +(defconst eif-control-flow-matching-keywords + (concat "deferred\\|do\\|once" "\\|" eif-control-flow-keywords) + "Keywords that may cause the indentation of an `eif-control-flow-keyword'. +If these occur prior to an `eif-control-flow-keyword' then the +`eif-control-flow-keyword' is indented. Note that technically, `end' +is part of this list but it is handled separately in the function +\[eif-matching-kw\].") + +(defconst eif-control-flow-matching-keywords-regexp + (eif-word-anchor eif-control-flow-matching-keywords) + "Regexp of keywords maybe causing indentation of `eif-control-flow-keyword'. +See `eif-control-flow-keywords'.") + +(defconst eif-check-keyword "check" + "The `check' keyword.") + +(defconst eif-check-keywords-regexp + (eif-word-anchor eif-check-keyword) + "The `check' keyword (with trailing context).") + +;; FIXME: Doesn't work if once keyword is followed by a string on next +;; line, but didn't get broken by this attempt at factoring. +(defconst eif-check-matching-keywords-regexp + eif-control-flow-matching-keywords-regexp + "Keywords that may cause the indentation of an `eif-check-keyword'. +If these occur prior to an `eif-check-keyword' then the +`eif-check-keyword' is indented. Note that technically, `end' is part +of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +;; FIXME: This could be fixed or removed. +(defconst eif-end-keyword-regexp "\\(^\\|[^a-z0-9_]\\)end\\($\\|[^a-z0-9_]\\)" + "The `end' keyword with context.") + +(defconst eif-end-matching-keywords + (concat "check\\|class\\|feature\\|rename\\|redefine\\|undefine" "\\|" + "select\\|export\\|separate\\|external\\|alias" "\\|" + eif-control-flow-matching-keywords) + "Those keywords whose clause is terminated by an `end' keyword.") + +(defconst eif-end-matching-keywords-regexp + (eif-word-anchor eif-end-matching-keywords) + "Regexp of keywords whose clause is terminated by an `end' keyword. +See `eif-end-matching-keywords'.") + +(defconst eif-rescue-keyword "rescue" "The `rescue' keyword.") + +(defconst eif-obsolete-keyword "obsolete" "The `obsolete' keyword.") + +(defconst eif-rescue-keywords-regexp + (eif-word-anchor eif-rescue-keyword) + "The `rescue' keyword (with trailing context).") + +(defconst eif-rescue-matching-keywords-regexp + (eif-word-anchor "deferred\\|do\\|once") + "Keywords that may cause the indentation of an `eif-rescue-keyword'. +If these occur prior to an `eif-rescue-keyword' then the +`eif-rescue-keyword' is indented. Note that technically, `end' is +part of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-from-level-keywords + "until\\|variant\\|loop" + "Keywords occuring inside of a from clause.") + +(defconst eif-from-level-keywords-regexp + (eif-word-anchor eif-from-level-keywords) + "Regexp of keywords occuring inside of a from clause. +See `eif-from-level-keywords'.") + +(defconst eif-from-keyword "from" "The keyword `from'.") + +(defconst eif-if-or-inspect-level-keywords + "elseif\\|else\\|when" + "Keywords occuring inside of an if or inspect clause.") + +(defconst eif-if-or-inspect-level-keywords-regexp + (eif-word-anchor eif-if-or-inspect-level-keywords) + "Regexp of keywords occuring inside of an if or inspect clause. +See eif-if-or-inspect-level-keywords.") + +(defconst eif-if-or-inspect-keyword-regexp + (eif-word-anchor "if\\|inspect") + "Regexp matching the `if' or `inspect' keywords.") + +(defconst eif-then-keyword ".*[ \t)]then[ \t]*$" + "The keyword `then' with possible leading text.") + +(defconst eif-solitary-then-keyword "then" "The keyword `then'.") + +(defconst eif-then-matching-keywords "\\(if\\|elseif\\|when\\)" + "Keywords that may alter the indentation of an `eif-then-keyword'. +If one of these occur prior to an `eif-then-keyword' then this sets +the indentation of the `eif-then-keyword'. Note that technically, +`end' is part of this list but it is handled separately in the +function \[eif-matching-kw\]. See also +`eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-invariant-keyword "invariant" "The `invariant' keyword.") + +(defconst eif-invariant-matching-keywords + "from\\|feature" + "Keywords that may cause the indentation of an `eif-invarient-keyword'. +If one of these occurs prior to an `eif-invariant-keyword' then the +`eif-invariant-keyword' is indented. Note that technically, `end' is +part of this list but it is handled separately in the function +\[eif-matching-kw\]. See also `eif-control-flow-matching-keywords-regexp'.") + +(defconst eif-obsolete-matching-keywords + "\\(is\\|class\\)" + "Keywords that may cause the indentation of an `eif-obsolete-keyword'. +If one of these occurs prior to an `eif-obsolete-keyword' then the +`eif-obsolete-keyword' is indented.") + +(defconst eif-create-keyword + "create" + "Eiffel `create' keyword. Can be used at class or minor level.") + +(defconst eif-create-keyword-regexp + (eif-post-word-anchor eif-create-keyword) + "Regexp matching `create' keyword, with trailing context.") + +(defconst eif-indexing-keyword + "indexing" + "Eiffel `indexing' keyword. Can be used at class or minor level.") + +(defconst eif-indexing-keyword-regexp + (eif-post-word-anchor eif-indexing-keyword) + "Regexp matching `indexing' keyword, with trailing context.") + +(defconst eif-indentation-keywords + (concat "indexing\\|convert\\|rescue\\|inherit\\|creation" "\\|" + "invariant\\|require\\|local\\|ensure\\|obsolete" "\\|" + eif-from-level-keywords "\\|" + eif-if-or-inspect-level-keywords "\\|" + eif-end-matching-keywords) + "Keywords that match any eiffel keyword triggering indentation.") + +(defconst eif-indentation-keywords-regexp + (eif-word-anchor eif-indentation-keywords) + "Regexp of keywords that match any eiffel keyword triggering indentation. +See `eif-indentation-keywords'.") + +(defconst eif-non-indenting-keywords-regexp + (concat "\\(" + "once\\(\\s-\\|\n\\)+\"" "\\|" + (concat (eif-post-anchor "feature") ".*\\..*$") + "\\)") + "Regexp of keywords with context cancelling any effect on indentation.") + +(defconst eif-feature-indentation-keywords-regexp + (eif-word-anchor "creation\\|feature") + "Keywords that denote the presence of features following them.") + +;; (defconst eif-is-keyword-regexp "\\(.*[ \t)]\\)?is[ \t]*\\(--.*\\)?$" +;; "The `is' keyword (with some context).") + +(defconst eif-multiline-routine-is-keyword-regexp + ".*([^)]*)\\([ \t\n]*\\|[ \t\n]*:[][ \t\nA-Za-x0-9_,]*\\)is[ \t]*\\(--.*\\)?$" + "The `is' keyword (with some context).") + +(defconst eif-operator-keywords + "and\\|or\\|implies" + "Eiffel operator keywords.") + +(defconst eif-operator-regexp + (concat "[ \t]*\\([@*/+]\\|-[^-]\\|\\<\\(" + eif-operator-keywords + "\\)[ \t(]\\)") + "Eiffel operators - used to identify continuation lines. +See `eif-operator-keywords'.") + +(defconst eif-operator-eol-regexp + (concat ".*\\([@*/+-]\\|\\<\\(" eif-operator-keywords + "\\)\\|:=\\)[ \t]*\\(--.*\\)?$") + "Eiffel operators - used to identify continuation lines.") + +(defconst eif-misc-keywords + (concat "agent\\|all\\|as\\|frozen\\|infix\\|like" "\\|" + "old\\|precursor\\|prefix\\|retry\\|strip\\|unique\\|xor" "\\|" + "expanded\\|reference") + "Eiffel miscellaneous keywords.") + +(defconst eif-preprocessor-keywords + "#\\(define\\|undefine\\|ifdef\\|else\\|endif\\|ifndef\\|include\\)" + "Eiffel GOBO preprocessor keywords.") + +(defconst eif-preprocessor-keywords-regexp + (eif-post-word-anchor eif-preprocessor-keywords) + "Eiffel GOBO preprocessor keywords, with context. +See `eif-preprocessor-keywords'.") + +(defconst eif-smarteiffel-guru-keywords + (concat "c_inline_c\\|c_inline_h\\|to_pointer" "\\|" + "is_expanded_type\\|is_basic_expanded_type" "\\|" + "object_size\\|object_id_memory" "\\|" + "se_guru01\\|se_guru02\\|se_guru03") + "Eiffel keywords used by gurus with the SmartEiffel compiler.") + +(defconst eif-major-variable-keywords + (concat "[Vv]oid\\|[Rr]esult\\|[Cc]urrent\\|[Tt]rue\\|[Ff]alse" "\\|" + "[Pp]recursor\\|io\\|std_input\\|std_output\\|std_error") + "Eiffel keywords representing major variables.") + +(defconst eif-standard-class-keywords + (concat "ANY\\|BIT\\|BOOLEAN\\|CHARACTER\\|DOUBLE\\|GENERAL" "\\|" + "INTEGER\\|NONE\\|POINTER\\|REAL\\|STRING") + "Eiffel keywords representing standard classes.") + +(defconst eif-all-keywords + (concat eif-indentation-keywords "\\|" + eif-solitary-then-keyword "\\|" + eif-create-keyword "\\|" + eif-end-keyword) + "Regexp matching (nearly) any eiffel keyword in a line. +Does not include `is'.") + +(defconst eif-all-keywords-regexp + (concat "\\(" + (eif-word-anchor eif-all-keywords) "\\|" + eif-preprocessor-keywords-regexp "\\)") + "Anchored regexp matching (nearly) any eiffel keyword in a line. +Does not include `is'. See `eif-all-keywords'.") + +(defconst eiffel-comment-start-skip + "--+|?[ \t]*" + "Regexp matching the beginning of an Eiffel comment.") + +(defconst eif-non-source-line + (concat "[ \t]*\\(\\(" "--" "\\|" + eif-preprocessor-keywords-regexp "\\).*\\)?$") + "RE matching line with only whitespace and comment or preprocessor keyword.") + +;; Factor out some important important regexps for use in +;; eif-{beginning,end}-of-feature. + +(defconst eif-routine-begin-regexp + "\\([a-z_][a-zA-Z_0-9]*\\)\\s-*\\(([^)]*)\\)?\\s-*\\(:\\s-*[A-Z]\\([][,A-Za-z0-9_]\\|\\s-\\)*\\)?\\s-*\\\\s-*\\(--.*\\)?$" + "Regexp matching the beginning of an Eiffel routine declaration.") + +(defconst eif-attribute-regexp + (concat "[a-z_][^-:\n]*:\\s-*" + "\\(like\\s-*[a-zA-Z][a-z_0-9]*\\|" + "\\(\\(expanded\\|reference\\)\\s-*\\)?[A-Z][A-Z_0-9]*" + "\\(\\s-*\\[[^-\n]*\\]\\)?\\)" + "\\s-*\\($\\|[;)].*\\|--.*\\)") + "Regexp matching an Eiffel attribute, parameter or local variable.") + +(defconst eif-constant-regexp + "[a-z_][^-:\n]*:[^-\n]*\\s-\\\\s-+[^ \t\n]" + "Regexp matching an Eiffel constant declaration.") + +(defconst eif-variable-or-const-regexp + (concat eif-attribute-regexp "\\|" + eif-constant-regexp) + "RE to match a variable or constant declaration.") + +(defconst eif-id-colon-regexp + "[ \t]*[a-zA-Z0-9_]+[ \t]*:" + "Regexp that matches an Eiffel assertion tag expression.") + +(defconst eif-probably-feature-regexp + (concat "\\(" eif-routine-begin-regexp + "\\|" eif-attribute-regexp + "\\|" eif-constant-regexp "\\)") + "Regexp probably matching an Eiffel feature. +This will also match local variable and parameter declarations.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar eif-matching-indent -1 + "Indentation of the keyword found on the last call to \[eif-matching-kw\]. +-1 if no match was found.") + +(defvar eif-matching-kw-for-end nil) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +;; Font-lock support. +;; +;; Most of this font-lock code was originally contributed by: Karl +;; Landstrm . Much of it has now been +;; factored out above. +;; + +(defconst eiffel-font-lock-keywords-1 + `(;; hidden comments + ("--|.*" 0 font-lock-keyword-face t) + ;; routines + (,(concat "^[ \t]*" eif-routine-begin-regexp) 1 font-lock-function-name-face )) + "Regular expressions to use with font-lock mode.") + +(defconst eiffel-font-lock-keywords-2 + (append + eiffel-font-lock-keywords-1 + `(;; Assertions. + ;; FIXME: Cyril thinks these should just be part of the keywords below. + (,(eif-anchor "check\\|ensure then\\|ensure\\|invariant\\|require else\\|require\\|variant") 2 font-lock-reference-face nil) + + ;; Preprocessor keywords. Note that, by luck more than planning, + ;; these aren't font-locked when they're not indented, since the + ;; '#' isn't a word boundary (which is added by eif-anchor). + (,(eif-post-word-anchor eif-preprocessor-keywords) 2 font-lock-builtin-face nil) + + ;; Keywords. The first few can appear in conjunction with other + ;; keywords, and the anchored regexp doesn't cater for overlaps, + ;; thus there are several entries here. + (,(eif-anchor "class\\|is\\|not") 2 font-lock-keyword-face nil) + (,(eif-anchor eif-operator-keywords) 2 font-lock-keyword-face nil) + (,(eif-anchor eif-misc-keywords) 2 font-lock-keyword-face nil) + (,(eif-anchor eif-all-keywords) 2 font-lock-keyword-face nil) + + ;; Quoted expr's in comments. + ("`[^`'\n]*'" 0 font-lock-string-face t) + + ;; Classes. + (,(eif-anchor eif-standard-class-keywords) 2 font-lock-type-face))) + "Regular expressions to use with font-lock mode and level 2 fontification.") + +(defconst eiffel-font-lock-keywords-3 + (append + eiffel-font-lock-keywords-2 + `(;; attributes/parameters/local variables + (,(concat "^[ \t]*" eif-attribute-regexp) (0 nil) + ("\\s-*\\(\\<[a-z][a-zA-Z_0-9]*\\)\\s-*\\(,\\|:[^;\n]*\\|).*\\)" + (re-search-backward "\\((\\|^\\)" nil t) + (end-of-line) + (1 font-lock-variable-name-face))) + ;; constants + (,(concat "^[ \t]*" eif-constant-regexp) (0 nil) + ("\\s-*\\(\\<[A-Za-z][a-zA-Z_0-9]*\\)\\s-*\\(,\\|:.*\\)" + (beginning-of-line) (end-of-line) + (1 font-lock-constant-face))) + (,(concat "^[ \t]*" eif-id-colon-regexp "\\($\\|[^=]\\)") (0 nil) + ("\\s-*\\(\\<[A-Za-z][a-zA-Z_0-9]*\\)\\s-*:" + (beginning-of-line) (end-of-line) + (1 font-lock-constant-face))) +)) + "Regular expressions to use with font-lock mode and level 3 fontification.") + +(defconst eiffel-font-lock-keywords-4 + ;; SmartEiffel guru keywords and major variables. + (append + eiffel-font-lock-keywords-3 + `((,(eif-anchor eif-smarteiffel-guru-keywords) 2 font-lock-warning-face) + (,(eif-anchor eif-major-variable-keywords) 2 font-lock-constant-face)))) + +(defvar eiffel-font-lock-keywords eiffel-font-lock-keywords-1 + "Default expressions to highlight in Eiffel mode. +See also `c-font-lock-extra-types'.") + +(defconst eiffel-font-lock-defaults + '((eiffel-font-lock-keywords + eiffel-font-lock-keywords-1 + eiffel-font-lock-keywords-2 + eiffel-font-lock-keywords-3 + eiffel-font-lock-keywords-4) + nil nil nil nil)) + +(and (boundp 'font-lock-defaults-alist) + (add-to-list 'font-lock-defaults-alist + (cons 'eiffel-mode + eiffel-font-lock-defaults))) + +;; font-lock faces used by GNU Emacs and XEmacs are inconsistent. +(if (and (not (boundp 'font-lock-constant-face)) + (fboundp 'copy-face)) + (copy-face 'font-lock-variable-name-face 'font-lock-constant-face)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +;; Compilation support for GNU SmartEiffel. +;; + +(defvar eif-compile-dir nil + "Current directory where Eiffel compilations are taking place. +Possibly used for error location.") + +(defvar eif-ace-file nil + "Current Eiffel ace file being compiled/debugged.") + +(defvar eif-root-class nil + "Current Eiffel root class being compiled/debugged.") + +(defvar eif-compile-target nil + "Current Eiffel compilation target.") + +(defvar eif-debug-target nil + "Current Eiffel debug target.") + +(defvar eif-root-proc "make" + "Current Eiffel root procedure.") + +(defvar eif-run-command nil + "Current command to run after Eiffel compile.") + +(defvar eif-debug-command nil + "Current debug command to run after Eiffel debug compile.") + +(defun eif-compilation-mode-hook () + "Hook function to set local value for `compilation-error-screen-columns'. +This should be nil for SmartEiffel compiles, because column positions are +returned as character positions rather than screen columns." + ;; In Emacs > 20.7 compilation-error-screen-columns is buffer local. + (or (assq 'compilation-error-screen-columns (buffer-local-variables)) + (make-local-variable 'compilation-error-screen-columns)) + (setq compilation-error-screen-columns nil)) + +(defun eif-compile () + "Compile an Eiffel root class." + (interactive) + (eif-compile-prompt) + (eif-compile-internal)) + +(defun eif-set-compile-options () + "Set Eiffel compiler options." + (interactive) + (setq eif-compile-options + (read-string "Eiffel compiler options: " eif-compile-options))) + +;; Taken from Emacs 20.3 subr.el (just in case we're running under Emacs 19). +(defun eif-split-string (string &optional separators) + "Split STRING into substrings separated by SEPARATORS. +Each match for SEPARATORS is a splitting point. The substrings +between the splitting points are made into a list which is returned. +If SEPARATORS is absent, it defaults to \"[ \\f\\t\\n\\r\\v]+\". + +If there is match for SEPARATORS at the beginning of STRING, we do not +include a null substring for that. Likewise, if there is a match +at the end of STRING, we do not include a null substring for that." + (let ((rexp (or separators "[ \f\t\n\r\v]+")) + (start 0) + notfirst + (list nil)) + (while (and (string-match rexp string + (if (and notfirst + (= start (match-beginning 0)) + (< start (length string))) + (1+ start) start)) + (< (match-beginning 0) (length string))) + (setq notfirst t) + (or (eq (match-beginning 0) 0) + (and (eq (match-beginning 0) (match-end 0)) + (eq (match-beginning 0) start)) + (setq list + (cons (substring string start (match-beginning 0)) + list))) + (setq start (match-end 0))) + (or (eq start (length string)) + (setq list + (cons (substring string start) + list))) + (nreverse list))) + +(defun eif-run () + "Run a compiled Eiffel program." + (interactive) + (setq eif-run-command + (read-string "Command to run: " + (or eif-run-command + eif-compile-target + (file-name-sans-extension + (if (eq system-type 'windows-nt) + buffer-file-name + (file-name-nondirectory (buffer-file-name))))))) + (eif-run-internal)) + +(defun eif-debug () + "Run the SmartEiffel debugger." + (interactive) + + (eif-compile-prompt) + + (setq eif-debug-target + (file-name-sans-extension + (read-string "Debug target name: " + (or eif-debug-target + (concat eif-compile-target "_debug"))))) + + (let* ((eif-compile-options (concat "-sedb " eif-compile-options)) + (eif-compile-target eif-debug-target) + (buff (eif-compile-internal)) + (proc (get-buffer-process buff))) + + ;; This works under GNU Emacs, but hangs under at least some + ;; versions of XEmacs if there is input pending. + (while (eq (process-status proc) 'run) + (sit-for 1)) + + (if (= (process-exit-status proc) 0) + (progn + (setq eif-debug-command + (read-string "Debugger command to run: " + (or eif-debug-command + eif-debug-target + (file-name-sans-extension + (if (eq system-type 'windows-nt) + buffer-file-name + (file-name-nondirectory + (buffer-file-name))))))) + (let ((eif-run-command eif-debug-command)) + (eif-run-internal)))))) + +(defun eif-compile-prompt () + "Prompt for information required to compile an Eiffel root class." + + ;; Do the save first, since the user might still have their hand on + ;; the mouse. + (save-some-buffers (not compilation-ask-about-save) nil) + + (setq eif-compile-dir (file-name-directory (buffer-file-name))) + (setq eif-ace-file + (read-string "Name of ace file (leave empty to get prompted for root class): " eif-ace-file)) + (if (string= eif-ace-file "") + (progn + (setq eif-root-class + (file-name-sans-extension + (read-string "Name of root class: " + (or eif-compile-target + (file-name-sans-extension + (file-name-nondirectory (buffer-file-name))))))) + (setq eif-compile-target eif-root-class) + (setq eif-root-proc + (read-string "Name of root procedure: " + eif-root-proc))))) + +(defun eif-compile-internal () + "Compile an Eiffel root class. Internal version. +Returns the same thing as \\[compile-internal] - the compilation buffer." + + (let + ((cmd (concat eif-compile-command + " " eif-compile-options + " " eif-ace-file + (if (string= eif-ace-file "") + (concat "-o " eif-compile-target + (if (eq system-type 'windows-nt) ".exe") + " " eif-root-class + " " eif-root-proc)))) + (compilation-mode-hook (cons 'eif-compilation-mode-hook + compilation-mode-hook))) + (compilation-start cmd nil + #'(lambda (mode-name) + "*eiffel*")))) + +(defun eif-run-internal () + "Run a compiled Eiffel program. Internal version." + + (let* ((tmp-buf (current-buffer)) + (words (eif-split-string eif-run-command)) + (cmd (expand-file-name (car words)))) + + (apply 'make-comint cmd cmd nil (cdr words)) + (switch-to-buffer tmp-buf) + (switch-to-buffer-other-window (concat "*" cmd "*")))) + +;; This has been loosened up to spot parts of messages that contain +;; references to multiple locations. Thanks to Andreas +;; . Also, the column number is a character +;; count rather than a screen column, so we need to make sure that +;; compilation-error-screen-columns is nil. Note that in XEmacs this +;; variable doesn't exist, so we end up in the wrong column. Hey, at +;; least we're on the correct line! +(add-to-list 'compilation-error-regexp-alist + '("^Line \\([0-9]+\\) column \\([0-9]+\\) in [^ ]+ (\\([^)]+\\.[Ee]\\))" 3 1 2)) + +(defun eif-short () + "Display the short form of an Eiffel class." + (interactive) + (let* ((class (read-string + "Class or file: " + (if (buffer-file-name) + (file-name-nondirectory (buffer-file-name))))) + (buf (get-buffer-create (concat "*Eiffel - short " class "*")))) + + (shell-command (concat eif-short-command " " class) buf) + (save-excursion + (set-buffer buf) + (let ((font-lock-defaults eiffel-font-lock-defaults)) + (font-lock-fontify-buffer)) + (toggle-read-only 1)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Utility Functions. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun eif-feature-quote () + "Put a `' around the current feature name." + (interactive) + (save-excursion + ;; Only try to go back to the beginning of the feature if we're + ;; not already there. + (if (/= (point) + (save-excursion + (forward-sexp) + (backward-sexp) + (point))) + (backward-sexp)) + (insert "`") + (forward-sexp) + (insert "'")) + (if (looking-at "'") + (forward-char 1))) + +(defun eif-peeking-backwards-at (regexp) + "Return non-nil is previous character exists and is matched by REGEXP. +The match is actually an unbounded match starting at the previous character." + (save-excursion + (save-match-data + (and (not (bobp)) + (or (backward-char) t) + (looking-at regexp))))) + +(defsubst eif-in-comment-p () + "Return t if point is in a comment." + (interactive) + (save-excursion + (nth 4 (parse-partial-sexp + (save-excursion (beginning-of-line) (point)) + (point))))) + +(defun eif-in-comment-or-quoted-string-p () + "Return t if point is in a comment or quoted string." + (or (eif-in-comment-p) + (eif-in-quoted-string-p))) + +(defun eif-not-in-comment-or-quoted-string-p () + "Return t if point is not in a comment or quoted string." + (not (eif-in-comment-or-quoted-string-p))) + +(defun eif-near-comment-p () + "Return t if point is close enough to a comment for filling purposes." + (or (eif-in-comment-p) + (and (or (looking-at comment-start-skip) + (eif-peeking-backwards-at comment-start-skip)) + (not (eif-in-quoted-string-p))) + (looking-at (concat "[ \t]*" comment-start-skip)))) + +(defun eif-re-search-forward (regexp &optional limit noerror) + "Search forward from point for REGEXP not in comment or string. +`case-fold-search' is set to nil when searching. For details on other +arguments see \\[re-search-forward]." + + (interactive "sRE search: ") + (let ((start (point)) + found case-fold-search) + (while (and (setq found (re-search-forward regexp limit noerror)) + (eif-in-comment-or-quoted-string-p))) + (if (and found + (eif-not-in-comment-or-quoted-string-p)) + found + (if (eq noerror t) + (goto-char start)) + nil))) + +(defun eif-re-search-backward (regexp &optional limit noerror) + "Search backward from point for REGEXP not in comment or string. +`case-fold-search' is set to nil when searching. For details on other +arguments see \\[re-search-forward]." + (interactive "sRE search: ") + (let ((start (point)) + found case-fold-search) + (while (and (setq found (re-search-backward regexp limit noerror)) + (eif-in-comment-or-quoted-string-p))) + (if (and found + (eif-not-in-comment-or-quoted-string-p)) + found + (if (eq noerror t) + (goto-char start)) + nil))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Indentation Functions. ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun eif-skip-leading-whitespace () + "OBSOLETE 2006-04-26: please use `back-to-indentation' instead." + (back-to-indentation)) + +(defun eif-calc-indent () + "Calculate the indentation of the current line of eiffel code. +This function handles the case where there is a keyword that affects +indentation at the beginning of the current line. For lines that +don't start with a relevant keyword, the calculation is handed off to +\\[eif-calc-non-keyword-indent]." + (let ((indent 0) + kw-match) + + (save-excursion + (back-to-indentation) + + ;; Look for a keyword on the current line. + (if (looking-at eif-all-keywords-regexp) + + (cond ((or (looking-at eif-create-keyword-regexp) + (looking-at eif-indexing-keyword-regexp)) + ;; Class-level or minor occurence? + (if (save-excursion (eif-find-beginning-of-feature)) + ;; Minor. + (setq indent (eif-calc-indent-non-keyword)) + ;; Class-level. + (setq indent (eif-class-level-kw-indent-m)))) + ;; There's possibly a better way of coding this exception. + ((looking-at eif-non-indenting-keywords-regexp) + (setq indent (eif-calc-indent-non-keyword))) + ((looking-at eif-class-level-keywords-regexp) + ;; File level keywords (indent defaults to 0) + (setq indent (eif-class-level-kw-indent-m))) + ((looking-at eif-inherit-level-keywords) + ;; Inherit level keywords (indent defaults to + ;; 2*eif-indent-increment) + (setq indent (eif-inherit-level-kw-indent-m))) + ((looking-at eif-feature-level-keywords-regexp) + ;; Feature level keywords (indent defaults to + ;; (eif-feature-level-indent-m) + eif-indent-increment) + (setq indent (eif-feature-level-kw-indent-m))) + ((looking-at eif-end-keyword) + ;; End keyword (indent to level of matching keyword) + (if (string-match "end" + (eif-matching-kw + eif-end-matching-keywords-regexp)) + ;; Then + (if (= eif-matching-indent + (eif-feature-level-kw-indent-m)) + ;; Then + (setq indent (eif-class-level-kw-indent-m)) + ;; Else + (setq indent + (- eif-matching-indent eif-indent-increment))) + ;; Else + (setq indent eif-matching-indent)) + ;; FIXME: This is broken!!! + (if (<= indent (eif-feature-level-indent-m)) + (save-excursion + (end-of-line) + (while (and (< (point) (point-max)) + (or (forward-char 1) t) + (looking-at eif-non-source-line)) + (end-of-line)) + (if (not (looking-at eif-non-source-line)) + (setq indent (eif-inherit-level-kw-indent-m)) + (setq indent (eif-class-level-kw-indent-m)))))) + ((looking-at eif-control-flow-keywords) + ;; Control flow keywords + ;; Indent to same level as a preceding "end" or + ;; if no preceding "end" is found, indent to the level + ;; of the preceding "do" plus the value of + ;; eif-indent-increment + (setq kw-match + (eif-matching-kw + eif-control-flow-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent eif-matching-indent)) + (t + (setq indent + (+ eif-matching-indent eif-indent-increment))))) + ((looking-at eif-check-keywords-regexp) + ;; Check keyword + ;; Indent to level of preceding "end"+eif-indent-increment or + ;; if no preceding "end" is found, indent to the level of + ;; the preceding eif-check-matching-keywords-regexp plus the + ;; value (eif-indent-increment + eif-check-keyword-indent). + + (setq kw-match (eif-matching-kw + eif-check-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent (+ eif-matching-indent + (eif-check-keyword-indent-m)))) + (t + (setq indent + (+ eif-matching-indent + (+ eif-indent-increment + (eif-check-keyword-indent-m))))))) + ((looking-at eif-rescue-keywords-regexp) + ;; Rescue keyword + ;; Indent to level of preceding "end"+eif-indent-increment or + ;; if no preceding "end" is found, indent to the level of + ;; the preceding eif-rescue-matching-keywords-regexp plus the + ;; value (eif-indent-increment + eif-rescue-keyword-indent). + (setq kw-match (eif-matching-kw + eif-rescue-matching-keywords-regexp)) + (cond ((string-match "end" kw-match) + (setq indent (+ eif-matching-indent + (eif-rescue-keyword-indent-m)))) + (t + (setq indent eif-matching-indent)))) + ((looking-at eif-from-level-keywords-regexp) + ;; From level keywords (indent to level of matching "From") + (if (string-match "end" (eif-matching-kw eif-from-keyword)) + ;; Closest matching KW is `end'. + (setq indent (- eif-matching-indent eif-indent-increment)) + ;; Closest matching KW is one of `eif-from-keyword'. + (setq indent eif-matching-indent))) + ((looking-at eif-if-or-inspect-level-keywords-regexp) + ;; If level keywords (indent to level of matching + ;; "If" or "Inspect") + (if (string-match "end" + (eif-matching-kw + eif-if-or-inspect-keyword-regexp)) + ;; Closest matching KW is `end'. + (setq indent (- eif-matching-indent eif-indent-increment)) + ;; Closest matching KW is one of `eif-if-or-inspect-keyword-regexp'. + (setq indent eif-matching-indent))) + ((looking-at eif-solitary-then-keyword) + ;; Handles case where "then" appears on a line by itself + ;; (Indented to level of the matching if, elseif or when) + (eif-matching-kw eif-then-matching-keywords) + (setq indent (+ eif-matching-indent (eif-then-indent-m)))) + ((looking-at eif-invariant-keyword) + ;; Invariant keyword + ;; (Indented to level of the matching from or feature) + (if (string-match "from" + (eif-matching-kw eif-invariant-matching-keywords)) + ;; Then - loop invariant + (setq indent eif-matching-indent) + ;; Else - class invariant + (setq indent (eif-class-level-kw-indent-m)))) + ((looking-at eif-obsolete-keyword) + ;; Obsolete keyword + ;; (Indented to the level of the matching from or feature) + (if (string-match "is" + (eif-matching-kw eif-obsolete-matching-keywords)) + ;; Then - feature obsolete + (setq indent (eif-feature-level-kw-indent-m)) + ;; Else - class obsolete + (setq indent (eif-class-level-kw-indent-m)))) + ((looking-at eif-preprocessor-keywords-regexp) + (setq indent (eif-preprocessor-indent-m)))) + ;; No keyword. Hand off... + (setq indent (eif-calc-indent-non-keyword)))) + indent)) + +(defun eif-calc-indent-non-keyword () + "Calculate indentation of current Eiffel code line, without leading +keyword. This function generally assumes that the preceding line of +code is indented properly, and usually bases the indentation of the +current line on that preceding line. This function assumes +`back-to-indentation' is in effect." + (let (previous-line-indent what-indentation) + (save-excursion + + ;; Are we in a multi-line string expression? + (if (eif-in-multi-line-string-expression) + ;; Depending on a setting, we either don't indent, or indent + ;; just as much as the previous line. + ;; The latter implies that the first line, immediately below + ;; the "[ is indented at the same level as the feature name, + ;; which isn't too bad. + (if eif-multi-line-string-indent + (if (looking-at "[]]\"") + 0 + (let (beginning-of-line-position) + (save-excursion + (end-of-line 0) + (backward-char 2) + (if (looking-at "\"[[]") + 0 + (back-to-indentation) + (current-column))))) + (back-to-indentation) (current-column)) + ;; TODO: + ;; 2. indentation with arrays? + (setq previous-line-indent (eif-previous-line-indent)) + ;; `eif-calc-indent' does not consider certain things a keyword we + ;; will consider a keyword here. So let's first handle those. + (cond + ;; + ((< previous-line-indent 0) (+ (abs previous-line-indent) eif-indent-increment)) + ;; recognise feature level comments + ((and (looking-at "--") (= previous-line-indent (eif-feature-level-indent-m))) + (eif-feature-level-comment-indent-m)) + ;; string continuation, distinguish between the first/second line + ;; of such a continuation. + ((looking-at "%") + (if (eif-previous-line-is-string-continuation-line) + previous-line-indent + (+ previous-line-indent (eif-string-continuation-indent-m)))) + ;; if current line starts with an operator, we have to indent or + ;; stay at the same indent if the previous line is already a continuation. + ((looking-at eif-operator-keywords) + (if (or (eif-previous-line-is-continuation) (eif-previous-previous-line-is-continuation)) + previous-line-indent + (+ previous-line-indent eif-indent-increment))) + ;; if line starts with closing parenthesis, we match the indent + ;; of opening parenthesis. + ((looking-at "\)") + (forward-char) + (backward-list) + (current-column)) + ;; else we have to look at the previous line + (t + (setq what-indentation (eif-what-indentation)) + (cond + ((eq what-indentation 'eif-what-indent-class-level-comment) + (eif-class-level-comment-indent-m)) + ((eq what-indentation 'eif-what-indent-as-previous) + previous-line-indent) + ((eq what-indentation 'eif-what-indent-increase) + (+ previous-line-indent eif-indent-increment)) + ((eq what-indentation 'eif-what-indent-decrease) + (- previous-line-indent eif-indent-increment)) + (what-indentation)))))))) + +(defun eif-what-indentation () + "Determine what indentation is required. There are basically three +options: increase the indentation, decrease it, or keep it the same as +the previous line. Besides that there are a few minor cases. This +function assumes `back-to-indentation' is in effect." + (let (looking-at-comment) + (save-excursion + + ;; Remember if we were looking at a comment + (setq looking-at-comment (looking-at "--")) + + (backward-sexp) + ;; in case where we might be looking at feature {NONE} for example + ;; go back one sexp to point at feature + ;; 2006-11-07: formerly also looked at ')' character, removed it. + (if (looking-at "[{]") + (backward-sexp)) + (cond + ;; the end statement is a bit difficult: inside a body the next + ;; line (our current line) should be indented at the same level + ;; but the end of feature signals a decrease. + ((looking-at "end\\([ \t]\\|$\\)") + (if (= (eif-current-line-indent) (eif-feature-level-kw-indent-m)) + 'eif-what-indent-decrease + 'eif-what-indent-as-previous)) + ;; indent if previous line starts with these keywords + ((looking-at "\\(indexing\\|deferred\\|expanded\\|separate\\|class\\|rename\\|export\\|undefine\\|redefine\\|inherit\\|creation\\|create\\|feature\\|is\\|obsolete\\|require\\|local\\|do\\|once\\|if\\|inspect\\|when\\|from\\|variant\\|invariant\\|until\\|loop\\|check\\|debug\\|rescue\\|ensure\\|invariant\\)\\([ \t]\\|$\\)") 'eif-what-indent-increase) + ;; then and else must be treated differently, it should not be + ;; part of the "and then" or "or else" operators. + ((and (looking-at "then\\([ \t]\\|$\\)") (not (eif-is-preceded-by "and"))) + 'eif-what-indent-increase) + ((and (looking-at "else\\([ \t]\\|$\\)") (not (eif-is-preceded-by "or"))) + 'eif-what-indent-increase) + ;; we always indent the next line if the previous line ends + ;; with "implies" + ((looking-at "implies\\([ \t]\\|$\\)") + 'eif-what-indent-increase) + ;; determine if we're on a continuation; like a string + ;; continuation we have to distinguish between the first + ;; continuation and subsequent continuations. + ((eif-line-ends-with-continuation-symbol) + (if (and (not (eif-line-begins-with-label)) (or (eif-current-line-is-continuation) (eif-previous-line-is-continuation) (eif-is-first-line-after-boolean-keyword))) + 'eif-what-indent-as-previous + 'eif-what-indent-increase)) + ;; The current line is a continuation if the previous line is a + ;; continuation. But the line we're asked to indent isn't as + ;; far as we can tell, because the current line gives no + ;; indication that the next line is a continuation. In that + ;; case we have to decrease the indentation back to the first + ;; line we can find that isn't a continuation. + ((eif-previous-line-is-continuation) + (eif-indent-of-last-non-continuation-line)) + ((= (point) 1) + (if looking-at-comment + 'eif-what-indent-class-level-comment + 'eif-what-indent-as-previous)) + (t `eif-what-indent-as-previous))))) + +(defun eif-is-preceded-by (word) + "Is the previous word equal to word?" + (save-excursion + (backward-sexp) + (looking-at (concat word "\\([ \t]\\|$\\)")))) + +(defun eif-line-begins-with-label () + "Does the current line begin with a label?" + (save-excursion + (back-to-indentation) + (looking-at "[a-zA-Z0-9_]+:"))) + +(defun eif-is-first-line-after-boolean-keyword () + "Are we on the first line following the keywords require, ensure, +until or if?" + (save-excursion + (beginning-of-line) + (condition-case nil + (let () (backward-sexp) (looking-at "\\(require\\|if\\|elseif\\|until\\|ensure\\)\\([ \t]\\|$\\)")) + (error t)))) + +(defun eif-previous-line-is-string-continuation-line () + "Is the previous line a string continuation line?" + (save-excursion + (backward-sexp) + (looking-at "%"))) + +(defun eif-line-ends-with-continuation-symbol () + "Does the line end with an operator or colon? Assumes that with a `backward-sexp' we have come unto this line." + (save-excursion + (cond + ((looking-at "\\(and\\|or\\|implies\\)\\([ \t]\\|$\\)") t) + ((and (looking-at "then\\([ \t]\\|$\\)") (eif-is-preceded-by "and")) t) + ((and (looking-at "else\\([ \t]\\|$\\)") (eif-is-preceded-by "or")) t) + (t + (forward-sexp) + (looking-at "[ \t]*\\([@*/+:=]\\|-[^-]\\)"))))) + +(defun eif-current-line-is-continuation () + "Is current line a continuation, based upon if it starts with an operator?" + (save-excursion + (back-to-indentation) + (looking-at eif-operator-regexp))) + +(defun eif-previous-line-is-continuation () + "Does the previous line indicate that the next line is a continuation?" + (save-excursion + (condition-case nil + (do-eif-previous-line-is-continuation) + (error nil)))) + +(defun do-eif-previous-line-is-continuation () + "Does the previous line indicate that the next line is a continuation?" + (save-excursion + (beginning-of-line) + (backward-sexp) + (eif-line-ends-with-continuation-symbol))) + +(defun eif-previous-previous-line-is-continuation () + "Is the line before the previous line a continuation?" + (save-excursion + (beginning-of-line) + (backward-sexp) + (beginning-of-line) + (backward-sexp) + (eif-line-ends-with-continuation-symbol))) + +(defun eif-calc-indent-in-multi-line-string () + "Indentation if inside a multi-line string." + ;; If user has just ended the string, the identation is zero. + (if (looking-at "[]]\"") + 0 + ;; Else for first line just below "[ the indentation is zero. + ;; For any subsequent line it's the identation of the previous line. + (save-excursion + (forward-line -1) + (end-of-line) + (backward-char 3) + (if (looking-at "[^%]\"[[]") + 0 + (back-to-indentation) + (current-column))))) + +(defun eif-previous-line-indent () + "Amount of identation of previous line." + (save-excursion + (condition-case nil + (do-eif-previous-line-indent) + (error (do-eif-previous-line-indent2))))) + +(defun do-eif-previous-line-indent () + "Indentation of previous sexp" + (backward-sexp) + (back-to-indentation) + (current-column)) + +(defun do-eif-previous-line-indent2 () + "Indentation of previous word, but negative" + (backward-word 1) + (back-to-indentation) + (- 0 (current-column))) + +(defun eif-indent-of-last-non-continuation-line () + "Amount of identation of last line that isn't a continuation" + (save-excursion + (while (or + (eif-current-line-is-continuation) + (eif-previous-line-is-continuation)) + (beginning-of-line) + (backward-sexp)) + (back-to-indentation) + (current-column))) + +(defun eif-indent-assertion-continuation (id-colon) + "Generally, are we in line that is a continuation of an assertion? +More precisely, are we inside a pre or a post condition clause on a +line that is a continuation of a multi-line assertion beginning with a +tag? If so, return the indentation of the continuation line. The +argument ID-COLON is t if the line we are indenting begins with +\" :\", and nil otherwise." + (let ((limit (point))) + (if (save-excursion + (if (re-search-backward + (concat eif-feature-level-keywords-regexp "\\|" + eif-end-keyword-regexp) nil t) + (if (looking-at "ensure\\|require") + (setq limit (point))))) + (save-excursion + (end-of-line) + (if (and (not id-colon) (re-search-backward ": *" limit t)) + (progn + (goto-char (match-end 0)) + (current-column))))))) + +(defun eif-indent-assertion-tag () + "Return indentation for part of a multi-line assertion. +That is, the current line is assumed to be a continuation of a +multi-line assertion, and we return the required indentation." + (save-excursion + (if (re-search-backward "ensure\\|require\\|variant\\|invariant\\|check" nil t) + (+ (eif-current-line-indent) eif-indent-increment) + ;; This option should not occur + (error "Could not find assertion tag")))) + +(defun eif-matching-kw (matching-keyword-regexp) + "Search backwards and return a keyword in MATCHING-KEYWORD-REGEXP. +Also set the value of variable `eif-matching-indent' to the +indentation of the keyword found. If an `end' keyword occurs prior to +finding one of the keywords in MATCHING-KEYWORD-REGEXP and it +terminates a check clause, set the value of variable +`eif-matching-indent' to the indentation of the `end' minus the value +of `eif-check-keyword-indent'." + (let* ((c "[^a-z0-9A-Z_.]") + (search-regexp (concat c eif-end-keyword c "\\|" + c matching-keyword-regexp)) + (keyword "")) + (save-excursion + ;; Search backward for a matching keyword. + ;; Note that eif-non-indenting-keywords-regexp indicates we haven't + ;; found a match so should keep going. + (while (and (eif-re-search-backward search-regexp 1 t) + (looking-at (concat c eif-non-indenting-keywords-regexp)) + (not (= (point) 1)))) + (if (looking-at search-regexp) + ;; Then - a keyword was found + (progn + (setq keyword + (buffer-substring (match-beginning 0) (match-end 0))) + (if (and (looking-at eif-end-keyword-regexp) + (eif-matching-line) + (string-match eif-check-keyword eif-matching-kw-for-end)) + ;; Then + (setq eif-matching-indent (- (eif-current-line-indent) + (eif-check-keyword-indent-m))) + ;; Else + (setq eif-matching-indent (eif-current-line-indent)))) + ;; Else no keyword was found. I think this is an error + (setq eif-matching-indent 0) + (message "No matching indent keyword was found")) + keyword))) + +(defun eif-line-contains-close-paren () + "Return t if the current line contains a close paren, nil otherwise. +If a close paren is found, the point is placed immediately after the +last close paren on the line. If no paren is found, the point is +placed at the beginning of the line." + (let ((search-min 0)) + (beginning-of-line) + (setq search-min (point)) + (end-of-line) + (if (search-backward ")" search-min t) + ;; Then + (progn + (forward-char 1) + t) + ;; Else + (beginning-of-line) + nil))) + +;; Not Currently Used +;;(defun eif-quoted-string-on-line-p () +;; "t if an Eiffel quoted string begins, ends, or is continued +;; on current line." +;; (save-excursion +;; (beginning-of-line) +;; ;; Line must either start with optional whitespace immediately followed +;; ;; by a '%' or include a '\"'. It must either end with a '%' character +;; ;; or must include a second '\"' character. +;; (looking-at "^\\([ \t]*%\\|[^\"\n]*\"\\)[^\"\n]*\\(%$\\|\"\\)"))) + +(defconst eif-opening-regexp + "\\<\\(external\\|check\\|deferred\\|do\\|once\\|from\\|if\\|inspect\\|debug\\)\\>" + "Keywords that open eiffel nesting constructs.") +;; OK, this is a horrible hack in all of this to handle "once" as a +;; special case because it has been overloaded. The search for the +;; opening keyword on the current line is quite reasonably limited to +;; the current line. Therefore, the standard hacky way that we avoid +;; matching once strings, by making sure they're followed by +;; whitespace and a non-double-quote, doesn't work here. +(defconst eif-non-opening-regexp + "\\" + "Keywords that close eiffel nesting constructs.") +(defconst eif-do-regexp "\\<\\(do\\|once\\|external\\)\\>" + "Keyword that opens eiffel routine body.") +(defconst eif-opening-or-closing-regexp + (concat "\\(" eif-opening-regexp "\\|" eif-closing-regexp "\\)") + "Keywords that open or close eiffel nesting constructs.") + +;; +;; Code to allow indenting whole eiffel blocks +;; + +(defun eif-matching-line (&optional return-line-break direction) + "Return the position of the keyword matching the one on the current line. +For example, a line containing the keyword `do' is matched by a line +containing the keyword `end' and a line containing `end' may be +matched by a number of opening keywords. If the optional parameter +RETURN-LINE-BREAK is non-nil, the character position returned is the +beginning (or end) of the line containing the matching keyword instead +of the position of the keyword itself. If the second optional +parameter, DIRECTION, is non-nil, the current line is not searched for +a keyword. Instead, if the value of direction is 'forward, the +function acts as if an `eif-opening-regexp' is on the current line. +If the value of direction is 'backward, the function acts as if a +`eif-closing-regexp' is on the current line. The effect of using the +direction parameter is to locate either the opening or closing keyword +of the syntactic construct containing the point." + (let ((nesting-level 0) + (search-end 0) + matching-point opening-keyword match-start match-end + success start-point) + (unwind-protect + (save-excursion + (modify-syntax-entry ?_ "w ") + (setq eif-matching-kw-for-end "");; public variable set by this function + (setq start-point (point)) + (end-of-line) + (setq search-end (point)) + (beginning-of-line) + ;; Set starting state: If direction was specified use it. + ;; If direction is nil, search for a keyword on the current line + ;; If the keyword is in eif-opening-regexp, set the search + ;; direction to 'forward, if the keyword on the current line is `end' + ;; set the search direction to 'backward. + (cond ((eq direction 'forward) + (end-of-line) ;; So we wont see keywords on this line. + (setq nesting-level 1)) + ((eq direction 'backward) + (beginning-of-line) ;; So we wont see keywords on this line. + (setq nesting-level -1)) + ((and (re-search-forward eif-opening-regexp search-end t) + (eif-not-in-comment-or-quoted-string-p)) + (setq match-start (match-beginning 0)) + (setq match-end (match-end 0)) + (goto-char match-start) + (if (and (not (looking-at eif-non-opening-regexp)) + (eif-not-in-comment-or-quoted-string-p)) + (setq nesting-level 1)) + (setq opening-keyword + (cons (buffer-substring match-start match-end) + opening-keyword)) + (goto-char match-end)) + ((and (progn (beginning-of-line) t) + (re-search-forward eif-closing-regexp search-end t) + (eif-not-in-comment-or-quoted-string-p)) + (goto-char (match-beginning 0)) + (if (eif-not-in-comment-or-quoted-string-p) + (setq nesting-level -1)))) + ;; Perform the search + (while (not (= nesting-level 0)) + (if (> nesting-level 0) + ;; Then search forward for the next keyword not in a comment + (while (and (re-search-forward eif-opening-or-closing-regexp nil 1) + (goto-char (setq match-start (match-beginning 0))) + (setq match-end (match-end 0)) + (setq success t) + (or (looking-at eif-non-opening-regexp) + (eif-in-comment-or-quoted-string-p))) + (goto-char match-end) + (setq success nil)) + ;; Else search backward for the next keyword not in a comment + (while (and (re-search-backward eif-opening-or-closing-regexp nil 1) + (goto-char (setq match-start (match-beginning 0))) + (setq success t) + (or (looking-at eif-non-opening-regexp) + (eif-in-comment-or-quoted-string-p))) + (setq success nil))) + (cond ((and (not (looking-at eif-non-opening-regexp)) + (looking-at eif-opening-regexp) + success) + ;; Found an opening keyword + (if (> nesting-level 0) + ;; Then + (if (looking-at eif-do-regexp) + ;; Then + (setq nesting-level -1) + ;; Else + (setq opening-keyword + (cons (buffer-substring match-start + (match-end 0)) + opening-keyword)) + (goto-char (match-end 0))) + ;; Else + (if (= nesting-level -1) + ;; Then + (progn + (setq eif-matching-kw-for-end + (buffer-substring match-start (match-end 0))) + (if (looking-at "[ \t\n]+") + (goto-char (match-end 0)))) + ;; Else + (if (looking-at eif-do-regexp) + ;; Then + (progn + (goto-char (eif-matching-line nil 'forward)) + (setq nesting-level -1)))) + (setq opening-keyword (cdr opening-keyword)) + (if return-line-break + (beginning-of-line))) + (setq nesting-level (1+ nesting-level))) + ((and (looking-at eif-closing-regexp) success) + ;; Found an opening keyword + (if (> nesting-level 0) + ;; Then + (progn + (setq opening-keyword (cdr opening-keyword)) + (if return-line-break + (end-of-line)) + (goto-char (match-end 0))) + ;; Else + (setq opening-keyword + (cons (buffer-substring (match-beginning 0) + (match-end 0)) + opening-keyword))) + (setq nesting-level (1- nesting-level))) + (t (message (concat "Could not find match" + (if (car opening-keyword) + (concat " for: " + (car opening-keyword))))) + (goto-char start-point) + (setq nesting-level 0)))) + (setq matching-point (point))) + (modify-syntax-entry ?_ "_ ")) + (set-mark matching-point))) + +;; ENHANCEME: Make this function correctly indent more than just routine +;; bodies and their sub-constructs. At the least it should +;; handle whole routines also. +(defun eif-indent-construct () + "Indent an entire eiffel syntactic construct. +It is assumed that the point is within a nesting construct ('do', +`once', 'check', 'if', 'from', or 'inspect'). The whole construct is +indented up to the matching end. If the point is not within such a +construct, then only that line is indented" + (interactive) + (let ((start-point 0) (end-point 0)) + (save-excursion + (end-of-line) + (if (not (= (point) (point-max))) (forward-char 1)) + (setq start-point (copy-marker (eif-matching-line t 'backward))) + (goto-char start-point) + (setq end-point (eif-matching-line t 'forward)) + (eif-indent-region start-point end-point)))) + +(defun eif-indent-region (&optional start end) + "Indent the lines in the current region. +The region may be specified using optional arguments START and END." + (interactive) + (let ((start-point (or start (region-beginning))) + (end-point (copy-marker (or end (region-end))))) + (save-excursion + (goto-char start-point) + (cond ((eq major-mode 'eiffel-mode) + (while (< (point) end-point) + (if (not (looking-at "[ \t]*$")) + (eif-indent-line)) + (forward-line 1) + (if (< (point) end-point) + (beginning-of-line)))) + (t (error "Buffer must be in eiffel mode")))))) + +;;(defun eif-goto-matching-line (&optional direction) +;; "Place the cursor on the line which closes(opens) the current +;;opening(closing) syntactic construct. For example if the point +;;is on `from', executing goto-matching-line places the point +;;on the matching `end' and vice-versa." +;; (interactive) +;; (if (not direction) +;; (progn +;; (cond ((save-excursion (beginning-of-line) (looking-at "[ \t]*end.*$")) +;; (goto-char (eif-matching-line nil 'backward))) +;; ((looking-at "(") +;; (forward-sexp)) +;; ((save-excursion (backward-char 1) (looking-at ")")) +;; (backward-sexp)) +;; (t +;; (goto-char (eif-matching-line nil 'forward))))))) + +(defun eif-forward-sexp () + "Put cursor on line that closes the current opening syntactic construct. +For example, if the point is on `from' then the point is placed on the +matching `end'. This also does matching of parens ala +\\[forward-sexp]." + (interactive) + (cond ((looking-at "[[(]") + (forward-sexp)) + (t + (goto-char (eif-matching-line nil 'forward))))) + +(defun eif-backward-sexp () + "Put cursor on line that opens the current closing syntactic construct. +For example, if the point is on the terminating `end' of an `if' +statement, then the point is place on the opening `if'. This also +does matching of parens ala \\[backward-sexp]'." + (interactive) + (cond ((eif-peeking-backwards-at "[])]") + (backward-sexp)) + (t + (goto-char (eif-matching-line nil 'backward))))) + +(defun eif-local-indent (amount) + "Set the value of `eif-indent-increment' to AMOUNT buffer-locally." + (interactive "NNumber of spaces for eif-indent-increment: ") + (make-local-variable 'eif-indent-increment) + (setq eif-indent-increment amount)) + +;; ---------------------------------------------------------------------- +;; This next portion of the file is derived from "eiffel.el" +;; Copyright (C) 1989, 1990 Free Software Foundation, Inc. and Bob Weiner +;; Available for use and distribution under the same terms as GNU Emacs. +;; ---------------------------------------------------------------------- + +(defvar eiffel-mode-map nil + "Keymap for Eiffel mode.") + +(if eiffel-mode-map + nil + (let ((map (make-sparse-keymap))) + (define-key map [(control j)] 'newline-and-indent) + (define-key map [(return)] 'reindent-then-newline-and-indent) + (define-key map [(meta control q)] 'eif-indent-construct) + (define-key map [(meta \')] 'eif-feature-quote) + (define-key map [(meta q)] 'eif-fill-paragraph) + (define-key map [(meta control a)] 'eif-beginning-of-feature) + (define-key map [(meta control e)] 'eif-end-of-feature) + (define-key map [(control x) ?n ?d] 'eif-narrow-to-feature) + (setq eiffel-mode-map map))) + +(defvar eiffel-mode-syntax-table nil + "Syntax table in use in Eiffel-mode buffers.") + +(if eiffel-mode-syntax-table + nil + (let ((table (make-syntax-table)) + (i 0)) + (while (< i ?0) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?9)) + (while (< i ?A) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?Z)) + (while (< i ?a) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (setq i (1+ ?z)) + (while (< i 128) + (modify-syntax-entry i "_ " table) + (setq i (1+ i))) + (modify-syntax-entry ? " " table) + (modify-syntax-entry ?- ". 12" table) + (modify-syntax-entry ?_ "_ " table) + (modify-syntax-entry ?\t " " table) + (modify-syntax-entry ?\n "> " table) + (modify-syntax-entry ?\f "> " table) + (modify-syntax-entry ?\" "\" " table) + (modify-syntax-entry ?\\ "." table) + (modify-syntax-entry ?\( "() " table) + (modify-syntax-entry ?\) ")( " table) + (modify-syntax-entry ?\[ "(] " table) + (modify-syntax-entry ?\] ")[ " table) + (modify-syntax-entry ?\{ "(} " table) + (modify-syntax-entry ?\} "){ " table) + (modify-syntax-entry ?' "\"" table) + (modify-syntax-entry ?` "." table) + (modify-syntax-entry ?/ "." table) + (modify-syntax-entry ?* "." table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "\\" table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?\; "." table) + (modify-syntax-entry ?: "." table) + (modify-syntax-entry ?! "." table) + (modify-syntax-entry ?. "." table) + (modify-syntax-entry ?, "." table) + (setq eiffel-mode-syntax-table table))) + +(defun eif-add-menu () + "Add the \"Eiffel\" menu to the menu bar." + + (easy-menu-define + eiffel-mode-menu + eiffel-mode-map + "Menu for eiffel-mode." + (append (list "Eiffel") + (if eif-use-gnu-eiffel + (list + ["Compile..." eif-compile t] + ["Compiler Options..." eif-set-compile-options t] + ["Next Compile Error..." next-error t] + ["Run..." eif-run t] + ["Debug..." eif-debug t] + ["Short..." eif-short t] + ["----------" nil nil])) + (list + ["Indent Construct" eif-indent-construct t] + ["----------" nil nil] + (list "Imenu" + ["By position" eif-imenu-add-menubar-by-position t] + ["By name" eif-imenu-add-menubar-by-name t]) + (list "Comments" + ["Feature Quote" eif-feature-quote (eif-in-comment-p)] + ["Fill " eif-fill-paragraph (eif-near-comment-p)]) + ["----------" nil nil] + ["Customize" eif-customize t]))) + (easy-menu-add eiffel-mode-menu)) + +;;;###autoload +(defun eiffel-mode () + "Major mode for editing Eiffel programs. +\\[indent-for-tab-command] indents the current Eiffel line correctly and +\\[reindent-then-newline-and-indent] causes the current and next line to be +properly indented. + +Key definitions: +\\{eiffel-mode-map} + +If variable `eif-use-gnu-eiffel' is non-nil (default t) then support +for using GNU SmartEiffel is enabled. Run \\[eif-customize] to see +compilation and indentation variables that can be customized." + + (interactive) + + (kill-all-local-variables) + + (setq major-mode 'eiffel-mode) + (setq mode-name "Eiffel") + + (if eif-use-gnu-eiffel + (progn + (define-key eiffel-mode-map "\C-c\C-c" 'eif-compile) + (define-key eiffel-mode-map "\C-c\C-o" 'eif-set-compile-options) + (define-key eiffel-mode-map "\C-c\C-r" 'eif-run) + (define-key eiffel-mode-map "\C-c\C-d" 'eif-debug) + (define-key eiffel-mode-map "\C-c\C-s" 'eif-short)) + (define-key eiffel-mode-map "\C-c\C-c" nil) + (define-key eiffel-mode-map "\C-c\C-o" nil) + (define-key eiffel-mode-map "\C-c\C-r" nil) + (define-key eiffel-mode-map "\C-c\C-s" nil)) + + (use-local-map eiffel-mode-map) + (eif-add-menu) + (set-syntax-table eiffel-mode-syntax-table) + + ;; Make local variables. + (make-local-variable 'paragraph-start) + (make-local-variable 'paragraph-separate) + (make-local-variable 'paragraph-ignore-fill-prefix) + (make-local-variable 'require-final-newline) + (make-local-variable 'parse-sexp-ignore-comments) + (make-local-variable 'indent-line-function) + (make-local-variable 'indent-region-function) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-column) + (make-local-variable 'comment-start-skip) + (make-local-variable 'font-lock-defaults) + (make-local-variable 'imenu-create-index-function) + ;; Now set their values. + (setq paragraph-start (concat "^$\\|" page-delimiter) + paragraph-separate paragraph-start + paragraph-ignore-fill-prefix t + require-final-newline 'ask + parse-sexp-ignore-comments t + indent-line-function 'eif-indent-line + indent-region-function 'eif-indent-region + comment-start "-- " + comment-end "" + comment-column 32 + comment-start-skip eiffel-comment-start-skip + font-lock-defaults eiffel-font-lock-defaults) + + (if eif-set-tab-width-flag + (setq tab-width eif-indent-increment)) + + (setq auto-fill-function 'eif-auto-fill) + (run-hooks 'eiffel-mode-hook)) + +(defconst eif-prefeature-regexp + (concat "\\(" eif-non-source-line "\\|\n\\)*" "[ \t]*") + "Regexp matching whitespace-equivalent content, possibly before a feature.") + +(defun eif-find-end-of-feature () + "Find the `end' of the current feature definition. +Assumes point is at the beginning of the feature, not in a comment or +quoted string." + (let (ret) + (modify-syntax-entry ?_ "w ") + (cond ((looking-at (concat eif-prefeature-regexp + eif-routine-begin-regexp)) + ;; At the start of a routine, find matching end. + (and (eif-re-search-forward eif-do-regexp nil t) + (goto-char (match-beginning 0)) + (goto-char (setq ret (eif-matching-line))))) + ((looking-at (concat eif-prefeature-regexp + eif-probably-feature-regexp)) + ;; Not a routine, find end of attribute or constant. + (goto-char (setq ret (match-end 0))))) + (modify-syntax-entry ?_ "_ ") + ret)) + +;; OK, this works well, but it doesn't work for the following cases: +;; * In the middle of the feature regexp that need to be matched. +;; However, it doesn't need to since eif-beginning-of-feature adds +;; some smarts around it... +(defun eif-find-beginning-of-feature () + "Find the beginning of the most recent feature definition. +This will always move backward, if possible." + (interactive) + + (let ((start (point)) + candidate routine-begin) + (if (eif-re-search-backward (concat "\\s-" eif-probably-feature-regexp) + nil t) + (progn + (forward-char) ;; Skip the whitespace character matched above. + (if (not (or (looking-at (concat + "\\(" eif-attribute-regexp + "\\|" eif-constant-regexp "\\)")))) + ;; This is a routine. Done. + (point) + ;; Variable/attribute or constant declaration matched. + ;; Now we go back and find the previous routine start, the + ;; following end, and see if the current position + ;; (candidate) is between. If it is, then candidate is a + ;; variable or constant declaration within a routine, so + ;; we're interested in the routine start. If it isn't, + ;; then it must be a class attribute or constant, so it is + ;; what we're looking for. + (setq candidate (point)) + (goto-char start) + (if (eif-re-search-backward + (concat "\\s-" eif-routine-begin-regexp) nil t) + (progn + (forward-char) + (setq routine-begin (point)) + (eif-find-end-of-feature) + (if (and (< routine-begin candidate) + (< candidate (point))) + (goto-char routine-begin) + (goto-char candidate))) + (goto-char candidate))))))) + +(defun eif-beginning-of-feature (&optional arg) + "Move backward to next feature beginning. +With ARG, do it that many times. Negative arg -N +means move forward to Nth following beginning of feature. +Returns t unless search stops due to beginning or end of buffer." + (interactive "p") + + (or arg + (setq arg 1)) + + (let ((start (point)) + (success t)) + (cond ((> arg 0) + ;; Going backward. + + ;; We have to move forward to make sure we find any feature + ;; that we might be in the middle of the beginning of. How + ;; far? How about this far? + (eif-re-search-forward eif-probably-feature-regexp nil 'move) + + ;; Change arg towards zero as we search, failing if we hit + ;; edge of buffer. + (while (and (> arg 0) + (or (eif-find-beginning-of-feature) + (setq success nil))) + ;; If we've gone backwards from the original start, then + ;; this counts. + (if (< (point) start) + (setq arg (1- arg)))) + (or success + (goto-char (point-min)))) + + ((< arg 0) + ;; Going forward. + + ;; Similar to above, let's go back to the beginning of the + ;; current feature, and then skip over features and find + ;; the beginning of the next repeatedly. + (eif-find-beginning-of-feature) + + (while (and (< arg 0) + (or (not (eobp)) (setq success nil))) + (eif-find-end-of-feature) + (if (eif-re-search-forward eif-probably-feature-regexp + nil 'move) + (progn + (goto-char (match-beginning 0)) + (if (> (point) start) + (setq arg (1+ arg)))))))) + success)) + +(defun eif-end-of-feature (&optional arg) + "Move forward to end of feature. +With argument, do it that many times. Negative argument means move +back ARG preceding ends of features." + (interactive "p") + + ;; Default is to find the first feature's end. + ;; Huh? Even if they specify 0? - martin@meltin.net + ;; Hmmm, it is what end-of-defun does... + (if (or (null arg) + (= arg 0)) + (setq arg 1)) + + ;; This is a bad way of trying to get into position. Happily, it + ;; seems to work. Hmmm, not sure if the comment skip is needed. + (if (eif-in-comment-p) + (end-of-line)) + (cond ((let ((curr (point))) + (save-excursion + (and (eif-beginning-of-feature) + (eif-find-end-of-feature) + (forward-line) + (or (< curr (point)) + (and (< arg 0) + (= curr (point))))))) + ;; Within a feature. Go to its beginning. + (eif-beginning-of-feature)) + ((eif-peeking-backwards-at (concat "\\s-" + eif-probably-feature-regexp)) + ;; Sitting at beginning of feature. Don't move! + t) + (t + ;; Not within a feature or at beginning, go to beginning of + ;; next feature. + (eif-beginning-of-feature -1))) + + ;; This part is correct. + (if (eif-beginning-of-feature (+ (if (< arg 0) 0 1) (- arg))) + (progn + (eif-find-end-of-feature) + (forward-line)))) + +(defun eif-narrow-to-feature () + "Make text outside current feature invisible. +The feature visible is the one that contains point or follows point." + (interactive) + (save-excursion + (widen) + (eif-end-of-feature) + (let ((end (point))) + (eif-beginning-of-feature) + (narrow-to-region (point) end)))) + +(defun eif-current-line-indent () + "Return the indentation of the line containing the point." + (save-excursion + (back-to-indentation) + (current-column))) + +(defun eif-in-quoted-string-p (&optional non-strict-p) + "Return t if point is in a quoted string. +Optional argument NON-STRICT-P if true causes the function to return +true even if the point is located in leading white space on a +continuation line. Normally leading white space is not considered part +of the string." + (let ((initial-regexp "^[ \t]*%\\|[^%]\"\\|%[ \t]*$") + (search-limit (point)) + (count 0)) + (save-excursion + ;; Line must either start with optional whitespace immediately followed + ;; by a '%' or include a '\"' before the search-limit. + (beginning-of-line) + (while (re-search-forward initial-regexp search-limit t) + (setq count (1+ count)) + (if (= count 1) (setq search-limit (1+ search-limit)))) + ;; If the number of quotes (including continuation line markers) + ;; is odd, then we are inside of a string. Also if non-strict-p + ;; and we are in the leading white space of a continuation line, + ;; then we are in a quote. + (or (= (% count 2) 1) + (progn + (beginning-of-line) + (and non-strict-p + (looking-at "^[ \t]*%"))))))) + +;; ---------------------------------------------------------------------- +;; End of portion derived from "eiffel.el" +;; ---------------------------------------------------------------------- + +(defun eif-comment-prefix () + "Return the prefix starting a comment that begins a line. +Comments that are not the only thing on a line return nil as their prefix." + (save-excursion + (end-of-line) + (let ((limit (point)) len + (in-string (eif-in-quoted-string-p))) + (beginning-of-line) + (cond ((re-search-forward "^[ \t]*--|?[ \t]*" limit t) + (buffer-substring (match-beginning 0) (match-end 0))) + ;; Handle string-literal continuation lines + (in-string + (end-of-line) + (re-search-backward "^[ \t]*%\\|[^%]\"" nil t) + (re-search-forward "%\\|\"" nil t) + (setq len (1- (current-column))) + (concat (make-string len ? ) "%")))))) + +(defun eif-auto-fill () + "Auto-fill an Eiffel comment." + (let ((fill-prefix (eif-comment-prefix)) + (pm (point-marker))) + (if (and (> (current-column) fill-column) + fill-prefix) + (if (string-match "^[ \t]*%" fill-prefix) + (progn + (backward-char 1) + (re-search-backward "[^][a-zA-Z0-9]" nil t) + (forward-char 1) + (insert "%\n") + (insert fill-prefix) + (goto-char pm)) + ;; (do-auto-fill) + (backward-char 1) + (re-search-backward "\\s-" nil t) + (forward-char 1) + (insert "\n") + (insert fill-prefix) + (goto-char pm))))) + +(defun eif-fill-paragraph () + "Textually fills Eiffel comments ala \\[fill-paragraph]." + (interactive) + (save-excursion + (let ((current-point (point)) + (fill-prefix (eif-comment-prefix)) + last-point para-begin para-end) + (if fill-prefix + (progn + (setq last-point (point)) + (forward-line -1) + (end-of-line) + (while (and (not (= (point) last-point)) + (eif-comment-prefix)) + (setq last-point (point)) + (forward-line -1) + (end-of-line)) + (if (= (point) last-point) + (setq para-begin (save-excursion (beginning-of-line) (point))) + (setq para-begin (1+ (point)))) + (goto-char current-point) + (setq last-point (point)) + (forward-line 1) + (end-of-line) + (while (and (not (= (point) last-point)) + (eif-comment-prefix)) + (setq last-point (point)) + (forward-line 1) + (end-of-line)) + (if (= (point) last-point) + (setq para-end (point)) + (beginning-of-line) + (setq para-end (point))) + ;; Avert eyes now - gross hack follows... how big can an + ;; Eiffel comment be anyway? :-) + (let ((orig-region (and (<= (- para-end para-begin) + eif-fill-max-save) + (buffer-substring para-begin para-end))) + (orig-state (buffer-modified-p)) + (ret (fill-region para-begin para-end))) + (and orig-region + (<= para-end (point-max)) + (string-equal + orig-region (buffer-substring para-begin para-end)) + (set-buffer-modified-p orig-state)) + ret)))))) + +(defun eif-indent-line (&optional whole-exp) + "Indent the current line as Eiffel code. +With optional argument WHOLE-EXP, indent any additional lines of the +same clause rigidly along with this one (not implemented yet)." + (interactive "p") + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (let ((indent (eif-calc-indent))) + (if (not (= indent (current-column))) + (progn + (delete-horizontal-space) + (indent-to indent))))) + (skip-chars-forward " \t")) + +(defun eif-move-to-prev-non-blank () + "Move point to previous line excluding blank lines. +Return t if successful, nil if not." + (beginning-of-line) + (re-search-backward "^[ \t]*[^ \t\n]" nil t)) + +(defun eif-in-multi-line-string-expression () + "Determine if we are inside a multi-line string expression. Searches a maximu m of 2048 characters backward, so will not work for really large strings." + (interactive) + (let (multi-line-string (limit 0)) + (if (>= (point) 2048) + (setq limit (- (point) 2048))) + (save-excursion + (re-search-backward "\\([^%]\"[[]\n\\|\n[ \t]*[]]\"\\)" limit t) + (if (looking-at "[ \t]\"[[]\n") + (setq multi-line-string t))) + multi-line-string)) + +(defvar eif-last-feature-level-indent -1) +(defvar eif-feature-level-indent-regexp nil) +(defun eif-in-paren-expression () + "Determine if we are inside of a parenthesized expression. Will return invalid data if called while inside a string." + (interactive) + (let ((paren-count 0) (limit 0)) + (save-excursion + (if (= eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq limit + (re-search-backward eif-feature-level-indent-regexp nil t)) + (setq eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq eif-feature-level-indent-regexp + (concat "^" (make-string eif-last-feature-level-indent ? ) + "[^ \t\n]")) + (setq limit + (or (re-search-backward eif-feature-level-indent-regexp nil t) + 0)))) + (save-excursion + (while (re-search-backward "[][()]" limit t) + (if (looking-at "[[(]") + (setq paren-count (1+ paren-count)) + (setq paren-count (1- paren-count))))) + paren-count)) + +(defun eif-manifest-array-common () + "Common code for handling indentation/presence of Eiffel manifest arrays." + (let ((paren-count 0)) + (if (= eif-last-feature-level-indent (eif-feature-level-indent-m)) + nil + (setq eif-last-feature-level-indent (eif-feature-level-indent-m)) + (setq eif-feature-level-indent-regexp + (concat "^" (make-string eif-last-feature-level-indent ? ) + "[^ \t\n]"))) + (while (and (<= paren-count 0) (re-search-backward "<<\\|>>" nil t)) + (if (not (eif-peeking-backwards-at "|\\|@")) + (if (looking-at "<<") + (setq paren-count (1+ paren-count)) + (setq paren-count (1- paren-count))))) + paren-count)) + +(defun eif-manifest-array-indent () + "Determine if we are inside of a manifest array." + (interactive) + (let (indent) + (save-excursion + (if (> (eif-manifest-array-common) 0) + (let ((eol (save-excursion (end-of-line) (point)))) + (setq indent + (or (and (re-search-forward "[^< \t]" eol t) + (1- (current-column))) + (+ (current-column) 2)))))) + indent)) + +(defun eif-manifest-array-start () + "Determine the indentation of the statement containing a manifest array." + (interactive) + (let (indent) + (save-excursion + (if (> (eif-manifest-array-common) 0) + (let ((limit (progn (end-of-line) (point)))) + (beginning-of-line) + (if (re-search-forward "^[ \t]*<<" limit t) + (setq indent (- (current-column) 2 eif-indent-increment)) + (re-search-forward "^[ \t]*" limit t) + (setq indent (current-column)))))) + indent)) + +;; ---------------------------------------------------------------------- +;; The function below is derived from "eif-mult-fmt.el" +;; Copyright (C) 1985 Free Software Foundation, Inc. +;; Copyright (C) 1990 Bob Weiner, Motorola Inc. +;; Available for use and distribution under the same terms as GNU Emacs. +;; ---------------------------------------------------------------------- + +(defun eif-indent-multi-line (&optional parse-start) + "Return indentation for line within parentheses or double quotes. +That is, we are in a multi-line parenthesised or double-quoted +expression, and want to know the suggested indentation for the current +line. If we are not within such an expression then return -1. +Optional argument PARSE-START is buffer position at which to begin +parsing, default is to begin at the feature enclosing or preceding +point." + (let ((eif-opoint (point)) + (indent-point (progn (beginning-of-line) (point))) + (eif-ind-val -1) + (eif-in-str nil) + (eif-paren-depth 0) + (retry t) + state + ;; setting this to a number inhibits calling hook + last-sexp containing-sexp) + (if parse-start + (goto-char parse-start) + (eif-beginning-of-feature)) + ;; Find outermost containing sexp + (while (< (point) indent-point) + (setq state (parse-partial-sexp (point) indent-point 0))) + ;; Find innermost containing sexp + (while (and retry + state + (> (setq eif-paren-depth (elt state 0)) 0)) + (setq retry nil) + (setq last-sexp (elt state 2)) + (setq containing-sexp (elt state 1)) + ;; Position following last unclosed open. + (goto-char (1+ containing-sexp)) + ;; Is there a complete sexp since then? + (if (and last-sexp (> last-sexp (point))) + ;; Yes, but is there a containing sexp after that? + (let ((peek (parse-partial-sexp last-sexp indent-point 0))) + (if (setq retry (car (cdr peek))) (setq state peek))))) + (if retry + nil + ;; Innermost containing sexp found + (goto-char (1+ containing-sexp)) + (if (not last-sexp) + ;; indent-point immediately follows open paren. + nil + ;; Find the start of first element of containing sexp. + (parse-partial-sexp (point) last-sexp 0 t) + (cond ((looking-at "\\s(") + ;; First element of containing sexp is a list. + ;; Indent under that list. + ) + ((> (save-excursion (forward-line 1) (point)) + last-sexp) + ;; This is the first line to start within the containing sexp. + (backward-prefix-chars)) + (t + ;; Indent beneath first sexp on same line as last-sexp. + ;; Again, it's almost certainly a routine call. + (goto-char last-sexp) + (beginning-of-line) + (parse-partial-sexp (point) last-sexp 0 t) + (backward-prefix-chars)))) + (setq eif-ind-val (current-column))) + ;; Point is at the point to indent under unless we are inside a string. + (setq eif-in-str (elt state 3)) + (goto-char eif-opoint) + (if (not eif-in-str) + nil + ;; Inside a string, indent 1 past string start + (setq eif-paren-depth 1);; To account for being inside string + (save-excursion + (if (re-search-backward "\"" nil t) + (if eif-indent-string-continuations-relatively-flag + (setq eif-ind-val (1+ (current-column))) + (setq eif-ind-val (eif-current-line-indent))) + (goto-char indent-point) + (if (looking-at "^[ \t]*[^ \t\n]") + (eif-move-to-prev-non-blank)) + (skip-chars-forward " \t") + (setq eif-ind-val (current-column))))) + (if (> eif-paren-depth 0) eif-ind-val -1))) + +;; ---------------------------------------------------------------------- +;; imenu support, great for browsing foreign code. +;; Originally contributed by Berend de Boer . +;; ---------------------------------------------------------------------- + +(defun eif-imenu-add-menubar-by-position () + "Add menu of features of a class, sorted in order of occurence." + (interactive) + (setq imenu-create-index-function 'eif-imenu-create-index-by-position) + (imenu-add-to-menubar "Eiffel features") + ) + +(defun eif-imenu-add-menubar-by-name () + "Add menu of features of a class, sorted by name." + (interactive) + (setq imenu-create-index-function 'eif-imenu-create-index-by-name) + (imenu-add-to-menubar "Eiffel names")) + +(defun eif-imenu-create-index-by-position () + "Generate index of features of a class, sorted in order of occurence." + (eif-imenu-create-index 0)) + +(defun eif-imenu-create-index-by-name () + "Generate index of features of a class, sorted by name." + (eif-imenu-create-index 1)) + +(defun eif-imenu-create-index (sort-method) + "Generate an index of all features of a class. +Sort by position if sort-method is 0. Sort by name if sort-method is 1." + + (let (menu prevpos) + + (imenu-progress-message prevpos 0 t) + + ;; scan for features + (goto-char (point-max)) + (while (eif-find-beginning-of-feature) + (imenu-progress-message prevpos nil t) + (if (looking-at "\\(\\sw\\|\\s_\\)+") + (add-to-list 'menu (cons (buffer-substring-no-properties + (match-beginning 0) + (match-end 0)) (point))))) + + (imenu-progress-message prevpos 100) + + ;; sort in increasing buffer position order or by name + (if (= sort-method 0) + (sort menu (function (lambda (a b) (< (cdr a) (cdr b))))) + (sort menu (function (lambda (a b) (string< (car a) (car b)))))))) + +;; XEmacs addition +;;;###autoload(add-to-list 'auto-mode-alist '("\\.e\\'" . eiffel-mode)) + +(provide 'eiffel) +;;; eiffel.el ends here diff --git a/old-config/lisp/elisp.el b/old-config/lisp/elisp.el new file mode 100644 index 0000000..4fa1130 --- /dev/null +++ b/old-config/lisp/elisp.el @@ -0,0 +1,111 @@ +;; +;; Some functions which will be used +;; in initialization of EMACS +;; + +(defun iterate-on-list (list action) + (when list + (let ((dir (car list))) + (let ((val (funcall action dir))) + (if val val + (iterate-on-list (cdr list) + action)))))) + +(defun which (prog) + (let ((app (executable-find prog))) + (if app + (file-truename app) + (iterate-on-list (split-string (getenv "PATH") ":") + #'(lambda (dir) + (let ((filename (concat dir "/" prog))) + (if (file-executable-p filename) + filename + nil))))))) + +(defun partition-list (lis separator-p sublis acc) + (if (null lis) + (if (null sublis) + acc + (append acc (list sublis))) + (let ((item (car lis))) + (if (funcall separator-p item) + (partition-list (cdr lis) separator-p () + (if (null sublis) + acc + (append acc (list sublis)))) + (partition-list (cdr lis) separator-p + (append sublis (list item)) + acc))))) + +(defun nth-op (n op arg) + (if (= n 0) + arg + (nth-op (- n 1) op (funcall op arg)))) + +(defun compose (f g &rest args) + (apply f (apply g args))) + +(defun my-reduce (acc lis op) + (cond ((and (not (null acc)) + (not (null lis))) + (cons (funcall op (car acc) (car lis)) + (my-reduce (cdr acc) (cdr lis) op))) + ((null lis) acc) + ((null acc) lis) + (t nil))) + +(defun merge-xlist (lis op acc) + (if (null lis) + acc + (merge-xlist (cdr lis) op + (my-reduce acc (car lis) op)))) + + +(defun sudo-shell-command (command) + (let ((proc (start-process-shell-command + "*sudo*" + "*sudo*" + (concat "sudo bash -c " + (shell-quote-argument command))))) + (process-send-string proc + (read-passwd "Your Password:")) + (process-send-string proc "\r") + (process-send-eof proc))) + +(defun find-file-by-search-dir (dir name) + (let ((find-cmd (concat "find " + dir + " -name \"" + name "\"" + " -print | head -n 1"))) + (let ((data (shell-command-to-string find-cmd))) + (if (> (length data) 0) + (substring data 0 -1) + nil)))) + +(defun my-fold-left (op acc lst) + (if lst + (my-fold-left op (funcall op acc (car lst)) + (cdr lst)) + acc)) + +(defun my-replace-string (s old new) + (replace-regexp-in-string (regexp-quote old) + new s t t)) + +(defun my-zap-multiple-empty-lines () + (while (re-search-forward "^\\([ ]*\n?\\)*\n") + (replace-match "\n"))) + +(defun first-n-elem (list n action) + (if (or (= n 0) + (not list)) + nil + (let ((ele (car list)) + (rem (cdr list))) + (if (funcall action ele) + (cons ele (first-n-elem rem (- n 1) action)) + (first-n-elem rem n action))))) +;; define key bindings +;; + diff --git a/old-config/lisp/mypkgs.el b/old-config/lisp/mypkgs.el new file mode 100644 index 0000000..36feddf --- /dev/null +++ b/old-config/lisp/mypkgs.el @@ -0,0 +1,174 @@ +(require 'package) +(require 'cl) + +;; load misc files +(dolist (file '("elisp.el" "os.el")) + (load-file (concat *lisp-dir* "/" file))) + +;; load some customization +;; +(defun load-customize () + ;; do not load custom.el + ;; because we load themes + ;; (when (file-exists-p custom-file) + ;; (load-file custom-file)) + (let ((fonts (first-n-elem '("Inconsolata LGC" "Inconsolata" + "Consolas" "Monaco") + 1 + #'(lambda (fnt) + (member fnt (font-family-list)))))) + (when fonts + (set-face-attribute 'default nil + :font (car fonts)))) + (put 'set-goal-column 'disabled nil) + (put 'narrow-to-region 'disabled nil)) + +;; configure EMACS package system + +(add-to-list 'package-archives + '("melpa" . "http://melpa.org/packages/")) + +(when (< emacs-major-version 24) + (add-tolist 'package-archives + '("gnu" . "http://elpa.gnu.org/packages/"))) + +;; functions for pkg load +(defvar *my-pkgs* nil + "List of pkg which should be enabled") + +(defvar *mypkgs-dir* + (concat *custom-dir* "/pkgs")) + +(defvar *idle-works* nil + "Idle configuration") +(defvar *idle-timer* + "Timer for idle works") +(defvar *idle-active-interval* 1.0 + "Interval of idle active") + +(defun mypkg-enabled (pkginfo) + (message "checking package %s" + (cl-getf pkginfo :name)) + (cl-getf pkginfo :enabled)) + +(defun register-mypkg (pkginfo) + (when (mypkg-enabled pkginfo) + (push pkginfo *my-pkgs*))) + +(defun mypkg-call (pkginfo tag) + (let ((func (cl-getf pkginfo tag))) + (when func + (let ((tagname (symbol-name tag)) + (pkgname (cl-getf pkginfo :name)) + (before (current-time))) + (progn (funcall func) + (let ((after (current-time))) + (message "CALL %s%s %f" + pkgname tagname + (float-time (time-subtract after + before))))))))) + + +(defun mypkg-do-install (pkginfo) + (let ((pkgs (cl-getf pkginfo :packages))) + (dolist (pkg pkgs) + (progn (package-install pkg) + (package-activate pkg))))) + +(defun mypkg-install-all () + (dolist (pkginfo *my-pkgs*) + (mypkg-do-install pkginfo))) + +;; worker for idle time +;; when no work need to do cancel +;; idle timer +(defun idle-worker () + (if *idle-works* + (let ((pkginfo (car *idle-works*)) + (remain (cdr *idle-works*))) + (mypkg-call pkginfo :idle-conf) + (setq *idle-works* remain)) + (progn (when *idle-timer* + (cancel-timer *idle-timer*) + (setq *idle-timer* nil)) + t))) + +;; install idle handler +(defun install-idle-handler () + (dolist (pkginfo *my-pkgs*) + (let ((func (cl-getf pkginfo :idle-conf))) + (when func + (add-to-list '*idle-works* + pkginfo)))) + (when *idle-works* + (setq *idle-timer* + (run-with-idle-timer *idle-active-interval* t + 'idle-worker)))) + +(defun my-load-file (file) + (let ((disabled (cl-map 'list #'(lambda (x) + (symbol-name x)) + '(asy guile))) + (xfile (my-replace-string (file-name-base file) + "-init" ""))) + (unless (member xfile disabled) + (load-file file)))) + +;; load pkg list +(defun load-mypkgs-info () + (let ((files (file-expand-wildcards (concat *mypkgs-dir* "/*.el")))) + (dolist (file files) + (my-load-file file)) + (setq *my-pkgs* (reverse *my-pkgs*)))) + +;; config packages after active +(defun mypkg-after-init () + (dolist (pkginfo *my-pkgs*) + (mypkg-call pkginfo :config)) + ;; load custom.el + (load-customize) + (install-idle-handler)) + +;; check whether "--update-archives" is in command line +;; args +(defun need-update-archives () + (let ((need-update (cl-some #'(lambda (x) + (string= x "--update-archives")) + command-line-args))) + (when need-update + (setq command-line-args + (cl-remove-if #'(lambda (x) + (string= x '--update-archives)) + command-line-args))) + need-update)) + +;; function to prepare to install/active +;; packages +(defun mypkgs-pre-active (update-archives) + (load-mypkgs-info) + + ;; initialize EMACS package system but + ;; without active any packages + (package-initialize t) + + ;; update package archive when option + ;; --update-archives in command line + ;; or there is no archive contents + (when (or update-archives + (not package-archive-contents)) + (package-refresh-contents)) + + ;; prepare to install/active packages + (dolist (pkginfo *my-pkgs*) + (mypkg-call pkginfo :init)) + + ;; install packages + (mypkg-install-all) + + ;; install functions to configure + ;; package after package actived + (add-hook 'after-init-hook + 'mypkg-after-init)) + +;; go +(mypkgs-pre-active (need-update-archives)) diff --git a/old-config/lisp/ob-metapost.el b/old-config/lisp/ob-metapost.el new file mode 100644 index 0000000..91db086 --- /dev/null +++ b/old-config/lisp/ob-metapost.el @@ -0,0 +1,206 @@ +;;; ob-metapost.el --- org-babel functions for metapost evaluation + +;; Copyright (C) 2009-2012 Free Software Foundation, Inc. + +;; Author: Rongsong Shen +;; Keywords: literate programming, metapost +;; Homepage: http://orgmode.org + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . + +;;; Commentary: + +;; Org-Babel support for evaluating metapost source code. +;; +;; This differs from most standard languages in that +;; +;; 1) there is no such thing as a "session" in metapost +;; +;; 2) we are generally only going to return results of type "file" +;; +;; 3) we are adding the "file" and "cmdline" header arguments, if file +;; is omitted then the -V option is passed to the metapost command for +;; interactive viewing + +;;; Requirements: + +;; +;; - metapost-mode :: Major mode for editing metapost files + +;;; Code: +(require 'ob) +(eval-when-compile (require 'cl)) + +(add-to-list 'org-babel-tangle-lang-exts '("metapost" . "mp")) + +(defvar org-babel-default-header-args:metapost + '((:results . "file") (:exports . "results")) + "Default arguments when evaluating an Metapost source block.") + +(defcustom org-metapost-program "mpost" + "Command of metapost. The command should use command line `mpost sourcefile'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defcustom org-metapost-convert "convert" + "Command for convert picture format. The command should use format `convert source destintion'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defvar mp-prologues) +(defvar mp-script) +(defvar mp-m-end) +(defvar mp-m-start) +(defvar mp-var-type) +(defvar mp-var-value) +(defvar mp-vpair) + +(defun metapost-shell-command (dir cmd) + (shell-command (concat "/bin/sh -c \" cd " + dir ";" + cmd "\""))) + +(defun metapost-fold (acc fun lst) + (if lst + (metapost-fold (funcall fun acc (car lst)) + fun (cdr lst)) + acc)) + +(defun metapost-script (fmt mp-libs body) + (setq mp-prologues + (cond ((string= fmt "svg") "outputformat:=\"svg\";\n") + (t "prologues:=3;\n"))) + + (setq mp-script (concat "beginfig(1);\n" + body + "\nendfig;\n" + "end\n")) + (message "%s" mp-script) + (concat mp-prologues + (if mp-libs + (metapost-fold "" #'(lambda (a b) + (concat a "input " b ";\n")) + (split-string mp-libs ",")) + "") + mp-script)) + +(defun metapost-post-run (fmt in-file out-file) + (cond ((or (string= fmt "svg") + (string= fmt "eps")) + (copy-file (concat (file-name-nondirectory in-file) ".1") + out-file)) + (t (metapost-shell-command org-babel-temporary-directory + (concat org-metapost-convert " " + (file-name-nondirectory in-file) + ".1" " " + out-file))))) + +(defun org-babel-execute:metapost (body params) + "Execute a block of Metapost code. +This function is called by `org-babel-execute-src-block'." + (let* ((result-params (split-string (or (cdr (assoc :results params)) ""))) + (out-file (expand-file-name (cdr (assoc :file params)))) + (format (or (and out-file + (string-match ".+\\.\\(.+\\)" out-file) + (match-string 1 out-file)) + "pdf")) + (cmdline (cdr (assoc :cmdline params))) + (in-file (org-babel-temp-file "metapost-")) + (cmd (concat org-metapost-program " --debug " + (file-name-nondirectory + (org-babel-process-file-name in-file))))) + (with-temp-file in-file + (insert (metapost-script format + (cdr (assoc :mp-libs params)) + (org-babel-expand-body:generic + body params + (org-babel-variable-assignments:metapost params))))) + (metapost-shell-command org-babel-temporary-directory + cmd) + (metapost-post-run format in-file out-file) + nil)) ;; signal that output has already been written to file + +(defun org-babel-prep-session:metapost (session params) + "Return an error if the :session header argument is set. +Metapost does not support sessions" + (error "Metapost does not support sessions")) + +(defun org-babel-variable-assignments:metapost (params) + "Return list of metapost statements assigning the block's variables" + (mapcar #'org-babel-metapost-var-to-metapost + (mapcar #'cdr (org-babel-get-header params :var)))) + +(defconst metapost-type-prefix "^[^:]*:") + + +(defun org-babel-metapost-var-value (val) + (setq mp-m-end 0) + (setq mp-m-start (string-match metapost-type-prefix val)) + (if mp-m-start + (setq mp-m-end (match-end 0))) + (setq mp-var-type "") + (setq mp-var-value val) + (if (> mp-m-end 0) + (progn (setq mp-var-type + (substring val mp-m-start (- mp-m-end 1))) + (setq mp-var-value + (substring val mp-m-end (length val))))) + (cons mp-var-type (cons mp-var-value nil))) + +(defun org-babel-metapost-var-to-metapost (pair) + "Convert an elisp value into an Metapost variable. +The elisp value PAIR is converted into Metapost code specifying +a variable of the same value." + (let ((var (car pair)) + (val (let ((v (cdr pair))) + (if (symbolp v) (symbol-name v) v)))) + (progn + (setq mp-vpair (org-babel-metapost-var-value val)) + (setq mp-var-type (nth 0 mp-vpair)) + (setq mp-var-value (nth 1 mp-vpair)) + (if (string= mp-var-type "string") + (format "%s %s;\n %s :=\"%s\";\n" + mp-var-type var var mp-var-value + ) + (format "%s %s;\n %s := %s;\n" + mp-var-type var var mp-var-value + ))))) + +(defun org-babel-metapost-define-type (data) + "Determine type of DATA. + +DATA is a list. Return type as a symbol. + +The type is `string' if any element in DATA is +a string. Otherwise, it is either `numeric', if some elements are +floats, or `numeric'." + (let* ((type 'numeric) + find-type ; for byte-compiler + (find-type + (function + (lambda (row) + (catch 'exit + (mapc (lambda (el) + (cond ((listp el) (funcall find-type el)) + ((stringp el) (throw 'exit (setq type 'string))) + ((floatp el) (setq type 'numeric)))) + row)))))) + (funcall find-type data) type)) + +(provide 'ob-metapost) +;;; ob-metapost.el ends here diff --git a/old-config/lisp/ob-tikz.el b/old-config/lisp/ob-tikz.el new file mode 100644 index 0000000..210fa26 --- /dev/null +++ b/old-config/lisp/ob-tikz.el @@ -0,0 +1,198 @@ +;;; ob-tikz.el --- org-babel functions for tikz evaluation + +;; Copyright (C) 2009-2012 Free Software Foundation, Inc. + +;; Author: Rongsong Shen +;; Keywords: literate programming, tikz +;; Homepage: http://orgmode.org + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 . + +;;; Commentary: + +;; Org-Babel support for evaluating tikz source code. +;; +;; This differs from most standard languages in that +;; +;; 1) there is no such thing as a "session" in tikz +;; +;; 2) we are generally only going to return results of type "file" +;; +;; 3) we are adding the "file" and "cmdline" header arguments, if file +;; is omitted then the -V option is passed to the tikz command for +;; interactive viewing + +;;; Requirements: + +;; +;; - tikz-mode :: Major mode for editing tikz files + +;;; Code: +(require 'ob) +(eval-when-compile (require 'cl)) +(require 'latex) + +(add-to-list 'org-babel-tangle-lang-exts '("tikz" . "tikz")) + +(define-derived-mode tikz-mode + latex-mode "tikz/pgf" + "Major mode for tikz/pgf script" + ) + +(font-lock-add-keywords + 'tikz-mode + '(("\\draw" . font-lock-keyword-face) + ("\\filldraw" . font-lock-keyword-face) + ("\\clip" . font-lock-keyword-face) + ("\\shadowdraw" . font-lock-keyword-face) + ("\\path" . font-lock-keyword-face) + ("\\foreach" . font-lock-keyword-face) + ("\\node" . font-lock-keyword-face) + ("\\fill" . font-lock-keyword-face) + )) + +(defvar org-babel-default-header-args:tikz + '((:results . "file") (:exports . "results")) + "Default arguments when evaluating an Tikz source block.") + +(defcustom org-tikz-program "pdflatex" + "Command of tikz. The command should use command line `pdflatex sourcefile'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defcustom org-tikz-convert "convert" + "Command for convert picture format. The command should use format `convert source destintion'" + :group 'org-babel + :version "24.1" + :type 'string) + +(defvar tikz-prologues) +(defvar tikz-script) +(defvar tikz-m-end) +(defvar tikz-m-start) +(defvar tikz-var-type) +(defvar tikz-var-value) +(defvar tikz-vpair) + +(defun tikz-shell-command (dir cmd) + (shell-command (concat "/bin/sh " " -c " + "\" cd " dir ";" + cmd "\""))) + +(defun tikz-script (fmt tikz-libs body) + (setq tikz-prologues + (concat "\\documentclass{article}\n" + "\\usepackage{tikz}\n" + "\\usepackage{pgfplots}\n" + (if tikz-libs + (concat "\\usetikzlibrary{" + tikz-libs + "}\n") + "") + "\\begin{document}\n" + "\\begin{tikzpicture}")) + + (setq tikz-script-data (concat body + "\n\\end{tikzpicture}\n" + "\\end{document}\n")) + (message "%s" (concat tikz-prologues tikz-script-data)) + (concat tikz-prologues tikz-script-data)) + +(defun tikz-post-run (fmt in-file out-file) + (tikz-shell-command "." + (concat org-tikz-convert " " + (concat org-babel-temporary-directory "/" + (file-name-nondirectory in-file) + ".pdf") + " " + out-file))) + +(defun org-babel-execute:tikz (body params) + "Execute a block of Tikz code. +This function is called by `org-babel-execute-src-block'." + (let* ((result-params (split-string (or (cdr (assoc :results params)) ""))) + (out-file (cdr (assoc :file params))) + (format (or (and out-file + (string-match ".+\\.\\(.+\\)" out-file) + (match-string 1 out-file)) + "pdf")) + (cmdline (cdr (assoc :cmdline params))) + (in-file (org-babel-temp-file "tikz-")) + (cmd + (concat (concat org-tikz-program " -shell-escape ") + (org-babel-process-file-name in-file) + ))) + (with-temp-file (concat in-file ".tex") + (insert (tikz-script format + (tikz-get-value-by-name 'tikz-libs + (mapcar #'cdr (org-babel-get-header params :var))) + (org-babel-expand-body:generic + body params + (org-babel-variable-assignments:tikz params))))) + (message cmd) + (tikz-shell-command org-babel-temporary-directory cmd) + (tikz-post-run format in-file out-file) + nil)) ;; signal that output has already been written to file + +(defun org-babel-prep-session:tikz (session params) + "Return an error if the :session header argument is set. +Tikz does not support sessions" + (error "Tikz does not support sessions")) + +(defun org-babel-variable-assignments:tikz (params) + "Return list of tikz statements assigning the block's variables" + (mapcar #'org-babel-tikz-var-to-tikz + (mapcar #'cdr (org-babel-get-header params :var)))) + +(defun tikz-get-value-by-name (name vpairs) + (let ((vp (assoc name vpairs))) + (if vp + (cdr vp) + nil))) + +(defun org-babel-tikz-var-value (val) + val) + +(defun org-babel-tikz-var-to-tikz (pair) + "Convert an elisp value into an Tikz variable. +The elisp value PAIR is converted into Tikz code specifying +a variable of the same value." + nil) + +(defun org-babel-tikz-define-type (data) + "Determine type of DATA. + +DATA is a list. Return type as a symbol. + +The type is `string' if any element in DATA is +a string. Otherwise, it is either `numeric', if some elements are +floats, or `numeric'." + (let* ((type 'numeric) + find-type ; for byte-compiler + (find-type + (function + (lambda (row) + (catch 'exit + (mapc (lambda (el) + (cond ((listp el) (funcall find-type el)) + ((stringp el) (throw 'exit (setq type 'string))) + ((floatp el) (setq type 'numeric)))) + row)))))) + (funcall find-type data) type)) + +(provide 'ob-tikz) +;;; ob-tikz.el ends here diff --git a/old-config/lisp/os.el b/old-config/lisp/os.el new file mode 100644 index 0000000..fe71bb9 --- /dev/null +++ b/old-config/lisp/os.el @@ -0,0 +1,33 @@ +(defvar *osname* 'unknown) + +(defun darwin-path () + (let ((files (file-expand-wildcards "/etc/paths.d/*"))) + (my-fold-left #'(lambda (acc e) + (if (not acc) + e + (concat acc ":" e))) + nil + (loop for d in files + collect (substring + (shell-command-to-string + (concat " cat " d + "|sed -e '/^$/d' ")) + 0 -1))))) +(defun darwin-init () + (setf *osname* 'darwin) + (setenv "PATH" + (concat (getenv "PATH") + ":/opt/local/bin:/opt/local/sbin:" + (darwin-path))) + (message "PATH=%s" (getenv "PATH"))) + +(defun berkeley-unix-init () + (setf *osname* 'bsd) + t) + +(defmacro os-init () + (let ((osinit (intern (concat (symbol-name system-type) + "-init")))) + `(,osinit))) + +(os-init) diff --git a/old-config/pkgs/asy-init.el b/old-config/pkgs/asy-init.el new file mode 100644 index 0000000..a0b82c8 --- /dev/null +++ b/old-config/pkgs/asy-init.el @@ -0,0 +1,13 @@ +(defun setup-asy () + (let ((texmf-dist (substring (shell-command-to-string "kpsewhich -var-value TEXMFDIST 2>/dev/null") + 0 -1))) + (when texmf-dist + (setq asy-mode-path (concat texmf-dist "/asymptote")) + (add-to-list 'load-path asy-mode-path) + (load-file (concat asy-mode-path "/asy-init.el"))))) + +(register-mypkg + (list :name "asy" + :enabled (which "asy") + :packages nil + :init #'setup-asy)) diff --git a/old-config/pkgs/dict-init.el b/old-config/pkgs/dict-init.el new file mode 100644 index 0000000..185aaa2 --- /dev/null +++ b/old-config/pkgs/dict-init.el @@ -0,0 +1,11 @@ +(defun dict-config () + (setq url-automatic-caching t) + (global-set-key (kbd "C-c y") 'youdao-dictionary-search-at-point) + (setq youdao-dictionary-use-chinese-word-segment t)) + +(register-mypkg + (list :name "dict" + :enabled t + :packages '(youdao-dictionary) + :config #'dict-config)) + diff --git a/old-config/pkgs/eiffel-init.el b/old-config/pkgs/eiffel-init.el new file mode 100644 index 0000000..2f8fc7b --- /dev/null +++ b/old-config/pkgs/eiffel-init.el @@ -0,0 +1,12 @@ +(defun setup-eiffel () + (load-file (concat *lisp-dir* "/eiffel.el")) + (setq auto-mode-alist + (append '(("\\.e\\'" . eiffel-mode)) + auto-mode-alist))) + +(register-mypkg + (list :name "eiffel" + :enabled t + :packages nil + :config #'setup-eiffel)) + diff --git a/old-config/pkgs/eldoc-init.el b/old-config/pkgs/eldoc-init.el new file mode 100644 index 0000000..554ac26 --- /dev/null +++ b/old-config/pkgs/eldoc-init.el @@ -0,0 +1,28 @@ +(defun eldoc-init () + (put 'c-eldoc-includes 'safe-local-variable 'stringp) + (put 'c-eldoc-cpp-macro-arguments 'safe-local-variable 'stringp) + (put 'c-eldoc-cpp-normal-arguments 'safe-local-variable 'stringp) + (put 'c-eldoc-cpp-command 'safe-local-variable 'stringp)) + +(defun eldoc-config () + (add-hook 'c-mode-hook + #'(lambda () + (c-turn-on-eldoc-mode))) + (add-hook 'c++-mode-hook + #'(lambda () + (c-turn-on-eldoc-mode))) + (eldoc-in-minibuffer-mode 1) + (setq ess-eval-visibly-p nil)) + + +(register-mypkg + (list :name "eldoc" + :enabled t + :packages '(eldoc-eval c-eldoc) + :init #'eldoc-init + :config #'eldoc-config)) + +;;(defvar c-eldoc-cpp-command "/lib/cpp ") ;; compiler +;;(defvar c-eldoc-cpp-macro-arguments "-dD -w -P") +;;(defvar c-eldoc-cpp-normal-arguments "-w -P") +;;(defvar c-eldoc-includes "`pkg-config gtk+-2.0 --cflags` -I./ -I../ ") ;; include flags diff --git a/old-config/pkgs/ess-init.el b/old-config/pkgs/ess-init.el new file mode 100644 index 0000000..c097a0d --- /dev/null +++ b/old-config/pkgs/ess-init.el @@ -0,0 +1,17 @@ +(defun ess-init () + (setq auto-mode-alist + (append '(("\\.R$" . R-mode) + ("\\.r$" . R-mode)) + auto-mode-alist))) + +(defun ess-config () + t) + +(register-mypkg + (list :name "ess" + :enabled t + :packages '(ess ess-R-data-view ess-R-object-popup + ess-smart-equals ess-smart-underscore + ess-view) + :init #'ess-init + :config #'ess-config)) diff --git a/old-config/pkgs/helm-init.el b/old-config/pkgs/helm-init.el new file mode 100644 index 0000000..a96da1c --- /dev/null +++ b/old-config/pkgs/helm-init.el @@ -0,0 +1,66 @@ + +(defun helm-add-hooks () + (let ((enabled-modes '(c c++ asm java python ocaml lisp gnuplot + haskell verilog ruby vhdl tuareg))) + (loop for m in enabled-modes do + (add-hook (intern (concat (symbol-name m) + "-mode-hook")) + 'helm-gtags-mode))) + + ;; initialize for helm-gtags + (with-eval-after-load 'helm-gtags + (define-key helm-gtags-mode-map + (kbd "M-t") 'helm-gtags-find-tag) + (define-key helm-gtags-mode-map + (kbd "M-r") 'helm-gtags-find-rtag) + (define-key helm-gtags-mode-map + (kbd "M-s") 'helm-gtags-find-symbol) + (define-key helm-gtags-mode-map + (kbd "M-p") 'helm-gtags-find-pattern) + (define-key helm-gtags-mode-map + (kbd "M-g M-p") 'helm-gtags-parse-file) + (define-key helm-gtags-mode-map + (kbd "C-c <") 'helm-gtags-previous-history) + (define-key helm-gtags-mode-map + (kbd "C-c >") 'helm-gtags-next-history) + (define-key helm-gtags-mode-map + (kbd "C-c r") 'helm-gtags-resume) + (define-key helm-gtags-mode-map + (kbd "M-,") 'helm-gtags-pop-stack))) + +(defun helm-conf () + (require 'helm-config) + (helm-mode 1) + (define-key global-map + [remap find-file] 'helm-find-files) + (define-key global-map + [remap occur] 'helm-occur) + (define-key global-map + [remap list-buffers] 'helm-buffers-list) + (define-key global-map + [remap dabbrev-expand] 'helm-dabbrev) + + (global-set-key (kbd "M-x") 'helm-M-x) + (global-set-key (kbd "C-c ") 'helm-yas-complete) + + (unless (boundp 'completion-in-region-function) + (define-key lisp-interaction-mode-map + [remap completion-at-point] + 'helm-lisp-completion-at-point) + (define-key emacs-lisp-mode-map + [remap completion-at-point] + 'helm-lisp-completion-at-point)) + (helm-add-hooks)) + +(register-mypkg + (list :name "helm" + :enabled t + :packages '(bind-key async yasnippet helm helm-core + helm-descbinds helm-proc + helm-gtags helm-git helm-flycheck + helm-flyspell helm-flymake helm-fuzzier + helm-fuzzy-find helm-ack helm-c-yasnippet + helm-themes helm-package helm-ls-git) + :config #'(lambda () + (helm-conf)))) + diff --git a/old-config/pkgs/misc-init.el b/old-config/pkgs/misc-init.el new file mode 100644 index 0000000..a1aecfc --- /dev/null +++ b/old-config/pkgs/misc-init.el @@ -0,0 +1,67 @@ +(defun insert-lozenge () + "inserts the lozenge character for use with Pollen" + ;; enables function through M-x + (interactive) + ;; insert the proper character + (insert (make-char + 'mule-unicode-2500-33ff 34 42))) + +(defun setup-i18n () + (setq file-coding-system-alist + '(("\\.dz\\'" no-conversion . no-conversion) + ("\\.txz\\'" no-conversion . no-conversion) + ("\\.xz\\'" no-conversion . no-conversion) + ("\\.lzma\\'" no-conversion . no-conversion) + ("\\.lz\\'" no-conversion . no-conversion) + ("\\.g?z\\'" no-conversion . no-conversion) + ("\\.\\(?:tgz\\|svgz\\|sifz\\)\\'" no-conversion . no-conversion) + ("\\.tbz2?\\'" no-conversion . no-conversion) + ("\\.bz2\\'" no-conversion . no-conversion) + ("\\.Z\\'" no-conversion . no-conversion) + ("\\.elc\\'" . utf-8-emacs) + ("\\.el\\'" . prefer-utf-8) + ("\\.utf\\(-8\\)?\\'" . utf-8) + ("\\.xml\\'" . xml-find-file-coding-system) + ("\\(\\`\\|/\\)loaddefs.el\\'" raw-text . raw-text-unix) + ("\\.tar\\'" no-conversion . no-conversion) + ("\\.po[tx]?\\'\\|\\.po\\." . po-find-file-coding-system) + ("\\.\\(tex\\|ltx\\|dtx\\|drv\\)\\'" . latexenc-find-file-coding-system) + ("" utf-8-unix . utf-8-unix)))) + +(defun config-hs-minor-mode () + (require 'hideshow) + (add-hook 'emacs-lisp-mode-hook 'hs-minor-mode) + (add-hook 'lisp-mode-hook 'hs-minor-mode) + (add-hook 'java-mode-hook 'hs-minor-mode) + (add-hook 'perl-mode-hook 'hs-minor-mode) + (add-hook 'sh-mode-hook 'hs-minor-mode) + (add-hook 'c-mode-common-hook 'hs-minor-mode)) + +(defun misc-config () + (setq auto-mode-alist + (append '(("\\.zsh\\'" . shell-script-mode) + ("\\.csh\\\'" . shell-script-mode)) + auto-mode-alist)) + (setup-i18n) + (global-undo-tree-mode) + (setq undo-tree-visualizer-timestamps t) + (setq undo-tree-visualizer-diff t) + (setq paradox-github-token "20294bb5aaf9ce694b205e6b5a9e000525277abe") + (bind-keys* ("C-x u" . undo-tree-visualize)) + (guide-key-mode 1) + (global-linum-mode 1) + (diminish 'guide-key-mode) + (setq guide-key/guide-key-sequence '("C-x r" "C-x 4" "C-c")) + (global-set-key (kbd "C-c C-g") 'goto-line) + (global-set-key "\M-\\" 'insert-lozenge) + (setq-default tab-width 4) + (config-hs-minor-mode) + (load-theme 'rongsong t)) + +(register-mypkg + (list :name "misc" + :enabled t + :packages '(undo-tree s guide-key rainbow-delimiters + paradox diminish) + :config #'misc-config)) + diff --git a/old-config/pkgs/my-c-init.el b/old-config/pkgs/my-c-init.el new file mode 100644 index 0000000..3a5ab7c --- /dev/null +++ b/old-config/pkgs/my-c-init.el @@ -0,0 +1,133 @@ +;; offset customizations not in my-c-style +;; This will take precedence over any setting of the syntactic symbol +;; made by a style. + +(defun my-c-initialization-hook () + (progn (define-key c-mode-base-map "\C-m" 'c-context-line-break))) + +;; Create my personal style. + +(defconst my-c-style + '("user" + (c-block-comment-prefix . "*") + (c-comment-prefix-regexp . "//+\\|\\*") + (c-basic-offset . 4) ; Guessed value + (c-offsets-alist + (block-close . 0) ; Guessed value + (defun-block-intro . +) ; Guessed value + (defun-close . 0) ; Guessed value + (defun-open . 0) ; Guessed value + (statement . 0) ; Guessed value + (statement-block-intro . +) ; Guessed value + (topmost-intro . 0) ; Guessed value + (access-label . -) + (annotation-top-cont . 0) + (annotation-var-cont . +) + (arglist-close . c-lineup-close-paren) + (arglist-cont c-lineup-gcc-asm-reg 0) + (arglist-cont-nonempty . c-lineup-arglist) + (arglist-intro . +) + (block-open . 0) + (brace-entry-open . 0) + (brace-list-close . 0) + (brace-list-entry . 0) + (brace-list-intro . +) + (brace-list-open . 0) + (c . c-lineup-C-comments) + (case-label . 0) + (catch-clause . 0) + (class-close . 0) + (class-open . 0) + (comment-intro . c-lineup-comment) + (composition-close . 0) + (composition-open . 0) + (cpp-define-intro c-lineup-cpp-define +) + (cpp-macro . -1000) + (cpp-macro-cont . +) + (do-while-closure . 0) + (else-clause . 0) + (extern-lang-close . 0) + (extern-lang-open . 0) + (friend . 0) + (func-decl-cont . +) + (inclass . +) + (incomposition . +) + (inexpr-class . +) + (inexpr-statement . +) + (inextern-lang . +) + (inher-cont . c-lineup-multi-inher) + (inher-intro . +) + (inlambda . c-lineup-inexpr-block) + (inline-close . 0) + (inline-open . +) + (inmodule . +) + (innamespace . +) + (knr-argdecl . 0) + (knr-argdecl-intro . +) + (label . 2) + (lambda-intro-cont . +) + (member-init-cont . c-lineup-multi-inher) + (member-init-intro . +) + (module-close . 0) + (module-open . 0) + (namespace-close . 0) + (namespace-open . 0) + (objc-method-args-cont . c-lineup-ObjC-method-args) + (objc-method-call-cont c-lineup-ObjC-method-call-colons c-lineup-ObjC-method-call +) + (objc-method-intro . + [0]) + (statement-case-intro . +) + (statement-case-open . 0) + (statement-cont . +) + (stream-op . c-lineup-streamop) + (string . -1000) + (substatement . +) + (substatement-label . 2) + (substatement-open . +) + (template-args-cont c-lineup-template-args +) + (topmost-intro-cont . c-lineup-topmost-intro-cont)))) + +;; Customizations for all modes in CC Mode. +(defun my-c-mode-common-hook () + ;; set my personal style for the current buffer + (c-add-style "PERSONAL" my-c-style) + (c-set-style "PERSONAL") + (electric-pair-mode 1) + (electric-layout-mode 1) + + ;; Follow will make character '#' to be moved to column 0 when # is + ;; the first non-space character + (setq c-electric-pound-behavior '(alignleft)) + + ;; (setq indent-tabs-mode nil) + ;; we like auto-newline, but not hungry-delete + (c-toggle-auto-newline 1) + (which-function-mode 1)) + + +(defun add-c-function-header (function-name) + "Add header description of c/c++ functions" + (interactive "sFunction Name:") + (progn + (insert "/*\n") + (insert " *---------------------------------------------------------------------------------\n") + (insert " *\n") + (insert (concat " * " function-name "() --\n")) + (insert " *\n") + (insert " * DESCRIPTION:\n") + (insert " *\n") + (insert " * ARGS:\n") + (insert " *\n") + (insert " * RETURN:\n") + (insert " *\n") + (insert " *---------------------------------------------------------------------------------\n") + (insert " */\n"))) + +(register-mypkg + (list :name "my-c" + :enabled t + :packages nil + :init #'(lambda () + (add-hook 'c-initialization-hook 'my-c-initialization-hook)) + :config #'(lambda () + (add-hook 'c-mode-common-hook 'my-c-mode-common-hook)))) diff --git a/old-config/pkgs/opam-init.el b/old-config/pkgs/opam-init.el new file mode 100644 index 0000000..6bf4b41 --- /dev/null +++ b/old-config/pkgs/opam-init.el @@ -0,0 +1,48 @@ +(defvar opam nil) +(defvar git-opam-url) +(defvar opam-vars '("lib" "libexec" "bin" + "sbin" "toplevel" + "share" "share_root" + "etc" "doc" "stublibs")) +(defvar utop nil + "the full path of utop") + +(setf git-opam-url "https://github.com/ocaml/opam.git") + +(defun opam-config-var (var) + (let ((command-string (concat "opam config var " var))) + (substring (shell-command-to-string command-string) + 0 -1))) + +(defun opam-config-env () + (dolist (var (car (read-from-string + (shell-command-to-string + "opam config env --sexp")))) + (let ((var-name (car var)) + (var-val (cadr var))) + (setenv var-name + (let ((old-v (getenv var-name))) + (if old-v + (concat old-v ":" var-val) + var-val))))) + (add-to-list 'load-path + (concat (opam-config-var "share") + "/emacs/site-lisp/"))) + +(defun check-opam () + (if (not (which "opam")) + (progn (message "Please install opam") + nil) + (progn (opam-config-env) + (setq utop (which "utop")) + (unless utop + (message "Please install utop with (opam install utop)")) + utop))) + +(register-mypkg + (list :name "opam" + :enabled (check-opam) + :packages nil + :init #'(lambda () + (setq utop-command (concat utop " -emacs")) + (autoload 'utop "utop" "toplevel of ocaml" t)))) diff --git a/old-config/pkgs/org-init.el b/old-config/pkgs/org-init.el new file mode 100644 index 0000000..801a6b5 --- /dev/null +++ b/old-config/pkgs/org-init.el @@ -0,0 +1,246 @@ +;;; + +(require 'cl) + +(defvar *backend* nil) +(defvar org-generate-default-toc t) +(defvar org-tex-engine "default") + +(setq org-babel-temporary-directory + (format "/tmp/emacs.babel.%d" (emacs-pid))) + +(defun choose-tex-engine (name) + (let ((tex-engines '(("pdflatex2" . + ("pdflatex -interaction nonstopmode -output-directory %o %f" + "pdflatex -interaction nonstopmode -output-directory %o %f")) + ("pdflatex3" . + ("pdflatex -interaction nonstopmode -output-directory %o %f" + "pdflatex -interaction nonstopmode -output-directory %o %f" + "pdflatex -interaction nonstopmode -output-directory %o %f")) + ("pdflatex3-bibtex" . + ("pdflatex -interaction nonstopmode -output-directory %o %f" + "bibtex %b" + "pdflatex -interaction nonstopmode -output-directory %o %f" + "pdflatex -interaction nonstopmode -output-directory %o %f")) + ("xelatex2" . + ("xelatex -interaction nonstopmode -output-directory %o %f" + "xelatex -interaction nonstopmode -output-directory %o %f")) + ("xelatex3" . + ("xelatex -interaction nonstopmode -output-directory %o %f" + "xelatex -interaction nonstopmode -output-directory %o %f" + "xelatex -interaction nonstopmode -output-directory %o %f")) + ("xelatex3-bibtex" . + ("xelatex -interaction nonstopmode -output-directory %o %f" + "bibtex %b" + "xelatex -interaction nonstopmode -output-directory %o %f" + "xelatex -interaction nonstopmode -output-directory %o %f")) + ("texi2dvi" . ("texi2dvi -p -b -V %f")) + ("rubber" . ("rubber -d --into %o %f")) + ("latexmk" . ("latexmk -g -pdf %f"))))) + (let ((engine (assoc name tex-engines))) + (if engine + (cdr engine) + (cdr (assoc "pdflatex2" tex-engines)))))) + + +(defun add-moderncv-class (backend) + (unless (member "moderncv" (mapcar #'car org-latex-classes)) + (setq org-latex-classes + (append '(("moderncv" "\\documentclass[10pt,a4paper,roman]{moderncv}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) + org-latex-classes)))) + + +(defun do-foreach (tag action) + (save-excursion + (progn (goto-char (point-min)) + (while (re-search-forward tag nil t) + (progn (funcall action) + (forward-line 1)))))) + +;; update all radio tables +;; in the document +(defun send-all-tables (backend) + (interactive) + (let ((*backend* backend)) + (do-foreach "[ \t]*#\\+ORGTBL:" + #'(lambda () + (forward-line) + (call-interactively 'orgtbl-send-table))))) + +(defun org-use-xelatex () + (interactive) + (setq org-latex-pdf-process + (quote ("xelatex -interaction nonstopmode -output-directory %o %f" + "bibtex %b" "xelatex -interaction nonstopmode -output-directory %o %f" + "xelatex -interaction nonstopmode -output-directory %o %f")))) + + +(defun org-odt-publish-to-odt (plist filename pub-dir) + (message "odt publishing\n") + (org-publish-org-to 'odt filename + (concat "." (or (plist-get plist :odt-extension) + org-html-extension "odt")) + plist pub-dir)) + +(defun org-before-publish (backend) + (org-choose-tex-engine) + (if (boundp 'org-babel-temporary-directory) + (unless (file-exists-p org-babel-temporary-directory) + (progn + (make-directory org-babel-temporary-directory t))))) + +(defun my-org-before-parsing-hook (backend) + (progn + (send-all-tables backend) + (add-moderncv-class backend))) ;; update radio tables + +(defun position-of-match (pattern) + (if (re-search-forward pattern nil t 1) + (progn + (list (match-beginning 0) + (match-end 0))) + nil)) + +(defun my-org-before-processing-hook (backend) + t) + + +(defun org-choose-tex-engine () + (hack-local-variables) + (setq org-latex-pdf-process + (choose-tex-engine (if org-tex-engine + org-tex-engine + "default")))) + +(defun customize-org () + (custom-set-variables + '(org-babel-load-languages + (quote ((emacs-lisp . t) + (C . t) + (calc . t) + (ditaa . t) + (gnuplot . t) + (mscgen . t) + (octave . t) + (plantuml . t) + (sh . t) + (haskell . t) + (metapost . t) + (dot . t) + (R . t) + (latex . t) + (tikz . t)))) + '(org-babel-tangle-lang-exts + (quote (("emacs-lisp" . "el") + ("metapost" . "mp") + ("Language name" . "File Extension")))) + '(org-confirm-babel-evaluate nil) + '(org-ditaa-jar-path "~/.emacs.d/misc/ditaa.jar") + '(org-enforce-todo-dependencies t) + '(org-export-backends (quote (ascii html icalendar latex odt md beamer))) + '(org-latex-default-packages-alist + (quote (("T1" "fontenc" t) + ("" "fixltx2e" nil) + ("" "graphicx" t) + ("" "longtable" nil) + ("" "float" nil) + ;; ("" "wrapfig" nil) + ("" "soul" t) + ("" "textcomp" t) + ("" "marvosym" t) + ("" "wasysym" t) + ("" "latexsym" t) + ("" "amssymb" t) + ("" "amstext" nil) + ("" "hyperref" nil) "\\tolerance=1000"))) + `(org-plantuml-jar-path ,(concat *custom-dir* "/misc/plantuml.jar")))) + +(defun my-org-init () + (make-local-variable 'org-tex-engine) + (make-local-variable 'buffer-file-coding-system) + (setq org-babel-load-languages nil) + (customize-org) + (put 'org-latex-default-packages-alist 'safe-local-variable 'listp) + (put 'org-tex-engine 'safe-local-variable 'stringp) + (put 'buffer-file-coding-system 'safe-local-variable 'symbolp) + (put 'org-latex-title-command 'safe-local-variable 'stringp) + (put 'org-latex-toc-command 'safe-local-variable 'stringp) + (unless (file-exists-p org-babel-temporary-directory) + (make-directory org-babel-temporary-directory))) + +(defun my-org-config () +;; (add-hook 'org-babel-after-execute-hook +;; 'org-display-inline-images) +;; (setq org-startup-with-inline-images t) + ;; Using xelatex to enable + ;; CJK support + ;;(add-hook 'org-mode-hook 'org-use-xelatex) + (add-hook 'org-mode-hook 'orgtbl-mode) + (add-hook 'org-export-before-parsing-hook 'my-org-before-parsing-hook) + (add-hook 'org-export-before-processing-hook 'my-org-before-processing-hook) + (add-hook 'org-export-before-processing-hook 'org-before-publish) + (add-hook 'org-mode-hook 'turn-on-org-cdlatex) + (setq org-export-allow-bind-keywords t) + (setq org-latex-to-mathml-convert-command + "java -jar %j -unicode -force -df %o %I" + org-latex-to-mathml-jar-file + "~/.emacs.d/misc/mathtoweb.jar") + ) + + +(defun org-use-template (template) + (interactive + (let ((template-used (read-file-name "choose template: " + (expand-file-name "~/.emacs.d/templates/") + nil nil nil))) + (list template-used))) + (when template + (insert-file-contents template) + ;; enable file local variables defined in template + ;; + (hack-local-variables))) + +(defun refill-org-paragraphs () + (interactive) + (save-excursion + (goto-char (point-min)) + (while (not (eql (point) (point-max))) + (org-fill-paragraph) + (org-forward-paragraph)))) + +;; reshape-web-paragraph () +;; this function is used to reshape the paragraph copied from +;; web browser which a paragraph is just a very log line +(defun reshape-web-paragraph () + (interactive) + (save-excursion + (goto-char (point-min)) + (when (< (point) (point-max)) + (forward-sentence) + (when (< (point) (point-max)) + (insert "\n") + (reshape-web-paragraph))))) + +(defun delete-extra-empty-lines () + (interactive) + (save-excursion + (goto-char (point-min)) + (my-zap-multiple-empty-lines))) + +(register-mypkg + (list :name "org" + :enabled t + :packages '(auctex org puml-mode cdlatex ox-ioslide + gnuplot gnuplot-mode) + :init #'(lambda () + (my-org-init) + (setq puml-plantuml-jar-path + (expand-file-name (concat *custom-dir* "/misc/plantuml.jar"))) + (setenv "GRAPHVIZ_DOT" (which "dot"))) + :config #'(lambda () + (my-org-config)))) diff --git a/old-config/pkgs/powerline-init.el b/old-config/pkgs/powerline-init.el new file mode 100644 index 0000000..a4ca3dc --- /dev/null +++ b/old-config/pkgs/powerline-init.el @@ -0,0 +1,10 @@ +(register-mypkg + (list :name "powerline" + :enabled t + :packages '(powerline airline-themes) + :config #'(lambda () + (with-eval-after-load 'powerline + (load-theme 'airline-kolor t))) + :idle-conf #'(lambda () + (require 'powerline) + (powerline-default-theme)))) diff --git a/old-config/pkgs/racket-init.el b/old-config/pkgs/racket-init.el new file mode 100644 index 0000000..f288864 --- /dev/null +++ b/old-config/pkgs/racket-init.el @@ -0,0 +1,46 @@ +(defvar *racket* + (which "racket")) +(defvar *guile* + (which "guile")) + +(defvar *scribble-dir* nil) + +(defun scribble-mode-install () + (shell-command "racket -e '(require (planet neil/scribble-emacs))'")) + +(defun racket-local-top () + (cond + ((equal *osname* 'darwin) "~/Library/") + ((equal *osname* 'bsd) "~/.racket") + (t "~/.racket"))) + +(defun racket-init () + (when *racket* + (progn + (setf geiser-racket-binary *racket*) + (let ((local-top (racket-local-top))) + (let ((scribble (find-file-by-search-dir local-top + "scribble.el"))) + (if scribble + (setf *scribble-dir* + (file-name-directory scribble)) + (progn (scribble-mode-install) + (setf *scribble-dir* + (file-name-directory (find-file-by-search-dir local-top + "scribble.el"))))))) + *scribble-dir*)) + (when *guile* + (setf geiser-guile-binary *guile*))) + +(defun racket-config () + (when *scribble-dir* + (add-to-list 'load-path *scribble-dir*) + (require 'scribble))) + +(register-mypkg + (list :name "racket" + :enabled (or *racket* + *guile*) + :packages '(geiser) + :init #'racket-init + :config #'racket-config)) diff --git a/old-config/pkgs/slime-init.el b/old-config/pkgs/slime-init.el new file mode 100644 index 0000000..3e510a6 --- /dev/null +++ b/old-config/pkgs/slime-init.el @@ -0,0 +1,40 @@ +(defvar *quicklisp-url* + "http://beta.quicklisp.org/quicklisp.lisp") + +(defvar *quicklisp-dir* "~/quicklisp") + +(defvar *quicklisp-file* "quicklisp.lisp") + +(defvar *slime-helper* + (expand-file-name (concat *quicklisp-dir* + "/slime-helper.el"))) + +(setq inferior-lisp-program "sbcl") + +(defun guide-install-quicklisp () + (message "You can install quicklisp with following steps") + (message "mkdir -p ~/quicklisp") + (message "cd ~/quicklisp") + (message "curl -O %s" *quicklisp-url*) + (message "%s --load quicklisp.lisp" + inferior-lisp-program) + (message "running following list of under LISP session") + (message "(quicklisp-quickstart:install)") + (message "(ql:update-client)") + (message "(ql:quickload \"quicklisp-slime-helper\")") + (message "(ql:add-to-init-file)") + nil) + +(defun check-enable-slime () + (let ((enabled (and (which inferior-lisp-program) + (file-exists-p *slime-helper*)))) + (if enabled t + (progn (guide-install-quicklisp) + nil)))) + +(register-mypkg + (list :name "slime" + :enabled (check-enable-slime) + :packages '(async slime slime-annot slime-ritz) + :idle-conf #'(lambda () + (load *slime-helper*)))) diff --git a/old-config/pkgs/smartabs-init.el b/old-config/pkgs/smartabs-init.el new file mode 100644 index 0000000..7425174 --- /dev/null +++ b/old-config/pkgs/smartabs-init.el @@ -0,0 +1,16 @@ +(defun smartabs-add-languages () + (smart-tabs-add-language-support sh sh-mode-hook + ((sh-indent-line . sh-basic-offset)))) + +(defun smartabs-config () + (smartabs-add-languages) + (smart-tabs-insinuate 'c 'javascript 'java + 'cperl 'python 'ruby + 'nxml 'sh)) + +(register-mypkg + (list :name "smartabs" + :enabled t + :packages '(smart-tabs-mode) + :config #'(lambda () + (smartabs-config)))) diff --git a/old-config/pkgs/spell-init.el b/old-config/pkgs/spell-init.el new file mode 100644 index 0000000..c2aa48b --- /dev/null +++ b/old-config/pkgs/spell-init.el @@ -0,0 +1,6 @@ +(register-mypkg + (list :name "spell" + :enabled t + :packages nil + :init #'(lambda () + (setq ispell-program-name "aspell")))) diff --git a/old-config/pkgs/tuareg-init.el b/old-config/pkgs/tuareg-init.el new file mode 100644 index 0000000..6370e1d --- /dev/null +++ b/old-config/pkgs/tuareg-init.el @@ -0,0 +1,28 @@ +(defun ocaml-init () + (setq opam-share + (substring (shell-command-to-string "opam config var share 2> /dev/null") 0 -1)) + (add-to-list 'load-path (concat opam-share "/emacs/site-lisp")) + (require 'cl)) + +(defun ocaml-config () + (let ((opam (which "opam")) + (ocp-indent (which "ocp-indent"))) + (with-eval-after-load 'tuareg-mode + (add-hook 'tuareg-mode-hook 'merlin-mode t) + (add-hook 'caml-mode-hook 'merlin-mode t) + (add-hook 'tuareg-mode-hook 'merlin-mode) + ;; (setq merlin-use-auto-complete-mode t) + ;; (setq merlin-error-after-save nil)))) + ;; Enable auto-complete + ;;(setq merlin-use-auto-complete-mode 'easy) + ;; Use opam switch to lookup ocamlmerlin binary + (setq merlin-command 'opam) + (setq ocp-indent-path ocp-indent)))) + +(register-mypkg + (list :name "tuareg" + :enabled (and (which "opam") + (which "ocp-indent")) + :packages '(tuareg ocp-indent merlin) + :init #'ocaml-init + :config #'ocaml-config)) diff --git a/old-config/pkgs/vc-init.el b/old-config/pkgs/vc-init.el new file mode 100644 index 0000000..fc01f72 --- /dev/null +++ b/old-config/pkgs/vc-init.el @@ -0,0 +1,22 @@ +;; Enable VC support +;; + +(defvar vc-username "RongsongShen") +(defvar vc-usermail "Rongsong.shen@icloud.com") + +(register-mypkg + (list :name "vc" + :enabled t + :packages '(with-editor magit magit-filenotify magit-gerrit + magit-gitflow magit-svn ) + :init #'(lambda () + (setq magit-log-edit-confirm-cancellation t) + (setq magit-last-seen-setup-instructions "1.4.0") + (unless (file-exists-p "~/.gitconfig") + (shell-command (concat "git config --global user.email " vc-usermail)) + (shell-command (concat "git config --global user.name " vc-username)))))) + + +;; Enable vc-rtc.el +;; by uncomment following +;;(add-to-list 'vc-handled-backends 'rtc) diff --git a/old-config/pkgs/www-init.el b/old-config/pkgs/www-init.el new file mode 100644 index 0000000..483624a --- /dev/null +++ b/old-config/pkgs/www-init.el @@ -0,0 +1,5 @@ +(register-mypkg + (list :name "www" + :enabled t + :packages '(restclient))) + diff --git a/old-config/pkgs/yasnippet-init.el b/old-config/pkgs/yasnippet-init.el new file mode 100644 index 0000000..c70f5f3 --- /dev/null +++ b/old-config/pkgs/yasnippet-init.el @@ -0,0 +1,7 @@ +(register-mypkg + (list :name "Yasnippet" + :enabled t + :packages '(yasnippet yatemplate common-lisp-snippets + el-autoyas helm-c-yasnippet) + :config #'(lambda () + (yas-global-mode 1)))) diff --git a/old-config/rongsong-theme.el b/old-config/rongsong-theme.el new file mode 100644 index 0000000..c79494a --- /dev/null +++ b/old-config/rongsong-theme.el @@ -0,0 +1,123 @@ +(deftheme rongsong + "Created 2016-05-04.") + +(custom-theme-set-variables + 'rongsong + '(ansi-color-faces-vector [default default default italic underline success warning error]) + '(ansi-color-names-vector ["black" "#d55e00" "#009e73" "#f8ec59" "#0072b2" "#cc79a7" "#56b4e9" "white"]) + '(current-language-environment "Chinese-GB18030") + '(custom-safe-themes (quote ("990d403cbdaff73fdaba75fc32a87d17093fa2c2dbaf0481ddb81d9a450c743e" + "7e8c508833dd24eefcf142a071f08a379c5d33d8fe685f28968a57f5c9cfb5e2" + "9a1599105ce1ef4ccc2c2eaa1dc8b04193a7fc25c211b698f3be1d39ad075328" + "5198355c8e1358b9238198ff1bb4c402bec65676a3d066e82818ca6cfd13e4c0" + "ca9d4065237e9d4d46fdd68601a6ad2e70331b1531bb4875438f50da6fe7a63a" + "582a12ec14635ab346bb630c9d7db8efb9f8040a03b325c91b10878b777d67d6" + "532769a638787d1196bc22c885e9b85269c3fc650fdecfc45135bb618127034c" + "3347bbcfc15e55cc979218266a4cae198d146131699ce5bc22aa9102ad951734" + "bc0174e4c93e082cf791be6d13a732de5ab9677e2d1d5ce4265b89646d41a0f4" + "de36102397998fcd5cbc7806c095ae6269660d94abc5b88a2717a633534c2072" + "06703dddcf50ca7e46a2a42877c86a2dc50527e74de080187e8677f84dd362c9" + "bc467385b2fc9b78ce8b589edd1fa1a4e48b1976126635b9009d43de12f7f7a3" + "ce77dfd497d1631c1e5ab524766cd260cd64ddd4dc9adfff338a511b5a99924b" + "c926ca3756d6fcdb09fcd2c332afcdd120894c9a7ce187df1cf23821f1f7a9f1" + "b5fe3893c8808466711c1b55bb7e66b9c6aa2a86811783375a43e1beabb1af33" + "2a5be663818e1e23fd2175cc8dac8a2015dcde6b2e07536712451b14658bbf68" + "8e7ca85479dab486e15e0119f2948ba7ffcaa0ef161b3facb8103fb06f93b428" + "f9d34593e9dd14b2d798494609aa0fddca618145a5d4b8a1819283bc5b7a2bfd" + "beeb5ac6b65fcccfe434071d4624ff0308b5968bf2f0c01b567d212bcaf66054" + "0ba116ff61a951579a83353f2adba41bfd6588ba1fc3f1f889932be6bc0ec00c" + "8c75217782ccea7e9f3ad2dae831487a5fb636d042263d0a0e0438d551da3224" + "30fbac7e14e98c583ec5091c81d8b80eb167cdc4bca0fef9eae7c827852a437d" + default))) + '(keyboard-coding-system (quote utf-8-unix)) + '(paradox-github-token t) + '(text-mode-hook (quote (turn-on-auto-fill text-mode-hook-identify))) + '(show-paren-mode t) + '(which-function-mode t) + '(org-babel-load-languages + (quote ((emacs-lisp . t) + (C . t) + (calc . t) + (ditaa . t) + (gnuplot . t) + (mscgen . t) + (octave . t) + (plantuml . t) + (sh . t) + (haskell . t) + (metapost . t) + (dot . t) + (R . t) + (latex . t) + (tikz . t))))) + +(custom-theme-set-faces + 'rongsong + '(default ((t (:background "gray20" :foreground "white smoke" + :family "Inconsolata LGC" :foundry "unknown" + :slant normal :weight normal :height 125 :width normal)))) + '(helm-header ((t (:background "DeepSkyBlue4" :weight bold)))) + '(helm-selection ((t (:foreground "#141413" :background "#0a9dff" :bold t)))) + '(helm-source-header ((t (:foreground "#0a9dff" :background "#242321" :bold t)))) + '(helm-candidate-number ((t (:foreground "#f4cf86" :background "#45413b" :bold t)))) + '(helm-selection-line ((t (:foreground "#8cffba" :background "#242321" :bold t)))) + '(which-func ((t (:foreground "#8cffba" :background "#242321" :bold t)))) + '(airline-normal-outer ((t (:foreground "#141413" :background "#aeee00")))) + '(airline-normal-inner ((t (:foreground "#f4cf86" :background "#45413b")))) + '(airline-normal-center ((t (:foreground "#8cffba" :background "#242321")))) + '(airline-insert-outer ((t (:foreground "#141413" :background "#0a9dff")))) + '(airline-insert-inner ((t (:foreground "#f4cf86" :background "#005faf")))) + '(airline-insert-center ((t (:foreground "#0a9dff" :background "#242321")))) + '(airline-visual-outer ((t (:foreground "#141413" :background "#ffa724")))) + '(airline-visual-inner ((t (:foreground "#000000" :background "#fade3e")))) + '(airline-visual-center ((t (:foreground "#000000" :background "#b88853")))) + '(airline-replace-outer ((t (:foreground "#141413" :background "#ff9eb8")))) + '(airline-emacs-outer ((t (:foreground "#d7d7ff" :background "#5f00af")))) + '(powerline-inactive1 ((t (:foreground "#45413b" :background "#141413")))) + '(powerline-inactive2 ((t (:foreground "#45413b" :background "#242321")))) + '(mode-line ((t (:background "gray30" :box (:line-width 1 :color "red") + :family "Inconsolata")))) +;; :family "DejaVu Sans")))) + '(mode-line-inactive ((t (:inherit mode-line :foreground "dark gray")))) + '(mode-line-buffer-id ((t (:foreground "#141413" :background "#aeee00" + :box nil :underline nil :overline nil)))) + '(minibuffer-prompt ((t (:background "yellow" :foreground "medium blue" + :box (:line-width -1 :color "red" :style released-button) + :weight bold)))) + '(dired-directory ((t (:foreground "DodgerBlue" :weight bold)))) + '(error ((t (:foreground "deep pink" :weight bold)))) + '(font-lock-builtin-face ((t (:foreground "chartreuse2")))) + '(font-lock-comment-face ((t (:foreground "#Add8e6")))) + '(font-lock-constant-face ((t (:foreground "dodger blue")))) + '(font-lock-doc-face ((t (:foreground "indian red")))) + '(font-lock-function-name-face ((t (:foreground "#Ff00ff")))) + '(font-lock-keyword-face ((t (:foreground "#Ff6347" :weight bold)))) + '(font-lock-preprocessor-face ((t (:foreground "cornflower blue")))) + '(font-lock-string-face ((t (:foreground "light salmon")))) + '(font-lock-type-face ((t (:foreground "#00ff00")))) + '(font-lock-variable-name-face ((t (:foreground "yellow green" :weight bold)))) + '(font-lock-warning-face ((t (:foreground "hot pink")))) + '(header-line ((t (:inverse-video t + :box (:line-width -1 :color "red" + :style released-button))))) + '(highlight ((t (:background "sea green")))) + '(ido-first-match ((t (:foreground "turquoise" :weight bold)))) + '(ido-only-match ((t (:foreground "medium spring green" :weight bold)))) + '(ido-subdir ((t (:inherit dired-directory :weight normal)))) + '(menu ((t (:background "gray30" :foreground "gray70")))) + '(outline-1 ((t (:foreground "cyan1" :weight bold)))) + '(outline-2 ((t (:foreground "SeaGreen1" :weight bold)))) + '(outline-3 ((t (:foreground "cyan3" :weight bold)))) + '(outline-4 ((t (:foreground "SeaGreen3" :weight bold)))) + '(outline-5 ((t (:foreground "LightGoldenrod1" :weight bold)))) + '(outline-6 ((t (:foreground "light salmon" :weight bold)))) + '(outline-7 ((t (:foreground "pale goldenrod" :weight bold)))) + '(outline-8 ((t (:foreground "OliveDrab1" :weight bold)))) + '(region ((t (:background "SeaGreen4")))) + '(scroll-bar ((t (:background "gray20" :foreground "dark turquoise")))) + '(secondary-selection ((t (:background "#333366" :foreground "#f6f3e8")))) + '(show-paren-match ((t (:background "DeepSkyBlue4")))) + '(show-paren-mismatch ((t (:background "dark magenta")))) + '(widget-field ((t (:box (:line-width 2 :color "grey75" :style pressed-button)))))) + +(provide-theme 'rongsong) diff --git a/old-config/rshen-theme.el b/old-config/rshen-theme.el new file mode 100644 index 0000000..d71f671 --- /dev/null +++ b/old-config/rshen-theme.el @@ -0,0 +1,10 @@ +(deftheme rshen + "Created 2016-04-30.") + +(custom-theme-set-variables + 'rshen + '(paradox-github-token t) + '(org-babel-load-languages (quote ((emacs-lisp . t) (C . t) (calc . t) (ditaa . t) (gnuplot . t) (mscgen . t) (octave . t) (plantuml . t) (sh . t) (haskell . t) (metapost . t) (dot . t) (R . t) (latex . t) (tikz . t)))) + '(custom-safe-themes (quote ("da28185f8c6b027359e8469257a7682afcf5ba94e9547720e5ca3939e3ab4efa" "8c75217782ccea7e9f3ad2dae831487a5fb636d042263d0a0e0438d551da3224" "0ba116ff61a951579a83353f2adba41bfd6588ba1fc3f1f889932be6bc0ec00c" "aca326172f6424b702a751dba6f93d633c1b12358faf7d3cdfe8ac618196f189" "450b29ed22abeeac279b7eeea592f4eea810105737716fc29807e1684e729c55" default)))) + +(provide-theme 'rshen) diff --git a/old-config/templates/design.org b/old-config/templates/design.org new file mode 100644 index 0000000..3058bbd --- /dev/null +++ b/old-config/templates/design.org @@ -0,0 +1,165 @@ +#+TITLE: Put the title here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+LATEX_HEADER: \usepackage{tabularx,mythemes} + +#+BEGIN_LATEX +\newcommand\docname{Put the title here} +\newcommand\doctype{Investigation Report} +\newcommand\docversion{0.1} +\newcommand\docauthor{Rongsong Shen} +\newcommand\docupdate{\today} +\newcommand\docstatus{Under Review} +\newcommand\contributors{} +\newcommand\docreviewers{} +\newcommand\circulation{} +\newcommand\projid{} +\newcommand\docdescription{} +\usetikzlibrary{calc, shapes, backgrounds} + +\begin{coverpage}{ibm-logo.png} +\begin{docinfo} +% BEGIN RECEIVE ORGTBL docinfo +% END RECEIVE ORGTBL docinfo +\end{docinfo} +\begin{copyrightnotice} + The materials contained herein are proprietary to Platform Computing and + are presented in draft form for the purposes of your review and + comment. By providing your comments and suggestions to Platform + Computing, you acknowledge that the intellectual property rights in + these materials and in your comments and suggestions regarding the + materials shall vest in and remain the exclusive property of Platform + Computing, for use by Platform Computing in its sole discretion and + without attribution as to the source of any comments or suggestions + received. These materials are not in a final form and are not + intended to be relied upon by you and you specifically affirm that you + will not rely on any statement contained in the materials as being a + definitive position, opinion or statement of Platform Computing. The + trademarks and registered trademarks contained herein are the property + of their respective owners. +\end{copyrightnotice} + +\begin{confidential} + Platform Computing Confidential + - No part of this document may be reproduced, copied or distributed + in any fashion without the express written permission of Platform Computing Corporation.\\ +\end{confidential} + +\end{coverpage} +\ibmpagestyle +\begin{projectinfo} +% BEGIN RECEIVE ORGTBL projectinfo +% END RECEIVE ORGTBL projectinfo +\end{projectinfo} + +\begin{dochistory} +% BEGIN RECEIVE ORGTBL dochistory +% END RECEIVE ORGTBL dochistory +\end{dochistory} + +\begin{comment} +#+ORGTBL: SEND docinfo orgtbl-to-latex :splice t :skip 0 +| *Document Name:* | \docname | +| *Document Version:* | \docversion | +| *Document Status:* | \docstatus | +| *Document Type:* | \doctype | +| *Document Author:* | \docauthor | +| *Last Updated:* | \docupdate | + + +#+ORGTBL: SEND projectinfo orgtbl-to-latex :splice t :skip 0 +|-----------------------+--------------------------| +| *Author* | \docauthor \contributors | +|-----------------------+--------------------------| +| *Reviewers* | \docreviewers | +|-----------------------+--------------------------| +| *Circulation* | \circulation | +|-----------------------+--------------------------| +| *Project Name* | \docname | +|-----------------------+--------------------------| +| *Project No* | \projid | +|-----------------------+--------------------------| +| *Project Description* | \docdescription | +|-----------------------+--------------------------| + +#+ORGTBL: SEND dochistory orgtbl-to-latex :splice t :skip 0 +| 0.1 | \today | \docauthor | Initial Version | +\end{comment} +\newpage +\tableofcontents\newpage +#+END_LATEX + +\newpage + +* Design Requirement + + #+BEGIN_SRC tikz :file require.png :var tikz-libs="mindmap, trees, shadows, positioning" + [mindmap, concept color=green!40,text=black, + every annotation/.style={fill=red!20} + ] + \node [concept] {Design} + child[grow=120,concept color=blue!40] { + node[concept] {Goal} + child[grow=60] { + node[concept] {Goal 1} + } + child[grow=150] { + node[concept] {Goal 2} + } + child[grow=-120] { + node[concept] {Goal 3} + } + } + child[grow=0,concept color=yellow,text=black] { + node[concept] {Assumption} + child[grow=120] { + node[concept] {Assumption 1} + } + child[grow=0] { + node[concept] {Assumption 2} + } + child[grow=-120] { + node[concept] {Assumption 3} + } + } + child[grow=-120,concept color=green] { + node[concept] {Use Cases} + child[grow=0] { + node[concept] {Use case 1} + } + child[grow=120] { + node[concept] {Use Case 2} + } + child[grow=-120] { + node[concept] {Use Case 3} + } + }; + #+END_SRC + + #+RESULTS: + [[file:require.png]] + +** Goals + + +** Assumptions + +** Use Cases + +* Design + +** Design decisions + +** Execution flow + +** Interface design + +** Components design + + # Local Variables: + # org-latex-title-command: "\\relax" + # org-latex-toc-command: "\\relax" + # End: + diff --git a/old-config/templates/lsf-beamer.org b/old-config/templates/lsf-beamer.org new file mode 100644 index 0000000..4852feb --- /dev/null +++ b/old-config/templates/lsf-beamer.org @@ -0,0 +1,44 @@ +#+TITLE: add titile here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+STARTUP: beamer showall +#+OPTIONS: toc:1 H:2 ^:{} + +#+LaTeX_CLASS: beamer +#+LaTeX_CLASS_OPTIONS: [presentation] +#+BEAMER_FRAME_LEVEL: 2 +#+BEAMER_THEME: IBM +#+latex_header: \usepackage[framesassubsections]{beamerprosper} +#+latex_header: \usepackage{fancyvrb} +#+latex_header: \usepackage{listings} +#+latex_header: \usepackage{xcolor} +#+latex_header: \usepackage{bardiag} +#+latex_header: \usepackage{filecontents} +#+BEGIN_LATEX +\newcommand\redtext[1]{ + \textcolor{red}{#1} +} +#+END_LATEX +#+COLUMNS: %35ITEM %10BEAMER_env(Env) %10BEAMER_envargs(Args) %4BEAMER_col(Col) %8BEAMER_extra(Ex) + +* Background + +** Problem Definition and Requirements + +** Benefits and Values + +* Competitors + +* Technical Solutions + +* Current works + +* Future works + +* Demo/Play + +* Others + +** Contact + + Please provide your feedback to shenrs@cn.ibm.com diff --git a/old-config/templates/lsf-fs.org b/old-config/templates/lsf-fs.org new file mode 100644 index 0000000..b435260 --- /dev/null +++ b/old-config/templates/lsf-fs.org @@ -0,0 +1,186 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:3 LaTeX:t +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx,mythemes} + +#+LATEX: \usetikzlibrary{calc, shapes, backgrounds} + +#+BEGIN_LaTeX +\newcommand\projname{Put Project Name Here} +\newcommand\projid{} +\newcommand\productname{LSF} +\newcommand\productversion{9.2} +\newcommand\docname{\projname} +\newcommand\docversion{0.1} +\newcommand\docstatus{Under Review} +\newcommand\doctype{Functional Specification} +\newcommand\docauthor{Rongsong Shen} +\newcommand\docupdate{\today} +\newcommand\contributors{} +\newcommand\docreviewers{} +\newcommand\circulation{Confidential, for internal use only} +\newcommand\docdescription{Add description here} +#+END_LaTeX + +#+BEGIN_LATEX +\begin{coverpage}{ibm-logo.png} +% BEGIN RECEIVE ORGTBL docinfo +% END RECEIVE ORGTBL docinfo +\begin{copyrightnotice} + The materials contained herein are proprietary to Platform Computing and + are presented in draft form for the purposes of your review and + comment. By providing your comments and suggestions to Platform + Computing, you acknowledge that the intellectual property rights in + these materials and in your comments and suggestions regarding the + materials shall vest in and remain the exclusive property of Platform + Computing, for use by Platform Computing in its sole discretion and + without attribution as to the source of any comments or suggestions + received. These materials are not in a final form and are not + intended to be relied upon by you and you specifically affirm that you + will not rely on any statement contained in the materials as being a + definitive position, opinion or statement of Platform Computing. The + trademarks and registered trademarks contained herein are the property + of their respective owners. +\end{copyrightnotice} + +\begin{confidential} + Platform Computing Confidential + - No part of this document may be reproduced, copied or distributed + in any fashion without the express written permission of Platform Computing Corporation.\\ +\end{confidential} + +\end{coverpage} +\ibmpagestyle +\begin{projectinfo} +% BEGIN RECEIVE ORGTBL projectinfo +% END RECEIVE ORGTBL projectinfo +\end{projectinfo} + +\begin{dochistory} +% BEGIN RECEIVE ORGTBL dochistory +% END RECEIVE ORGTBL dochistory +\end{dochistory} +#+END_LATEX + +\newpage +#+LATEX: \tableofcontents +\newpage + +* Setup information :hidden: +#+ORGTBL: SEND docinfo orgtbl-to-latex :splice nil :skip 0 +| *Document Name:* | \docname | +| *Document Version:* | \docversion | +| *Document Status:* | \docstatus | +| *Document Type:* | \doctype | +| *Document Author:* | \docauthor | +| *Last Updated:* | \docupdate | + + +#+ORGTBL: SEND projectinfo orgtbl-to-latex :splice t :skip 0 +|-----------------------+--------------------------| +| *Author* | \docauthor \contributors | +|-----------------------+--------------------------| +| *Reviewers* | \docreviewers | +|-----------------------+--------------------------| +| *Circulation* | \circulation | +|-----------------------+--------------------------| +| *Project Name* | \docname \projname | +|-----------------------+--------------------------| +| *Project No* | \projid | +|-----------------------+--------------------------| +| *Project Description* | \docdescription | +|-----------------------+--------------------------| + + +#+ORGTBL: SEND dochistory orgtbl-to-latex :splice t :skip 0 +|-----+------------+------------+----------------------------| +| 0.2 | \today | \docauthor | using \TeX{}4ht to convert | +| | | | document to other formats | +|-----+------------+------------+----------------------------| +| 0.1 | Feb 2,2015 | \docauthor | Initial Version | +|-----+------------+------------+----------------------------| + +* Introduction + +** Purpose + + This Detailed Requirement Specification is to be used as a guide + for the design and verification of the \textcolor{blue}{\projname} + for \textcolor{blue}{\productname} product release + \textcolor{blue}{\productversion} . This document should be + detailed enough to allow the creation of high level design + documents, test cases and customer documentation. It is intended + for the internal use of Product Management, Development, QA, + Documentation, Professional Services, Support, and agents of IBM. + +** Definitions, Acronyms, Buzzwords And Abbreviations + + +* Specifications + +** Functional Requirements + +*** Summary + +*** Context + +*** Scope + + 1. Scope + + 2. Out Of Scope + +*** Assumptions and Dependencies + +*** Functional Description + + 1. Detail Functional Description + + 2. Interactions + + 3. Criteria + +*** Interface Requirements + + 1. Command line + 2. Configuration + 3. Events File Changes + 4. API Requirements + 5. Installation + 6. PERF Requirement + 7. Licensing Requirements + 8. Multi-head Consideration + 9. ID Requirement + +** Use Cases + +** Non-Functional Requirements + +*** Time, Performance and Throughput + +*** Scalability + +*** Robustness, Reliability and Recovery + +*** Platform(s) Configuration + +*** 3rd Party and External Applications + +*** Administration and Supportability + +*** Security + +*** Migration and Compatibility + + +* References + + + # Local Variables: + # org-latex-title-command: "\\relax" + # org-latex-toc-command: "\\relax" + # End: + diff --git a/old-config/templates/lsf-high-level-design.org b/old-config/templates/lsf-high-level-design.org new file mode 100644 index 0000000..8ee80d4 --- /dev/null +++ b/old-config/templates/lsf-high-level-design.org @@ -0,0 +1,482 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:3 LaTeX:t +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx,mythemes} + +#+LATEX: \usetikzlibrary{calc, shapes, backgrounds} + +#+BEGIN_LaTeX +\newcommand\projname{Put Project Name Here} +\newcommand\projid{} +\newcommand\productname{LSF} +\newcommand\productversion{9.2} +\newcommand\docname{\projname} +\newcommand\docversion{0.1} +\newcommand\docstatus{Under Review} +\newcommand\doctype{Functional Specification} +\newcommand\docauthor{Rongsong Shen} +\newcommand\docupdate{\today} +\newcommand\contributors{} +\newcommand\docreviewers{} +\newcommand\circulation{Confidential, for internal use only} +\newcommand\docdescription{Add description here} +#+END_LaTeX + +#+BEGIN_LATEX +\begin{coverpage}{ibm-logo.png} +% BEGIN RECEIVE ORGTBL docinfo +% END RECEIVE ORGTBL docinfo +\begin{copyrightnotice} + The materials contained herein are proprietary to Platform Computing and + are presented in draft form for the purposes of your review and + comment. By providing your comments and suggestions to Platform + Computing, you acknowledge that the intellectual property rights in + these materials and in your comments and suggestions regarding the + materials shall vest in and remain the exclusive property of Platform + Computing, for use by Platform Computing in its sole discretion and + without attribution as to the source of any comments or suggestions + received. These materials are not in a final form and are not + intended to be relied upon by you and you specifically affirm that you + will not rely on any statement contained in the materials as being a + definitive position, opinion or statement of Platform Computing. The + trademarks and registered trademarks contained herein are the property + of their respective owners. +\end{copyrightnotice} + +\begin{confidential} + Platform Computing Confidential + - No part of this document may be reproduced, copied or distributed + in any fashion without the express written permission of Platform Computing Corporation.\\ +\end{confidential} + +\end{coverpage} +\ibmpagestyle +\begin{projectinfo} +% BEGIN RECEIVE ORGTBL projectinfo +% END RECEIVE ORGTBL projectinfo +\end{projectinfo} + +\begin{dochistory} +% BEGIN RECEIVE ORGTBL dochistory +% END RECEIVE ORGTBL dochistory +\end{dochistory} +#+END_LATEX + +\newpage +#+LATEX: \tableofcontents +\newpage + +* Hide information :hidden: + +#+ORGTBL: SEND docinfo orgtbl-to-latex :splice nil :skip 0 +| *Document Name:* | \docname | +| *Document Version:* | \docversion | +| *Document Status:* | \docstatus | +| *Document Type:* | \doctype | +| *Document Author:* | \docauthor | +| *Last Updated:* | \docupdate | + +#+ORGTBL: SEND projectinfo orgtbl-to-latex :splice t :skip 0 +|-----------------------+--------------------------| +| *Author* | \docauthor \contributors | +|-----------------------+--------------------------| +| *Reviewers* | \docreviewers | +|-----------------------+--------------------------| +| *Circulation* | \circulation | +|-----------------------+--------------------------| +| *Project Name* | \docname \projname | +|-----------------------+--------------------------| +| *Project No* | \projid | +|-----------------------+--------------------------| +| *Project Description* | \docdescription | +|-----------------------+--------------------------| + +#+ORGTBL: SEND dochistory orgtbl-to-latex :splice t :skip 0 +|-----+------------+------------+----------------------------| +| 0.2 | \today | \docauthor | using \TeX{}4ht to convert | +| | | | document to other formats | +|-----+------------+------------+----------------------------| +| 0.1 | Feb 2,2015 | \docauthor | Initial Version | +|-----+------------+------------+----------------------------| + +* Scope + +# This section shall be divided into the following paragraphs. + +** Identification + +# This paragraph shall contain a full identification of the system and +# the software to which this document applies, including, as applicable, +# identification number(s) and name(s), title(s), abbreviation(s), +# version number(s), and release number(s). + +** System overview + +# This paragraph shall briefly state the purpose of the system and the +# software to which this document applies. It shall describe the general +# nature of the system and software; summarize the history of system +# development, operation, and maintenance; identify the project sponsor, +# and developer; and list other relevant documents. + +** Document overview + +# This paragraph shall summarize the purpose and contents of this +# document and shall describe any security or privacy considerations +# associated with its use. + + +* Reference documents + +# This section shall list the number, title, revision, and date of all +# documents referenced in this document (for example, internal documents +# such as functional specifications, marketing requirements documents +# and investigation reports, and external documents such as reference +# guides, user manuals, etc.). + +* System-wide design decisions + +# This section shall be divided into paragraphs as needed to present +# system-wide design decisions, that is, decisions about the system's +# behavioral design (how it will behave, from a user's point of view, in +# meeting its requirements, ignoring internal implementation) and other +# decisions affecting the selection and design of the components that +# make up the system. If all such decisions are explicit in the +# requirements or are deferred to the design of the software units, this +# section shall so state. Design decisions that respond to requirements +# deemed critical, such as those for safety, security, or privacy, shall +# be placed in separate subparagraphs. Design conventions needed to +# understand the design shall be presented or referenced. Examples of +# system-wide design decisions are the following: + +# 1. Design decisions regarding inputs the system will accept and +# outputs it will produce, including interfaces with other systems, +# hardware, software, and users (4.3.x of this document identifies +# topics to be considered in this description). +# 2. Design decisions on system behavior in response to each input or +# condition, including actions to perform, response times and other +# performance characteristics, description of physical systems +# modelled, selected equations/algorithms/rules, and handling of +# disallowed inputs or conditions. +# 3. Design decisions on how databases/data files will appear to the +# user (4.3.x of this document identifies topics to be considered in +# this description). +# 4. Selected approach to meeting safety, security, and privacy +# requirements. +# 5. Other system-wide design decisions made in response to +# requirements, such as selected approach to providing required +# flexibility, availability, and maintainability. + +* Architectural design + +# This section shall be divided into the following paragraphs to +# describe the architectural design. If design information falls into +# more than one paragraph, it may be presented once and referenced from +# other paragraphs. Design conventions needed to understand the design +# shall be presented or referenced. + +** Components + +# This paragraph shall: + +# 1. Identify the software units that make up the system. +# Note: A software unit is an element in the design of a system; for +# example, a major subdivision of a system, a component of that +# subdivision, a class, object, module, function, routine or +# database. Software units may occur at different levels of a +# hierarchy and may consist of other software units. Software units +# in the design may or may not have a one-to-one relationship with +# the code and data entities (routines, procedures, databases, data +# files, etc.) that implement them or with the computer files +# containing those entities. + +# 2. Show the static (``consists of'') relationship(s) of the software +# units. Multiple relationships may be presented, depending on the +# selected software design methodology (for example, in an +# object-oriented design, this paragraph may present the class and +# object structures as well as the modules and process +# architectures). +# 3. State the purpose of each software unit and identify the +# requirements and system design decisions allocated to +# it. (Alternatively, the allocation of requirements may be provided +# in Section 5). +# 4. Identify each software unit's development status/type (such as new +# development, existing design or software to be reused as is, +# existing design or software to be reengineered, software to be +# developed for reuse, etc.) For existing design or software, the +# description shall provide identifying information, such as name, +# version, documentation references, library, etc. +# 5. Describe planned utilization of computer hardware resources (such +# as processor capacity, auxiliary storage capacity, and +# communications/network equipment capacity), if appropriate. +# 6. Identify the program library in which the software that implements +# each software unit is to be placed. + +** Concept of execution + + # This paragraph shall describe the concept of execution among the + # software units. It shall include diagrams and descriptions showing + # the dynamic relationship of the software units, that is, how they + # will interact during operation, including, as applicable: + + # - Flow of execution control, + # - Data flow, + # - Dynamically controlled sequencing, + # - State transition diagrams, + # - Timing diagrams, + # - Priorities among units, + # - Handling of interrupts and signals, + # - Timing/sequencing relationships, + # - Exception and error handling, + # - Concurrent execution, + # - Dynamic allocation/deallocation of memory or other resources, + # - Dynamic creation/deletion of objects, + # - Processes, Tasks, and Other aspects of dynamic behavior. + +** Interface design + + # This paragraph shall be divided into the following subparagraphs to + # describe the interface characteristics of the software units. It + # shall include both interfaces among the software units and their + # interfaces with external entities such as systems, configuration + # items, and users. If part or all of this information is described + # elsewhere, these sources may be referenced. + +*** Interface identification and diagrams + +# **** Interface A + +# This paragraph (beginning with 4.3.2) shall identify an interface, +# briefly identify the interfacing entities, and shall be divided into +# subparagraphs as needed to describe the interface characteristics of +# one or both the interfacing entities. If a given interfacing entity +# is not covered by this document (for example, an external system or +# user) but its interface characteristics need to be mentioned to +# describe interfacing entities that are, these characteristics shall +# be stated as assumptions or as ``When [the entity not covered] does +# this, [the entity that is covered] will ...'' This paragraph may +# reference other documents (such as data dictionaries, standards for +# protocols, and standards for user interfaces) in place of stating +# the information here. The design description shall include the +# following, as applicable, presented in any order suited to the +# information to be provided, and shall note any differences in these +# characteristics from the point of view of the interfacing entities +# (such as different expectations about the size, frequency, or other +# characteristics of data elements): + +# 1. Priority assigned to the interface by interfacing entities +# 2. Type of interface (such as real-time data transfer, storage of +# data, command-line user interface, etc.) to be implemented +# 3. Characteristics of individual data elements that interfacing +# entity(ies) will provide, store, send, access, receive, etc., +# such as: +# - Technical name (e.g., variable or field name in code or +# database), non-technical name, or other identifier +# - Data type (alphanumeric, integer, etc.) +# - Size and format +# - Units of measurement +# - Range or enumeration of possible values +# - Accuracy and precision +# - Priority, timing, frequency, volume, sequencing, and other +# constraints, such as whether the data element may be updated +# and whether business rules apply +# - Security and privacy constraints +# - Sources (setting/sending entities) and recipients +# (using/receiving entities) + +# 4. Characteristics of data element assemblies (records, messages, +# files, arrays, displays, reports, etc.) that the interfacing +# entity(ies) will provide, store, send, access, receive, etc., +# such as: +# - Technical name (e.g., record or data structure name in code or +# database), non-technical name, or other identifier +# - Data elements in the assembly and their structure (number, +# order, grouping) +# - Medium (such as disk) and structure of data elements/assemblies +# on the medium +# - Visual and auditory characteristics of displays and other +# outputs (such as colours, layouts, fonts, icons and other +# display elements, beeps, lights) +# - Relationships among assemblies, such as sorting/access +# characteristics +# - Priority, timing, frequency, volume, sequencing, and other +# constraints, such as whether the data assembly may be updated +# and whether business rules apply +# - Security and privacy constraints +# - Sources (setting/sending entities) and recipients +# (using/receiving entities) + +# 5. Characteristics of communication methods that the interfacing +# entity(ies) will use for interface, such as: +# - Identifier +# - Communication links/bands/frequencies/media and their +# characteristics +# - Message formatting +# - Flow control (such as sequence numbering and buffer allocation) +# - Data transfer rate, whether periodic/aperiodic, and interval +# between transfers +# - Routing, addressing, and naming conventions +# - Transmission services, including priority and grade +# - Safety/security/privacy considerations, such as encryption, +# user authentication, compartmentalization, and auditing + +# 6. Characteristics of protocols the interfacing entity(ies) will use +# for the interface, such as: +# - Identifier +# - Priority/layer of the protocol +# - Packeting, including fragmentation and reassembly, routing, and +# addressing +# - Legality checks, error control, and recovery procedures +# - Synchronization, including connection establishment, +# maintenance, termination +# - Status, identification, and other reporting features + +# 7. Other characteristics + +* Use case study + + # Run use cases through the proposed architecture and interface design + # to see whether it addresses appropriately the quality dimensions of + # the system, such as: + + # - Functionality? + # - Performance requirements or expectations? + # - System availability? + # - System operability? + # - Resource constraints and limitations? + # - Operational and data integrity? + # - Security and controls? + # - Usability? + # - Maintainability? Debugging? + + # Use negative and worse cases as well. + +* Performance analysis + + # Analyze the performance of the proposed system, including (but not + # limited to): + + # - System resource usage (CPU, Memory) + # - User query time + # - Job submission time + # - System response time + # - System throughput + # - Communication overhead, latency I/O rate + + # Apply use cases (including negative and worse ones) in performance + # analysis. + +* Requirement traceability + + # This section shall contain: + + # 1. Traceability from each software unit in this document to the + # requirements allocated to it. (Alternatively, this traceability + # may be provided in 4.1.) + + # 2. Traceability from each requirement to the software units to which + # it is allocated. + +* Checklist + + # To avoid loose ends and ensure project quality, check the following + # questions while you start low-level design and implementation. + + # - Have you run use cases against the design successfully? + # - Have you done performance analysis for the design? + # - Does the implementation consider platform-dependency (if + # applicable)? + # - Is the acceptance test plan inspected against FS? + # - Is the integrate test plan ready for inspection? + +* Notes + + # This section shall contain any general information that aids in + # understanding this document (e.g., background information, glossary, + # rationale). This section shall include an alphabetical listing of + # all acronyms, abbreviations, and their meanings as used in this + # document and a list of any terms and definitions needed to + # understand this document. + +* Unit test plan and integration test considerations + +** Unit test plan + +# Document the test cases that will be used for unit +# tests. Documented test cases are important because we need them at +# least for the coverage analysis. +# *Some guidelines* + +# - Can use the above LL implementation design and codes as hints to +# figure out the test cases, trying to cover all the branches and +# functions in the new changes of the project. + +# - General description of how to execute the testing scnerios; not +# necessary to give the detail procedures. + +# - Can use pseudo code to describe combination testing; e.g., + +# #+BEGIN_VERSE +# for Ioption = -I, -Ip +# for io = -i, -o, -e +# bsub {Ioption} {io} +# #+END_VERSE + +# - Internal State Verification + +# Test internal state change are correct. This may be done by +# running certain scenerios, and then dumping the data structures +# to syslog. + +# - Try to give an indication of the percentage testing coverage by +# considering all the combinations, but only executing some of +# them. + +** Integration test considerations + + # - Scalability + + # Test number of hosts, jobs, users, etc. + + # - Performance + + # Testcases for performance. + + # - Regression + + # Identify which existing regression testcases must be rerun. + + # - Platform-Dependenent + + # Identifiy platform specific testcases. + + # - Faulty Tolerance + + # Test how well the feature works under faulty conditions (e.g., + # host crash). + + # - Security + + # Test any security issues related to the feature. + + # - Usability + + # Describe some testcases which test how user friendly the feature + # is. + +* Appendixes + +# Appendixes may be used to provide information published separately for +# convenience in document maintenance (e.g., charts). As applicable, +# each appendix shall be referenced in the main body of the document +# where the data would normally have been provided. Appendixes shall be +# lettered alphabetically (A, B, etc.). + + +# Local Variables: +# org-latex-title-command: "\\relax" +# org-latex-toc-command: "\\relax" +# End: + diff --git a/old-config/templates/lsf-investigation.org b/old-config/templates/lsf-investigation.org new file mode 100644 index 0000000..9abc09a --- /dev/null +++ b/old-config/templates/lsf-investigation.org @@ -0,0 +1,153 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+LATEX_HEADER: \usepackage{tabularx,mythemes} + +#+BEGIN_LATEX +\newcommand\docname{Put the title of project here} +\newcommand\doctype{Investigation Report} +\newcommand\docversion{0.1} +\newcommand\docauthor{Rongsong Shen} +\newcommand\docupdate{\today} +\newcommand\docstatus{Under Review} +\newcommand\contributors{} +\newcommand\docreviewers{} +\newcommand\circulation{} +\newcommand\projid{} +\newcommand\docdescription{} +\usetikzlibrary{calc, shapes, backgrounds} + +\begin{coverpage}{ibm-logo.png} +% BEGIN RECEIVE ORGTBL docinfo +% END RECEIVE ORGTBL docinfo +\begin{copyrightnotice} + The materials contained herein are proprietary to Platform Computing and + are presented in draft form for the purposes of your review and + comment. By providing your comments and suggestions to Platform + Computing, you acknowledge that the intellectual property rights in + these materials and in your comments and suggestions regarding the + materials shall vest in and remain the exclusive property of Platform + Computing, for use by Platform Computing in its sole discretion and + without attribution as to the source of any comments or suggestions + received. These materials are not in a final form and are not + intended to be relied upon by you and you specifically affirm that you + will not rely on any statement contained in the materials as being a + definitive position, opinion or statement of Platform Computing. The + trademarks and registered trademarks contained herein are the property + of their respective owners. +\end{copyrightnotice} + +\begin{confidential} + Platform Computing Confidential + - No part of this document may be reproduced, copied or distributed + in any fashion without the express written permission of Platform Computing Corporation.\\ +\end{confidential} + +\end{coverpage} +\ibmpagestyle +\begin{projectinfo} +% BEGIN RECEIVE ORGTBL projectinfo +% END RECEIVE ORGTBL projectinfo +\end{projectinfo} + +\begin{dochistory} +% BEGIN RECEIVE ORGTBL dochistory +% END RECEIVE ORGTBL dochistory +\end{dochistory} + +\begin{comment} +#+ORGTBL: SEND docinfo orgtbl-to-latex :splice nil :skip 0 +| *Document Name:* | \docname | +| *Document Version:* | \docversion | +| *Document Status:* | \docstatus | +| *Document Type:* | \doctype | +| *Document Author:* | \docauthor | +| *Last Updated:* | \docupdate | + + +#+ORGTBL: SEND projectinfo orgtbl-to-latex :splice t :skip 0 +|-----------------------+--------------------------| +| *Author* | \docauthor \contributors | +|-----------------------+--------------------------| +| *Reviewers* | \docreviewers | +|-----------------------+--------------------------| +| *Circulation* | \circulation | +|-----------------------+--------------------------| +| *Project Name* | \docname | +|-----------------------+--------------------------| +| *Project No* | \projid | +|-----------------------+--------------------------| +| *Project Description* | \docdescription | +|-----------------------+--------------------------| + +#+ORGTBL: SEND dochistory orgtbl-to-latex :splice t :skip 0 +| 0.1 | \today | \docauthor | Initial Version | +\end{comment} +\newpage +\tableofcontents\newpage +#+END_LATEX + +\newpage +* Requirement + +** Problem Definition and Requirement(DEV) + + - What're problems that customer is facing? + + - What're the requirements for this project to solve above problem? + + - Where to find out the reference information(RFC, PRD, problem + ticks,...)? + +** High Level End to End Use Cases(DEV) + +** Scope(DEV) + +*** In Scope + +*** Out of Scope + +** Platform/Operating Systems(DEV) + +** Deliverable(DEV) + +** Assumptions and Dependencies(DEV) + +** Hardware & Software Requirements(DEV) + +** Document Requirements(ID) + +* Solution + +** High Level Design(DEV) + +** Concept of execution(DEV) + +** Feature Interaction(DEV, QA) + +* Estimation(DEV, QA, ID) + +** WBS Tasks +|---------+-------------+------------+---------------------+---------------| +| Task Id | Description | Dependency | Completion Criteria | Efforts(Days) | +|---------+-------------+------------+---------------------+---------------| +| | | | | | +| Buffer | | | | | +|---------+-------------+------------+---------------------+---------------| +| Total | | | | | +|---------+-------------+------------+---------------------+---------------| + +** Risks(DEV, QA, ID) + +** Additional Notes + +* References + + + # Local Variables: + # org-latex-title-command: "\\relax" + # org-latex-toc-command: "\\relax" + # End: + diff --git a/old-config/templates/my-scribble-template.scrbl b/old-config/templates/my-scribble-template.scrbl new file mode 100644 index 0000000..ae8263b --- /dev/null +++ b/old-config/templates/my-scribble-template.scrbl @@ -0,0 +1,16 @@ +#lang scribble/base + +@author+email["Rongsong Shen" "rongsong.shen@gmail.com"] + +@title{Add title here} + +@section{This is section 1} + +text of section 1 + +@section{This is section 2} + +@; Local Variables: +@; buffer-file-coding-system: utf-8-unix +@; End: + diff --git a/old-config/templates/personal.org b/old-config/templates/personal.org new file mode 100644 index 0000000..a2d3783 --- /dev/null +++ b/old-config/templates/personal.org @@ -0,0 +1,12 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: rongsong.shen@gmail.com +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+LATEX_HEADER: \usepackage{tabularx} + +* start to write document + +# Local Variables: +# End: + diff --git a/old-config/templates/personal_zh.org b/old-config/templates/personal_zh.org new file mode 100644 index 0000000..cc09010 --- /dev/null +++ b/old-config/templates/personal_zh.org @@ -0,0 +1,21 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: rongsong.shen@gmail.com +#+LANGUAGE: zh-CN +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+LATEX_HEADER: \usepackage{tabularx} +#+LATEX_HEADER: \usepackage{xeCJK} +#+LATEX_HEADER: \setCJKmainfont{ZhunYuan} + +* 从这开始 + + 你好 + +# Please do not change following if you +# do not known what you really want +# Local Variables: +# buffer-file-coding-system: utf-8-unix +# org-tex-engine: "xelatex2" +# End: + diff --git a/templates/beamer_template.ibm.org b/templates/beamer_template.ibm.org new file mode 100644 index 0000000..6d8cf14 --- /dev/null +++ b/templates/beamer_template.ibm.org @@ -0,0 +1,88 @@ +#+TITLE: Beamer Template Document +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+STARTUP: beamer showall +#+OPTIONS: toc:1 H:2 ^:{} +#+EXCLUDE_TAGS: hidden + +#+LaTeX_CLASS: beamer +#+LaTeX_CLASS_OPTIONS: [presentation] +#+BEAMER_THEME: ibmbrl +#+BEAMER_FRAME_LEVEL: 2 + +#+COLUMNS: %35ITEM %10BEAMER_env(Env) %10BEAMER_envargs(Args) %4BEAMER_col(Col) %8BEAMER_extra(Ex) + +* Prepare + +** Notes + + This is a very simple template of using beamer class in EMACS ORG mode. + +** Check hardware + + Please check whether your system meets: + - Ubuntu 13.04 or higher version + - More than 8G memory + - More than 100M disk space + +** Download source code + + You can get source code from http://www.abc.net/project/y + +** Unpack source + + run following command to extract source code: +#+BEGIN_EXAMPLE + gzip -dc abc.tar.gz |tar xvf - +#+END_EXAMPLE + +* Configuration + +** Run autoconf + + You can run following command to configure the source code: + +#+BEGIN_EXAMPLE + cd abc + ./configure --with-abc --without-gx +#+END_EXAMPLE + +* Compile + +** Run make + + You can use following to build: + +#+BEGIN_EXAMPLE + make +#+END_EXAMPLE + +* Install + +** Run install + + do install with: +#+BEGIN_EXAMPLE + sudo make install +#+END_EXAMPLE + +* Test + +** Create simple + + create you first abc as following: +#+BEGIN_EXAMPLE + # do nothing +#+END_EXAMPLE +** do test + + run test +#+BEGIN_EXAMPLE + abc test.app +#+END_EXAMPLE + +* Others + +** Contact + + please contact to shenrs@cn.ibm.com diff --git a/templates/design.org b/templates/design.org new file mode 100644 index 0000000..33e358a --- /dev/null +++ b/templates/design.org @@ -0,0 +1,111 @@ +#+TITLE: Put the title here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx} + +#+LATEX: \usetikzlibrary{calc, shapes, backgrounds} + +* DOCUMENT METADATA :hidden: +:PROPERTIES: +:THEME: mythemes +:REVIEWERS: Dog Wang +:VERSION: 1.0 +:STATUS: Under Review +:CONTRIBUTORS: +:TYPE: Design +:END: + +#+NAME: document-history +|-----+-------------+---------------+-----------------| +| 1.0 | Jul 17,2016 | Rongsong Shen | Initial version | +|-----+-------------+---------------+-----------------| + + +* Design Requirement + + #+BEGIN_SRC tikz :file require.png :var tikz-libs="mindmap, trees, shadows, positioning" + [mindmap, concept color=green!40,text=black, + every annotation/.style={fill=red!20} + ] + \node [concept] {Design} + child[grow=120,concept color=blue!40] { + node[concept] {Goal} + child[grow=60] { + node[concept] {Goal 1} + } + child[grow=150] { + node[concept] {Goal 2} + } + child[grow=-120] { + node[concept] {Goal 3} + } + } + child[grow=0,concept color=yellow,text=black] { + node[concept] {Assumption} + child[grow=120] { + node[concept] {Assumption 1} + } + child[grow=0] { + node[concept] {Assumption 2} + } + child[grow=-120] { + node[concept] {Assumption 3} + } + } + child[grow=-120,concept color=green] { + node[concept] {Use Cases} + child[grow=0] { + node[concept] {Use case 1} + } + child[grow=120] { + node[concept] {Use Case 2} + } + child[grow=-120] { + node[concept] {Use Case 3} + } + }; + #+END_SRC + + #+RESULTS: + [[file:require.png]] + +** Goals + + +** Assumptions + +** Use Cases + +* Design + +** Design decisions + +** Execution flow + +** Interface design + +** Components design + +#+BEGIN_SRC metapost :file ex.png + def midpoint(expr a,b) = 0.5[a,b] enddef; + u=1cm; + z0=(0,0); + z1=(2u,2u); + z2=(3u,0); + z3=(0,3u); + z4=(4u,4u); + draw z0--z1--z2--z3--z4--cycle; + draw midpoint(z0,z1){dir 0} .. midpoint(z1,z2){dir 90} + .. midpoint(z2,z3){dir 180}..midpoint(z3,z4){dir 270} + .. midpoint(z4,z0){dir 0} ..{dir 45}cycle; +#+END_SRC + +#+RESULTS: +[[file:ex.png]] + +# Local Variables: +# End: + diff --git a/templates/lsf-fs.org b/templates/lsf-fs.org new file mode 100644 index 0000000..3cd35d7 --- /dev/null +++ b/templates/lsf-fs.org @@ -0,0 +1,104 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:3 LaTeX:t +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx} + +#+LATEX: \usetikzlibrary{calc, shapes, backgrounds} + +* DOCUMENT METADATA :hidden: +:PROPERTIES: +:THEME: mythemes +:REVIEWERS: Dog Wang +:VERSION: 1.0 +:STATUS: Under Review +:CONTRIBUTORS: +:TYPE: Functional Specification +:END: + +#+NAME: document-history +|-----+-------------+---------------+-----------------| +| 1.0 | Jul 17,2016 | Rongsong Shen | Initial version | +|-----+-------------+---------------+-----------------| + +* Introduction + +** Purpose + + This Detailed Requirement Specification is to be used as a guide + for the design and verification of the \textcolor{blue}{\projname} + for \textcolor{blue}{\productname} product release + \textcolor{blue}{\productversion} . This document should be + detailed enough to allow the creation of high level design + documents, test cases and customer documentation. It is intended + for the internal use of Product Management, Development, QA, + Documentation, Professional Services, Support, and agents of IBM. + +** Definitions, Acronyms, Buzzwords And Abbreviations + + +* Specifications + +** Functional Requirements + +*** Summary + +*** Context + +*** Scope + + 1. Scope + + 2. Out Of Scope + +*** Assumptions and Dependencies + +*** Functional Description + + 1. Detail Functional Description + + 2. Interactions + + 3. Criteria + +*** Interface Requirements + + 1. Command line + 2. Configuration + 3. Events File Changes + 4. API Requirements + 5. Installation + 6. PERF Requirement + 7. Licensing Requirements + 8. Multi-head Consideration + 9. ID Requirement + +** Use Cases + +** Non-Functional Requirements + +*** Time, Performance and Throughput + +*** Scalability + +*** Robustness, Reliability and Recovery + +*** Platform(s) Configuration + +*** 3rd Party and External Applications + +*** Administration and Supportability + +*** Security + +*** Migration and Compatibility + + +* References + + + # Local Variables: + # End: + diff --git a/templates/lsf-high-level-design.org b/templates/lsf-high-level-design.org new file mode 100644 index 0000000..7e1deb0 --- /dev/null +++ b/templates/lsf-high-level-design.org @@ -0,0 +1,401 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:3 LaTeX:t +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx} + +#+LATEX: \usetikzlibrary{calc, shapes, backgrounds} + +* DOCUMENT METADATA :hidden: +:PROPERTIES: +:THEME: mythemes +:REVIEWERS: Dog Wang +:VERSION: 1.0 +:STATUS: Under Review +:CONTRIBUTORS: +:TYPE: Functional Specification +:END: + +#+NAME: document-history +|-----+-------------+---------------+-----------------| +| 1.0 | Jul 17,2016 | Rongsong Shen | Initial version | +|-----+-------------+---------------+-----------------| + +* Scope + +# This section shall be divided into the following paragraphs. + +** Identification + +# This paragraph shall contain a full identification of the system and +# the software to which this document applies, including, as applicable, +# identification number(s) and name(s), title(s), abbreviation(s), +# version number(s), and release number(s). + +** System overview + +# This paragraph shall briefly state the purpose of the system and the +# software to which this document applies. It shall describe the general +# nature of the system and software; summarize the history of system +# development, operation, and maintenance; identify the project sponsor, +# and developer; and list other relevant documents. + +** Document overview + +# This paragraph shall summarize the purpose and contents of this +# document and shall describe any security or privacy considerations +# associated with its use. + + +* Reference documents + +# This section shall list the number, title, revision, and date of all +# documents referenced in this document (for example, internal documents +# such as functional specifications, marketing requirements documents +# and investigation reports, and external documents such as reference +# guides, user manuals, etc.). + +* System-wide design decisions + +# This section shall be divided into paragraphs as needed to present +# system-wide design decisions, that is, decisions about the system's +# behavioral design (how it will behave, from a user's point of view, in +# meeting its requirements, ignoring internal implementation) and other +# decisions affecting the selection and design of the components that +# make up the system. If all such decisions are explicit in the +# requirements or are deferred to the design of the software units, this +# section shall so state. Design decisions that respond to requirements +# deemed critical, such as those for safety, security, or privacy, shall +# be placed in separate subparagraphs. Design conventions needed to +# understand the design shall be presented or referenced. Examples of +# system-wide design decisions are the following: + +# 1. Design decisions regarding inputs the system will accept and +# outputs it will produce, including interfaces with other systems, +# hardware, software, and users (4.3.x of this document identifies +# topics to be considered in this description). +# 2. Design decisions on system behavior in response to each input or +# condition, including actions to perform, response times and other +# performance characteristics, description of physical systems +# modelled, selected equations/algorithms/rules, and handling of +# disallowed inputs or conditions. +# 3. Design decisions on how databases/data files will appear to the +# user (4.3.x of this document identifies topics to be considered in +# this description). +# 4. Selected approach to meeting safety, security, and privacy +# requirements. +# 5. Other system-wide design decisions made in response to +# requirements, such as selected approach to providing required +# flexibility, availability, and maintainability. + +* Architectural design + +# This section shall be divided into the following paragraphs to +# describe the architectural design. If design information falls into +# more than one paragraph, it may be presented once and referenced from +# other paragraphs. Design conventions needed to understand the design +# shall be presented or referenced. + +** Components + +# This paragraph shall: + +# 1. Identify the software units that make up the system. +# Note: A software unit is an element in the design of a system; for +# example, a major subdivision of a system, a component of that +# subdivision, a class, object, module, function, routine or +# database. Software units may occur at different levels of a +# hierarchy and may consist of other software units. Software units +# in the design may or may not have a one-to-one relationship with +# the code and data entities (routines, procedures, databases, data +# files, etc.) that implement them or with the computer files +# containing those entities. + +# 2. Show the static (``consists of'') relationship(s) of the software +# units. Multiple relationships may be presented, depending on the +# selected software design methodology (for example, in an +# object-oriented design, this paragraph may present the class and +# object structures as well as the modules and process +# architectures). +# 3. State the purpose of each software unit and identify the +# requirements and system design decisions allocated to +# it. (Alternatively, the allocation of requirements may be provided +# in Section 5). +# 4. Identify each software unit's development status/type (such as new +# development, existing design or software to be reused as is, +# existing design or software to be reengineered, software to be +# developed for reuse, etc.) For existing design or software, the +# description shall provide identifying information, such as name, +# version, documentation references, library, etc. +# 5. Describe planned utilization of computer hardware resources (such +# as processor capacity, auxiliary storage capacity, and +# communications/network equipment capacity), if appropriate. +# 6. Identify the program library in which the software that implements +# each software unit is to be placed. + +** Concept of execution + + # This paragraph shall describe the concept of execution among the + # software units. It shall include diagrams and descriptions showing + # the dynamic relationship of the software units, that is, how they + # will interact during operation, including, as applicable: + + # - Flow of execution control, + # - Data flow, + # - Dynamically controlled sequencing, + # - State transition diagrams, + # - Timing diagrams, + # - Priorities among units, + # - Handling of interrupts and signals, + # - Timing/sequencing relationships, + # - Exception and error handling, + # - Concurrent execution, + # - Dynamic allocation/deallocation of memory or other resources, + # - Dynamic creation/deletion of objects, + # - Processes, Tasks, and Other aspects of dynamic behavior. + +** Interface design + + # This paragraph shall be divided into the following subparagraphs to + # describe the interface characteristics of the software units. It + # shall include both interfaces among the software units and their + # interfaces with external entities such as systems, configuration + # items, and users. If part or all of this information is described + # elsewhere, these sources may be referenced. + +*** Interface identification and diagrams + +# **** Interface A + +# This paragraph (beginning with 4.3.2) shall identify an interface, +# briefly identify the interfacing entities, and shall be divided into +# subparagraphs as needed to describe the interface characteristics of +# one or both the interfacing entities. If a given interfacing entity +# is not covered by this document (for example, an external system or +# user) but its interface characteristics need to be mentioned to +# describe interfacing entities that are, these characteristics shall +# be stated as assumptions or as ``When [the entity not covered] does +# this, [the entity that is covered] will ...'' This paragraph may +# reference other documents (such as data dictionaries, standards for +# protocols, and standards for user interfaces) in place of stating +# the information here. The design description shall include the +# following, as applicable, presented in any order suited to the +# information to be provided, and shall note any differences in these +# characteristics from the point of view of the interfacing entities +# (such as different expectations about the size, frequency, or other +# characteristics of data elements): + +# 1. Priority assigned to the interface by interfacing entities +# 2. Type of interface (such as real-time data transfer, storage of +# data, command-line user interface, etc.) to be implemented +# 3. Characteristics of individual data elements that interfacing +# entity(ies) will provide, store, send, access, receive, etc., +# such as: +# - Technical name (e.g., variable or field name in code or +# database), non-technical name, or other identifier +# - Data type (alphanumeric, integer, etc.) +# - Size and format +# - Units of measurement +# - Range or enumeration of possible values +# - Accuracy and precision +# - Priority, timing, frequency, volume, sequencing, and other +# constraints, such as whether the data element may be updated +# and whether business rules apply +# - Security and privacy constraints +# - Sources (setting/sending entities) and recipients +# (using/receiving entities) + +# 4. Characteristics of data element assemblies (records, messages, +# files, arrays, displays, reports, etc.) that the interfacing +# entity(ies) will provide, store, send, access, receive, etc., +# such as: +# - Technical name (e.g., record or data structure name in code or +# database), non-technical name, or other identifier +# - Data elements in the assembly and their structure (number, +# order, grouping) +# - Medium (such as disk) and structure of data elements/assemblies +# on the medium +# - Visual and auditory characteristics of displays and other +# outputs (such as colours, layouts, fonts, icons and other +# display elements, beeps, lights) +# - Relationships among assemblies, such as sorting/access +# characteristics +# - Priority, timing, frequency, volume, sequencing, and other +# constraints, such as whether the data assembly may be updated +# and whether business rules apply +# - Security and privacy constraints +# - Sources (setting/sending entities) and recipients +# (using/receiving entities) + +# 5. Characteristics of communication methods that the interfacing +# entity(ies) will use for interface, such as: +# - Identifier +# - Communication links/bands/frequencies/media and their +# characteristics +# - Message formatting +# - Flow control (such as sequence numbering and buffer allocation) +# - Data transfer rate, whether periodic/aperiodic, and interval +# between transfers +# - Routing, addressing, and naming conventions +# - Transmission services, including priority and grade +# - Safety/security/privacy considerations, such as encryption, +# user authentication, compartmentalization, and auditing + +# 6. Characteristics of protocols the interfacing entity(ies) will use +# for the interface, such as: +# - Identifier +# - Priority/layer of the protocol +# - Packeting, including fragmentation and reassembly, routing, and +# addressing +# - Legality checks, error control, and recovery procedures +# - Synchronization, including connection establishment, +# maintenance, termination +# - Status, identification, and other reporting features + +# 7. Other characteristics + +* Use case study + + # Run use cases through the proposed architecture and interface design + # to see whether it addresses appropriately the quality dimensions of + # the system, such as: + + # - Functionality? + # - Performance requirements or expectations? + # - System availability? + # - System operability? + # - Resource constraints and limitations? + # - Operational and data integrity? + # - Security and controls? + # - Usability? + # - Maintainability? Debugging? + + # Use negative and worse cases as well. + +* Performance analysis + + # Analyze the performance of the proposed system, including (but not + # limited to): + + # - System resource usage (CPU, Memory) + # - User query time + # - Job submission time + # - System response time + # - System throughput + # - Communication overhead, latency I/O rate + + # Apply use cases (including negative and worse ones) in performance + # analysis. + +* Requirement traceability + + # This section shall contain: + + # 1. Traceability from each software unit in this document to the + # requirements allocated to it. (Alternatively, this traceability + # may be provided in 4.1.) + + # 2. Traceability from each requirement to the software units to which + # it is allocated. + +* Checklist + + # To avoid loose ends and ensure project quality, check the following + # questions while you start low-level design and implementation. + + # - Have you run use cases against the design successfully? + # - Have you done performance analysis for the design? + # - Does the implementation consider platform-dependency (if + # applicable)? + # - Is the acceptance test plan inspected against FS? + # - Is the integrate test plan ready for inspection? + +* Notes + + # This section shall contain any general information that aids in + # understanding this document (e.g., background information, glossary, + # rationale). This section shall include an alphabetical listing of + # all acronyms, abbreviations, and their meanings as used in this + # document and a list of any terms and definitions needed to + # understand this document. + +* Unit test plan and integration test considerations + +** Unit test plan + +# Document the test cases that will be used for unit +# tests. Documented test cases are important because we need them at +# least for the coverage analysis. +# *Some guidelines* + +# - Can use the above LL implementation design and codes as hints to +# figure out the test cases, trying to cover all the branches and +# functions in the new changes of the project. + +# - General description of how to execute the testing scnerios; not +# necessary to give the detail procedures. + +# - Can use pseudo code to describe combination testing; e.g., + +# #+BEGIN_VERSE +# for Ioption = -I, -Ip +# for io = -i, -o, -e +# bsub {Ioption} {io} +# #+END_VERSE + +# - Internal State Verification + +# Test internal state change are correct. This may be done by +# running certain scenerios, and then dumping the data structures +# to syslog. + +# - Try to give an indication of the percentage testing coverage by +# considering all the combinations, but only executing some of +# them. + +** Integration test considerations + + # - Scalability + + # Test number of hosts, jobs, users, etc. + + # - Performance + + # Testcases for performance. + + # - Regression + + # Identify which existing regression testcases must be rerun. + + # - Platform-Dependenent + + # Identifiy platform specific testcases. + + # - Faulty Tolerance + + # Test how well the feature works under faulty conditions (e.g., + # host crash). + + # - Security + + # Test any security issues related to the feature. + + # - Usability + + # Describe some testcases which test how user friendly the feature + # is. + +* Appendixes + +# Appendixes may be used to provide information published separately for +# convenience in document maintenance (e.g., charts). As applicable, +# each appendix shall be referenced in the main body of the document +# where the data would normally have been provided. Appendixes shall be +# lettered alphabetically (A, B, etc.). + + +# Local Variables: +# End: + diff --git a/templates/lsf-investigation.org b/templates/lsf-investigation.org new file mode 100644 index 0000000..4a82d0c --- /dev/null +++ b/templates/lsf-investigation.org @@ -0,0 +1,82 @@ +#+TITLE: Put the title of project here +#+AUTHOR: Rongsong Shen +#+EMAIL: shenrs@cn.ibm.com +#+OPTIONS: ^:{} H:2 +#+STARTUP: showall +#+EXCLUDE_TAGS: hidden +#+LATEX_HEADER: \usepackage{tabularx} + +* DOCUMENT METADATA :hidden: +:PROPERTIES: +:THEME: mythemes +:REVIEWERS: Dog Wang +:VERSION: 1.0 +:STATUS: Under Review +:CONTRIBUTORS: +:TYPE: Functional Specification +:END: + +#+NAME: document-history +|-----+-------------+---------------+-----------------| +| 1.0 | Jul 17,2016 | Rongsong Shen | Initial version | +|-----+-------------+---------------+-----------------| + +* Requirement + +** Problem Definition and Requirement(DEV) + + - What're problems that customer is facing? + + - What're the requirements for this project to solve above problem? + + - Where to find out the reference information(RFC, PRD, problem + ticks,...)? + +** High Level End to End Use Cases(DEV) + +** Scope(DEV) + +*** In Scope + +*** Out of Scope + +** Platform/Operating Systems(DEV) + +** Deliverable(DEV) + +** Assumptions and Dependencies(DEV) + +** Hardware & Software Requirements(DEV) + +** Document Requirements(ID) + +* Solution + +** High Level Design(DEV) + +** Concept of execution(DEV) + +** Feature Interaction(DEV, QA) + +* Estimation(DEV, QA, ID) + +** WBS Tasks +|---------+-------------+------------+---------------------+---------------| +| Task Id | Description | Dependency | Completion Criteria | Efforts(Days) | +|---------+-------------+------------+---------------------+---------------| +| | | | | | +| Buffer | | | | | +|---------+-------------+------------+---------------------+---------------| +| Total | | | | | +|---------+-------------+------------+---------------------+---------------| + +** Risks(DEV, QA, ID) + +** Additional Notes + +* References + + + # Local Variables: + # End: + diff --git a/templates/org-html-themes/.gitignore b/templates/org-html-themes/.gitignore new file mode 100644 index 0000000..62a50a1 --- /dev/null +++ b/templates/org-html-themes/.gitignore @@ -0,0 +1,5 @@ +setup/theme-bigblow-local-abs.setup +setup/theme-readtheorg-local-abs.setup +demo/mbacou.org +demo/cdominik-muziek2.org +demo/dev.org diff --git a/templates/org-html-themes/README.html b/templates/org-html-themes/README.html new file mode 100644 index 0000000..e8665f7 --- /dev/null +++ b/templates/org-html-themes/README.html @@ -0,0 +1,775 @@ + + + + + + +How to export Org mode files into awesome HTML in 2 minutes + + + + + + + + + + + + + +
+

How to export Org mode files into awesome HTML in 2 minutes

+ + +:license-gpl-blue.svg + + +btn_donate_LG.gif + + +
+

1 Overview

+
+
+

1.1 Description

+
+

+Though you can easily override CSS stylesheets and add your own HTML themes, we +can say (or write) that Org mode provides a basic HTML support. +

+ +

+Org-HMTL themes is an open source framework for providing you with a list of +very nice (cross-browser) themes for all your Org documents. Use them to style +your docs, and your colleagues will come up to tell you that you are a genius! +

+ +

+Share this content by tweeting this page: +

+ + + + +

+Follow f_niessen on Twitter for updates on Org-HTML themes! +

+
+
+ +
+

1.2 Requirements

+
+

+Org mode version 8 (or later) is required. +

+ +

+If such a version is not bundled with your Emacs, install one from ELPA. +

+
+
+
+ +
+

2 Quotations

+
+
+

2.1 About Bigblow

+
+

+“Very very nice, I enjoy it a lot.”
+– Ista Zahn +

+ +

+“This is awesome. I love it!”
+– Rainer M Krug +

+ +

+“This is awesome!!”
+– Mehul Sanghvi +

+ +

+“This very nice html theme. […] I cannot use another emacs-theme than your +emacs-leuven-theme, and it is going to be probably the same with your html +theme!”
+– Joseph Vidal-Rosset +

+ +

+“Thanks a lot for sharing […] the wonderful Bigblow theme. I create lot of +specification for other team members to use. It has always been a trouble to +share and maintain such spec. Now, I can create a much neater spec which is +available for the team’s reference as a webpage.”
+– Shankar R. +

+ +

+“I like Bigblow the best. I’ve exported most of my Org files using this theme +and published them within my company’s intranet. Thanks for sharing this +wonderful package!”
+– Richard K. +

+
+
+ +
+

2.2 About ReadTheOrg

+
+

+“OMG. The ReadTheOrg theme for exported HTML from org mode files is eye +wateringly beautiful. Thank you!”
+– Rob Stewart +

+ +

+“It is fantastic, so beautiful. I will switch several of my pages over to +this theme.”
+– Carsten D. +

+ +

+“That is incredibly impressive. Thanks for this.”
+– Noah R. +

+ +

+“Thank you! I enjoy your themes. The best ones I’ve ever found.”
+– Kang T. +

+ +

+“Awesome theme. Wonderful job. You’re doing a wonderful thing — it will +enable people (at least those who use Emacs and Org mode) to put together +on-line reference works in a much-more usable fashion than is currently +available.”
+– D. C. Toedt +

+ +

+“Extremely useful.”
+– Thomas S. Dye +

+
+
+
+ +
+

3 Gallery

+
+

+This is a list of available HTML themes for Org mode, which you can use right +now! Well, I hope to have more than one in a couple of weeks… +

+
+ +
+

3.1 Bigblow

+
+

+Bigblow is perfect for your work: it is a clean design aimed at optimal Org +mode experience in your browser. It looks just awesome! +

+ + +
+

bigblow.png +

+
+ +

+Click on the image for a quick demo of Bigblow (2:49 min, no audio). +

+ +

+Keyboard shortcuts to save time and boost your productivity: +

+ + + + +++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ShortcutWhat it does
? or hAccess the dashboard
nMove to the next main heading
pMove to the previous main heading
bScroll up
<Scroll to top
>Scroll to bottom
-Collapse all
+Expand all
rGo to next task in list
RGo to previous task in list
qStop reviewing the list of tasks
gReload the page
+
+
+ +
+

3.2 ReadTheOrg

+
+

+ReadTheOrg is a clone of the official – and great! – theme (called Sphinx) +used in the Read The Docs site. It gives a beautiful and professional style to +all your Org docs. +

+ +

+Thanks to the creator(s) of Sphinx! +

+ + +
+

readtheorg.png +

+
+ +
+

+While the original theme shines on mobile devices as well, ReadTheOrg does not +stay completely functional. +

+ +

+I don’t have a lot of time to maintain this project due to other +responsibilities. Help is welcome to work on that (and eventually improve the +default structure of the HTML export)! +

+ +
+
+
+
+ +
+

4 Demo

+
+

+I’ve written a demo page for the themes that provides a maximal working support +of Org mode syntax. +

+ +

+Please see the Org mode refcard page for full examples of headings, code, +admonitions, footnotes, tables and other details. +

+
+
+ +
+

5 Installing a theme

+
+

+Using a theme from the theme gallery for your own Org documents is very easy: +you just need to clone the Org-HTML themes project, add a #+SETUPFILE: directive +in the preamble to include the CSS and JavaScript files, then export your Org +mode file to HTML. +

+ +

+You can either: +

+ +
    +
  • +copy the “setup file” of the chosen theme to the directory of your Org files, +

    + +
    +
      #+SETUPFILE: THEME-NAME.setup
    +
    +
    + +

    +or +

  • + +
  • +use the (relative or absolute) path to the “setup file” (in your Git local +repository) +

    + +
    +
      #+SETUPFILE: path/to/Git/repo/setup/THEME-NAME.setup
    +
    +
  • +
+ +

+Then export your Org mode file to HTML with org-html-export-to-html or with C-c +C-e h h. +

+
+ +
+

5.1 Bigblow

+
+

+In order to use the Bigblow style, just copy the theme-bigblow.setup file to +your project and link to it this way: +

+ +
+
#+SETUPFILE: theme-bigblow.setup
+
+
+ +

+If you prefer, you can add the content of the setup file at the beginning of +your Org file instead: +

+ +
+
# -*- mode: org; -*-
+
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/bigblow/css/htmlize.css"/>
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/bigblow/css/bigblow.css"/>
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/bigblow/css/hideshow.css"/>
+
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/jquery-1.11.0.min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/jquery-ui-1.10.2.min.js"></script>
+
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/jquery.localscroll-min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/jquery.scrollTo-1.4.3.1-min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/jquery.zclip.min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/bigblow.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/bigblow/js/hideshow.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/lib/js/jquery.stickytableheaders.min.js"></script>
+
+
+
+ +
+

Local version

+
+

+Here a local version (using relative paths): +

+ +
+
# -*- mode: org; -*-
+
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="styles/bigblow/css/htmlize.css"/>
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="styles/bigblow/css/bigblow.css"/>
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="styles/bigblow/css/hideshow.css"/>
+
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/jquery-1.11.0.min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/jquery-ui-1.10.2.min.js"></script>
+
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/jquery.localscroll-min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/jquery.scrollTo-1.4.3.1-min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/jquery.zclip.min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/bigblow.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/bigblow/js/hideshow.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="styles/lib/js/jquery.stickytableheaders.min.js"></script>
+
+
+
+
+
+ +
+

5.2 ReadTheOrg

+
+

+In order to use the ReadTheOrg style, just copy the theme-readtheorg.setup file +to your project and link to it this way: +

+ +
+
#+SETUPFILE: theme-readtheorg.setup
+
+
+ +

+If you prefer, you can add the content of the setup file at the beginning of +your Org file instead: +

+ +
+
# -*- mode: org; -*-
+
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/htmlize.css"/>
+#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/readtheorg.css"/>
+
+#+HTML_HEAD: <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+#+HTML_HEAD: <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/lib/js/jquery.stickytableheaders.js"></script>
+#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/readtheorg/js/readtheorg.js"></script>
+
+
+
+
+
+ +
+

6 Contributing

+
+
+

6.1 Issues

+
+

+Report issues and suggest features and improvements on the GitHub issue tracker. +

+
+
+ +
+

6.2 Patches

+
+

+I love contributions! Patches under any form are always welcome! +

+
+
+ +
+

6.3 Donations

+
+

+If you use the org-html-themes project (or any of my other projects) and feel it +is making your life better and easier, you can show your appreciation and help +support future development by making today a donation through PayPal. Thank +you! +

+ +

+Regardless of the donations, org-html-themes will always be free both as in +beer and as in speech. +

+
+
+ +
+

6.4 Follow me

+
+

+I have an f_niessen account on Twitter. You should follow it. +

+
+
+
+ +
+

7 License

+
+

+Copyright (C) 2011-2017 Fabrice Niessen. +

+ +

+Author: Fabrice Niessen
+Keywords: org-mode html themes +

+ +

+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 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/. +

+ + +:license-gpl-blue.svg + + +btn_donate_LG.gif + +
+
+
+
+

Author: Fabrice Niessen

+

Validate

+
+ + diff --git a/templates/org-html-themes/README.org b/templates/org-html-themes/README.org new file mode 100644 index 0000000..ea5625e --- /dev/null +++ b/templates/org-html-themes/README.org @@ -0,0 +1,319 @@ +#+TITLE: How to export Org mode files into awesome HTML in 2 minutes +#+AUTHOR: Fabrice Niessen +#+EMAIL: (concat "fniessen" at-sign "pirilampo.org") +#+DESCRIPTION: Org-HTML export made simple. +#+KEYWORDS: org-mode, export, html, theme, style, css, js, bigblow +#+LANGUAGE: en +#+OPTIONS: H:4 toc:t num:2 + +#+PROPERTY: header-args :padline no +#+SETUPFILE: setup/theme-readtheorg.setup + +#+html: +#+html: :license-gpl-blue.svg +#+html: +#+html: +#+html: btn_donate_LG.gif +#+html: + +* Tasks :noexport: + +** TODO Add a demo page + +Example: +- http://demo.thi.ng/org-spec/ +- https://raw.githubusercontent.com/thi-ng/org-spec/master/index.org + +* Overview + +** Description + +Though you can easily override CSS stylesheets and add your own HTML themes, we +can say (or write) that Org mode provides a /basic/ HTML support. + +*Org-HMTL themes* is an open source framework for providing you with a list of +very nice (cross-browser) themes for all your Org documents. Use them to *style +your docs*, and your colleagues will come up to tell you that you are a genius! + +Share this content by tweeting this page: + +#+html: +#+html: + +Follow [[https://twitter.com/f_niessen][f_niessen]] on Twitter for updates on Org-HTML themes! + +** Requirements + +Org mode version 8 (or later) is required. + +If such a version is not bundled with your Emacs, install one from ELPA. + +* Quotations + +** About Bigblow + +"Very very nice, I enjoy it a lot." \\ +-- /Ista Zahn/ + +"This is awesome. I love it!" \\ +-- /Rainer M Krug/ + +"This is awesome!!" \\ +-- /Mehul Sanghvi/ + +"This very nice html theme. [...] I cannot use another emacs-theme than your +[[https://github.com/fniessen/emacs-leuven-theme][emacs-leuven-theme]], and it is going to be probably the same with your html +theme!" \\ +-- /Joseph Vidal-Rosset/ + +"Thanks a lot for sharing [...] the wonderful Bigblow theme. I create lot of +specification for other team members to use. It has always been a trouble to +share and maintain such spec. Now, I can create a much neater spec which is +available for the team's reference as a webpage." \\ +-- /Shankar R./ + +"I like Bigblow the best. I've exported most of my Org files using this theme +and published them within my company's intranet. Thanks for sharing this +wonderful package!" \\ +-- /Richard K./ + +** About ReadTheOrg + +"OMG. The ReadTheOrg theme for exported HTML from org mode files is eye +wateringly beautiful. Thank you!" \\ +-- /Rob Stewart/ + +"It is fantastic, so beautiful. I will switch several of my pages over to +this theme." \\ +-- /Carsten D./ + +"That is incredibly impressive. Thanks for this." \\ +-- /Noah R./ + +"Thank you! I enjoy your themes. The best ones I've ever found." \\ +-- /Kang T./ + +"Awesome theme. Wonderful job. You're doing a wonderful thing --- it will +enable people (at least those who use Emacs and Org mode) to put together +on-line reference works in a much-more usable fashion than is currently +available." \\ +-- /D. C. Toedt/ + +"Extremely useful." \\ +-- /Thomas S. Dye/ + +* Gallery + :PROPERTIES: + :ID: 79e0ed21-c3b0-4f00-bdab-29fbff9dcad4 + :END: + +This is a list of available *HTML themes for Org mode*, which you can use right +now! Well, I hope to have more than one in a couple of weeks... + +** Bigblow + +Bigblow is perfect for your work: it is a clean design aimed at optimal *Org +mode experience in your browser*. It looks just awesome! + +#+ATTR_HTML: :width 640 +[[https://www.youtube.com/watch?v=DnSGSiXYuOk][file:bigblow.png]] + +Click on the image for a quick demo of Bigblow (2:49 min, no audio). + +Keyboard shortcuts to save time and boost your productivity: + +| Shortcut | What it does | +|----------+-----------------------------------| +| =?= or =h= | Access the *dashboard* | +| =n= | Move to the *next* main heading | +| =p= | Move to the *previous* main heading | +| =b= | Scroll up | +| =<= | Scroll to top | +| =>= | Scroll to bottom | +| =-= | Collapse all | +| =+= | Expand all | +| =r= | Go to next task in list | +| =R= | Go to previous task in list | +| =q= | Stop reviewing the list of tasks | +| =g= | Reload the page | + +** ReadTheOrg + +ReadTheOrg is a clone of the official -- and great! -- theme (called [[https://github.com/snide/sphinx_rtd_theme][Sphinx]]) +used in the [[http://docs.readthedocs.org/en/latest/][Read The Docs]] site. It gives a beautiful and professional style to +all your Org docs. + +*Thanks to the creator(s) of Sphinx!* + +#+ATTR_HTML: :width 640 +[[file:readtheorg.png]] + +#+begin_note +While the original theme shines on mobile devices as well, ReadTheOrg does not +stay completely functional. + +I don't have a lot of time to maintain this project due to other +responsibilities. Help is welcome to work on that (and eventually improve the +default structure of the HTML export)! +#+end_note + +* Demo + +I've written a demo page for the themes that provides a maximal working support +of Org mode syntax. + +Please see the [[https://github.com/fniessen/refcard-org-mode][Org mode refcard]] page for full examples of headings, code, +admonitions, footnotes, tables and other details. + +* Installing a theme + +Using a theme from the [[id:79e0ed21-c3b0-4f00-bdab-29fbff9dcad4][theme gallery]] for your own Org documents is very easy: +you just need to clone the Org-HTML themes project, add a =#+SETUPFILE:= directive +in the preamble to include the CSS and JavaScript files, then export your Org +mode file to HTML. + +You can either: + +- copy the "setup file" of the chosen theme to the directory of your Org files, + + #+begin_src org :exports code + ,#+SETUPFILE: THEME-NAME.setup + #+end_src + + or + +- use the (relative or absolute) path to the "setup file" (in your Git local + repository) + + #+begin_src org :exports code + ,#+SETUPFILE: path/to/Git/repo/setup/THEME-NAME.setup + #+end_src + +Then export your Org mode file to HTML with =org-html-export-to-html= or with =C-c +C-e h h=. + +** Bigblow + +In order to use the Bigblow style, just copy the [[file:setup/theme-bigblow.setup][theme-bigblow.setup]] file to +your project and link to it this way: + +#+begin_src org :exports code +,#+SETUPFILE: theme-bigblow.setup +#+end_src + +If you prefer, you can add the content of the setup file at the beginning of +your Org file instead: + +#+begin_src org :exports code :tangle setup/theme-bigblow.setup +# -*- mode: org; -*- + +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: + +,#+HTML_HEAD: +,#+HTML_HEAD: + +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +#+end_src + +*** Local version + +Here a local version (using relative paths): + +#+begin_src org :exports code :tangle setup/theme-bigblow-local.setup +# -*- mode: org; -*- + +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: + +,#+HTML_HEAD: +,#+HTML_HEAD: + +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +#+end_src + +** ReadTheOrg + +In order to use the ReadTheOrg style, just copy the [[file:setup/theme-readtheorg.setup][theme-readtheorg.setup]] file +to your project and link to it this way: + +#+begin_src org :exports code +,#+SETUPFILE: theme-readtheorg.setup +#+end_src + +If you prefer, you can add the content of the setup file at the beginning of +your Org file instead: + +#+begin_src org :exports code :tangle setup/theme-readtheorg.setup +# -*- mode: org; -*- + +,#+HTML_HEAD: +,#+HTML_HEAD: + +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +,#+HTML_HEAD: +#+end_src + +* Contributing + +** Issues + +Report issues and suggest features and improvements on the [[https://github.com/fniessen/org-html-themes/issues/new][GitHub issue tracker]]. + +** Patches + +I love contributions! Patches under any form are always welcome! + +** Donations + +If you use the org-html-themes project (or any of [[https://github.com/fniessen/][my other projects]]) and feel it +is making your life better and easier, you can show your appreciation and help +support future development by making today a [[https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=VCVAS6KPDQ4JC&lc=BE&item_number=org%2dhtml%2dthemes¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted][donation]] through PayPal. Thank +you! + +Regardless of the donations, org-html-themes will always be free both as in +beer and as in speech. + +** Follow me + +I have an [[https://twitter.com/f_niessen][f_niessen]] account on Twitter. You should follow it. + +* License + +Copyright (C) 2011-2017 Fabrice Niessen. + +Author: Fabrice Niessen \\ +Keywords: org-mode html themes + +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 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/. + +#+html: +#+html: :license-gpl-blue.svg +#+html: +#+html: +#+html: btn_donate_LG.gif +#+html: diff --git a/templates/org-html-themes/bigblow.png b/templates/org-html-themes/bigblow.png new file mode 100644 index 0000000..c1e5ee5 Binary files /dev/null and b/templates/org-html-themes/bigblow.png differ diff --git a/templates/org-html-themes/demo/example.html b/templates/org-html-themes/demo/example.html new file mode 100644 index 0000000..c70f21e --- /dev/null +++ b/templates/org-html-themes/demo/example.html @@ -0,0 +1,235 @@ + + + + + +Example of Tasks + + + + + + + + + + + +
+

Example of Tasks

+
+

Table of Contents

+ +
+ +
+
+

Work work

+
+

Only work tasks in this list.

+
+
+

Marketing

+
+

Project "Corporate Marketing".

+
+
+

Background and research

+
+
+
TODO Who are the competitors?
+
+
+
TODO What are our product's advantages?
+
+
+
TODO Target market
+
+
+
TODO Elevator pitch
+
+
+
+

PR firm

+
+
+
TODO Call Laura about PR firm phone
+
+
+
TODO Interview PR firm candidates
+
+
+
+
+

Advertising campaign

+
+
+
TODO Call Joe
+
+
+
+
+

Plan conference

+
+

Calendar events/invitations.

+
+
+
TODO Recruit volunteers
+
+
+
+
TODO Make sure responses are coming back
+
+
+
+
+

Operations

+
+
+

TODO Update database to latest version

+
+
+
+

TODO Update Website

+
+

Update blog.

+
+
+
+
+

Travel

+
+
+

Boston

+
+
+
TODO Find a flight
+
+
+
TODO Book hotel room
+
+
+
TODO Schedule meetings
+
+
+
TODO Submit expense report
+
+
+
+
+
+
+
+

Personal home

+
+
+

Reading

+
+
+

DONE Read "Getting Things Done"

+
+
+
+
+

Health

+
+
+

TODO Make dentist appointment

+
+
+
+

TODO Go to the gym

+
+

It should be as natural to some as showering or eating.

+
+
+
+

TODO Do jogging

+
+

Marathon = 42.195 kilometres.

+
+
+
+
+

Finance

+
+
+

TODO Pay electricity bill FLAGGED

+
+
+

TODO Renew newspaper subscription

+
+
+

TODO Cancel insurance

+
+
+
+

Chores

+
+
+

TODO Buy milk

+
+
+

TODO Buy dog food

+
+
+

WAIT Mail package to Susan

+
+
+

TODO Buy groceries

+
+
+

TODO Mow the lawn

+
+
+

TODO Get a haircut

+
+
+

TODO Buy anniversary present

+
+
+

TODO Take out trash

+
+
+

TODO Get the car fixed

+
+
+
+

Recreation

+
+
+

TODO Go to concert

+
+
+
+
+
+

Date: 2015-04-28

+

Author: Fabrice Niessen

+

Validate

+
+ + diff --git a/templates/org-html-themes/demo/example.org b/templates/org-html-themes/demo/example.org new file mode 100644 index 0000000..2f2e1fd --- /dev/null +++ b/templates/org-html-themes/demo/example.org @@ -0,0 +1,158 @@ +#+TITLE: Example of Tasks +#+AUTHOR: Fabrice Niessen +#+EMAIL: (concat "fniessen" at-sign "pirilampo.org") +#+DATE: 2015-04-28 +#+LANGUAGE: en +#+OPTIONS: H:4 num:nil toc:2 + +#+SETUPFILE: ~/src/org-html-themes/setup/theme-readtheorg.setup + +#+begin_html + +#+end_html + +----- + +* Work :work: + :PROPERTIES: + :CATEGORY: Work + :END: + +Only work tasks in this list. + +** Marketing + :PROPERTIES: + :CATEGORY: Marketing + :END: + +Project "Corporate Marketing". + +*** Background and research + +**** TODO Who are the competitors? + +**** TODO What are our product's advantages? + +**** TODO Target market + +**** TODO Elevator pitch + +*** PR firm + +**** TODO Call Laura about PR firm :phone: + +# *************** TODO Test with an inline task +# *************** END + +**** TODO Interview PR firm candidates + DEADLINE: <2014-03-12 Wed> + :LOGBOOK: + CLOCK: [2013-02-05 Tue 09:00]--[2013-02-05 Tue 10:11] => 1:11 + - State "TODO" -> "STRT" [2013-02-05 Tue 17:48] + - State "TODO" -> "STRT" [2013-08-19 Mon 15:16] + :END: + +# *************** TODO Another test with an inline task + +*** Advertising campaign + +**** TODO Call Joe + DEADLINE: <2014-03-06 Thu> + :PROPERTIES: + :Effort: 0:10 + :END: + +*** Plan conference + +Calendar events/invitations. + +**** TODO Recruit volunteers + DEADLINE: <2014-03-13 Thu> + +**** TODO Make sure responses are coming back + +** Operations + +*** TODO Update database to latest version + SCHEDULED: <2014-03-13 Thu> + +*** TODO Update Website + +Update blog. + +** Travel + +*** Boston + +**** TODO Find a flight + +**** TODO Book hotel room + +**** TODO Schedule meetings + +**** TODO Submit expense report + +----- + +* Personal :home: + :PROPERTIES: + :CATEGORY: Personal + :END: + +** Reading + +*** DONE Read "Getting Things Done" + :LOGBOOK: + - State "TODO" -> "DONE" [2014-01-06 Mon 15:10] + :END: + +** Health + +*** TODO Make dentist appointment + SCHEDULED: <2014-03-12 Wed> + +*** TODO Go to the gym + SCHEDULED: <2014-03-11 Tue> + :PROPERTIES: + :Effort: 0:10 + :END: + +It should be as natural to some as showering or eating. + +*** TODO Do jogging + +Marathon = 42.195 kilometres. + +** Finance + +*** TODO Pay electricity bill :FLAGGED: + +*** TODO Renew newspaper subscription + +*** TODO Cancel insurance + +** Chores + +*** TODO Buy milk + +*** TODO Buy dog food + +*** WAIT Mail package to Susan + +*** TODO Buy groceries + +*** TODO Mow the lawn + +*** TODO Get a haircut + +*** TODO Buy anniversary present + +*** TODO Take out trash + +*** TODO Get the car fixed + +** Recreation + +*** TODO Go to concert diff --git a/templates/org-html-themes/demo/images/Rplot.png b/templates/org-html-themes/demo/images/Rplot.png new file mode 100644 index 0000000..56e605c Binary files /dev/null and b/templates/org-html-themes/demo/images/Rplot.png differ diff --git a/templates/org-html-themes/demo/images/digraph.png b/templates/org-html-themes/demo/images/digraph.png new file mode 100644 index 0000000..1d2a72a Binary files /dev/null and b/templates/org-html-themes/demo/images/digraph.png differ diff --git a/templates/org-html-themes/demo/images/graph.png b/templates/org-html-themes/demo/images/graph.png new file mode 100644 index 0000000..af35c23 Binary files /dev/null and b/templates/org-html-themes/demo/images/graph.png differ diff --git a/templates/org-html-themes/demo/images/org-mode-unicorn.png b/templates/org-html-themes/demo/images/org-mode-unicorn.png new file mode 100644 index 0000000..c559d07 Binary files /dev/null and b/templates/org-html-themes/demo/images/org-mode-unicorn.png differ diff --git a/templates/org-html-themes/readtheorg.png b/templates/org-html-themes/readtheorg.png new file mode 100644 index 0000000..981892d Binary files /dev/null and b/templates/org-html-themes/readtheorg.png differ diff --git a/templates/org-html-themes/setup/theme-bigblow-local.setup b/templates/org-html-themes/setup/theme-bigblow-local.setup new file mode 100644 index 0000000..2488692 --- /dev/null +++ b/templates/org-html-themes/setup/theme-bigblow-local.setup @@ -0,0 +1,15 @@ +# -*- mode: org; -*- + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: diff --git a/templates/org-html-themes/setup/theme-bigblow.setup b/templates/org-html-themes/setup/theme-bigblow.setup new file mode 100644 index 0000000..fae5956 --- /dev/null +++ b/templates/org-html-themes/setup/theme-bigblow.setup @@ -0,0 +1,15 @@ +# -*- mode: org; -*- + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: diff --git a/templates/org-html-themes/setup/theme-readtheorg-local.setup b/templates/org-html-themes/setup/theme-readtheorg-local.setup new file mode 100755 index 0000000..365ae09 --- /dev/null +++ b/templates/org-html-themes/setup/theme-readtheorg-local.setup @@ -0,0 +1,9 @@ +# -*- mode: org; -*- + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: diff --git a/templates/org-html-themes/setup/theme-readtheorg.setup b/templates/org-html-themes/setup/theme-readtheorg.setup new file mode 100644 index 0000000..3d19744 --- /dev/null +++ b/templates/org-html-themes/setup/theme-readtheorg.setup @@ -0,0 +1,9 @@ +# -*- mode: org; -*- + +#+HTML_HEAD: +#+HTML_HEAD: + +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: +#+HTML_HEAD: diff --git a/templates/org-html-themes/styles/bigblow/css/bigblow.css b/templates/org-html-themes/styles/bigblow/css/bigblow.css new file mode 100644 index 0000000..4a3836c --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/css/bigblow.css @@ -0,0 +1,756 @@ +/* bigblow.css --- BigBlow CSS file */ + +/* Copyright (C) 2011-2014 All Right Reserved, Fabrice Niessen */ + +/* This file 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. */ + +/* This file 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. */ + +/* Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> */ +/* URL: https://github.com/fniessen/org-html-themes/ */ +/* Version: 20140605.0925 */ + +html, body { + border: 0; + margin: 0; + padding: 0; +} + +@media print { + .dontprint { + display: none; + } +} + +#preamble { + background: none repeat scroll 0 0 #46484B; + color: #FFFFFF; + font-family: Arial,Helvetica,sans-serif; + font-size: 70%; + font-weight: bold; + height: 224px; /* so that content begins after... */ + padding: 2px 2px 0 6px; +} + +#banner { + text-align: center; +} + +#tabs { + background-color: #2061A2; + float: left; + margin: 0px 0px 20px 0px; + padding: 0; + width: 100%; +} + + #tabs ul { + margin: 0; + padding: 0; + } + + #tabs li { + float: left; + list-style-type: none; + margin: 0px 2px 0px 0px; + padding: 0px 0px 0px 0px; + white-space: nowrap; + } + + #tabs li a { + color: #EEEEEE; + display: block; + font-size: 13px; + font-weight: bold; + margin: 0; + padding: 4px 10px 4px 10px; + text-decoration: none; + } + + #tabs li a:hover { + background: #759FCF; + color: #FFFFFF; + } + + #tabs li.ui-tabs-active a { + background: #FFFFFF; + color: #555555; + } + +#content { + clear: both; + background-color: #FFFFFF; + font-size: 100%; + margin: 0 auto; + max-width: 810px; + overflow-x: hidden; + overflow-y: auto; + padding: 0px 10px 2px 10px; +} + +#postamble { + color: #999999; + font-family: Arial,Helvetica,sans-serif; + font-size: 70%; + height: 40px; + margin: 0 auto; + max-width: 810px; + padding-right: 30px; + padding-top: 22px; + padding: 2px 2px 0 6px; + text-align: right; +} + +body { + color: #333333; + font: 13px/1.385 arial,helvetica,clean,sans-serif; + margin: 0 .1em; + padding: 0; +} + +b { + color: #000000; +} + +i { + color: #1A1A1A; +} + +h1, ul#tabs, h2, h3, h4, h5 { + font-family: "Trebuchet MS",Verdana,sans-serif; +} + +h1 { + background-color: #0A3F69; + color: #F8F8F8; + font-size: 24px; + margin: 0; + padding: 9px 0px 0px 10px; +} + +h2 { + border-bottom: 4px solid #67B3E3; + color: #13679D; + font-size: 20px; +} + +h3, h4, h5, h6 { + color: #1572AE; +} + +h3 { + border-bottom: 1px solid #B5DAF1; + font-size: 16px; + margin-left: 25px; +} + +h4 { + border-bottom: 1px dotted #C9E3F5; + font-size: 14px; + margin-left: 60px; +} + +h5 { + font-size: 1em; + margin-left: 87px; +} + +h6 { + font-size: 1em; + margin-left: 100px; +} + +.DONEheader { + color: #ADADAD; + text-decoration: line-through; +} + + h3.DONEheader { + border-bottom: 1px solid #DDDDDD; + } + + h4.DONEheader { + border-bottom: 1px dotted #DDDDDD; + } + +.outline-text-2, .outline-text-3, .outline-text-4, .outline-text-5, +.outline-3 > ul, /* for HTML export of Beamer slides */ +.outline-4 > ol, #text-footnotes { + margin-left: 100px; +} + +li > .outline-text-5 { + margin-left: 20px; +} + +ul, ol { + padding-left: 1.5em; +} + +dt { + color: #1572AE; + font-weight: bold; +} + +dd { + margin-bottom: 6px; +} + +pre { + /* Use #EAEAEA for background-color of border with src code block's name */ + background-color: #F8F8FF; + border: 1px solid #DEDEDE; + color: #444444; + font-family: monospace; + line-height: 1.14em; + overflow: auto; + /* overflow-x: auto; */ + padding: 10px; +} + +code { + background-color: #F8F8FF; + border: 1px solid #DEDEDE; + color: #444444; + font-family: monospace; + /* font-size: 0.93em; */ + margin: 0px 1px; + padding: 0px 2px; +} + +li > p, li > ul, li > .inlinetask, li > dl { + margin-left: 0px; +} + +dd > p, dd > ul, dd > .inlinetask, dd > dl { + margin-left: 0px; +} + +li.checked { + list-style-image: url('../images/checked.png'); +} + +li.halfchecked { + list-style-image: url('../images/halfchecked.png'); +} + +li.unchecked { + list-style-image: url('../images/unchecked.png'); +} + +a, a:link, a:visited { + color: #2061A2; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:focus { + outline: none; +} + +#search { + border-radius: 3px; + background: none repeat scroll 0 0 #FFFFFF; + display: block; + float: right; + height: 18px; + margin: 5px 10px 0 0; + overflow: hidden; + padding: 0 3px; + width: 188px; +} + + #search input { + border: 0 none; + color: #666666; + float: left; + font-family: Arial,Helvetica,sans-serif; + font-size: 11px; + font-weight: normal; + margin: 0; + padding: 2px 4px; + width: 160px; + } + + #search button { + background: url("../images/search-glass.png") no-repeat scroll 0 50% transparent; + border: 0 none; + cursor: pointer; + display: block; + float: right; + height: 18px; + margin: 0; + text-indent: -999em; + width: 14px; + } + +table { + border-collapse: collapse; + margin-right: auto; + margin-left: auto; +} + + table td { + padding: 3px 5px; + } + +table, th, td +{ + border: 1px solid #B5DAF1; + border-left: 2px solid white; + border-right: 2px solid white; +} + +th +{ + border-width: 1px 2px; + border-color: white; + background-color: #2061A2; + color: white; +} + +caption { + color: #8D8D84; +} + +img { + display: block; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.figure { + color: #8D8D84; + text-align: center; +} + +.fixme { + background: #FFFF88 url('../images/fixme.png') no-repeat top left; + color: #CC0000; + display: inline-block; + height: 16px; + text-indent: -9999px; + width: 82px; +} + +.left { + text-align: left; +} + +.right { + text-align: right; +} + +.center { + text-align: center; +} + +.justify { + text-align: justify; +} + +.inlinetask { + background-color: #F7F7F7; + border-collapse: separate; + border-color: #EEEEEE #EEEEEE #EEEEEE #1E90FF; + border-style: solid; + border-width: 1px 1px 1px 6px; + padding: 8px 8px 0px 8px; + margin: 10px 0px; +} + + .inlinetask td { + padding: 2px 5px 0px 2px; + border: 0px; + } + +.info { + border: 1px solid; + background: url('../images/info.png') no-repeat 10px 10px #BDE5F8; + color: #00529B; + padding: 4px 10px 4px 52px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + margin: 10px 0px; +} + +.tip { + border: 1px solid; + background: url('../images/tip.png') no-repeat 10px 10px #DFF2BF; + color: #4F8A10; + padding: 4px 10px 4px 52px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + margin: 10px 0px; +} + +.note { + border: 1px solid; + background: url('../images/note.png') no-repeat 10px 10px #FFFCCB; + color: #9F6000; + padding: 4px 10px 4px 52px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + margin: 10px 0px; +} + +.warning { + border: 1px solid; + background: url('../images/warning.png') no-repeat 10px 10px #FFBABA; + color: #D8000C; + padding: 4px 10px 4px 52px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; + margin: 10px 0px; +} + +.todo, .done { + margin: 10px 0; + padding: 0px 2px; +} + +.NEW { + background-color: #FDFCD8; + border: 1px solid #EEE9C3; + color: #302B13; + font-weight: normal; +} + +.TODO { + background-color: #FED5D7; + border: 1px solid #FC5158; + color: #FC5158; +} + +.STRT, .STARTED { + background-color: #FEF2D4; + border: 1px solid #FDBF3D; + color: #FDBF3D; +} + +.WAIT, .WAITING, .DLGT, .DELEGATED { + background-color: #DFFFDF; + border: 1px solid #55BA80; + color: #55BA80; +} + +.SDAY, .SOMEDAY, .DFRD, .DEFERRED { + background-color: #D3EEFF; + border: 1px solid #42B5FF; + color: #42B5FF; +} + +.DONE, .CANX, .CANCELED { + background-color: #F2F2EE; + border: 1px solid #969696; + color: #969696; +} + +.tag span { + background-color: #EDEDED; + border: 1px solid #EDEDED; + color: #939393; + cursor: pointer; + display: block; + float: right; + font-size: 80%; + font-weight: normal; + margin: 0 3px; + padding: 1px 2px; + border-radius: 10px; +} + + #right-panel-contents .tag span { + font-size: 100%; + } + + .tag span:hover { + background: #BABDB6; + } + + .tag .FLAGGED { + background-color: #EDC6C8; + border: 1px solid #EDC6C8; + color: #C15F4E; + } + +.tag .selected { + background-color: #FFEBC1; + border: 1px solid #FDBF3B; + color: #A6750C; +} + +#listOfTags .tag span { + display: inline; + float: none; +} + +span.todo { + cursor: pointer; + /* display: block; */ + /* float: left; */ + margin: -1px 3px 0px 0px; +} + + span.todo:hover { + background: #BABDB6; + color: #888888; + } + +span.todo .selected { + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; +} + +.matchtag { + background-color: #FBFFC0; +} + +.matchNEW { + background-color: #FDFCD8; +} + +.matchTODO { + background-color: #FFE6E4; +} + +.matchSTRT { + background-color: #FEF2D4; +} + +.matchWAIT, .matchDLGT { + background-color: #DFFFDF; +} + +.matchSDAY, .matchDFRD { + background-color: #E0EFFF; +} + +#listOfTodo, #listOfDone, #listOfTags { + /* bottom: 10px; /\* together with this to put the div at the bottom*\/ */ + /* left: 10px; */ + /* list-style-type: none; */ + margin-left: 0px; + /* position: fixed; /\* this is the magic *\/ */ +} + +.timestamp-kwd { + background-color: #FFF1F1; + color: #880000; + margin: 0px 4px 0px 0px; + padding: 2px 0px 2px 2px; +} + +.timestamp { + color: #777777; + font-size: 80%; +} + +#table-of-contents { + background-color: #FFFFDD; + border: 1px solid #E4E4E4; + display: table; + line-height: 1.2em; + padding: 4px; + margin: 4px; + max-width: 400px; + float: right; + width: auto; +} + + #table-of-contents h2 { + display: none; + } + + #table-of-contents ul { + margin: 0; + padding: 0; + } + + #table-of-contents li { + list-style-type: none; + margin: 0; + } + + #table-of-contents li li { + margin-left: 1.5em; + } + + #table-of-contents li li li { + font-size: 0.8em; + } + + #table-of-contents a { + color: #606060; + font-size: 0.9em; + font-weight: normal; + text-decoration: none; + } + + #table-of-contents a:hover { + color: #C61A1A; + text-decoration: underline; + } + +#minitoc { + background-color: #FFFFDD; + border: 1px solid #E4E4E4; + color: #484848; + line-height: 1.2em; + margin: 12px; + padding: 4px; + position: fixed; + width: auto; +} + +#minitoc a { + display: block; + font-size: 10px; + font-weight: normal; +} + +#minitoc a { + display: none; +} + +#minitoc:hover a { + display: block; +} + +#minitoc h2 { + margin: 3px 0px; + border: none; + font-size: 11px; +} + +p.verse { + color: #808080; + font-style: italic; +} + +.example { + background-color: #DDFADE; + border: 1px solid #9EC49F; + color: #333333; +} + +.alert { + font-weight: bold; + color: #FF0000; +} + +#toTop { + background: #F7F7F7; + border: 1px solid #CCCCCC; + top: 10px; /* together with this to put the div at the top */ + color: #333333; + cursor: pointer; + display: none; + font-family: verdana; + font-size: 11px; + padding: 5px; + position: fixed; /* this is the magic */ + right: 10px; + text-align: center; + width: 100px; + z-index: 999; +} + + #toTop:hover { + text-decoration: underline; + } + +#left-panel-wrapper { + position: fixed; + z-index: 200; + /* display: none; /\* hide the panel if Javascript is not running *\/ */ +} + +#left-panel-contents { + background-color: #EFEFEF; + border-right: 1px dotted #ADADAD; + display: none; + height: 100%; + left: 0px; + position: fixed; + text-align: left; + top: 0; + width: 199px; + z-index: 200; + padding-top: 7px; + padding-left: 7px; +} + +#left-panel-button { + transform: rotate(90deg); + background-color: #EFEFEF; + border: 1px dotted #ADADAD; + border-bottom-width: 0px; + left: -23px; + position: fixed; + top: 50%; + z-index: 200; + padding: 2px 5px 5px 5px; +} + +#right-panel-wrapper { + position: fixed; + z-index: 200; + /* display: none; /\* hide the panel if Javascript is not running *\/ */ +} + +#right-panel-contents { + background-color: #EFEFEF; + border-left: 1px dotted #ADADAD; + display: none; + height: 100%; + right: 0px; + position: fixed; + text-align: left; + top: 0; + width: 199px; + z-index: 200; + padding-top: 7px; + padding-left: 7px; +} + +.org-src-container { + position: relative; +} + +.snippet-copy-to-clipboard { + display: none; + position: absolute; + right: 10px; + top: 5px; + font-size: 0.9em; + text-decoration:underline; +} + +.copy-to-clipboard-button:hover { + cursor: pointer; +} + +/* This is for the sake of Emacs. */ +/* Local Variables: */ +/* eval: (when (locate-library "rainbow-mode") (require 'rainbow-mode) (rainbow-mode)) */ +/* End: */ diff --git a/templates/org-html-themes/styles/bigblow/css/hideshow.css b/templates/org-html-themes/styles/bigblow/css/hideshow.css new file mode 100644 index 0000000..e0263c3 --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/css/hideshow.css @@ -0,0 +1,116 @@ +/* hideshow.css --- HideShow CSS file */ + +/* Copyright (C) 2014 All Right Reserved, Fabrice Niessen */ + +/* This file 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. */ + +/* This file 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. */ + +/* Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> */ +/* URL: https://github.com/fniessen/hide-show/ */ +/* Version: 20140912.1722 */ + +.hsExpanded.hsAnchor {background: #EE7700;} + +.buttons { + padding: 0px 7px 13px 0px; + background: #0A3F69; +} + +.hsButton { + color: white; + float: right; + font-size: 70%; + margin-left: 10px; +} + + .hsButton:hover { + background: #FBE448; + color: black; + cursor: pointer; + } + +.ellipsis { + color: #999999; + /* background-color: #FFF8C0; */ + /* float: right; */ + margin-left: 0.6em; +} + +.hsReview { + border: 1px solid #A4A4A4; + background-color: white; + z-index: 500; /* must be greater then z-index of hsOverlay */ + position: relative; /* required for z-index to work */ +} + +#hsOverlay { + width: 100%; + height: 100%; + position: fixed; + left: 0px; + top: 0px; + background-color: #000; + opacity: .70; + z-index: 250; /* must be greater than any other z-index (except the one for .hsReview */ +} + +.hsReviewPanel { + background-color: #757176; + color: white; + line-height: 1.1em; + margin: 10px 0px; + padding: 10px; + position: fixed; + width: auto; + bottom: 0px; + right: 0px; + z-index: 501; + text-align: center; +} + + .hsReviewPanel.hsReviewing { + display: none; + } + + .hsReviewPanel:hover { + cursor: pointer; + } + +.hsReviewingPanel { + background-color: white; + color: #757176; + line-height: 1.1em; + margin: 10px 0px; + padding: 10px; + position: fixed; + width: auto; + bottom: 0px; + right: 0px; + z-index: 501; + text-align: center; +} + +.hsReviewButton:hover { + cursor: pointer; +} + +.hsUnselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* This is for the sake of Emacs. */ +/* Local Variables: */ +/* eval: (when (locate-library "rainbow-mode") (require 'rainbow-mode) (rainbow-mode)) */ +/* End: */ diff --git a/templates/org-html-themes/styles/bigblow/css/htmlize.css b/templates/org-html-themes/styles/bigblow/css/htmlize.css new file mode 100644 index 0000000..f08e781 --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/css/htmlize.css @@ -0,0 +1,145 @@ +.org-bold { /* bold */ font-weight: bold; } +.org-bold-italic { /* bold-italic */ font-weight: bold; font-style: italic; } +.org-buffer-menu-buffer { /* buffer-menu-buffer */ font-weight: bold; } +.org-builtin { /* font-lock-builtin-face */ color: #7a378b; } +.org-button { /* button */ text-decoration: underline; } +.org-calendar-today { /* calendar-today */ text-decoration: underline; } +.org-change-log-acknowledgement { /* change-log-acknowledgement */ color: #b22222; } +.org-change-log-conditionals { /* change-log-conditionals */ color: #a0522d; } +.org-change-log-date { /* change-log-date */ color: #8b2252; } +.org-change-log-email { /* change-log-email */ color: #a0522d; } +.org-change-log-file { /* change-log-file */ color: #0000ff; } +.org-change-log-function { /* change-log-function */ color: #a0522d; } +.org-change-log-list { /* change-log-list */ color: #a020f0; } +.org-change-log-name { /* change-log-name */ color: #008b8b; } +.org-comint-highlight-input { /* comint-highlight-input */ font-weight: bold; } +.org-comint-highlight-prompt { /* comint-highlight-prompt */ color: #00008b; } +.org-comment { /* font-lock-comment-face */ color: #b22222; } +.org-comment-delimiter { /* font-lock-comment-delimiter-face */ color: #b22222; } +.org-completions-annotations { /* completions-annotations */ font-style: italic; } +.org-completions-common-part { /* completions-common-part */ color: #000000; background-color: #ffffff; } +.org-completions-first-difference { /* completions-first-difference */ font-weight: bold; } +.org-constant { /* font-lock-constant-face */ color: #008b8b; } +.org-diary { /* diary */ color: #ff0000; } +.org-diff-context { /* diff-context */ color: #7f7f7f; } +.org-diff-file-header { /* diff-file-header */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-function { /* diff-function */ background-color: #cccccc; } +.org-diff-header { /* diff-header */ background-color: #cccccc; } +.org-diff-hunk-header { /* diff-hunk-header */ background-color: #cccccc; } +.org-diff-index { /* diff-index */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-nonexistent { /* diff-nonexistent */ background-color: #b3b3b3; font-weight: bold; } +.org-diff-refine-change { /* diff-refine-change */ background-color: #d9d9d9; } +.org-dired-directory { /* dired-directory */ color: #0000ff; } +.org-dired-flagged { /* dired-flagged */ color: #ff0000; font-weight: bold; } +.org-dired-header { /* dired-header */ color: #228b22; } +.org-dired-ignored { /* dired-ignored */ color: #7f7f7f; } +.org-dired-mark { /* dired-mark */ color: #008b8b; } +.org-dired-marked { /* dired-marked */ color: #ff0000; font-weight: bold; } +.org-dired-perm-write { /* dired-perm-write */ color: #b22222; } +.org-dired-symlink { /* dired-symlink */ color: #a020f0; } +.org-dired-warning { /* dired-warning */ color: #ff0000; font-weight: bold; } +.org-doc { /* font-lock-doc-face */ color: #8b2252; } +.org-escape-glyph { /* escape-glyph */ color: #a52a2a; } +.org-file-name-shadow { /* file-name-shadow */ color: #7f7f7f; } +.org-flyspell-duplicate { /* flyspell-duplicate */ color: #cdad00; font-weight: bold; text-decoration: underline; } +.org-flyspell-incorrect { /* flyspell-incorrect */ color: #ff4500; font-weight: bold; text-decoration: underline; } +.org-fringe { /* fringe */ background-color: #f2f2f2; } +.org-function-name { /* font-lock-function-name-face */ color: #0000ff; } +.org-header-line { /* header-line */ color: #333333; background-color: #e5e5e5; } +.org-help-argument-name { /* help-argument-name */ font-style: italic; } +.org-highlight { /* highlight */ background-color: #b4eeb4; } +.org-holiday { /* holiday */ background-color: #ffc0cb; } +.org-isearch { /* isearch */ color: #b0e2ff; background-color: #cd00cd; } +.org-isearch-fail { /* isearch-fail */ background-color: #ffc1c1; } +.org-italic { /* italic */ font-style: italic; } +.org-keyword { /* font-lock-keyword-face */ color: #a020f0; } +.org-lazy-highlight { /* lazy-highlight */ background-color: #afeeee; } +.org-link { /* link */ color: #0000ff; text-decoration: underline; } +.org-link-visited { /* link-visited */ color: #8b008b; text-decoration: underline; } +.org-log-edit-header { /* log-edit-header */ color: #a020f0; } +.org-log-edit-summary { /* log-edit-summary */ color: #0000ff; } +.org-log-edit-unknown-header { /* log-edit-unknown-header */ color: #b22222; } +.org-match { /* match */ background-color: #ffff00; } +.org-next-error { /* next-error */ background-color: #eedc82; } +.org-nobreak-space { /* nobreak-space */ color: #a52a2a; text-decoration: underline; } +.org-org-archived { /* org-archived */ color: #7f7f7f; } +.org-org-block { /* org-block */ color: #7f7f7f; } +.org-org-block-begin-line { /* org-block-begin-line */ color: #b22222; } +.org-org-block-end-line { /* org-block-end-line */ color: #b22222; } +.org-org-checkbox { /* org-checkbox */ font-weight: bold; } +.org-org-checkbox-statistics-done { /* org-checkbox-statistics-done */ color: #228b22; font-weight: bold; } +.org-org-checkbox-statistics-todo { /* org-checkbox-statistics-todo */ color: #ff0000; font-weight: bold; } +.org-org-clock-overlay { /* org-clock-overlay */ background-color: #ffff00; } +.org-org-code { /* org-code */ color: #7f7f7f; } +.org-org-column { /* org-column */ background-color: #e5e5e5; } +.org-org-column-title { /* org-column-title */ background-color: #e5e5e5; font-weight: bold; text-decoration: underline; } +.org-org-date { /* org-date */ color: #a020f0; text-decoration: underline; } +.org-org-document-info { /* org-document-info */ color: #191970; } +.org-org-document-info-keyword { /* org-document-info-keyword */ color: #7f7f7f; } +.org-org-document-title { /* org-document-title */ color: #191970; font-size: 144%; font-weight: bold; } +.org-org-done { /* org-done */ color: #228b22; font-weight: bold; } +.org-org-drawer { /* org-drawer */ color: #0000ff; } +.org-org-ellipsis { /* org-ellipsis */ color: #b8860b; text-decoration: underline; } +.org-org-footnote { /* org-footnote */ color: #a020f0; text-decoration: underline; } +.org-org-formula { /* org-formula */ color: #b22222; } +.org-org-headline-done { /* org-headline-done */ color: #bc8f8f; } +.org-org-hide { /* org-hide */ color: #ffffff; } +.org-org-latex-and-export-specials { /* org-latex-and-export-specials */ color: #8b4513; } +.org-org-level-1 { /* org-level-1 */ color: #0000ff; } +.org-org-level-2 { /* org-level-2 */ color: #a0522d; } +.org-org-level-3 { /* org-level-3 */ color: #a020f0; } +.org-org-level-4 { /* org-level-4 */ color: #b22222; } +.org-org-level-5 { /* org-level-5 */ color: #228b22; } +.org-org-level-6 { /* org-level-6 */ color: #008b8b; } +.org-org-level-7 { /* org-level-7 */ color: #7a378b; } +.org-org-level-8 { /* org-level-8 */ color: #8b2252; } +.org-org-link { /* org-link */ color: #0000ff; text-decoration: underline; } +.org-org-meta-line { /* org-meta-line */ color: #b22222; } +.org-org-mode-line-clock { /* org-mode-line-clock */ color: #000000; background-color: #bfbfbf; } +.org-org-mode-line-clock-overrun { /* org-mode-line-clock-overrun */ color: #000000; background-color: #ff0000; } +.org-org-quote { /* org-quote */ color: #7f7f7f; } +.org-org-scheduled { /* org-scheduled */ color: #006400; } +.org-org-scheduled-previously { /* org-scheduled-previously */ color: #b22222; } +.org-org-scheduled-today { /* org-scheduled-today */ color: #006400; } +.org-org-sexp-date { /* org-sexp-date */ color: #a020f0; } +.org-org-special-keyword { /* org-special-keyword */ color: #a020f0; } +.org-org-table { /* org-table */ color: #0000ff; } +.org-org-tag { /* org-tag */ font-weight: bold; } +.org-org-target { /* org-target */ text-decoration: underline; } +.org-org-time-grid { /* org-time-grid */ color: #b8860b; } +.org-org-todo { /* org-todo */ color: #ff0000; font-weight: bold; } +.org-org-upcoming-deadline { /* org-upcoming-deadline */ color: #b22222; } +.org-org-verbatim { /* org-verbatim */ color: #7f7f7f; } +.org-org-verse { /* org-verse */ color: #7f7f7f; } +.org-org-warning { /* org-warning */ color: #ff0000; font-weight: bold; } +.org-outline-1 { /* outline-1 */ color: #0000ff; } +.org-outline-2 { /* outline-2 */ color: #a0522d; } +.org-outline-3 { /* outline-3 */ color: #a020f0; } +.org-outline-4 { /* outline-4 */ color: #b22222; } +.org-outline-5 { /* outline-5 */ color: #228b22; } +.org-outline-6 { /* outline-6 */ color: #008b8b; } +.org-outline-7 { /* outline-7 */ color: #7a378b; } +.org-outline-8 { /* outline-8 */ color: #8b2252; } +.org-preprocessor { /* font-lock-preprocessor-face */ color: #7a378b; } +.org-query-replace { /* query-replace */ color: #b0e2ff; background-color: #cd00cd; } +.org-regexp-grouping-backslash { /* font-lock-regexp-grouping-backslash */ font-weight: bold; } +.org-regexp-grouping-construct { /* font-lock-regexp-grouping-construct */ font-weight: bold; } +.org-region { /* region */ background-color: #eedc82; } +.org-secondary-selection { /* secondary-selection */ background-color: #ffff00; } +.org-shadow { /* shadow */ color: #7f7f7f; } +.org-show-paren-match { /* show-paren-match */ background-color: #40e0d0; } +.org-show-paren-mismatch { /* show-paren-mismatch */ color: #ffffff; background-color: #a020f0; } +.org-string { /* font-lock-string-face */ color: #8b2252; } +.org-tool-bar { /* tool-bar */ color: #000000; background-color: #bfbfbf; } +.org-tooltip { /* tooltip */ color: #000000; background-color: #ffffe0; } +.org-trailing-whitespace { /* trailing-whitespace */ background-color: #ff0000; } +.org-type { /* font-lock-type-face */ color: #228b22; } +.org-underline { /* underline */ text-decoration: underline; } +.org-variable-name { /* font-lock-variable-name-face */ color: #a0522d; } +.org-warning { /* font-lock-warning-face */ color: #ff0000; font-weight: bold; } +.org-widget-button { /* widget-button */ font-weight: bold; } +.org-widget-button-pressed { /* widget-button-pressed */ color: #ff0000; } +.org-widget-documentation { /* widget-documentation */ color: #006400; } +.org-widget-field { /* widget-field */ background-color: #d9d9d9; } +.org-widget-inactive { /* widget-inactive */ color: #7f7f7f; } +.org-widget-single-line-field { /* widget-single-line-field */ background-color: #d9d9d9; } diff --git a/templates/org-html-themes/styles/bigblow/images/checked.png b/templates/org-html-themes/styles/bigblow/images/checked.png new file mode 100644 index 0000000..ebdc03b Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/checked.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/fixme.png b/templates/org-html-themes/styles/bigblow/images/fixme.png new file mode 100644 index 0000000..5b861d8 Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/fixme.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/halfchecked.png b/templates/org-html-themes/styles/bigblow/images/halfchecked.png new file mode 100644 index 0000000..afd695e Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/halfchecked.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/info.png b/templates/org-html-themes/styles/bigblow/images/info.png new file mode 100644 index 0000000..83de654 Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/info.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/note.png b/templates/org-html-themes/styles/bigblow/images/note.png new file mode 100644 index 0000000..1c6b8eb Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/note.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/tip.png b/templates/org-html-themes/styles/bigblow/images/tip.png new file mode 100644 index 0000000..743ef89 Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/tip.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/unchecked.png b/templates/org-html-themes/styles/bigblow/images/unchecked.png new file mode 100644 index 0000000..b75b7a9 Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/unchecked.png differ diff --git a/templates/org-html-themes/styles/bigblow/images/warning.png b/templates/org-html-themes/styles/bigblow/images/warning.png new file mode 100644 index 0000000..296415e Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/images/warning.png differ diff --git a/templates/org-html-themes/styles/bigblow/js/ZeroClipboard.swf b/templates/org-html-themes/styles/bigblow/js/ZeroClipboard.swf new file mode 100644 index 0000000..13bf8e3 Binary files /dev/null and b/templates/org-html-themes/styles/bigblow/js/ZeroClipboard.swf differ diff --git a/templates/org-html-themes/styles/bigblow/js/bigblow.js b/templates/org-html-themes/styles/bigblow/js/bigblow.js new file mode 100644 index 0000000..b8ea8c6 --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/js/bigblow.js @@ -0,0 +1,529 @@ +// bigblow.js --- BigBlow JS file +// +// Copyright (C) 2011-2016 All Right Reserved, Fabrice Niessen +// +// This file 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. +// +// This file 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. +// +// Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> +// URL: https://github.com/fniessen/org-html-themes/ +// Version: 20140515.1841 + +$(function() { + $('p'). + html(function(index, old) { + return old.replace('FIXME', + 'FIXME'); + }); + $('p'). + html(function(index, old) { + return old.replace('XXX', + 'XXX'); + }); +}); + +// Remove leading section number +$(function() { + $('.section-number-2').text(""); + for (var i = 3; i <= 5; i++) { + $('.section-number-' + i).each(function() { + $(this).text($(this).text().replace(/^[0-9]+\./g, "")); + }); + } +}); + +$(function() { + $('
').prependTo('body'); +}); + +// generate contents of minitoc +function generateMiniToc(divId) { + $('#minitoc').empty().append('

In this section

'); + $('#' + divId).find('h3').each(function(i) { + $("#minitoc").append("" + + $(this).text() + ""); + }); + // Ensure that the target is expanded (hideShow) + $('#minitoc a[href^="#"]').click(function() { + var href = $(this).attr('href'); + hsExpandAnchor(href); + }); +} + +// display tabs +function tabifySections() { + + // hide TOC (if present) + $('#table-of-contents').hide(); + + // grab the list of `h2' from the page + var allSections = []; + $('h2') + .each(function() { + // Remove TODO keywords and tags (contained in spans) + var tabText = $(this).clone().find('span').remove().end() + .text().trim(); + var tabId = $(this).parent().attr('id'); + if (tabText) { + // - remove heading number (all leading digits) + // - remove progress logging (between square brackets) + // - remove leading and trailing spaces + tabText = tabText.replace(/^\d+\s+/, '').replace(/\[[\d/%]+\]/, '').trim(); + + allSections.push({ + text: tabText, + id: tabId + }); + } + }); + + // create the tab links + var tabs = $('
    '); + for (i = 0; i < allSections.length; i++) { + var item = allSections[i]; + html = $('
  • ' + item.text + '
  • '); + tabs.append(html); + } + + // insert tabs menu after title (`h1'), or at the beginning of the content + if($('.title').length !== 0) { + $('.title').after(tabs); + } + else { + $('#content').prepend(tabs); + } +} + +function selectTabAndScroll(href) { + // At this point we assume that href is local (starts with #) + // alert(href); + + // Find the tab to activate + var targetTab = $(href).closest('.ui-tabs-panel'); + var targetTabId = targetTab.attr('id'); + var targetTabAriaLabel = targetTab.attr('aria-labelledby'); + + var targetTabIndex = $("#content ul li") + .index($('[aria-labelledby="' + targetTabAriaLabel + '"]')); + + // Activate target tab + $('#content').tabs('option', 'active', targetTabIndex); + + // Rebuild minitoc + generateMiniToc(targetTabId); + + // Set the location hash + // document.location.hash = href; + + // Scroll to top if href was a tab + if (href == '#' + targetTabId) { + // alert(targetTabId); + $.scrollTo(0); + } + // Scroll to href if href was not a tab + else { + $.scrollTo(href); + } +} + +$(document).ready(function() { + $('#preamble').remove(); + $('#table-of-contents').remove(); + + // Prepare for tabs + tabifySections(); + + // Build the tabs from the #content div + $('#content').tabs(); + + // Set default animation + $('#content').tabs('option', 'show', true); + + // Rebuild minitoc when a tab is activated + $('#content').tabs({ + activate: function(event, ui) { + var divId = ui.newTab.attr('aria-controls'); + generateMiniToc(divId); + } + }); + + // Required to get the link of the tab in URL + $('#content ul').localScroll({ + target: '#content', + duration: 0, + hash: true + }); + + // Handle hash in URL + if ($('#content') && document.location.hash) { + hsExpandAnchor(document.location.hash); + selectTabAndScroll(document.location.hash); + } + // If no hash, build the minitoc anyway for selected tab + else { + var divId = $('#content div[aria-expanded=true]').attr('id'); + generateMiniToc(divId); + } + + // Handle click on internal links + $('.ui-tabs-panel a[href^="#"]').click(function(e) { + var href = $(this).attr('href'); + hsExpandAnchor(href); + selectTabAndScroll(href); + e.preventDefault(); + }); + + // Initialize hideShow + hsInit(); + + // add sticky headers to tables + $('table').stickyTableHeaders(); +}); + +function copyToClipboard(text) +{ + if (window.clipboardData && window.clipboardData.setData) { // Internet Explorer + window.clipboardData.setData("Text", text); + } + else { // Fallback solution + window.prompt("Copy to clipboard: Ctrl+C, Enter", text); + } +} + +$(document).ready(function() { + // Assuming that the ZeroClipboard swf file is in the same folder than bigblow, + // get the path to it (it will be relative to the current page location). + var bbScriptPath = $('script[src$="bigblow.js"]').attr('src'); // the js file path + var bbPathToZeroClipboardSwf = bbScriptPath.replace('bigblow.js', 'ZeroClipboard.swf'); + + // Add copy to clipboard snippets + $('.org-src-container').prepend('
    [copy]
    '); + + // Display/hide snippets on source block mouseenter/mouseleave + $(document).on('mouseenter', '.org-src-container', function () { + $(this).find('.snippet-copy-to-clipboard').show(); + + // Need to call zclip here, once the button is visible. + // Beacause when the button is not visible, zclip does nothing. + if ((window.location.protocol != 'file:') && ($(this).find('.zclip').length == 0)) { + $(this).find('.copy-to-clipboard-button').zclip({ + //path: 'http://www.steamdev.com/zclip/js/ZeroClipboard.swf', + //path: 'styles/bigblow/js/ZeroClipboard.swf', + path: bbPathToZeroClipboardSwf, + copy: function() { + return $(this).parent().parent().find('.src').text(); + } + }); + } + }).on('mouseleave', '.org-src-container', function () { + $(this).find('.snippet-copy-to-clipboard').hide(); + }); + + // Handle copy to clipboard (here, for a local file only 'file://...' + if (window.location.protocol == 'file:') { // if local file use browser-specific code + $('.copy-to-clipboard-button').click(function() { + // Get the text to be copied + var text = $(this).parent().parent().find('.src').text(); + text = text.replace(/\n/g, "\r\n"); + // alert(text); + copyToClipboard(text); + }); + } +}); + +$(function() { + $('li > code :contains("[X]")') + .parent() + .addClass('checked') + .end() + .remove(); + $('li > code :contains("[-]")') + .parent() + .addClass('halfchecked') + .end() + .remove(); + $('li > code :contains("[ ]")') + .parent() + .addClass('unchecked') + .end() + .remove(); +}); + +$(function() { + $('i :contains("[#A]")') + .replaceWith('[#A]'); + $('i :contains("[#B]")') + .replaceWith('[#B]'); + $('i :contains("[#C]")') + .replaceWith('[#C]'); +}); + +$(function() { + $('
    ^ Back to Top
    ').appendTo('body'); + + $(window).scroll(function() { + if ($(this).scrollTop() != 0) { + $('#toTop').fadeIn(); + } else { + $('#toTop').fadeOut(); + } + }); + + $('#toTop').click(function(e) { + $('html, body').animate({scrollTop: 0}, 800); + e.preventDefault(); // Disable default browser behavior + }); +}); + +function togglePanel(e) { + e.preventDefault(); + + $("#left-panel-contents").toggleClass('active').toggle(200); + $("#right-panel-contents").toggleClass('active').toggle(200); + + var slidePos = + $("#left-panel-button").css("left") == "-23px"? '182px': '-23px'; + + $("#left-panel-button"). + animate({"left": slidePos, "opacity": 0.9}, {duration: "200" }); + + // if ($("#left-panel-contents").hasClass('active')) { + // hsHideTodoKeyword('done'); + // } else { + // hsShowTodoKeyword('done'); + // } + + // return false; +} + +$(function() { + $('') + .appendTo('body'); + + $('
    ') + .appendTo('body'); + + $('#left-panel-button').click(togglePanel); +}); + +$(function() { + var ul = $('
      ').appendTo('#left-panel-contents'); + var countOfTodo = {}, listOfTodo = [], totalOfTodo = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.todo').not($('#table-of-contents span.todo')).each(function() { + var $thisTodo = $(this).text().trim(); + + if ($.inArray($thisTodo, listOfTodo) == -1) { + countOfTodo[$thisTodo] = 1; + listOfTodo.push($thisTodo); + } + else + countOfTodo[$thisTodo] += 1; + totalOfTodo += 1; + }); + + function scoreTodo(t) { + switch (t) { + case 'NEW': return 1; + case 'TODO': return 2; + case 'STRT': return 3; + case 'WAIT': return 4; + case 'DLGT': return 5; + case 'SDAY': return 6; + case 'DFRD': return 7; + case 'DONE': return 8; + case 'CANX': return 9; + default: return 0; + } + } + + function compareTodo(a, b) { + if (scoreTodo(a) < scoreTodo(b)) return -1; + if (scoreTodo(a) > scoreTodo(b)) return 1; + return 0; + } + + listOfTodo.sort(compareTodo); + + // display + for (i = 0; i < listOfTodo.length; i++) { + var $thisTodo = listOfTodo[i]; + $(ul).append('
    • '+ $thisTodo + '' + + ' (' + countOfTodo[$thisTodo] + ')
    • '); + } + + $('#listOfTodo') + .before('Next Actions (' + totalOfTodo + '):
      '); +}); + +$(function() { + var ul = $('
        ').appendTo('#left-panel-contents'); + var countOfDone = {}, listOfDone = [], totalOfDone = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.done').not($('#table-of-contents span.done')).each(function() { + var $thisDone = $(this).text().trim(); + + if ($.inArray($thisDone, listOfDone) == -1) { + countOfDone[$thisDone] = 1; + listOfDone.push($thisDone); + } + else + countOfDone[$thisDone] += 1; + totalOfDone += 1; + }); + + // display + for (i = 0; i < listOfDone.length; i++) { + var $thisDone = listOfDone[i]; + $(ul).append('
      • '+ $thisDone + '' + + ' (' + countOfDone[$thisDone] + ')
      • '); + } + + $('#listOfDone') + .before('Done Actions (' + totalOfDone + '):
        '); +}); + +$(function() { + var ul = $('
          ').appendTo('#right-panel-contents'); + var countOfTags = {}, listOfTags = [], totalOfTags = 0; + + // assign the counts (avoid double-counting elements from the ToC) + $('span.tag').not($('#table-of-contents span.tag')).each(function() { + var $thisTagGroup = $(this).text().trim().split(/\s/); + // \s matches spaces, tabs, new lines, etc. + + for (tag in $thisTagGroup) { + if ($.inArray($thisTagGroup[tag], listOfTags) == -1) { + countOfTags[$thisTagGroup[tag]] = 1; + listOfTags.push($thisTagGroup[tag]); + } + else + countOfTags[$thisTagGroup[tag]] += 1; + totalOfTags += 1; + } + }); + + listOfTags.sort(); + + // display + for (i = 0; i < listOfTags.length; i++) { + var $thisTag = listOfTags[i]; + // $(ul).append('
        • '+ + // $thisTag + ' (' + countOfTags[$thisTag] + ')
        • '); + $(ul).append('
        • ' + $thisTag + + '' + + ' (' + countOfTags[$thisTag] + ')
        • '); + } + + $('#listOfTags') + .before('Contexts (' + totalOfTags + '):
          '); +}); + +$(function() { + $('.done').parent(':header').parent().find(':header').addClass('DONEheader'); + $('.done').parent(':header').parent().css({color: '#999999'}); +}); + +$(function() { + $('span.todo').click(function(e) { + var orgKeyword = $(this).text().trim(); + $('.' + orgKeyword).toggleClass('selected'); + $('#content .' + orgKeyword).parent().parent() + .toggleClass('match' + orgKeyword); + $('#left-panel-wrapper .' + orgKeyword).parent() + .toggleClass('match' + orgKeyword); + e.preventDefault(); + }) +}); + +$(function() { + $('.tag span').click(function(e) { + var orgTag = $(this).text().trim(); + $('.' + orgTag).toggleClass('selected'); + $('#content .' + orgTag).parent().parent().parent() + .toggleClass('matchtag'); + $('#right-panel-wrapper .' + orgTag).parent().parent() + .toggleClass('matchtag'); + e.preventDefault(); + }) +}); + +function clickPreviousTab() { + var active = $('#content').tabs('option', 'active'); + // Avoid going back to last tab + if (active == 0) return; + + $('#content').tabs('option', 'active', active - 1); + + // Set the location href + var href = $('#content div[aria-expanded=true]').attr('id'); + document.location.hash = href; + $.scrollTo(0); +} + +function clickNextTab() { + var active = $('#content').tabs('option', 'active'); + $('#content').tabs('option', 'active', active + 1); + + // Set the location href + var href = $('#content div[aria-expanded=true]').attr('id'); + document.location.hash = href; + $.scrollTo(0); +} + +function orgDefkey(e) { + if (!e) + var e = window.event; + var keycode = (e.keyCode) ? e.keyCode : e.which; + var actualkey = String.fromCharCode(keycode); + switch (actualkey) { + case "?": // help (dashboard) + case "h": + togglePanel(e); + break; + case "n": // next + clickNextTab(); + break; + case "p": // previous + clickPreviousTab(); + break; + // case "b": // scroll down - should be mapped to Shift-SPC + // $(window).scrollTop($(window).scrollTop()-$(window).height()); + // break; + case "<": // scroll to top + $(window).scrollTop(0); + break; + case ">": // scroll to bottom + $(window).scrollTop($(document).height()); + break; + case "-": // collapse all + hsCollapseAll(); + break; + case "+": // expand all + hsExpandAll(); + break; + case "r": // go to next task + hsReviewTaskNext(); + break; + case "R": // go to previous task + hsReviewTaskPrev(); + break; + case "q": // quit reviewing + hsReviewTaskQuit(); + break; + case "g": // refresh the page (from the server, rather than the cache) + location.reload(true); + break; + } +} + +document.onkeypress = orgDefkey; diff --git a/templates/org-html-themes/styles/bigblow/js/hideshow.js b/templates/org-html-themes/styles/bigblow/js/hideshow.js new file mode 100644 index 0000000..72684d8 --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/js/hideshow.js @@ -0,0 +1,332 @@ +// hideshow.js --- HideShow JS file +// +// Copyright (C) 2014 All Right Reserved, Fabrice Niessen +// +// This file 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. +// +// This file 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. +// +// Author: Fabrice Niessen <(concat "fniessen" at-sign "pirilampo.org")> +// URL: https://github.com/fniessen/hide-show/ +// Version: 20140912.1722 + +// var HS_COLLAPSIBLE_HEADERS = $('h3, h4, h5'); // collapsible headers + +if (typeof HS_STARTUP_FOLDED === 'undefined') { + var HS_STARTUP_FOLDED = false; // Show just the overview, or show all. +} + +if (typeof HS_SHOW_ALL_TEXT === 'undefined') { + var HS_SHOW_ALL_TEXT = '[Expand all]'; +} +if (typeof HS_HIDE_ALL_TEXT === 'undefined') { + var HS_HIDE_ALL_TEXT = '[Collapse all]'; +} + +if (typeof HS_ALWAYS_DISPLAY_ICON === 'undefined') { + var HS_ALWAYS_DISPLAY_ICON = false; // Display an icon for all states, or + // just when closed. +} + +if (typeof HS_ICON_CLOSED === 'undefined') { + var HS_ICON_CLOSED = '►'; // black right-pointing pointer +} +if (typeof HS_ICON_OPEN === 'undefined') { + var HS_ICON_OPEN = '▼'; // black down-pointing triangle +} +if (typeof HS_ICON_EMPTY === 'undefined') { + var HS_ICON_EMPTY = '■'; // black square +} + +if (typeof HS_SHOW_ALL_OPEN_DONE_TREES === 'undefined') { + var HS_SHOW_ALL_OPEN_DONE_TREES = false; // Expand all will open DONE trees. +} + +if (typeof HS_CLASS === 'undefined') { + var HS_CLASS = 'hsCollapsible'; +} + +// Expand a header +function hsExpand(header) { + hsExpand2(header, true); +} + +// Expand a header +function hsExpand2(header, expandDoneHeader) { + // Ignore non collapsible entries + if (!header.parent().hasClass(HS_CLASS)) return; + + // Do not expand DONE node if not required + if (hsIsDoneHeader(header) && !expandDoneHeader) return; + + header.children('span[class="ellipsis"]').remove(); + if (HS_ALWAYS_DISPLAY_ICON == true) { + header.append(' ' + HS_ICON_OPEN + ''); + } + header.parent().removeClass('hsCollapsed').addClass('hsExpanded'); + header.nextAll().show(); +} + +// Expand a header and all its parents +function hsExpandParents(header) { + hsExpand(header); + header.parents('.hsCollapsed').each(function() { + hsExpand($(this).children(':header')); + }); +} + +// Collapse a header and all its parents +function hsCollapseParents(header) { + hsCollapse(header); + header.parents('.hsExpanded').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Collapse a header +function hsCollapse(header) { + // Ignore non collapsible entries + if (!header.parent().hasClass(HS_CLASS)) return; + + header.children('span[class="ellipsis"]').remove(); + header.append(' ' + HS_ICON_CLOSED + ''); + header.parent().removeClass('hsExpanded').addClass('hsCollapsed'); + // header.nextAll().hide('fast'); + header.nextAll().hide(); +} + +// Toggle a header +function hsToggleCollapsing(header) { + if (header.parent().hasClass('hsCollapsed')) + hsExpand(header); + else if (header.parent().hasClass('hsExpanded')) + hsCollapse(header); +} + +// Expand all headers +function hsExpandAll() { + $('#content .hsCollapsed').each(function() { + hsExpand2($(this).children(':header'), HS_SHOW_ALL_OPEN_DONE_TREES); + }); +} + +// Collapse all headers +function hsCollapseAll() { + $('#content .hsExpanded').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Collapse all visible headers +function hsCollapseAllVisible() { + $('#content .hsExpanded:visible').each(function() { + hsCollapse($(this).children(':header')); + }); +} + +// Add click events to H3/H4/H5 headers which have contents. +function hsInit() { + for (var i = 3; i <= 5; i++) { + $('#content .outline-' + i).each(function() { + var header = $(this).children(':header'); + if (header.siblings().length > 0) { + $(this).addClass(HS_CLASS); + header.css({cursor: 'pointer'}); + header.click(function() { + hsToggleCollapsing($(this)); }); + + // Allow to override global Collapse/Expand default on an entry + // basis (see property `:HTML_CONTAINER_CLASS:') + if (header.parent().hasClass('hsCollapsed')) { + hsCollapse(header); + } else if (header.parent().hasClass('hsExpanded')) { + hsExpand(header); + } else { + hsSetDefaultVisibility(header); + } + } + else { + if (HS_ALWAYS_DISPLAY_ICON == true) { + header.append(' ' + HS_ICON_EMPTY + + ''); + } + $(this).addClass('hsEmpty'); + } + }); + } + + // Add buttons + $('.title').after($('
          ')); + $('.buttons').append($('' + HS_SHOW_ALL_TEXT + '') + .addClass('hsButton') + .click(hsExpandAll)); + $('.buttons').append($('' + HS_HIDE_ALL_TEXT + '') + .addClass('hsButton') + .click(hsCollapseAll)); +} + +// Returns true if a header is a DONE header +function hsIsDoneHeader(header) { + return $('span.done', header).length; +} + +// Sets the default visibility state to a header +function hsSetDefaultVisibility(header) { + if (HS_STARTUP_FOLDED) { + hsCollapse(header); + } + else { + if (!hsIsDoneHeader(header) | HS_SHOW_ALL_OPEN_DONE_TREES) { + hsExpand(header); + } + else { + hsCollapse(header); + } + } +} + +// Expands an anchor, i.e. expand all parent headers +function hsExpandAnchor(id) { + // alert(id); + if (id) { + // alert($(id + '.hsNode').length); + $(id).parents('.hsCollapsed').each(function() { + hsExpand2($(this).children(':header'), true); + }); + } +} + +// Search for next task to review, starting from beginning of current tab. +// If BACKWARD is true, search in the reverse direction. +function hsReviewTaskNext(backward) { + // If no tasks to review at all, do nothing. + if ($('.outline-2 span.todo').length == 0) return; + + if ($('.hsReviewing').length == 0) { // reviewing is starting + $('body').addClass('hsReviewing'); + $('.hsReviewPanel').addClass('hsReviewing'); + $('body').prepend('
          '); + hsAddReviewingPanels(); + + hsCollapseAll(); + // Get first task to review on each tab and expand it + $('.outline-2').each(function(){ + var firstTodo = $(this).find('span.todo:first').parent().parent(); + firstTodo.addClass('hsReview'); + hsExpandParents($(firstTodo).children(':header')); + }); + } + else { + // Get all todos + var todosElements = $('.outline-2:visible span.todo').parent().parent(); + // alert(todosElements.length); + var todos = jQuery.makeArray(todosElements); + if (backward) { + todos = todos.reverse(); + } + + // Find current review item and review the next one + var foundReview = false; + var index; + for (index = 0; index < todos.length; ++index) { + var todo = todos[index]; + if (foundReview) { + $(todo).addClass('hsReview'); + hsExpandParents($(todo).children(':header')); + break; + } + if ($(todo).hasClass('hsReview')) { + foundReview = true; + if (index < todos.length - 1) { + $(todo).removeClass('hsReview'); + hsCollapseParents($(todo).children(':header')); + } + } + } + + // Update reviewing panel + if (index < todos.length) { + var reviewItem = index + 1; + if (backward) { + reviewItem = todos.length - index; + } + + $('.outline-2:visible .hsReviewingPanel .hsReviewItem').text(reviewItem); + } + } + + // Scroll to the current review item + $('html, body').animate({ + scrollTop: $(".hsReview:visible").offset().top + }, 200); +} + +// go to previous task to review +function hsReviewTaskPrev() { + hsReviewTaskNext(true); +} + +// stop reviewing tasks +function hsReviewTaskQuit() { + $('body').removeClass('hsReviewing'); + $('.hsReviewPanel').removeClass('hsReviewing'); + $('.hsReview').removeClass('hsReview'); + $('#hsOverlay').remove(); + $('.hsReviewingPanel').remove(); +} + +function hsHideTodoKeyword(kw) { + $('span.' + kw).addClass('hsHidden').parent().parent().hide(); +} + +function hsShowTodoKeyword(kw) { + $('span.' + kw).removeClass('hsHidden').parent().parent().show(); + // XXX Show if parent is not collapsed! +} + +function hsAddReviewPanels() { + $('.outline-2').each(function(e) { + var nbItems = $(this).find('span.todo').length; + if (nbItems > 0) { + $(this).prepend('
          ' + + 'Press r or click here
          ' + + 'to review ' + nbItems + ' tasks
          ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
          '); + } + }); +} + +function hsAddReviewingPanels() { + $('.outline-2').each(function(e) { + var nbItems = $(this).find('span.todo').length; + if (nbItems > 0) { + $(this).prepend('
          Reviewing task 1 / ' + nbItems + '
          ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
          ' + + 'Shortcuts: ' + + 'r (next) - ' + + 'R (previous)' + + '
          '); + } + else { + $(this).prepend('
          No task to review
          ' + + '(out of ' + nbReviewTotalTasks + ' tasks)
          ' + + 'Shortcuts: ' + + 'r (next) - ' + + 'R (previous)' + + '
          '); + } + }); +} + +var nbReviewTotalTasks; + +$(document).ready(function() { + nbReviewTotalTasks = $('.outline-2 span.todo').length; + hsAddReviewPanels(); +}); diff --git a/templates/org-html-themes/styles/bigblow/js/jquery-1.11.0.min.js b/templates/org-html-themes/styles/bigblow/js/jquery-1.11.0.min.js new file mode 100644 index 0000000..73f33fb --- /dev/null +++ b/templates/org-html-themes/styles/bigblow/js/jquery-1.11.0.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
          ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f +}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
          a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
          ","
          "],area:[1,"",""],param:[1,"",""],thead:[1,"","
          "],tr:[2,"","
          "],col:[2,"","
          "],td:[3,"","
          "],_default:l.htmlSerialize?[0,"",""]:[1,"X
          ","
          "]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("