mirror of
https://github.com/OlafvdSpek/ctemplate.git
synced 2025-10-05 19:16:54 +08:00
ctemplate 0.3
This commit is contained in:
parent
187110dc1a
commit
14d041d16d
|
@ -15,3 +15,11 @@ Wed Jun 14 14:56:04 2006 Google Inc. <opensource@google.com>
|
|||
* SetTemplateGlobalValue(): new variable type with new scoping (ehamon)
|
||||
* Export a nothreads version of the ctemplate library (csilvers)
|
||||
* Got rid of scandir call, which should improve portability (csilvers)
|
||||
|
||||
Mon Aug 21 17:44:32 2006 Google Inc. <opensource@google.com>
|
||||
|
||||
* ctemplate: version 0.3 release
|
||||
* New contrib/ directory entry: vi syntax highlighting (patlac)
|
||||
* New contrib/ directory entry: emacs syntax highlighting (tonyg)
|
||||
* Allow escape-modifiers to affect includes, not just vars (csilvers)
|
||||
* Add JSON escape-functor (majewski)
|
||||
|
|
|
@ -152,7 +152,8 @@ deb: dist-gzip packages/deb.sh packages/deb/*
|
|||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
|
||||
$(SCRIPTS) libtool
|
||||
$(SCRIPTS) libtool \
|
||||
contrib
|
||||
|
||||
## If you create hash_map.h, hash_set.h, and/or hash_fun.h via the
|
||||
## ACC_CXX_MAKE_*_H configure.ac macros, add those files here.
|
||||
|
|
|
@ -209,7 +209,8 @@ template_nothreads_regtest_LDADD = libctemplate_nothreads.la
|
|||
|
||||
noinst_PROGRAMS = $(TESTS)
|
||||
EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \
|
||||
$(SCRIPTS) libtool
|
||||
$(SCRIPTS) libtool \
|
||||
contrib
|
||||
|
||||
|
||||
DISTCLEANFILES = src/google/ctemplate/hash_map.h src/google/ctemplate/hash_set.h
|
||||
|
|
1784
trunk/aclocal.m4
vendored
1784
trunk/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
5533
trunk/configure
vendored
5533
trunk/configure
vendored
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
|||
## Process this file with autoconf to produce configure.
|
||||
## In general, the safest way to proceed is to run the following:
|
||||
## % aclocal -I `pwd`/../autoconf && autoheader && autoconf && automake
|
||||
## % aclocal -I . -I `pwd`/../autoconf && autoheader && autoconf && automake
|
||||
|
||||
# make sure we're interpreted by some minimal autoconf
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(ctemplate, 0.2, opensource@google.com)
|
||||
AC_INIT(ctemplate, 0.3, opensource@google.com)
|
||||
# The argument here is just something that should be in the current directory
|
||||
# (for sanity checking)
|
||||
AC_CONFIG_SRCDIR(README)
|
||||
|
|
13
trunk/contrib/README.contrib
Normal file
13
trunk/contrib/README.contrib
Normal file
|
@ -0,0 +1,13 @@
|
|||
All files under this contrib directory are UNSUPPORTED; use at your
|
||||
own risk. They were provided by users of ctemplate and were not
|
||||
tested by the authors of ctemplate. These files are not owned by
|
||||
Google. Please contact the authors of the contributions for help
|
||||
about these, not the ctemplate authors. Thanks!, and enjoy.
|
||||
|
||||
highlighting.vim by Patrick Lacasse <patlac@borabora.crchul.ulaval.ca>
|
||||
How to set up syntax highlighting (colorization) for ctemplate .tpl
|
||||
files, using vim. A shar file; see top-of-file for how to extract.
|
||||
|
||||
tpl-mode.el by Tony Gentilcore
|
||||
Elisp file for syntax highlighting (colorization) for ctemplate
|
||||
.tpl files, using emacs. See top-of-file for how to use.
|
212
trunk/contrib/highlighting.vim
Normal file
212
trunk/contrib/highlighting.vim
Normal file
|
@ -0,0 +1,212 @@
|
|||
#!/bin/sh
|
||||
# This is a shell archive (produced by GNU sharutils 4.2.1).
|
||||
# To extract the files from this archive, save it to some FILE, remove
|
||||
# everything before the `!/bin/sh' line above, then type `sh FILE'.
|
||||
#
|
||||
# Made on 2006-08-08 13:38 PDT by <patlac@borabora.crchul.ulaval.ca>.
|
||||
# Commandline: shar -T .vim
|
||||
#
|
||||
# Existing files will *not* be overwritten unless `-c' is specified.
|
||||
#
|
||||
# This shar contains:
|
||||
# length mode name
|
||||
# ------ ---------- ------------------------------------------
|
||||
# 1477 -rw-r--r-- .vim/syntax/tpl.vim
|
||||
# 56 -rw-r--r-- .vim/ftdetect/tpl.vim
|
||||
#
|
||||
echo >/dev/null <<_NOTES_EOF
|
||||
From: Patrick Lacasse <patlac@borabora.crchul.ulaval.ca>
|
||||
Subject: vim color for google-ctemplate howto
|
||||
To: google-ctemplate@googlegroups.com
|
||||
Date: Fri, 4 Aug 2006 11:38:39 -0400
|
||||
|
||||
Hi group,
|
||||
|
||||
I'm now using google-ctemplate. My text editor is vim. Here is a little gift
|
||||
for other people like me.
|
||||
|
||||
Howto have google-ctemplate colored by vim :
|
||||
|
||||
In your home directory, run 'sh $0'.
|
||||
|
||||
Now restart vim.
|
||||
|
||||
This will autodetects file with tpl extension and colors them. You can change
|
||||
the color by changing the HiLink lines ( try changing String by
|
||||
Identifier ) .
|
||||
|
||||
I'm not sure exactly about what are the legal marker names. Feel free to
|
||||
change the regexes.
|
||||
|
||||
I only tryed this with vim 6.4 , I just cut and past the things about version
|
||||
checking.
|
||||
|
||||
For more information about syntax higlithning in vim, try
|
||||
:help syntax
|
||||
|
||||
Amusez-vous bien,
|
||||
|
||||
Patrick Lacasse
|
||||
patlac@borabora.crchul.ulaval.ca
|
||||
_NOTES_EOF
|
||||
|
||||
save_IFS="${IFS}"
|
||||
IFS="${IFS}:"
|
||||
gettext_dir=FAILED
|
||||
locale_dir=FAILED
|
||||
first_param="$1"
|
||||
for dir in $PATH
|
||||
do
|
||||
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
|
||||
&& ($dir/gettext --version >/dev/null 2>&1)
|
||||
then
|
||||
set `$dir/gettext --version 2>&1`
|
||||
if test "$3" = GNU
|
||||
then
|
||||
gettext_dir=$dir
|
||||
fi
|
||||
fi
|
||||
if test "$locale_dir" = FAILED && test -f $dir/shar \
|
||||
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
|
||||
then
|
||||
locale_dir=`$dir/shar --print-text-domain-dir`
|
||||
fi
|
||||
done
|
||||
IFS="$save_IFS"
|
||||
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
|
||||
then
|
||||
echo=echo
|
||||
else
|
||||
TEXTDOMAINDIR=$locale_dir
|
||||
export TEXTDOMAINDIR
|
||||
TEXTDOMAIN=sharutils
|
||||
export TEXTDOMAIN
|
||||
echo="$gettext_dir/gettext -s"
|
||||
fi
|
||||
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
|
||||
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
|
||||
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
|
||||
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
|
||||
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
|
||||
shar_touch='touch -am $3$4$5$6$2 "$8"'
|
||||
else
|
||||
shar_touch=:
|
||||
echo
|
||||
$echo 'WARNING: not restoring timestamps. Consider getting and'
|
||||
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
|
||||
echo
|
||||
fi
|
||||
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
|
||||
#
|
||||
if mkdir _sh09814; then
|
||||
$echo 'x -' 'creating lock directory'
|
||||
else
|
||||
$echo 'failed to create lock directory'
|
||||
exit 1
|
||||
fi
|
||||
# ============= .vim/syntax/tpl.vim ==============
|
||||
if test ! -d '.vim'; then
|
||||
$echo 'x -' 'creating directory' '.vim'
|
||||
mkdir '.vim'
|
||||
fi
|
||||
if test ! -d '.vim/syntax'; then
|
||||
$echo 'x -' 'creating directory' '.vim/syntax'
|
||||
mkdir '.vim/syntax'
|
||||
fi
|
||||
if test -f '.vim/syntax/tpl.vim' && test "$first_param" != -c; then
|
||||
$echo 'x -' SKIPPING '.vim/syntax/tpl.vim' '(file already exists)'
|
||||
else
|
||||
$echo 'x -' extracting '.vim/syntax/tpl.vim' '(text)'
|
||||
sed 's/^X//' << 'SHAR_EOF' > '.vim/syntax/tpl.vim' &&
|
||||
" Vim syntax file
|
||||
" Language: google-ctemplate
|
||||
" Maintainer: Patrick Lacasse <patlac@borabora.crchul.ulaval.ca>
|
||||
" Last Change: 2006 Août 03
|
||||
"
|
||||
" For information about google-ctemplate see
|
||||
" http://goog-ctemplate.sourceforge.net/
|
||||
"
|
||||
" This vim syntax file works on vim 5.6, 5.7, 5.8 and 6.x.
|
||||
" It implements Bram Moolenaar's April 25, 2001 recommendations to make
|
||||
" the syntax file maximally portable across different versions of vim.
|
||||
X
|
||||
" For version 5.x: Clear all syntax items
|
||||
" For version 6.x: Quit when a syntax file was already loaded
|
||||
if version < 600
|
||||
X syntax clear
|
||||
elseif exists("b:current_syntax")
|
||||
X finish
|
||||
endif
|
||||
X
|
||||
syntax match tplMarkerError "{{}\?\([^}]\+}\?\)*}}"
|
||||
syntax match tplSectionMarker "{{[#/][A-Za-z_]\+}}"
|
||||
syntax match tplInclude "{{>[A-Za-z_]\+}}"
|
||||
syntax match tplComment "{{![A-Za-z_]\+}}"
|
||||
syntax match tplVariableMarker "{{[_A-Za-z]\+}}"
|
||||
X
|
||||
" Define the default highlighting.
|
||||
" For version 5.7 and earlier: only when not done already
|
||||
" For version 5.8 and later: only when an item doesn't have highlighting yet
|
||||
if version >= 508 || !exists("did_tpl_syn_inits")
|
||||
X if version < 508
|
||||
X let did_tpl_syn_inits = 1
|
||||
X command -nargs=+ HiLink hi link <args>
|
||||
X else
|
||||
X command -nargs=+ HiLink hi def link <args>
|
||||
X endif
|
||||
X
|
||||
X HiLink tplSectionMarker Repeat
|
||||
X HiLink tplInclude Include
|
||||
X HiLink tplComment Comment
|
||||
X HiLink tplVariableMarker String
|
||||
X HiLink tplMarkerError Error
|
||||
X
|
||||
X delcommand HiLink
|
||||
endif
|
||||
X
|
||||
let b:current_syntax = "tpl"
|
||||
SHAR_EOF
|
||||
(set 20 06 08 08 13 34 11 '.vim/syntax/tpl.vim'; eval "$shar_touch") &&
|
||||
chmod 0644 '.vim/syntax/tpl.vim' ||
|
||||
$echo 'restore of' '.vim/syntax/tpl.vim' 'failed'
|
||||
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
|
||||
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
|
||||
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|
||||
|| $echo '.vim/syntax/tpl.vim:' 'MD5 check failed'
|
||||
536faef79eff0597e642c5db04c1f79d .vim/syntax/tpl.vim
|
||||
SHAR_EOF
|
||||
else
|
||||
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < '.vim/syntax/tpl.vim'`"
|
||||
test 1477 -eq "$shar_count" ||
|
||||
$echo '.vim/syntax/tpl.vim:' 'original size' '1477,' 'current size' "$shar_count!"
|
||||
fi
|
||||
fi
|
||||
# ============= .vim/ftdetect/tpl.vim ==============
|
||||
if test ! -d '.vim/ftdetect'; then
|
||||
$echo 'x -' 'creating directory' '.vim/ftdetect'
|
||||
mkdir '.vim/ftdetect'
|
||||
fi
|
||||
if test -f '.vim/ftdetect/tpl.vim' && test "$first_param" != -c; then
|
||||
$echo 'x -' SKIPPING '.vim/ftdetect/tpl.vim' '(file already exists)'
|
||||
else
|
||||
$echo 'x -' extracting '.vim/ftdetect/tpl.vim' '(text)'
|
||||
sed 's/^X//' << 'SHAR_EOF' > '.vim/ftdetect/tpl.vim' &&
|
||||
au BufRead,BufNewFile *.tpl set filetype=tpl
|
||||
SHAR_EOF
|
||||
(set 20 06 08 08 13 34 20 '.vim/ftdetect/tpl.vim'; eval "$shar_touch") &&
|
||||
chmod 0644 '.vim/ftdetect/tpl.vim' ||
|
||||
$echo 'restore of' '.vim/ftdetect/tpl.vim' 'failed'
|
||||
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
|
||||
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
|
||||
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|
||||
|| $echo '.vim/ftdetect/tpl.vim:' 'MD5 check failed'
|
||||
774fd4a092b77400ef6e74a7256ff8ef .vim/ftdetect/tpl.vim
|
||||
SHAR_EOF
|
||||
else
|
||||
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < '.vim/ftdetect/tpl.vim'`"
|
||||
test 56 -eq "$shar_count" ||
|
||||
$echo '.vim/ftdetect/tpl.vim:' 'original size' '56,' 'current size' "$shar_count!"
|
||||
fi
|
||||
fi
|
||||
rm -fr _sh09814
|
||||
exit 0
|
263
trunk/contrib/tpl-mode.el
Normal file
263
trunk/contrib/tpl-mode.el
Normal file
|
@ -0,0 +1,263 @@
|
|||
;;; tpl-mode.el -- a major mode for editing Google CTemplate files.
|
||||
;;; By Tony Gentilcore, July 2006
|
||||
;;;
|
||||
;;; TO USE:
|
||||
;;; 1) Copy this file somewhere you in emacs load-path. To see what
|
||||
;;; your load-path is, run inside emacs: C-h v load-path<RET>
|
||||
;;; 2) Add the following two lines to your .emacs file:
|
||||
;;; (setq auto-mode-alist (cons '("\\.tpl$" . tpl-mode) auto-mode-alist))
|
||||
;;; (autoload 'tpl-mode "tpl-mode" "Major mode for editing CTemplate files." t)
|
||||
;;; 3) Optionally (but recommended), add this third line as well:
|
||||
;;; (add-hook 'tpl-mode-hook '(lambda () (font-lock-mode 1)))
|
||||
;;; ---
|
||||
;;;
|
||||
;;; While the CTemplate language can be used for any types of text,
|
||||
;;; this mode is intended for using CTemplate to write HTML.
|
||||
;;;
|
||||
;;; The indentation still has minor bugs due to the fact that
|
||||
;;; templates do not require valid HTML.
|
||||
;;;
|
||||
;;; It would be nice to be able to highlight attributes of HTML tags,
|
||||
;;; however this is difficult due to the presence of CTemplate symbols
|
||||
;;; embedded within attributes.
|
||||
|
||||
(eval-when-compile
|
||||
(require 'font-lock))
|
||||
|
||||
(defgroup tpl-mode nil
|
||||
"Major mode for editing Google CTemplate files"
|
||||
:group 'languages)
|
||||
|
||||
(defvar tpl-mode-version "1.0"
|
||||
"Version of `tpl-mode.el'.")
|
||||
|
||||
(defvar tpl-mode-abbrev-table nil
|
||||
"Abbrev table for use in tpl-mode buffers.")
|
||||
|
||||
(define-abbrev-table 'tpl-mode-abbrev-table ())
|
||||
|
||||
(defcustom tpl-mode-hook nil
|
||||
"*Hook that runs upon entering tpl-mode."
|
||||
:type 'hook
|
||||
)
|
||||
|
||||
(defvar tpl-mode-map nil
|
||||
"Keymap for tpl-mode major mode")
|
||||
|
||||
(if tpl-mode-map
|
||||
nil
|
||||
(setq tpl-mode-map (make-sparse-keymap))
|
||||
)
|
||||
|
||||
(define-key tpl-mode-map "\t" 'tpl-indent-command)
|
||||
(define-key tpl-mode-map "\C-m" 'newline-and-indent)
|
||||
|
||||
|
||||
(defvar tpl-mode-syntax-table nil
|
||||
"Syntax table in use in tpl-mode buffers.")
|
||||
|
||||
;; Syntax table.
|
||||
(if tpl-mode-syntax-table
|
||||
nil
|
||||
(setq tpl-mode-syntax-table (make-syntax-table text-mode-syntax-table))
|
||||
(modify-syntax-entry ?< "(> " tpl-mode-syntax-table)
|
||||
(modify-syntax-entry ?> ")< " tpl-mode-syntax-table)
|
||||
(modify-syntax-entry ?\" ". " tpl-mode-syntax-table)
|
||||
(modify-syntax-entry ?\\ ". " tpl-mode-syntax-table)
|
||||
(modify-syntax-entry ?' "w " tpl-mode-syntax-table)
|
||||
)
|
||||
|
||||
(defvar tpl-basic-offset 2
|
||||
"The basic indentation offset.")
|
||||
|
||||
;; Constant regular expressions to identify template elements.
|
||||
(defconst tpl-mode-tpl-token "[a-zA-Z][a-zA-Z0-9_:]*?")
|
||||
(defconst tpl-mode-section (concat "\\({{[#/]"
|
||||
tpl-mode-tpl-token
|
||||
"}}\\)"))
|
||||
(defconst tpl-mode-open-section (concat "\\({{#"
|
||||
tpl-mode-tpl-token
|
||||
"}}\\)"))
|
||||
(defconst tpl-mode-close-section (concat "{{/\\("
|
||||
tpl-mode-tpl-token
|
||||
"\\)}}"))
|
||||
;; TODO(tonyg) Figure out a way to support multiline comments.
|
||||
(defconst tpl-mode-comment "\\({{!.*?}}\\)")
|
||||
(defconst tpl-mode-include (concat "\\({{>"
|
||||
tpl-mode-tpl-token
|
||||
"}}\\)"))
|
||||
(defconst tpl-mode-variable (concat "\\({{"
|
||||
tpl-mode-tpl-token
|
||||
"}}\\)"))
|
||||
(defconst tpl-mode-builtins
|
||||
(concat
|
||||
"\\({{\\<"
|
||||
(regexp-opt
|
||||
'("BI_NEWLINE" "BI_SPACE")
|
||||
t)
|
||||
"\\>}}\\)"))
|
||||
(defconst tpl-mode-close-section-at-start (concat "^[ \t]*?"
|
||||
tpl-mode-close-section))
|
||||
|
||||
;; Constant regular expressions to identify html tags.
|
||||
;; Taken from HTML 4.01 / XHTML 1.0 Reference found at:
|
||||
;; http://www.w3schools.com/tags/default.asp.
|
||||
(defconst tpl-mode-html-constant "\\(&#?[a-z0-9]\\{2,5\\};\\)")
|
||||
(defconst tpl-mode-pair-tag
|
||||
(concat
|
||||
"\\<"
|
||||
(regexp-opt
|
||||
'("a" "abbr" "acronym" "address" "applet" "area" "b" "bdo"
|
||||
"big" "blockquote" "body" "button" "caption" "center" "cite"
|
||||
"code" "col" "colgroup" "dd" "del" "dfn" "dif" "div" "dl"
|
||||
"dt" "em" "fieldset" "font" "form" "frame" "frameset" "h1"
|
||||
"h2" "h3" "h4" "h5" "h6" "head" "html" "i" "iframe" "ins"
|
||||
"kbd" "label" "legend" "li" "link" "map" "menu" "noframes"
|
||||
"noscript" "object" "ol" "optgroup" "option" "p" "pre" "q"
|
||||
"s" "samp" "script" "select" "small" "span" "strike"
|
||||
"strong" "style" "sub" "sup" "table" "tbody" "td" "textarea"
|
||||
"tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var")
|
||||
t)
|
||||
"\\>"))
|
||||
(defconst tpl-mode-standalone-tag
|
||||
(concat
|
||||
"\\<"
|
||||
(regexp-opt
|
||||
'("base" "br" "hr" "img" "input" "meta" "param")
|
||||
t)
|
||||
"\\>"))
|
||||
(defconst tpl-mode-open-tag (concat "<\\("
|
||||
tpl-mode-pair-tag
|
||||
"\\)"))
|
||||
(defconst tpl-mode-close-tag (concat "</\\("
|
||||
tpl-mode-pair-tag
|
||||
"\\)>"))
|
||||
(defconst tpl-mode-close-tag-at-start (concat "^[ \t]*?"
|
||||
tpl-mode-close-tag))
|
||||
|
||||
(defconst tpl-mode-blank-line "^[ \t]*?$")
|
||||
(defconst tpl-mode-dangling-open (concat "\\("
|
||||
tpl-mode-open-section
|
||||
"\\)\\|\\("
|
||||
tpl-mode-open-tag
|
||||
"\\)[^/]*$"))
|
||||
|
||||
(defun tpl-indent-command ()
|
||||
"Command for indenting text. Just calls tpl-indent."
|
||||
(interactive)
|
||||
(tpl-indent))
|
||||
|
||||
;; Function to control indenting.
|
||||
(defun tpl-indent ()
|
||||
"Indent current line"
|
||||
;; Set the point to beginning of line.
|
||||
(beginning-of-line)
|
||||
;; If we are at the beginning of the file, indent to 0.
|
||||
(if (bobp)
|
||||
(indent-line-to 0)
|
||||
(let ((tag-stack 1) (close-tag "") (cur-indent 0) (old-pnt (point-marker))
|
||||
(close-at-start) (open-token) (dangling-open))
|
||||
(progn
|
||||
;; Determine if this is a template line or an html line.
|
||||
(if (looking-at "^[ \t]*?{{")
|
||||
(setq close-at-start tpl-mode-close-section-at-start
|
||||
open-token "{{#")
|
||||
(setq close-at-start tpl-mode-close-tag-at-start
|
||||
open-token "<")
|
||||
)
|
||||
;; If there is a closing tag at the start of the line, search back
|
||||
;; for its opener and indent to that level.
|
||||
(if (looking-at close-at-start)
|
||||
(progn
|
||||
(save-excursion
|
||||
(setq close-tag (match-string 1))
|
||||
;; Keep searching for a match for the close tag until
|
||||
;; the tag-stack is 0.
|
||||
(while (and (not (bobp))
|
||||
(> tag-stack 0)
|
||||
(re-search-backward (concat open-token
|
||||
"\\(/?\\)"
|
||||
close-tag) nil t))
|
||||
(if (string-equal (match-string 1) "/")
|
||||
;; We found another close tag, so increment tag-stack.
|
||||
(setq tag-stack (+ tag-stack 1))
|
||||
;; We found an open tag, so decrement tag-stack.
|
||||
(setq tag-stack (- tag-stack 1))
|
||||
)
|
||||
(setq cur-indent (current-indentation))
|
||||
)
|
||||
)
|
||||
(if (> tag-stack 0)
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(setq cur-indent (current-indentation))
|
||||
)
|
||||
)
|
||||
)
|
||||
;; This was not a closing tag, so we check if the previous line
|
||||
;; was an opening tag.
|
||||
(save-excursion
|
||||
;; Keep moving back until we find a line that is not blank
|
||||
(while (progn
|
||||
(forward-line -1)
|
||||
(and (not (bobp)) (looking-at tpl-mode-blank-line))
|
||||
)
|
||||
)
|
||||
(setq cur-indent (current-indentation))
|
||||
(if (re-search-forward tpl-mode-dangling-open old-pnt t)
|
||||
(setq cur-indent (+ cur-indent tpl-basic-offset))
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Finally, we execute the actual indentation.
|
||||
(if (> cur-indent 0)
|
||||
(indent-line-to cur-indent)
|
||||
(indent-line-to 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; controls highlighting
|
||||
(defconst tpl-mode-font-lock-keywords
|
||||
(list
|
||||
(list tpl-mode-section
|
||||
'(1 font-lock-keyword-face))
|
||||
(list tpl-mode-comment
|
||||
'(1 font-lock-comment-face))
|
||||
(list tpl-mode-include
|
||||
'(1 font-lock-builtin-face))
|
||||
(list tpl-mode-builtins
|
||||
'(1 font-lock-variable-name-face))
|
||||
(list tpl-mode-variable
|
||||
'(1 font-lock-reference-face))
|
||||
(list (concat "</?\\(" tpl-mode-pair-tag "\\)")
|
||||
'(1 font-lock-function-name-face))
|
||||
(list (concat "<\\(" tpl-mode-standalone-tag "\\)")
|
||||
'(1 font-lock-function-name-face))
|
||||
(list tpl-mode-html-constant
|
||||
'(1 font-lock-variable-name-face))
|
||||
))
|
||||
|
||||
(put 'tpl-mode 'font-lock-defaults '(tpl-font-lock-keywords nil t))
|
||||
|
||||
(defun tpl-mode ()
|
||||
"Major mode for editing Google CTemplate file."
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(use-local-map tpl-mode-map)
|
||||
(setq major-mode 'tpl-mode)
|
||||
(setq mode-name "tpl-mode")
|
||||
(setq local-abbrev-table tpl-mode-abbrev-table)
|
||||
(setq indent-tabs-mode nil)
|
||||
(set-syntax-table tpl-mode-syntax-table)
|
||||
; show trailing whitespace, but only when the user can fix it
|
||||
(setq show-trailing-whitespace (not buffer-read-only))
|
||||
(make-local-variable 'indent-line-function)
|
||||
(setq indent-line-function 'tpl-indent)
|
||||
(setq font-lock-defaults '(tpl-mode-font-lock-keywords))
|
||||
(run-hooks 'tpl-mode-hook)
|
||||
)
|
||||
|
||||
(provide 'tpl-mode)
|
|
@ -234,7 +234,10 @@ HREF="#modifiers">modifiers</A>. In that case, the template-system
|
|||
starts by finding the appropriate value for that variable in the
|
||||
dictionary, just like normal. Then it applies each modifier to the
|
||||
variable, left to right. Finally, it emits the modified value to the
|
||||
output.</p>
|
||||
output. Template-includes can have modifiers in a similar way. In
|
||||
such cases, after the sub-template is expanded, but before its content
|
||||
is injected into the current template, it has the modifiers
|
||||
applied.</p>
|
||||
|
||||
<p>If no dictionary key is found for a given template marker, then the
|
||||
template marker is ignored: if a variable, it expands to the empty
|
||||
|
@ -252,7 +255,7 @@ syntax error for any template marker to violate this rule.</p>
|
|||
whatsoever, including (single) curly braces and NUL characters.</p>
|
||||
|
||||
|
||||
<h3><A NAME="modifiers">Variable Modifiers</A></h3>
|
||||
<h3><A NAME="modifiers">Modifiers</A></h3>
|
||||
|
||||
<p>Recall that variables look like this: <code>{{VARNAME}}</code>. We
|
||||
actually allow a more generic form: the variable name may be followed
|
||||
|
@ -270,6 +273,11 @@ this:</p>
|
|||
dictionary to be <code>Jim & Bob</code>, what will actually be
|
||||
emitted in the template is <code>Jim &amp; Bob</code>.</p>
|
||||
|
||||
<p>Modifiers work for variable names and also for template-includes:
|
||||
<code>{{>SUB_TEMPLATE:html_escape}}</code> means that when you expand
|
||||
<code>SUB_TEMPLATE</code>, html-escape the expanded text before
|
||||
inserting it into the current template.</p>
|
||||
|
||||
<p>You can chain modifiers together. This template first html-escapes
|
||||
<code>NAME</code>, and then javascript-escapes that result:</p>
|
||||
<pre>
|
||||
|
|
6397
trunk/libtool.m4
vendored
Normal file
6397
trunk/libtool.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -54,7 +54,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%files
|
||||
%defattr(-,root,root)
|
||||
|
||||
%doc AUTHORS COPYING ChangeLog INSTALL NEWS README doc/designstyle.css doc/index.html doc/howto.html doc/tips.html doc/example.html
|
||||
%doc AUTHORS COPYING ChangeLog INSTALL NEWS README doc/designstyle.css doc/index.html doc/howto.html doc/tips.html doc/example.html contrib/README.contrib contrib/highlighting.vim contrib/tpl-mode.el
|
||||
|
||||
%{prefix}/lib/libctemplate.so.0
|
||||
%{prefix}/lib/libctemplate.so.0.0.0
|
||||
|
|
|
@ -210,6 +210,10 @@ class TemplateDictionary {
|
|||
struct JavascriptEscape { std::string operator()(const std::string&) const; };
|
||||
static JavascriptEscape javascript_escape;
|
||||
|
||||
// Escapes " \ / <FF> <CR> <LF> <BS> <TAB> to \" \\ \/ \f \r \n \b \t
|
||||
struct JsonEscape { std::string operator()(const std::string&) const; };
|
||||
static JsonEscape json_escape;
|
||||
|
||||
|
||||
// --- DEBUGGING TOOLS
|
||||
|
||||
|
|
|
@ -337,6 +337,14 @@ struct Token {
|
|||
}
|
||||
};
|
||||
|
||||
// This applies the modifiers to a string, modifying the string in place
|
||||
static void ModifyString(const ModifierAndNonces& modifiers, string* s) {
|
||||
for (ModifierAndNonces::const_iterator it = modifiers.begin();
|
||||
it != modifiers.end(); ++it) {
|
||||
*s = (*it->first)(*s, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
}; // anonymous namespace
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -538,10 +546,7 @@ void VariableTemplateNode::Expand(ExpandEmitter *output_buffer,
|
|||
output_buffer->Emit(value); // so just emit it
|
||||
} else {
|
||||
string modified_value(value);
|
||||
for (ModifierAndNonces::const_iterator it = token_.modifier_plus_values.begin();
|
||||
it != token_.modifier_plus_values.end(); ++it) {
|
||||
modified_value = (*it->first)(modified_value, it->second);
|
||||
}
|
||||
ModifyString(token_.modifier_plus_values, &modified_value);
|
||||
output_buffer->Emit(modified_value);
|
||||
}
|
||||
|
||||
|
@ -644,10 +649,22 @@ void TemplateTemplateNode::Expand(ExpandEmitter *output_buffer,
|
|||
|
||||
// sub-dictionary NULL means 'just use the current dictionary instead'.
|
||||
// We force children to annotate the output if we have to.
|
||||
included_template->Expand(output_buffer,
|
||||
*dv_iter ? *dv_iter : dictionary,
|
||||
ShouldAnnotateOutput(dictionary, force_annotate));
|
||||
|
||||
// If the include-template has modifiers, we need to expand to a string,
|
||||
// modify the string, and append to output_buffer. Otherwise (common
|
||||
// case), we can just expand into the output-buffer directly.
|
||||
if (token_.modifier_plus_values.empty()) { // no need to modify sub-template
|
||||
included_template->Expand(output_buffer,
|
||||
*dv_iter ? *dv_iter : dictionary,
|
||||
ShouldAnnotateOutput(dictionary, force_annotate));
|
||||
} else {
|
||||
string sub_template;
|
||||
StringEmitter subtemplate_buffer(&sub_template);
|
||||
included_template->Expand(&subtemplate_buffer,
|
||||
*dv_iter ? *dv_iter : dictionary,
|
||||
ShouldAnnotateOutput(dictionary, force_annotate));
|
||||
ModifyString(token_.modifier_plus_values, &sub_template);
|
||||
output_buffer->Emit(sub_template);
|
||||
}
|
||||
if (ShouldAnnotateOutput(dictionary, force_annotate)) {
|
||||
output_buffer->Emit(CloseAnnotation("INC"));
|
||||
}
|
||||
|
@ -1123,11 +1140,13 @@ Token SectionTemplateNode::GetNextToken(Template *my_template) {
|
|||
g_modifiers[mod_index].modifier, value_string));
|
||||
}
|
||||
|
||||
// For now, we only allow variable nodes to have modifiers
|
||||
// TODO(csilvers): figure out what they mean for sections/includes
|
||||
if (!modifiers.empty() && ttype != TOKENTYPE_VARIABLE) {
|
||||
// For now, we only allow variable and include nodes to have modifiers.
|
||||
// TODO(csilvers): figure out if it's useful to have to for sections
|
||||
if (!modifiers.empty() &&
|
||||
ttype != TOKENTYPE_VARIABLE && ttype != TOKENTYPE_TEMPLATE) {
|
||||
FAIL(string(token_start, token_end - token_start)
|
||||
<< "malformed: only variables are allowed to have modifiers");
|
||||
<< "malformed: only variables and template-includes "
|
||||
<< "are allowed to have modifiers");
|
||||
}
|
||||
|
||||
// Whew! We passed the guantlet. Get ready for the next token
|
||||
|
|
|
@ -90,6 +90,7 @@ static StaticMutexInit g_static_mutex_initializer; // constructs early
|
|||
/*static*/ TemplateDictionary::HtmlEscape TemplateDictionary::html_escape;
|
||||
/*static*/ TemplateDictionary::XmlEscape TemplateDictionary::xml_escape;
|
||||
/*static*/ TemplateDictionary::JavascriptEscape TemplateDictionary::javascript_escape;
|
||||
/*static*/ TemplateDictionary::JsonEscape TemplateDictionary::json_escape;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -804,4 +805,25 @@ string TemplateDictionary::JavascriptEscape::operator()(const string& in) const
|
|||
return out;
|
||||
}
|
||||
|
||||
// Escapes " / \ <BS> <FF> <CR> <LF> <TAB> to \" \/ \\ \b \f \r \n \t
|
||||
string TemplateDictionary::JsonEscape::operator()(const string& in) const {
|
||||
string out;
|
||||
// we'll reserve some space in out to account for minimal escaping: say 1.5%
|
||||
out.reserve(in.size() + in.size()/64 + 2);
|
||||
for (int i = 0; i < in.length(); ++i) {
|
||||
switch (in[i]) {
|
||||
case '"': out += "\\\""; break;
|
||||
case '\\': out += "\\\\"; break;
|
||||
case '/': out += "\\/"; break;
|
||||
case '\b': out += "\\b"; break;
|
||||
case '\f': out += "\\f"; break;
|
||||
case '\n': out += "\\n"; break;
|
||||
case '\r': out += "\\r"; break;
|
||||
case '\t': out += "\\t"; break;
|
||||
default: out += in[i];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
|
|
@ -207,6 +207,13 @@ class TemplateDictionaryUnittest {
|
|||
dict.SetEscapedValue("hardest JS",
|
||||
("f = 'foo';\r\n\tprint \"\\&foo = \b\", \"foo\""),
|
||||
TemplateDictionary::javascript_escape);
|
||||
dict.SetEscapedValue("easy JSON", "joo",
|
||||
TemplateDictionary::json_escape);
|
||||
dict.SetEscapedValue("harder JSON", "f = \"joo\"; e = 'joo';",
|
||||
TemplateDictionary::json_escape);
|
||||
dict.SetEscapedValue("hardest JSON",
|
||||
("f = 'foo';\r\n\t\fprint \"\\&foo = /\b\", \"foo\""),
|
||||
TemplateDictionary::json_escape);
|
||||
FooEscaper foo_escaper;
|
||||
dict.SetEscapedValue("easy foo", "hello there!",
|
||||
FooEscaper());
|
||||
|
@ -233,6 +240,10 @@ class TemplateDictionaryUnittest {
|
|||
ASSERT_STREQ(dict.GetSectionValue("harder JS"), "f = \\'joo\\';");
|
||||
ASSERT_STREQ(dict.GetSectionValue("hardest JS"),
|
||||
"f = \\'foo\\';\\r\\n\tprint \\\"\\\\&foo = \\b\\\", \\\"foo\\\"");
|
||||
ASSERT_STREQ(dict.GetSectionValue("easy JSON"), "joo");
|
||||
ASSERT_STREQ(dict.GetSectionValue("harder JSON"), "f = \\\"joo\\\"; e = 'joo';");
|
||||
ASSERT_STREQ(dict.GetSectionValue("hardest JSON"),
|
||||
"f = 'foo';\\r\\n\\t\\fprint \\\"\\\\&foo = \\/\\b\\\", \\\"foo\\\"");
|
||||
ASSERT_STREQ(dict.GetSectionValue("easy foo"), "foo");
|
||||
ASSERT_STREQ(dict.GetSectionValue("harder foo"), "foo");
|
||||
ASSERT_STREQ(dict.GetSectionValue("easy double"), "doo");
|
||||
|
|
|
@ -294,6 +294,12 @@ static TemplateDictionary* MakeDict1() {
|
|||
TemplateDictionary* footer_dict = dict->AddIncludeDictionary("FOOTER");
|
||||
footer_dict->SetFilename("template_unittest_test_footer.in");
|
||||
|
||||
// --- These are used by template_unittest_test_modifiers.in
|
||||
|
||||
// UPDATE and UPDATE_SECTION we inherit from test_html.in
|
||||
TemplateDictionary* inc_simple = dict->AddIncludeDictionary("SIMPLE");
|
||||
inc_simple->SetFilename("template_unittest_test_simple.in");
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
|
|
@ -248,11 +248,9 @@ class TemplateUnittest {
|
|||
tpl = StringToTemplate("hi {{VAR:html_escape=yes}} lo", STRIP_WHITESPACE);
|
||||
ASSERT(tpl == NULL);
|
||||
|
||||
// Check we don't allow modifiers on sections or include-templates
|
||||
// Check we don't allow modifiers on sections
|
||||
tpl = StringToTemplate("hi {{#VAR:h}} lo {{/VAR}}", STRIP_WHITESPACE);
|
||||
ASSERT(tpl == NULL);
|
||||
tpl = StringToTemplate("hi {{>VAR:html_escape}} lo", STRIP_WHITESPACE);
|
||||
ASSERT(tpl == NULL);
|
||||
}
|
||||
|
||||
static void TestSection() {
|
||||
|
@ -307,6 +305,25 @@ class TemplateUnittest {
|
|||
AssertExpandIs(tpl2, &dict, "hi include file\ninclude file\ninc2\n bar");
|
||||
}
|
||||
|
||||
static void TestIncludeWithModifiers() {
|
||||
string incname = StringToTemplateFile("include & print file\n");
|
||||
string incname2 = StringToTemplateFile("inc2\n");
|
||||
// Note this also tests that html-escape, but not javascript-escape,
|
||||
// escapes \n to <space>
|
||||
Template* tpl1 = StringToTemplate("hi {{>INC:h}} bar\n", DO_NOT_STRIP);
|
||||
Template* tpl2 = StringToTemplate("hi {{>INC:javascript_escape}} bar\n",
|
||||
DO_NOT_STRIP);
|
||||
TemplateDictionary dict("dict");
|
||||
AssertExpandIs(tpl1, &dict, "hi bar\n");
|
||||
dict.AddIncludeDictionary("INC")->SetFilename(incname);
|
||||
AssertExpandIs(tpl1, &dict, "hi include & print file bar\n");
|
||||
dict.AddIncludeDictionary("INC")->SetFilename(incname2);
|
||||
AssertExpandIs(tpl1, &dict, "hi include & print file inc2 bar\n");
|
||||
AssertExpandIs(tpl2, &dict, "hi include & print file\\ninc2\\n bar\n");
|
||||
|
||||
// Don't test modifier syntax here; that's in TestVariableWithModifiers()
|
||||
}
|
||||
|
||||
// Tests that vars inherit/override their parents properly
|
||||
static void TestInheritence() {
|
||||
Template* tpl = StringToTemplate("{{FOO}}{{#SEC}}{{FOO}}{{#SEC}}{{FOO}}{{/SEC}}{{/SEC}}",
|
||||
|
@ -353,6 +370,8 @@ class TemplateUnittest {
|
|||
}
|
||||
|
||||
// Tests annotation, in particular inheriting annotation among children
|
||||
// This should be called first, so the filenames don't change as we add
|
||||
// more tests.
|
||||
static void TestAnnotation() {
|
||||
string incname = StringToTemplateFile("include {{#ISEC}}file{{/ISEC}}\n");
|
||||
string incname2 = StringToTemplateFile("include #2\n");
|
||||
|
@ -369,11 +388,11 @@ class TemplateUnittest {
|
|||
dict.SetAnnotateOutput("");
|
||||
char expected[10240]; // 10k should be big enough!
|
||||
snprintf(expected, sizeof(expected),
|
||||
"{{#FILE=%s/template.034}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=%s/template.032}}"
|
||||
"{{#FILE=%s/template.003}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=%s/template.001}}"
|
||||
"{{#SEC=__MAIN__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#INC=INC}}{{#FILE=%s/template.033}}"
|
||||
"{{#INC=INC}}{{#FILE=%s/template.002}}"
|
||||
"{{#SEC=__MAIN__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"\nhi {{#SEC=SEC}}lo{{/SEC}} bar{{/SEC}}{{/FILE}}",
|
||||
FLAGS_test_tmpdir.c_str(), FLAGS_test_tmpdir.c_str(),
|
||||
|
@ -382,11 +401,11 @@ class TemplateUnittest {
|
|||
|
||||
dict.SetAnnotateOutput("/template.");
|
||||
AssertExpandIs(tpl, &dict,
|
||||
"{{#FILE=/template.034}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=/template.032}}"
|
||||
"{{#FILE=/template.003}}{{#SEC=__MAIN__}}boo!\n"
|
||||
"{{#INC=INC}}{{#FILE=/template.001}}"
|
||||
"{{#SEC=__MAIN__}}include {{#SEC=ISEC}}file{{/SEC}}\n"
|
||||
"{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"{{#INC=INC}}{{#FILE=/template.033}}"
|
||||
"{{#INC=INC}}{{#FILE=/template.002}}"
|
||||
"{{#SEC=__MAIN__}}include #2\n{{/SEC}}{{/FILE}}{{/INC}}"
|
||||
"\nhi {{#SEC=SEC}}lo{{/SEC}} bar{{/SEC}}{{/FILE}}");
|
||||
|
||||
|
@ -671,13 +690,16 @@ class TemplateUnittest {
|
|||
int main(int argc, char** argv) {
|
||||
CleanTestDir(FLAGS_test_tmpdir);
|
||||
|
||||
// This goes first so that future tests don't mess up the filenames
|
||||
TemplateUnittest::TestAnnotation();
|
||||
|
||||
TemplateUnittest::TestVariable();
|
||||
TemplateUnittest::TestVariableWithModifiers();
|
||||
TemplateUnittest::TestSection();
|
||||
TemplateUnittest::TestInclude();
|
||||
TemplateUnittest::TestIncludeWithModifiers();
|
||||
TemplateUnittest::TestInheritence();
|
||||
TemplateUnittest::TestExpand();
|
||||
TemplateUnittest::TestAnnotation();
|
||||
|
||||
TemplateUnittest::TestGetTemplate();
|
||||
TemplateUnittest::TestStrip();
|
||||
|
|
|
@ -8,5 +8,7 @@
|
|||
{{! There should be no problem with this comment having a : in it. }}
|
||||
<IMG src=foo.jpg align={{ALIGNMENT}}>
|
||||
<IMG src="mouseover() {img=\'foo.jpg\' align={{ALIGNMENT:j}}}">
|
||||
|
||||
{{>SIMPLE:html_escape}}
|
||||
</body>
|
||||
</html>{{BI_NEWLINE}}
|
|
@ -1 +1 @@
|
|||
<html><body>monday & tuesdaymonday &amp; tuesdaymonday & tuesday<IMG src=foo.jpg align="right"><IMG src="mouseover() {img=\'foo.jpg\' align=\"right\"}"></body></html>
|
||||
<html><body>monday & tuesdaymonday &amp; tuesdaymonday & tuesday<IMG src=foo.jpg align="right"><IMG src="mouseover() {img=\'foo.jpg\' align=\"right\"}"><html><head></head><body></body></html> </body></html>
|
||||
|
|
Loading…
Reference in New Issue
Block a user