(setq org-src-fontify-natively t)
#+END_SRC
-* cfengine
+* CFEngine
#+BEGIN_SRC emacs-lisp
;; (load-library "cfengine")
=cut
#+END_SRC
+* Puppet
+[2016-02-29 Mon 16:36]
+
+#+BEGIN_SRC emacs-lisp
+ (add-to-list 'auto-mode-alist '("\\.erb$" . rhtml-mode))
+#+END_SRC
+
* mwheel
#+BEGIN_SRC emacs-lisp
--- /dev/null
+;;;
+;;; rhtml-erb.el - ERB tag support for `rhtml-mode'
+;;;
+
+;; ***** BEGIN LICENSE BLOCK *****
+;; Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+;; The contents of this file are subject to the Mozilla Public License Version
+;; 1.1 (the "License"); you may not use this file except in compliance with
+;; the License. You may obtain a copy of the License at
+;; http://www.mozilla.org/MPL/
+
+;; Software distributed under the License is distributed on an "AS IS" basis,
+;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+;; for the specific language governing rights and limitations under the
+;; License.
+
+;; The Original Code is ERB Tag Support for RHTML-MODE.
+
+;; The Initial Developer of the Original Code is
+;; Paul Nathan Stickney <pstickneNOSPAMgmail.com>.
+;; Portions created by the Initial Developer are Copyright (C) 2006
+;; the Initial Developer. All Rights Reserved.
+
+;; Contributor(s):
+
+;; Alternatively, the contents of this file may be used under the terms of
+;; either the GNU General Public License Version 2 or later (the "GPL"), or
+;; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+;; in which case the provisions of the GPL or the LGPL are applicable instead
+;; of those above. If you wish to allow use of your version of this file only
+;; under the terms of either the GPL or the LGPL, and not to allow others to
+;; use your version of this file under the terms of the MPL, indicate your
+;; decision by deleting the provisions above and replace them with the notice
+;; and other provisions required by the GPL or the LGPL. If you do not delete
+;; the provisions above, a recipient may use your version of this file under
+;; the terms of any one of the MPL, the GPL or the LGPL.
+
+;; ***** END LICENSE BLOCK *****
+
+
+;;; History
+;; 2006SEP12 - Created
+
+;; Brief note on conventions:
+;; DELIM - refers to the things like <% and %>
+;; TAG - refers to entire <%ERB%> area, -including- the delims
+
+;; (load-file "~/.emacs.d/macro-utils.el")
+;; (defmacro symbol-name-or-nil (symbol)
+;; (once-only (symbol)
+;; `(if ,symbol (symbol-name ,symbol))))
+;; (put 'symbol-name-or-nil 'lisp-indent-function 1)
+
+
+(defconst rhtml-erb-open-delim
+ "<%"
+ "ERB opening tag.
+Due to implementation of `sgml-mode', this absolutely must begin with a
+< and be at least two characters long to work correctly.")
+
+(defconst rhtml-erb-close-delim
+ "%>"
+ "ERB ending tag.
+I don't think this has any restrictions.")
+
+(defconst rhtml-erb-open-delim-len
+ (length rhtml-erb-open-delim))
+
+(defconst rhtml-erb-close-delim-len
+ (length rhtml-erb-open-delim))
+
+(defconst rhtml-erb-delim-re
+ (concat rhtml-erb-open-delim "\\|" rhtml-erb-close-delim))
+
+(defconst rhtml-erb-tag-open-re
+ (concat rhtml-erb-open-delim "\\(?:-=\\|[-=#]?\\)?"))
+
+;; specific tags
+(defconst rhtml-erb-exec-tag-open-re
+ (concat rhtml-erb-open-delim "\\(?:-\\(?:[^=#]\\|$\\)\\|[^-=#]\\|$\\)")
+ "<%, and who would have thought it would be so complicated?")
+(defconst rhtml-erb-out-tag-open-re
+ (concat rhtml-erb-open-delim "-?=")
+ "<%=")
+(defconst rhtml-erb-comment-tag-open-re
+ (concat rhtml-erb-open-delim "-?#")
+ "<%#")
+
+(defconst rhtml-erb-tag-body-re
+ "\\(?:.\\|\n\\)*?")
+
+(defconst rhtml-erb-tag-close-re
+ (concat "-?" rhtml-erb-close-delim))
+
+(defconst rhtml-erb-tag-re
+ (concat "\\(" rhtml-erb-tag-open-re "\\)"
+ "\\(" rhtml-erb-tag-body-re "\\)"
+ "\\(" rhtml-erb-tag-close-re "\\)"))
+
+(defun rhtml-erb-delim-type (start-delim)
+ "Return `exec', `out', `comment' or nil dependin on the type of delimeter this is."
+ (flet ((match? (regex)
+ (eq (string-match regex start-delim) 0)))
+ (cond ((match? rhtml-erb-exec-tag-open-re)
+ 'exec)
+ ((match? rhtml-erb-out-tag-open-re)
+ 'out)
+ ((match? rhtml-erb-comment-tag-open-re)
+ 'comment))))
+
+(defun rhtml-erb-middle-offset (prev-line-start cur-line-start)
+ "Helper method for modified `sgml-calculate-indent'.
+Calculates adjustment of branches like \"else\". PREV-LINE-START
+and CUR-LINE-START should be the first non-white space on each
+line, respectively."
+ (save-excursion
+ (+ (progn
+ (goto-char cur-line-start)
+ (if (rhtml-scan-for-erb-tags '(erb-middle)) sgml-basic-offset 0))
+ (progn
+ (goto-char prev-line-start)
+ (if (rhtml-scan-for-erb-tags '(erb-middle)) (- sgml-basic-offset) 0)))))
+
+(defconst rhtml-erb-block-open-re
+ (concat "[]A-Za-z_)}][ ]+do[ ]+\\(?:|[A-Za-z_, ]*|\\)?[ ]*" rhtml-erb-tag-close-re))
+
+(defconst rhtml-erb-brace-block-open-re
+ (concat "[ ]+{[ ]+\\(?:|[A-Za-z_, ]*|\\)?[ ]*" rhtml-erb-tag-close-re)
+ "Slightly less strictive to allow for \"hash = {\n\".")
+
+(defmacro rhtml-erb-block-open-p ()
+ "Guess if a Ruby fragment opens a block with do.
+Returns `block' or `brace-block' on success."
+ `(re-search-forward ,rhtml-erb-block-open-re nil t))
+
+(defmacro rhtml-erb-brace-block-open-p ()
+ "Guess if a Ruby fragment opens a brace block (with {)
+Returns `block' or `brace-block' on success."
+ `(re-search-forward ,rhtml-erb-brace-block-open-re nil t))
+
+(defun rhtml-at-erb-tag-p ()
+ "Returns (TAG-START . TAG-END) if at beginning of ERB tag."
+ (if (looking-at rhtml-erb-tag-re)
+ (cons (match-beginning 0) (match-end 0))))
+
+(defun rhtml-skip-erb-tag ()
+ "Skips over an ERB tag starting at (POINT); returns non-nil if succesful.
+If the search is successful (POINT) will be advanced."
+ (let ((found (rhtml-at-erb-tag-p)))
+ (when found
+ (goto-char (cdr found)))))
+
+(defun rhtml-erb-tag-type-p (type)
+ (memq type '(erb-open erb-middle erb-close erb-data)))
+
+(defun rhtml-scan-for-erb-tags (tags)
+ "Like `rhtml-scan-erb-tag' but will only return (ERB-TYPE . NAME)
+if (memq ERB-TYPE tags)."
+ (let ((start (point))
+ (tag-info (rhtml-scan-erb-tag)))
+ (if (memq (car tag-info) tags)
+ tag-info
+ ;; reset on failure
+ (goto-char start)
+ nil)))
+
+
+(defun rhtml-scan-erb-tag ()
+ "Scans an ERB tag moving (POINT) to the end and returning (ERB-TYPE . NAME) on success.
+ERB-TYPE is `erb-open', `erb-data', `erb-middle', or `erb-close'.
+NAME is something like \"erb-brace-block\" or \"erb-start-form-tag\" that is
+used for level-matching."
+ (let* ((erb-tag (rhtml-at-erb-tag-p))
+ (erb-tag-end (cdr erb-tag)))
+ (cond (erb-tag
+ ;; Lead-in
+ (looking-at rhtml-erb-tag-open-re)
+ (goto-char (match-end 0))
+ (skip-whitespace-forward)
+ (prog1
+ (save-restriction
+ (narrow-to-region (point) erb-tag-end) ;(- end 2))
+ (cond ((looking-at "if \\|unless ")
+ (cons 'erb-open "erb-multi-block"))
+ ((looking-at "for\\b\\|while ")
+ (cons 'erb-open "erb-block"))
+ ((rhtml-erb-block-open-p)
+ (cons 'erb-open "erb-block"))
+ ((rhtml-erb-brace-block-open-p)
+ (cons 'erb-open "erb-brace-block"))
+ ((looking-at "else \\|elsif")
+ (cons 'erb-middle "erb-middle"))
+ ((looking-at "end\\b")
+ (cons 'erb-close "erb-block"))
+ ((looking-at "}")
+ (cons 'erb-close "erb-brace-block"))
+ ((looking-at "start_form_tag\\b")
+ (cons 'erb-open "erb-form-tag"))
+ ((looking-at "end_form_tag\\b")
+ (cons 'erb-close "erb-form-tag"))
+ (t
+ (cons 'erb-data "erb-data"))))
+ (goto-char erb-tag-end)))
+ (t ;no match
+ (cons nil nil)))))
+
+;; TODO - simply by removing point parameter
+(defun rhtml-erb-tag-region (&optional point)
+ "If inside a ERB tag returns (START . END) of the tag, otherwise nil.
+If POINT is specified it will be used instead of (POINT)."
+ (if point
+ (save-excursion
+ (goto-char point)
+ (rhtml-erb-tag-region))
+ (let ((prev (save-excursion ; -> (STR . START)
+ (skip-chars-forward rhtml-erb-open-delim)
+ (when (re-search-backward rhtml-erb-delim-re nil t)
+ (cons (match-string 0) (match-beginning 0)))))
+ (next (save-excursion ; -> (STR . END)
+ (skip-chars-backward rhtml-erb-open-delim)
+ (when (re-search-forward rhtml-erb-delim-re nil t)
+ (cons (match-string 0) (match-end 0))))))
+ ;; limit matches to valid regions
+ (when (and (string= (car prev) rhtml-erb-open-delim)
+ (string= (car next) rhtml-erb-close-delim))
+ (cons (cdr prev) (cdr next))))))
+
+(defun rhtml-erb-regions (begin end)
+ "Returns a list of elements in the form (TYPE START END) where type is
+`exec', `comment', `out'."
+ (let* (tag-start regions last-tag-end)
+ (catch 'done
+ (save-excursion
+ (goto-char begin)
+ (while t
+ (when (not (search-forward rhtml-erb-open-delim end t))
+ (throw 'done regions))
+ (setq tag-start (- (point) 2))
+ (when (not (search-forward rhtml-erb-close-delim end t))
+ (throw 'done regions))
+ ;; erb tag
+ (push (list
+ (case (char-after (+ tag-start 2))
+ (?= 'out) (?# 'comment) (t 'exec))
+ tag-start (point))
+ regions))))))
+
+;; PST -- what is the point? At the very least it needs a better name.
+(defun rhtml-erb-regions2 (begin end)
+ "Returns a list of elements in the form (TYPE START END) where type is
+`exec', `comment', `out' or, for non-ERb secions, `other'."
+ (let* (tag-start regions last-tag-end)
+ (catch 'done
+ (save-excursion
+ (goto-char begin)
+ (while t
+
+ (when (not (search-forward rhtml-erb-open-delim end t))
+ ;; no more erb tags
+ (push (list 'other (or last-tag-end begin) end)
+ regions)
+ (throw 'done regions))
+ (setq tag-start (- (point) 2))
+
+ (when (not (search-forward rhtml-erb-close-delim end t))
+ (throw 'done regions))
+ ;; other section
+ ;; PST -- may catch partial start tag
+ (when (> (point) (or last-tag-end begin))
+ (push (list 'other begin (point))
+ regions))
+ (setq last-tag-end (point))
+
+ ;; erb tag
+ (push (list
+ (case (char-after (+ tag-start 2))
+ (?= 'out) (?# 'comment) (t 'exec))
+ tag-start (point))
+ regions))))))
+
+(defun rhtml-union-region-containing-erb-tags (r-start r-end)
+ "Returns (START . END) for a region which is an aggregate of
+the region defined by R-START, R-END and any ERB tags which
+start, stop, or are contained in the region."
+ (let* ((unopened-tag (rhtml-erb-tag-region r-start))
+ (unclosed-tag (rhtml-erb-tag-region r-end))
+ (new-start (or (and unopened-tag (car unopened-tag)) r-start))
+ (new-end (or (and unclosed-tag (cdr unclosed-tag)) r-end)))
+ (cons new-start new-end)))
+
+(defun rhtml-widen-to-erb-tag ()
+ "Widens the buffer to the ERB tag.
+If no ERB tag is found the buffer will be reset to pre-state.
+The point is advanced to the beginning of the new region (even if no ERB found)."
+ (let ((r-start (point-min))
+ (r-end (point-max)))
+ (widen)
+ (let ((region (rhtml-erb-tag-region)))
+ (when region
+ (setq r-start (car region))
+ (setq r-end (cdr region)))
+ (narrow-to-region r-start r-end)
+ (goto-char (point-min)))))
+
+(defun rhtml-region-has-erb-tag-p (start end)
+ "Returns non-nil if the region bounded by START and END
+contains an ERB tag."
+ (save-excursion
+ (goto-char start)
+ (re-search-forward rhtml-erb-tag-re end t)))
+
+
+;; utility functions
+
+(defun skip-whitespace-forward ()
+ "Skip forward common ([ \t\r\n]) whitespace."
+ (skip-chars-forward " \t\r\n"))
+
+;;
+(provide 'rhtml-erb)
\ No newline at end of file
--- /dev/null
+;;;
+;;; rhtml-fonts.el - font-lock-based fontification support for `rhtml-mode'
+;;;
+
+;; This file is not 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 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 Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+
+;; 2007 MAR 22 - Rewrote to work with jit-lock-mode, cleanup
+;; 2007 MAR 28 - PST: changed to GPL license from MPL (using font-lock code)
+
+
+(defvar rhtml-in-erb-keywords
+ '(;("\\([A-Z][0-9a-zA-Z_]*\\)" . (1 font-lock-type-face prepend))
+ ("[^_]\\<\\(alias\\|and\\|begin\\|break\\|case\\|catch\\|class\\|def\\|do\\|elsif\\|else\\|fail\\|ensure\\|for\\|end\\|if\\|in\\|module\\|next\\|not\\|or\\|raise\\|redo\\|rescue\\|retry\\|return\\|then\\|throw\\|super\\|unless\\|undef\\|until\\|when\\|while\\|yield\\|render\\)\\>[^_]" .
+ (1 font-lock-keyword-face prepend))
+ ("\\(@[0-9a-zA-Z_]*\\)" . (1 font-lock-variable-name-face prepend))
+ ("\\(:[0-9a-zA-Z_]*\\)" . (1 font-lock-constant-face prepend))))
+
+(defvar rhtml-font-lock-syntactic-keywords
+ '(("\\(<\\)!--" (1 "< b"))
+ ("--[ \t\n]*\\(>\\)" (1 "> b"))
+ ("\\(<\\)%" (1 "<"))
+ ("%\\(>\\)" (1 ">"))
+ "Override `sgml-mode' syntactic keywords to support ERb tags."))
+
+(defun rhtml-activate-fontification ()
+ "Activate font-lock fontification support for the current buffer."
+ ;; PST: note `jit-lock-mode' seems to play okay with
+ ;; `font-lock-mode' (but I'm still fighting with `font-lock-mode')
+
+ (font-lock-mode t)
+ (jit-lock-mode t)
+
+ ;; PST -- ERb regions are treated syntactically as comments but have
+ ;; their `face' text property cleared and are overwritten.
+ (set (make-local-variable 'font-lock-syntactic-keywords)
+ 'rhtml-font-lock-syntactic-keywords)
+
+ (add-hook 'jit-lock-functions 'rhtml-fontify-region t t))
+
+(defun rhtml-fontify-buffer ()
+ (interactive)
+ (jit-lock-refontify))
+
+(defun rhtml-fontify-erb-block (type begin end)
+ (let ((delim-face (cdr (assoc type erb-type-to-delim-face)))
+ (body-face (cdr (assoc type erb-type-to-face)))
+ (open-start begin)
+ (open-end (+ begin (if (eq type 'exec) 2 3)))
+ (close-start (- end 2))
+ (close-end end))
+ ;; apply edging and base
+ (font-lock-append-text-property open-start open-end 'face delim-face)
+ (when body-face
+ (font-lock-append-text-property open-end close-start 'face body-face))
+ (font-lock-append-text-property close-start close-end 'face delim-face)
+ ;; apply normal ERb fontification
+ (when (not (eq type 'comment))
+ (let ((font-lock-keywords rhtml-in-erb-keywords)
+ (case-fold-search nil))
+ (font-lock-fontify-keywords-region open-end close-start)))))
+
+(defun rhtml-font-unfontify-region (beg end)
+ "Taken from ``font-lock.el''. Similar to
+`font-lock-default-unfontify-region' but does not clear syntactical
+information. This is useful to keep syntactical state without the
+colorization."
+ (remove-list-of-text-properties
+ beg end (append
+ font-lock-extra-managed-props
+ '(face font-lock-multiline))))
+
+(defun rhtml-fontify-region (begin end)
+ ;; PST -- hack to greedily grab more ERb tags to update (ensures
+ ;; that the current ERb tag is updated entirely)
+ (save-excursion
+ (goto-char begin)
+ (search-backward rhtml-erb-open-delim nil t)
+ (setq begin (point))
+ (goto-char end)
+ (search-forward rhtml-erb-close-delim nil t)
+ (setq end (point)))
+ ;; fontify ERb tags -- fontification has already been applied by
+ ;; font-lock-mode for sgml-mode so we need to clear faces (but not
+ ;; syntactical information)
+ (mapc (lambda (i)
+ (rhtml-font-unfontify-region (nth 1 i) (nth 2 i))
+ (apply 'rhtml-fontify-erb-block i))
+ (rhtml-erb-regions begin end)))
+
+
+;; ERB faces - each type of ERB tag has it's own face properties
+
+(defface erb-face
+ '((((class color) (min-colors 88) (background dark))
+ :background "#383838")
+ (((class color) (min-colors 88) (background light))
+ ;; :background "azure")
+ :background "snow2")
+ (((class color) (min-colors 16) (background dark))
+ :background "blue3")
+ (((class color) (min-colors 16) (background light))
+ :background "azure")
+ (((class color) (min-colors 8))
+ :background "blue")
+ (((type tty) (class mono))
+ :inverse-video t)
+ (t :background "gray"))
+ "Default inherited face for ERB tag body"
+ :group 'rhtml-faces)
+
+(defface erb-delim-face
+ '((t (:inherit font-lock-preprocessor-face :bold t :italic t)))
+ "Default inherited face for ERB tag delimeters"
+ :group 'rhtml-faces)
+
+(defface erb-exec-face
+ `((t (:inherit erb-face)))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+(defface erb-exec-delim-face
+ `((t (:inherit erb-delim-face :weight bold)))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+(defface erb-out-face
+ `((t (:inherit erb-face)))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+(defface erb-out-delim-face
+ `((((background dark)) :foreground "#aaffff" :background "#383838")
+ (t (:inherit erb-delim-face :weight bold :foreground "darkred")))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+(defface erb-comment-face
+ `((((background dark)) :foreground "lightgreen")
+ (t (:inherit erb-face :weight bold :foreground "darkgreen")))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+(defface erb-comment-delim-face
+ `((((background dark)) :foreground "lightgreen")
+ (t (:inherit erb-delim-face :weight bold :foreground "darkgreen")))
+ "Basic face for Ruby embedded into HTML"
+ :group 'rhtml-faces)
+
+
+(defvar erb-type-to-face
+ '((exec . erb-exec-face)
+ (out . erb-out-face)
+ (comment . erb-comment-face)))
+
+(defvar erb-type-to-delim-face
+ '((exec . erb-exec-delim-face)
+ (out . erb-out-delim-face)
+ (comment . erb-comment-delim-face)))
+
+;;
+(provide 'rhtml-fonts)
\ No newline at end of file
--- /dev/null
+;;; rhtml-mode-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
+\f
+;;;### (autoloads nil "rhtml-mode" "rhtml-mode.el" (22228 24358 0
+;;;;;; 0))
+;;; Generated autoloads from rhtml-mode.el
+
+(autoload 'rhtml-mode "rhtml-mode" "\
+Embedded Ruby Mode (RHTML)
+
+\(fn)" t nil)
+
+(add-to-list 'auto-mode-alist '("\\.html\\.erb$" . rhtml-mode))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("rhtml-erb.el" "rhtml-fonts.el" "rhtml-mode-pkg.el"
+;;;;;; "rhtml-navigation.el" "rhtml-ruby-hook.el" "rhtml-sgml-hacks.el")
+;;;;;; (22228 24358 363543 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; rhtml-mode-autoloads.el ends here
--- /dev/null
+(define-package "rhtml-mode" "20130422.611" "major mode for editing RHTML files" 'nil)
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; rhtml-mode.el --- major mode for editing RHTML files
+
+;; ***** BEGIN LICENSE BLOCK *****
+;; Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+;; The contents of this file are subject to the Mozilla Public License Version
+;; 1.1 (the "License"); you may not use this file except in compliance with
+;; the License. You may obtain a copy of the License at
+;; http://www.mozilla.org/MPL/
+
+;; Software distributed under the License is distributed on an "AS IS" basis,
+;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+;; for the specific language governing rights and limitations under the
+;; License.
+
+;; The Original Code is RHTML-MODE.
+
+;; The Initial Developer of the Original Code is
+;; Paul Nathan Stickney <pstickneNOSPAMgmail.com>.
+;; Portions created by the Initial Developer are Copyright (C) 2006
+;; the Initial Developer. All Rights Reserved.
+
+;; Contributor(s):
+;; Phil Hagelberg
+
+;; Alternatively, the contents of this file may be used under the terms of
+;; either the GNU General Public License Version 2 or later (the "GPL"), or
+;; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+;; in which case the provisions of the GPL or the LGPL are applicable instead
+;; of those above. If you wish to allow use of your version of this file only
+;; under the terms of either the GPL or the LGPL, and not to allow others to
+;; use your version of this file under the terms of the MPL, indicate your
+;; decision by deleting the provisions above and replace them with the notice
+;; and other provisions required by the GPL or the LGPL. If you do not delete
+;; the provisions above, a recipient may use your version of this file under
+;; the terms of any one of the MPL, the GPL or the LGPL.
+
+;; ***** END LICENSE BLOCK *****
+
+
+(require 'rhtml-fonts) ;; basic fontification
+
+;; don't require if you don't want it...
+(require 'rhtml-sgml-hacks) ;; indent erb with sgml
+
+;;;###autoload
+(define-derived-mode rhtml-mode
+ html-mode "RHTML"
+ "Embedded Ruby Mode (RHTML)"
+ (interactive)
+ (abbrev-mode)
+ ;; disable if you don't want it...
+ (rhtml-activate-fontification))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.html\\.erb$" . rhtml-mode))
+
+(define-key ruby-mode-map
+ "\C-c\C-v" (lambda () (interactive) (toggle-buffer 'rails-view)))
+(define-key rhtml-mode-map
+ "\C-c\C-b" 'rinari-find-by-context)
+
+(defun extract-partial (begin end partial-name)
+ (interactive "r\nsName your partial: ")
+ (kill-region begin end)
+ (find-file (concat "_" partial-name "\\.html\\.erb"))
+ (yank)
+ (pop-to-buffer nil)
+ (insert (concat "<%= render :partial => '" partial-name "' %>\n")))
+
+;; PST -- uses rhtml-erb-regions which is defined in rhtml-font which
+;; should be moved.
+(defun rhtml-dashize (&optional mode)
+ "Add or remove dashes from the end of ERb blocks. The dash tells ERb to
+strip the following newline. This function will NOT add or remove dashes
+from blocks that end in a # or #- sequence.
+
+MODE controls how dashes are added or removed. If MODE is `strip' then all
+ERb blocks will have the dash removed. If MODE is `add' then all blocks
+will have a dash added. If MODE is `auto' or nil then ERb blocks which are
+followed by a newline will have a dash added while all other blocks will
+have the dash removed."
+ (interactive "cDashize mode: s) strip, a) add, x) auto (default)")
+ (let ((real-mode (case mode
+ ((?s strip) 'strip)
+ ((?a add) 'add))))
+ (mapc (lambda (i)
+ (let ((end (nth 2 i)))
+ (save-excursion
+ (goto-char (- end 2))
+ (case (or real-mode
+ (if (eq (char-after end) ?\n)
+ 'add
+ 'strip))
+ (strip
+ (when (and (eq (char-before) ?-)
+ (not (eq (char-before (1- (point))) ?#)))
+ (delete-backward-char 1)))
+ (add
+ (unless (memq (char-before) '(?# ?-))
+ (insert "-")))))))
+ ;; seq.
+ (rhtml-erb-regions (point-min) (point-max)))))
+
+
+(require 'rhtml-navigation)
+(provide 'rhtml-mode)
--- /dev/null
+;; TODO -- need a license boiler-plate
+
+;; Handy RHTML functions
+;; (C) 2006 Phil Hagelberg
+
+;; Ripped from the previous rhtml-mode, sorry about making it break
+;; too :( -- pst
+(defun rails-root (file-path)
+ "Guess the project root of the given FILE-PATH."
+ (or (vc-git-root file-path)
+ (vc-svn-root file-path)
+ file-path))
+
+(defun rhtml-controller-name-from-view ()
+ (let* ((dirname (expand-file-name "."))
+ (controller-with-module
+ (and (string-match "app/views/\\(.*\\)$" dirname)
+ (match-string 1 dirname))))
+ (concat (rails-root (expand-file-name "."))
+ "/app/controllers/"
+ controller-with-module
+ "_controller.rb")))
+
+(defun rhtml-find-action ()
+ (interactive)
+ (let ((action (file-name-sans-extension (file-name-nondirectory buffer-file-name))))
+ (find-file (rhtml-controller-name-from-view))
+ (beginning-of-buffer)
+ (search-forward-regexp (concat "def *" action))
+ (recenter)))
+
+(defun rinari-find-by-context ()
+ (interactive)
+ (mapc (lambda (rule) (let ((pattern (car rule)) (line (current-line)))
+ (if (string-match pattern line) (apply (cdr rule) (match-strings line)))))
+ ;; rules (warning; ALL matches will be acted upon, not just first!)
+ '((":partial +=> +['\":]\\([a-zA-Z_]+\\)['\" ]" . rhtml-find-partial)
+ (":controller +=> +['\":]\\([a-zA-Z_]+\\)['\" ,]?.*:action +=> +['\":]\\([a-zA-Z_]+\\)['\" ,]?"
+ . rinari-find-action)
+ (":action +=> +['\":]\\([a-zA-Z_]+\\)['\"]?" . rinari-find-action)
+ )
+ ))
+
+(defun rhtml-find-partial (partial)
+ (interactive "MPartial: ")
+ (find-file (concat "_" partial "\\.html\\.erb")))
+
+;; utility functions
+
+(defun current-line ()
+ (save-excursion
+ (beginning-of-line)
+ (set-mark-command nil)
+ (end-of-line)
+ (buffer-substring-no-properties (mark) (point))))
+
+(defun match-strings (string &optional n)
+ (let* ((n (or n 1))
+ (this-match (match-string n string)))
+ (when this-match
+ (append (list this-match) (match-strings string (+ 1 n))))))
+
+(provide 'rhtml-navigation)
--- /dev/null
+;;;
+;;; rhtml-ruby-hook.el - `ruby-mode' access for `rhtml-mode'
+;;;
+
+;; ***** BEGIN LICENSE BLOCK *****
+;; Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+;; The contents of this file are subject to the Mozilla Public License Version
+;; 1.1 (the "License"); you may not use this file except in compliance with
+;; the License. You may obtain a copy of the License at
+;; http://www.mozilla.org/MPL/
+
+;; Software distributed under the License is distributed on an "AS IS" basis,
+;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+;; for the specific language governing rights and limitations under the
+;; License.
+
+;; The Original Code is RUBY-MODE Hook Support for RHTML-MODE.
+
+;; The Initial Developer of the Original Code is
+;; Paul Nathan Stickney <pstickneNOSPAMgmail.com>.
+;; Portions created by the Initial Developer are Copyright (C) 2006
+;; the Initial Developer. All Rights Reserved.
+
+;; Contributor(s):
+
+;; Alternatively, the contents of this file may be used under the terms of
+;; either the GNU General Public License Version 2 or later (the "GPL"), or
+;; the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+;; in which case the provisions of the GPL or the LGPL are applicable instead
+;; of those above. If you wish to allow use of your version of this file only
+;; under the terms of either the GPL or the LGPL, and not to allow others to
+;; use your version of this file under the terms of the MPL, indicate your
+;; decision by deleting the provisions above and replace them with the notice
+;; and other provisions required by the GPL or the LGPL. If you do not delete
+;; the provisions above, a recipient may use your version of this file under
+;; the terms of any one of the MPL, the GPL or the LGPL.
+
+;; ***** END LICENSE BLOCK *****
+
+
+;;;
+;;; Provide an API to 'hook' into Ruby-mode, or rather, provide access
+;;; to a temporary `ruby-mode' buffer which can be used to apply
+;;; various ruby-mode stuff, primarily indenting.
+;;;
+
+;;; History:
+
+;; 2006SEP18
+;; - initial implementation
+
+(require 'rhtml-erb)
+(require 'ruby-mode) ; for well, `ruby-mode'
+
+(defvar rhtml-ruby-temp-buffer-name
+ "*rhtml-ruby-hook temp buffer*"
+ "Buffer name to use for temporary Ruby buffer. Should begin with a * or
+ space as those carry special meaning.")
+
+(defun rhtml-ruby-temp-buffer ()
+ "Returns the temporary ruby buffer creating it if needed."
+ (or (get-buffer rhtml-ruby-temp-buffer-name)
+ (let ((ruby-buffer (get-buffer-create rhtml-ruby-temp-buffer-name)))
+ (with-current-buffer ruby-buffer
+ (buffer-disable-undo)
+ (ruby-mode))
+ ruby-buffer)))
+
+(defun rhtml-copy-to-ruby-temp (begin end)
+ "Buffer to copy from should be selected. BEGIN and END are points in the
+current buffer. All existing text in the temporary buffer is replaced."
+ (let ((source-buffer (current-buffer))
+ (temp-buffer (rhtml-ruby-temp-buffer)))
+ (with-current-buffer temp-buffer
+ (delete-region (point-min) (point-max))
+ (insert-buffer-substring source-buffer begin end))))
+
+(defun rhtml-ruby-indent-at (indent-pos)
+ "Returns the indentation for INDENT-POS inside the temporary Ruby buffer
+after updating the indenting."
+ (with-current-buffer (rhtml-ruby-temp-buffer)
+ (indent-region 0 indent-pos) ; force update
+ (goto-char indent-pos)
+ (ruby-calculate-indent)))
+
+(defun rthml-insert-from-ruby-temp ()
+ "Insert the contents of `rhtml-ruby-temp-buffer' into the current
+buffer."
+ (insert-from-buffer (rhtml-ruby-temp-buffer)))
+
+
+(provide 'rhtml-ruby-hook)
\ No newline at end of file
--- /dev/null
+;;;
+;;; rhtml-sgml-hacks.el --- add ERB contextual indenting support to sgml-mode
+;;;
+
+;;; Initial Developer: Paul Stickney <pstickneNOSPAMgmail.com>, 2006
+
+;; 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 2 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.
+
+;; You should have received a copy of the GNU General Public
+;; License along with GNU Emacs; if not, write to the Free
+;; Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+
+;;; README
+
+;;
+;; Hacks to sgml-mode *against* Emacs 22.0.5 (2006/09/01 build)
+;; - diff'ing and editing for your version may be required!
+;; Changes to original code marked with ``PST''.
+;;
+;; Note: `sgml-mode' indenting in Emacs 21 seems very broken.
+;; Please use sgml-mode.el from Emacs 22.
+;;
+;; Hints to use Emacs 22 sgml-mode with Emacs 21:
+;; 1) Replace all occurances of "?\s" with "?\ ". I have no idea what
+;; ?\s is supposed to mean (super?) but this lets it eval in Emacs 21.
+;; 2) Comment the line containing 'defvaralias'. No reference seems to
+;; be made to the alias anyway.
+;; 3) Make sure sgml-mode.el is in load-path before stock version and restart
+;; emacs. You will have problems if the old `sgml-mode' is
+;; loaded first.
+;;
+
+;;; History
+
+;; 2006SEP12
+;; - Created
+;; 2006SEP14
+;; - enable/disable hacks use setf so they no longer require feature reloading
+;; 2006SEP15
+;; - Revert back to old style unloading
+;; 2006SEP19
+;; - Ruby code inside ERB blocks is now indented. See `rhtml-ruby-hook'.
+;; 2006SEP22
+;; - < inside ERB tags correctly ignored.
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'rhtml-erb)
+(require 'sgml-mode) ; Force load here, make sure our functions will munge in.
+(require 'rhtml-ruby-hook) ; For sub-indenting
+
+
+;; Crude method of hack control
+;; TODO replace, see below
+;;
+(defun rhtml-disable-sgml-hacks ()
+ "Try to return `sgml-mode' to its normal state."
+ (rhtml-remove-feature 'rhtml-sgml-hacks)
+ (rhtml-reload-feature 'sgml-mode))
+
+(defun rhtml-enable-sgml-hacks ()
+ "Reload `sgml-mode' hacks. Might be useful after
+`rhtml-disable-sgml-hacks'."
+ (rhtml-reload-feature 'sgml-mode)
+ (rhtml-reload-feature 'rhtml-sgml-hacks))
+
+(defun rhtml-remove-feature (feature)
+ (setq features (delq feature features)))
+(defun rhtml-reload-feature (feature)
+ (rhtml-remove-feature feature)
+ (require feature))
+
+
+;;; Failed attempt at non feature-realoding
+;;; (What is wrong?)
+;; Save original functions
+;;
+;; (defconst rhtml-dirty-functions
+;; '(sgml-get-context
+;; sgml-calculate-indent
+;; sgml-lexical-context
+;; sgml-beginning-of-tag
+;; sgml-parse-tag-backward)
+;; "Functions to back up.")
+;; (setq rhtml-hacks-backed-up nil)
+;; (defconst rhtml-sgml-backup-prop 'rhtml-sgml-definition)
+;; (defconst rhtml-hack-backup-prop 'rhtml-hack-definition)
+
+;; (defun rhtml-backup-functions (prop)
+;; (dolist (fn rhtml-dirty-functions)
+;; (put fn prop (symbol-function fn))))
+
+;; (defun rhtml-restore-functions (prop)
+;; (dolist (fn rhtml-dirty-functions)
+;; (setf fn (get fn prop))))
+
+;; ;; Backup sgml-mode functions so we can restore them later
+;; (rhtml-backup-functions rhtml-sgml-backup-prop)
+
+;; (defun rhtml-disable-sgml-hacks ()
+;; "Restore normal functions."
+;; ;; Backup rhtml-sgml-hacks functions if not done yet.
+;; ;; Without (correctly) doing so we will accidently mix definitions!
+;; (unless rhtml-hacks-backed-up
+;; (rhtml-backup-functions rhtml-hack-backup-prop)
+;; (setq rhtml-hacks-backed-up t))
+;; (rhtml-restore-functions rhtml-sgml-backup-prop))
+
+;; (defun rhtml-enable-sgml-hacks ()
+;; "Restore hacked functions."
+;; (rhtml-restore-functions rhtml-hack-backup-prop))
+
+
+
+;; PST - handling of `erb-*'
+(defun sgml-get-context (&optional until)
+ "Determine the context of the current position.
+By default, parse until we find a start-tag as the first thing on a line.
+If UNTIL is `empty', return even if the context is empty (i.e.
+we just skipped over some element and got to a beginning of line).
+
+The context is a list of tag-info structures. The last one is the tag
+immediately enclosing the current position.
+
+Point is assumed to be outside of any tag. If we discover that it's
+not the case, the first tag returned is the one inside which we are."
+ (let ((here (point))
+ (stack nil)
+ (ignore nil)
+ (context nil)
+ tag-info)
+ ;; CONTEXT keeps track of the tag-stack
+ ;; STACK keeps track of the end tags we've seen (and thus the start-tags
+ ;; we'll have to ignore) when skipping over matching open..close pairs.
+ ;; IGNORE is a list of tags that can be ignored because they have been
+ ;; closed implicitly.
+ (skip-chars-backward " \t\n") ; Make sure we're not at indentation.
+ (while
+ (and (not (eq until 'now))
+ (or stack
+ (not (if until (eq until 'empty) context))
+ (not (sgml-at-indentation-p))
+ (and context
+ (/= (point) (sgml-tag-start (car context)))
+ (sgml-unclosed-tag-p (sgml-tag-name (car context)))))
+ (setq tag-info (ignore-errors (sgml-parse-tag-backward))))
+
+ ;; This tag may enclose things we thought were tags. If so,
+ ;; discard them.
+ (while (and context
+ (> (sgml-tag-end tag-info)
+ (sgml-tag-end (car context))))
+ (setq context (cdr context)))
+
+ (cond
+ ((> (sgml-tag-end tag-info) here)
+ ;; Oops!! Looks like we were not outside of any tag, after all.
+ (push tag-info context)
+ (setq until 'now))
+
+ ;; start-tag
+ ((memq (sgml-tag-type tag-info) '(open erb-open)) ;; PST
+ (cond
+ ((null stack)
+ (if (member-ignore-case (sgml-tag-name tag-info) ignore)
+ ;; There was an implicit end-tag.
+ nil
+ (push tag-info context)
+ ;; We're changing context so the tags implicitly closed inside
+ ;; the previous context aren't implicitly closed here any more.
+ ;; [ Well, actually it depends, but we don't have the info about
+ ;; when it doesn't and when it does. --Stef ]
+ (setq ignore nil)))
+ ((eq t (compare-strings (sgml-tag-name tag-info) nil nil
+ (car stack) nil nil t))
+ (setq stack (cdr stack)))
+ ;; PST - "erb-block" closes both "erb-block" and "erb-multi-block"
+ ((and (member (sgml-tag-name tag-info) '("erb-block" "erb-multi-block"))
+ (string= (car stack) '"erb-block"))
+ (setq stack (cdr stack)))
+ ;; /PST
+ (t
+ ;; The open and close tags don't match.
+ (if (not sgml-xml-mode)
+ (unless (sgml-unclosed-tag-p (sgml-tag-name tag-info))
+ (message "Unclosed tag <%s>" (sgml-tag-name tag-info))
+ (let ((tmp stack))
+ ;; We could just assume that the tag is simply not closed
+ ;; but it's a bad assumption when tags *are* closed but
+ ;; not properly nested.
+ (while (and (cdr tmp)
+ (not (eq t (compare-strings
+ (sgml-tag-name tag-info) nil nil
+ (cadr tmp) nil nil t))))
+ (setq tmp (cdr tmp)))
+ (if (cdr tmp) (setcdr tmp (cddr tmp)))))
+ (message "Unmatched tags <%s> and </%s>"
+ (sgml-tag-name tag-info) (pop stack)))))
+
+ (if (and (null stack) (sgml-unclosed-tag-p (sgml-tag-name tag-info)))
+ ;; This is a top-level open of an implicitly closed tag, so any
+ ;; occurrence of such an open tag at the same level can be ignored
+ ;; because it's been implicitly closed.
+ (push (sgml-tag-name tag-info) ignore)))
+
+ ;; end-tag
+ ((memq (sgml-tag-type tag-info) '(close erb-close)) ;; PST
+ (if (sgml-empty-tag-p (sgml-tag-name tag-info))
+ (message "Spurious </%s>: empty tag" (sgml-tag-name tag-info))
+ (push (sgml-tag-name tag-info) stack)))
+ ))
+
+ ;; return context
+ context))
+
+
+
+;; PST - added calulations for ERB tags
+;; *** Bug when point at end?
+(defun sgml-calculate-indent (&optional lcon)
+ "Calculate the column to which this line should be indented.
+LCON is the lexical context, if any."
+ (unless lcon (setq lcon (sgml-lexical-context)))
+
+ ;; Indent comment-start markers inside <!-- just like comment-end markers.
+ (if (and (eq (car lcon) 'tag)
+ (looking-at "--")
+ (save-excursion (goto-char (cdr lcon)) (looking-at "<!--")))
+ (setq lcon (cons 'comment (+ (cdr lcon) 2))))
+
+ (case (car lcon)
+
+ (string
+ ;; Go back to previous non-empty line.
+ (while (and (> (point) (cdr lcon))
+ (zerop (forward-line -1))
+ (looking-at "[ \t]*$")))
+ (if (> (point) (cdr lcon))
+ ;; Previous line is inside the string.
+ (current-indentation)
+ (goto-char (cdr lcon))
+ (1+ (current-column))))
+
+ (comment
+ (let ((mark (looking-at "--")))
+ ;; Go back to previous non-empty line.
+ (while (and (> (point) (cdr lcon))
+ (zerop (forward-line -1))
+ (or (looking-at "[ \t]*$")
+ (if mark (not (looking-at "[ \t]*--"))))))
+ (if (> (point) (cdr lcon))
+ ;; Previous line is inside the comment.
+ (skip-chars-forward " \t")
+ (goto-char (cdr lcon))
+ ;; Skip `<!' to get to the `--' with which we want to align.
+ (search-forward "--")
+ (goto-char (match-beginning 0)))
+ (when (and (not mark) (looking-at "--"))
+ (forward-char 2) (skip-chars-forward " \t"))
+ (current-column)))
+
+ ;; We don't know how to indent it. Let's be honest about it.
+ (cdata nil)
+
+ ;; PST - Indent Ruby inside ERB tags
+ ((erb-open erb-close erb-middle erb-data)
+ (let ((indent-pos (point)))
+ (re-search-backward rhtml-erb-tag-open-re)
+ (goto-char (match-end 0)) ; skip tag
+ (let* ((content-start (point))
+ (base-indent (current-column))
+ ;; inside-indent-pos also accounts for sync'ing injection
+ (inside-indent-pos (+ 1 base-indent (- indent-pos content-start))))
+ (re-search-forward rhtml-erb-tag-close-re)
+ (let ((content-end (match-beginning 0)))
+ (rhtml-copy-to-ruby-temp content-start content-end)
+ ;; Inject spaces into first-line (which might have had
+ ;; previous contents trimmed) to keep points in sync.
+ (with-current-buffer (rhtml-ruby-temp-buffer)
+ (goto-char 0)
+ (insert (make-string base-indent ?\ )))
+ (rhtml-ruby-indent-at inside-indent-pos)))))
+ ;; /PST
+
+ (tag
+ (goto-char (1+ (cdr lcon)))
+ (skip-chars-forward "^ \t\n") ;Skip tag name.
+ (skip-chars-forward " \t")
+ (if (not (eolp))
+ (current-column)
+ ;; This is the first attribute: indent.
+ (goto-char (1+ (cdr lcon)))
+ (+ (current-column) sgml-basic-offset)))
+
+ (text
+ (while
+ (if (looking-at "</")
+ (forward-sexp 1)
+ ;; PST do likewise for ERB tags
+ (rhtml-scan-for-erb-tags '(erb-close)))
+ (skip-chars-forward " \t"))
+ (let* ((here (point))
+ (unclosed (and ;; (not sgml-xml-mode)
+ (looking-at sgml-tag-name-re)
+ (member-ignore-case (match-string 1)
+ sgml-unclosed-tags)
+ (match-string 1)))
+ (context
+ ;; If possible, align on the previous non-empty text line.
+ ;; Otherwise, do a more serious parsing to find the
+ ;; tag(s) relative to which we should be indenting.
+ (if (and (not unclosed) (skip-chars-backward " \t")
+ (< (skip-chars-backward " \t\n") 0)
+ (back-to-indentation)
+ (> (point) (cdr lcon)))
+ nil
+ (goto-char here)
+ (nreverse (sgml-get-context (if unclosed nil 'empty)))))
+ (there (point)))
+ ;; Ignore previous unclosed start-tag in context.
+ (while (and context unclosed
+ (eq t (compare-strings
+ (sgml-tag-name (car context)) nil nil
+ unclosed nil nil t)))
+ (setq context (cdr context)))
+ ;; Indent to reflect nesting.
+ (cond
+ ;; If we were not in a text context after all, let's try again.
+ ((and context (> (sgml-tag-end (car context)) here))
+ (goto-char here)
+ (sgml-calculate-indent
+ (cons (if (memq (sgml-tag-type (car context)) '(comment cdata))
+ (sgml-tag-type (car context)) 'tag)
+ (sgml-tag-start (car context)))))
+ ;; Align on the first element after the nearest open-tag, if any.
+ ((and context
+ (goto-char (sgml-tag-end (car context)))
+ (skip-chars-forward " \t\n")
+ (< (point) here) (sgml-at-indentation-p))
+ (+ (current-column)
+ (rhtml-erb-middle-offset here there))) ;; PST
+ (t ;; follows another a tag
+ (goto-char there)
+ (+ (current-column)
+ (rhtml-erb-middle-offset here there) ;; PST
+ (* sgml-basic-offset (length context)))))))
+
+ (otherwise
+ (error "Unrecognized context %s" (car lcon)))
+
+ ))
+
+
+
+;; PST - support for `erb-*' (replaces `jsp') as well as getting name
+(defun sgml-parse-tag-backward (&optional limit)
+ "Parse an SGML tag backward, and return information about the tag.
+Assume that parsing starts from within a textual context.
+Leave point at the beginning of the tag."
+ (catch 'found
+ (let (tag-type tag-start tag-end name)
+ (or (re-search-backward "[<>]" limit 'move)
+ (error "No tag found"))
+ (when (eq (char-after) ?<)
+ ;; Oops!! Looks like we were not in a textual context after all!.
+ ;; Let's try to recover.
+ (with-syntax-table sgml-tag-syntax-table
+ (let ((pos (point)))
+ (condition-case nil
+ (forward-sexp)
+ (scan-error
+ ;; This < seems to be just a spurious one, let's ignore it.
+ (goto-char pos)
+ (throw 'found (sgml-parse-tag-backward limit))))
+ ;; Check it is really a tag, without any extra < or > inside.
+ (unless (sgml-tag-text-p pos (point))
+ (goto-char pos)
+ (throw 'found (sgml-parse-tag-backward limit)))
+ (forward-char -1))))
+ (setq tag-end (1+ (point)))
+ (cond
+ ((sgml-looking-back-at "--") ; comment
+ (setq tag-type 'comment
+ tag-start (search-backward "<!--" nil t)))
+ ((sgml-looking-back-at "]]") ; cdata
+ (setq tag-type 'cdata
+ tag-start (re-search-backward "<!\\[[A-Z]+\\[" nil t)))
+ (t
+ (setq tag-start
+ (with-syntax-table sgml-tag-syntax-table
+ (goto-char tag-end)
+ (condition-case nil
+ (backward-sexp)
+ (scan-error
+ ;; This > isn't really the end of a tag. Skip it.
+ (goto-char (1- tag-end))
+ (throw 'found (sgml-parse-tag-backward limit))))
+ ;; PST, ignore <'s in ERB tags
+ (when (rhtml-erb-tag-region)
+ (throw 'found (sgml-parse-tag-backward limit)))
+ ;; /PST
+ (point)))
+ (goto-char (1+ tag-start))
+ (case (char-after)
+ (?! ; declaration
+ (setq tag-type 'decl))
+ (?? ; processing-instruction
+ (setq tag-type 'pi))
+ (?/ ; close-tag
+ (forward-char 1)
+ (setq tag-type 'close
+ name (sgml-parse-tag-name)))
+ ;; PST - ERB
+ ;; TODO does not work with defvar delim setup.
+ (?%
+ (backward-char 1) ; ERB tags *always* include delims
+ (let ((erb-info (save-excursion (rhtml-scan-erb-tag))))
+ (when (car erb-info)
+ (setq tag-type (car erb-info))
+ (setq name (cdr erb-info)))))
+ ;; /PST
+ (t ; open or empty tag
+ (setq tag-type 'open
+ name (sgml-parse-tag-name))
+ (if (or (eq ?/ (char-before (- tag-end 1)))
+ (sgml-empty-tag-p name))
+ (setq tag-type 'empty))))))
+ (goto-char tag-start)
+ (sgml-make-tag tag-type tag-start tag-end name))))
+
+
+;; PST -- ERB tags return useful stuff such as "erb-block"
+(defun sgml-beginning-of-tag (&optional top-level)
+ "Skip to beginning of tag and return its name.
+If this can't be done, return nil."
+ (let ((context (sgml-lexical-context)))
+ (if (memq (car context) '(tag erb-open erb-close erb-middle)) ;; PST
+ (progn
+ (goto-char (cdr context))
+ ;; PST cond added for ERB
+ (or (cdr (save-excursion (rhtml-scan-erb-tag)))
+ (if (looking-at sgml-tag-name-re)
+ (match-string-no-properties 1))))
+ (if top-level nil
+ (when (not (eq (car context) 'text))
+ (goto-char (cdr context))
+ (sgml-beginning-of-tag t))))))
+
+
+;; PST -- Added support for `erb-*' types
+(defun sgml-lexical-context (&optional limit)
+ "Return the lexical context at point as (TYPE . START).
+START is the location of the start of the lexical element.
+TYPE is one of `string', `comment', `tag', `cdata', `erb-*' or `text'.
+Optional argument LIMIT is the position to start parsing from.
+If nil, start from a preceding tag at indentation."
+ (interactive) ;; PST
+ (save-excursion
+ (let ((pos (point))
+ text-start state)
+ (if limit
+ (goto-char limit)
+ ;; Skip tags backwards until we find one at indentation
+ (while (and (ignore-errors (sgml-parse-tag-backward))
+ (not (sgml-at-indentation-p)))))
+ (with-syntax-table sgml-tag-syntax-table
+ (while (< (point) pos)
+ ;; When entering this loop we're inside text.
+ (setq text-start (point))
+ (skip-chars-forward "^<" pos)
+ (setq state
+ (cond
+ ((= (point) pos)
+ ;; We got to the end without seeing a tag.
+ nil)
+ ((looking-at "<!\\[[A-Z]+\\[")
+ ;; We've found a CDATA section or similar.
+ (let ((cdata-start (point)))
+ (unless (search-forward "]]>" pos 'move)
+ (list 0 nil nil 'cdata nil nil nil nil cdata-start))))
+ ;; PST
+ ((looking-at rhtml-erb-tag-open-re)
+ (let ((erb-start (point))
+ (tag-type (car (rhtml-scan-erb-tag))))
+ (if tag-type
+ (list 0 nil nil tag-type nil nil nil nil erb-start)
+ (forward-char 1) ;not really an ERB tag, skip it (could cause <<tag>)?
+ nil)))
+ ;; /PST
+ (t
+ ;; We've reached a tag. Parse it.
+ ;; FIXME: Handle net-enabling start-tags
+ (parse-partial-sexp (point) pos 0))))))
+ (let ((lcon
+ (cond
+ ((eq (nth 3 state) 'cdata) (cons 'cdata (nth 8 state)))
+ ((rhtml-erb-tag-type-p (nth 3 state)) (cons (nth 3 state) (nth 8 state))) ;; PST
+ ((nth 3 state) (cons 'string (nth 8 state)))
+ ((nth 4 state) (cons 'comment (nth 8 state)))
+ ((and state (> (nth 0 state) 0)) (cons 'tag (nth 1 state)))
+ (t (cons 'text text-start)))))
+ lcon))))
+
+
+;;;
+;;; Hacks disabled by default
+;;;
+;;(rhtml-disable-sgml-hacks)
+
+;;;
+(provide 'rhtml-sgml-hacks)
\ No newline at end of file