--- /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 (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "rhtml-erb" "rhtml-erb.el" (0 0 0 0))
+;;; Generated autoloads from rhtml-erb.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-erb" '("skip-whitespace-forward" "rhtml-")))
+
+;;;***
+\f
+;;;### (autoloads nil "rhtml-fonts" "rhtml-fonts.el" (0 0 0 0))
+;;; Generated autoloads from rhtml-fonts.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-fonts" '("erb-type-to-" "rhtml-")))
+
+;;;***
+\f
+;;;### (autoloads nil "rhtml-mode" "rhtml-mode.el" (0 0 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))
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-mode" '("rhtml-dashize" "extract-partial")))
+
+;;;***
+\f
+;;;### (autoloads nil "rhtml-navigation" "rhtml-navigation.el" (0
+;;;;;; 0 0 0))
+;;; Generated autoloads from rhtml-navigation.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-navigation" '("match-strings" "current-line" "rails-root" "rinari-find-by-context" "rhtml-")))
+
+;;;***
+\f
+;;;### (autoloads nil "rhtml-ruby-hook" "rhtml-ruby-hook.el" (0 0
+;;;;;; 0 0))
+;;; Generated autoloads from rhtml-ruby-hook.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-ruby-hook" '("rhtml-" "rthml-insert-from-ruby-temp")))
+
+;;;***
+\f
+;;;### (autoloads nil "rhtml-sgml-hacks" "rhtml-sgml-hacks.el" (0
+;;;;;; 0 0 0))
+;;; Generated autoloads from rhtml-sgml-hacks.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rhtml-sgml-hacks" '("sgml-" "rhtml-")))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("rhtml-mode-pkg.el") (0 0 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; rhtml-mode-autoloads.el ends here
--- /dev/null
+(define-package "rhtml-mode" "20130422.1311" "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
+++ /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