Fixed bug #15965: codemirror lib for t3editor should be moved to contrib and updated...
authorSteffen Kamper <info@sk-typo3.de>
Tue, 12 Oct 2010 21:46:29 +0000 (21:46 +0000)
committerSteffen Kamper <info@sk-typo3.de>
Tue, 12 Oct 2010 21:46:29 +0000 (21:46 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@9050 709f56b5-9817-0410-a4d7-c38de5d9e867

211 files changed:
ChangeLog
typo3/contrib/codemirror/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/._bigtest.html [new file with mode: 0644]
typo3/contrib/codemirror/._compress.html [new file with mode: 0644]
typo3/contrib/codemirror/._csstest.html [new file with mode: 0644]
typo3/contrib/codemirror/._faq.html [new file with mode: 0644]
typo3/contrib/codemirror/._favicon.ico [new file with mode: 0644]
typo3/contrib/codemirror/._highlight.html [new file with mode: 0644]
typo3/contrib/codemirror/._htmltest.html [new file with mode: 0644]
typo3/contrib/codemirror/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/._jstest.html [new file with mode: 0644]
typo3/contrib/codemirror/._manual.html [new file with mode: 0644]
typo3/contrib/codemirror/._mixedtest.html [new file with mode: 0644]
typo3/contrib/codemirror/._sparqltest.html [new file with mode: 0644]
typo3/contrib/codemirror/._story.html [new file with mode: 0644]
typo3/contrib/codemirror/._unittests.html [new file with mode: 0644]
typo3/contrib/codemirror/._unittests.js [new file with mode: 0644]
typo3/contrib/codemirror/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/bigtest.html [new file with mode: 0644]
typo3/contrib/codemirror/compress.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/css/._csharpcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/css/csharpcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/js/._parsecsharp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/js/._tokenizecsharp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/js/parsecsharp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/csharp/js/tokenizecsharp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/groovy/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/groovy/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/css/._luacolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/css/luacolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/js/._parselua.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/lua/js/parselua.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/css/._ometacolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/css/ometacolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/js/._parseometa.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/js/._tokenizeometa.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/js/parseometa.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/ometa/js/tokenizeometa.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/css/._phpcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/css/phpcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/._parsephp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/._parsephphtmlmixed.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/._tokenizephp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/parsephp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/parsephphtmlmixed.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/php/js/tokenizephp.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/css/._plsqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/css/plsqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/js/._parseplsql.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/plsql/js/parseplsql.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/css/._pythoncolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/css/pythoncolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/js/._parsepython.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/python/js/parsepython.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/css/._schemecolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/css/schemecolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/js/._parsescheme.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/js/._tokenizescheme.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/js/parsescheme.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/scheme/js/tokenizescheme.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/css/._sqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/css/sqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/js/._parsesql.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/sql/js/parsesql.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/._LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/LICENSE [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/._xqcolors-dark.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/._xqcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/._xqcolors2.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/xqcolors-dark.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/xqcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/css/xqcolors2.css [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/index.html [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/js/._parsexquery.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/js/._tokenizexquery.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/js/parsexquery.js [new file with mode: 0644]
typo3/contrib/codemirror/contrib/xquery/js/tokenizexquery.js [new file with mode: 0644]
typo3/contrib/codemirror/css/._csscolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/._docs.css [new file with mode: 0644]
typo3/contrib/codemirror/css/._jscolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/._people.jpg [new file with mode: 0644]
typo3/contrib/codemirror/css/._sparqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/._xmlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/csscolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/docs.css [new file with mode: 0644]
typo3/contrib/codemirror/css/jscolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/people.jpg [new file with mode: 0644]
typo3/contrib/codemirror/css/sparqlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/css/xmlcolors.css [new file with mode: 0644]
typo3/contrib/codemirror/csstest.html [new file with mode: 0644]
typo3/contrib/codemirror/faq.html [new file with mode: 0644]
typo3/contrib/codemirror/favicon.ico [new file with mode: 0644]
typo3/contrib/codemirror/highlight.html [new file with mode: 0644]
typo3/contrib/codemirror/htmltest.html [new file with mode: 0644]
typo3/contrib/codemirror/index.html [new file with mode: 0644]
typo3/contrib/codemirror/js/._codemirror.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._editor.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._highlight.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._mirrorframe.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsecss.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsedummy.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsehtmlmixed.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsejavascript.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsesparql.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._parsexml.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._select.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._stringstream.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._tokenize.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._tokenizejavascript.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._undo.js [new file with mode: 0644]
typo3/contrib/codemirror/js/._util.js [new file with mode: 0644]
typo3/contrib/codemirror/js/codemirror.js [new file with mode: 0644]
typo3/contrib/codemirror/js/editor.js [new file with mode: 0644]
typo3/contrib/codemirror/js/highlight.js [new file with mode: 0644]
typo3/contrib/codemirror/js/mirrorframe.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsecss.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsedummy.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsehtmlmixed.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsejavascript.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsesparql.js [new file with mode: 0644]
typo3/contrib/codemirror/js/parsexml.js [new file with mode: 0644]
typo3/contrib/codemirror/js/select.js [new file with mode: 0644]
typo3/contrib/codemirror/js/stringstream.js [new file with mode: 0644]
typo3/contrib/codemirror/js/tokenize.js [new file with mode: 0644]
typo3/contrib/codemirror/js/tokenizejavascript.js [new file with mode: 0644]
typo3/contrib/codemirror/js/undo.js [new file with mode: 0644]
typo3/contrib/codemirror/js/util.js [new file with mode: 0644]
typo3/contrib/codemirror/jstest.html [new file with mode: 0644]
typo3/contrib/codemirror/manual.html [new file with mode: 0644]
typo3/contrib/codemirror/mixedtest.html [new file with mode: 0644]
typo3/contrib/codemirror/sparqltest.html [new file with mode: 0644]
typo3/contrib/codemirror/story.html [new file with mode: 0644]
typo3/contrib/codemirror/unittests.html [new file with mode: 0644]
typo3/contrib/codemirror/unittests.js [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._.htaccess [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._.htpasswd [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._ctry_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._daily_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._hourly_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._index.html [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._usage.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._usage_201008.html [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._webalizer.current [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/._webalizer.hist [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/.htaccess [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/.htpasswd [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/ctry_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/daily_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/hourly_usage_201008.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/index.html [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/usage.png [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/usage_201008.html [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/webalizer.current [new file with mode: 0644]
typo3/contrib/codemirror/webalizer/webalizer.hist [new file with mode: 0644]
typo3/sysext/t3editor/classes/class.tx_t3editor.php
typo3/sysext/t3editor/classes/class.tx_t3editor_hooks_fileedit.php [new file with mode: 0644]
typo3/sysext/t3editor/res/jslib/codemirror/LICENSE [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/README [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/codemirror.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/editor.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/highlight.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/mirrorframe.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsecss.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsedummy.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsehtmlmixed.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsejavascript.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsesparql.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsetyposcript.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/parsexml.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/select.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/stringstream.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/tokenize.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/tokenizejavascript.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/tokenizetyposcript.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/undo.js [deleted file]
typo3/sysext/t3editor/res/jslib/codemirror/util.js [deleted file]
typo3/sysext/t3editor/res/jslib/parse_typoscript/parsetyposcript.js [new file with mode: 0644]
typo3/sysext/t3editor/res/jslib/parse_typoscript/tokenizetyposcript.js [new file with mode: 0644]
typo3/sysext/t3editor/res/jslib/t3editor.js
typo3/sysext/t3editor/res/jslib/ts_codecompletion/tscodecompletion.js

index 3f93722..63d82f2 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@
 
 2010-10-12  Steffen Kamper  <steffen@typo3.org>
 
+       * Fixed bug #15965: codemirror lib for t3editor should be moved to contrib and updated to latest version
        * Fixed bug #15968: Remove block mode from syntaxhighlighted code
        * Added feature #15621: Feature: TYPO3 misses page-option to force SSL oder Non-SSL to page (Thanks to Steffen Ritter)
        * Update #15970: Update ExtJS to version 3.3.0
diff --git a/typo3/contrib/codemirror/._LICENSE b/typo3/contrib/codemirror/._LICENSE
new file mode 100644 (file)
index 0000000..df7938e
Binary files /dev/null and b/typo3/contrib/codemirror/._LICENSE differ
diff --git a/typo3/contrib/codemirror/._bigtest.html b/typo3/contrib/codemirror/._bigtest.html
new file mode 100644 (file)
index 0000000..3a645ef
Binary files /dev/null and b/typo3/contrib/codemirror/._bigtest.html differ
diff --git a/typo3/contrib/codemirror/._compress.html b/typo3/contrib/codemirror/._compress.html
new file mode 100644 (file)
index 0000000..347f657
Binary files /dev/null and b/typo3/contrib/codemirror/._compress.html differ
diff --git a/typo3/contrib/codemirror/._csstest.html b/typo3/contrib/codemirror/._csstest.html
new file mode 100644 (file)
index 0000000..231f401
Binary files /dev/null and b/typo3/contrib/codemirror/._csstest.html differ
diff --git a/typo3/contrib/codemirror/._faq.html b/typo3/contrib/codemirror/._faq.html
new file mode 100644 (file)
index 0000000..70af02f
Binary files /dev/null and b/typo3/contrib/codemirror/._faq.html differ
diff --git a/typo3/contrib/codemirror/._favicon.ico b/typo3/contrib/codemirror/._favicon.ico
new file mode 100644 (file)
index 0000000..10d6c4c
Binary files /dev/null and b/typo3/contrib/codemirror/._favicon.ico differ
diff --git a/typo3/contrib/codemirror/._highlight.html b/typo3/contrib/codemirror/._highlight.html
new file mode 100644 (file)
index 0000000..4b262c4
Binary files /dev/null and b/typo3/contrib/codemirror/._highlight.html differ
diff --git a/typo3/contrib/codemirror/._htmltest.html b/typo3/contrib/codemirror/._htmltest.html
new file mode 100644 (file)
index 0000000..3a0cd1a
Binary files /dev/null and b/typo3/contrib/codemirror/._htmltest.html differ
diff --git a/typo3/contrib/codemirror/._index.html b/typo3/contrib/codemirror/._index.html
new file mode 100644 (file)
index 0000000..538ff65
Binary files /dev/null and b/typo3/contrib/codemirror/._index.html differ
diff --git a/typo3/contrib/codemirror/._jstest.html b/typo3/contrib/codemirror/._jstest.html
new file mode 100644 (file)
index 0000000..993823c
Binary files /dev/null and b/typo3/contrib/codemirror/._jstest.html differ
diff --git a/typo3/contrib/codemirror/._manual.html b/typo3/contrib/codemirror/._manual.html
new file mode 100644 (file)
index 0000000..2977f64
Binary files /dev/null and b/typo3/contrib/codemirror/._manual.html differ
diff --git a/typo3/contrib/codemirror/._mixedtest.html b/typo3/contrib/codemirror/._mixedtest.html
new file mode 100644 (file)
index 0000000..4d8dd5e
Binary files /dev/null and b/typo3/contrib/codemirror/._mixedtest.html differ
diff --git a/typo3/contrib/codemirror/._sparqltest.html b/typo3/contrib/codemirror/._sparqltest.html
new file mode 100644 (file)
index 0000000..701df70
Binary files /dev/null and b/typo3/contrib/codemirror/._sparqltest.html differ
diff --git a/typo3/contrib/codemirror/._story.html b/typo3/contrib/codemirror/._story.html
new file mode 100644 (file)
index 0000000..06bfb4e
Binary files /dev/null and b/typo3/contrib/codemirror/._story.html differ
diff --git a/typo3/contrib/codemirror/._unittests.html b/typo3/contrib/codemirror/._unittests.html
new file mode 100644 (file)
index 0000000..b0ed6b2
Binary files /dev/null and b/typo3/contrib/codemirror/._unittests.html differ
diff --git a/typo3/contrib/codemirror/._unittests.js b/typo3/contrib/codemirror/._unittests.js
new file mode 100644 (file)
index 0000000..dae2507
Binary files /dev/null and b/typo3/contrib/codemirror/._unittests.js differ
diff --git a/typo3/contrib/codemirror/LICENSE b/typo3/contrib/codemirror/LICENSE
new file mode 100644 (file)
index 0000000..aab5d22
--- /dev/null
@@ -0,0 +1,23 @@
+ Copyright (c) 2007-2010 Marijn Haverbeke
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
+ damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
+ redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+    not claim that you wrote the original software. If you use this
+    software in a product, an acknowledgment in the product
+    documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+    not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+    distribution.
+
+ Marijn Haverbeke
+ marijnh@gmail.com
diff --git a/typo3/contrib/codemirror/bigtest.html b/typo3/contrib/codemirror/bigtest.html
new file mode 100644 (file)
index 0000000..04ebcda
--- /dev/null
@@ -0,0 +1,1296 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: JavaScript demonstration</title>
+    <link rel="stylesheet" type="text/css" href="css/docs.css"/>
+  </head>
+  <body style="padding: 20px;">
+
+<p>This page demonstrates <a href="index.html">CodeMirror</a>'s
+JavaScript parser. Note that the ugly buttons at the top are not are
+not part of CodeMirror proper -- they demonstrate the way it can be
+embedded in a web-application.</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="30">
+/* The Editor object manages the content of the editable frame. It
+ * catches events, colours nodes, and indents lines. This file also
+ * holds some functions for transforming arbitrary DOM structures into
+ * plain sequences of &lt;span> and &lt;br> elements
+ */
+
+// Make sure a string does not contain two consecutive 'collapseable'
+// whitespace characters.
+function makeWhiteSpace(n) {
+  var buffer = [], nb = true;
+  for (; n > 0; n--) {
+    buffer.push((nb || n == 1) ? nbsp : " ");
+    nb = !nb;
+  }
+  return buffer.join("");
+}
+
+// Create a set of white-space characters that will not be collapsed
+// by the browser, but will not break text-wrapping either.
+function fixSpaces(string) {
+  if (string.charAt(0) == " ") string = nbsp + string.slice(1);
+  return string.replace(/[\t \u00a0]{2,}/g, function(s) {return makeWhiteSpace(s.length);});
+}
+
+function cleanText(text) {
+  return text.replace(/\u00a0/g, " ").replace(/\u200b/g, "");
+}
+
+// Create a SPAN node with the expected properties for document part
+// spans.
+function makePartSpan(value, doc) {
+  var text = value;
+  if (value.nodeType == 3) text = value.nodeValue;
+  else value = doc.createTextNode(text);
+
+  var span = doc.createElement("SPAN");
+  span.isPart = true;
+  span.appendChild(value);
+  span.currentText = text;
+  return span;
+}
+
+// On webkit, when the last BR of the document does not have text
+// behind it, the cursor can not be put on the line after it. This
+// makes pressing enter at the end of the document occasionally do
+// nothing (or at least seem to do nothing). To work around it, this
+// function makes sure the document ends with a span containing a
+// zero-width space character. The traverseDOM iterator filters such
+// character out again, so that the parsers won't see them. This
+// function is called from a few strategic places to make sure the
+// zwsp is restored after the highlighting process eats it.
+var webkitLastLineHack = webkit ?
+  function(container) {
+    var last = container.lastChild;
+    if (!last || !last.isPart || last.textContent != "\u200b")
+      container.appendChild(makePartSpan("\u200b", container.ownerDocument));
+  } : function() {};
+
+var Editor = (function(){
+  // The HTML elements whose content should be suffixed by a newline
+  // when converting them to flat text.
+  var newlineElements = {"P": true, "DIV": true, "LI": true};
+
+  function asEditorLines(string) {
+    return fixSpaces(string.replace(/\t/g, "  ").replace(/\u00a0/g, " ")).replace(/\r\n?/g, "\n").split("\n");
+  }
+
+  // Helper function for traverseDOM. Flattens an arbitrary DOM node
+  // into an array of textnodes and &lt;br> tags.
+  function simplifyDOM(root) {
+    var doc = root.ownerDocument;
+    var result = [];
+    var leaving = true;
+
+    function simplifyNode(node) {
+      if (node.nodeType == 3) {
+        var text = node.nodeValue = fixSpaces(node.nodeValue.replace(/[\r\u200b]/g, "").replace(/\n/g, " "));
+        if (text.length) leaving = false;
+        result.push(node);
+      }
+      else if (node.nodeName == "BR" &amp;&amp; node.childNodes.length == 0) {
+        leaving = true;
+        result.push(node);
+      }
+      else {
+        forEach(node.childNodes, simplifyNode);
+        if (!leaving &amp;&amp; newlineElements.hasOwnProperty(node.nodeName)) {
+          leaving = true;
+          result.push(doc.createElement("BR"));
+        }
+      }
+    }
+
+    simplifyNode(root);
+    return result;
+  }
+
+  // Creates a MochiKit-style iterator that goes over a series of DOM
+  // nodes. The values it yields are strings, the textual content of
+  // the nodes. It makes sure that all nodes up to and including the
+  // one whose text is being yielded have been 'normalized' to be just
+  // &lt;span> and &lt;br> elements.
+  // See the story.html file for some short remarks about the use of
+  // continuation-passing style in this iterator.
+  function traverseDOM(start){
+    function yield(value, c){cc = c; return value;}
+    function push(fun, arg, c){return function(){return fun(arg, c);};}
+    function stop(){cc = stop; throw StopIteration;};
+    var cc = push(scanNode, start, stop);
+    var owner = start.ownerDocument;
+    var nodeQueue = [];
+
+    // Create a function that can be used to insert nodes after the
+    // one given as argument.
+    function pointAt(node){
+      var parent = node.parentNode;
+      var next = node.nextSibling;
+      return function(newnode) {
+        parent.insertBefore(newnode, next);
+      };
+    }
+    var point = null;
+
+    // Insert a normalized node at the current point. If it is a text
+    // node, wrap it in a &lt;span>, and give that span a currentText
+    // property -- this is used to cache the nodeValue, because
+    // directly accessing nodeValue is horribly slow on some browsers.
+    // The dirty property is used by the highlighter to determine
+    // which parts of the document have to be re-highlighted.
+    function insertPart(part){
+      var text = "\n";
+      if (part.nodeType == 3) {
+        select.snapshotChanged();
+        part = makePartSpan(part, owner);
+        text = part.currentText;
+      }
+      part.dirty = true;
+      nodeQueue.push(part);
+      point(part);
+      return text;
+    }
+
+    // Extract the text and newlines from a DOM node, insert them into
+    // the document, and yield the textual content. Used to replace
+    // non-normalized nodes.
+    function writeNode(node, c){
+      var toYield = [];
+      forEach(simplifyDOM(node), function(part) {
+        toYield.push(insertPart(part));
+      });
+      return yield(toYield.join(""), c);
+    }
+
+    // Check whether a node is a normalized &lt;span> element.
+    function partNode(node){
+      if (node.isPart &amp;&amp; node.childNodes.length == 1 &amp;&amp; node.firstChild.nodeType == 3) {
+        node.currentText = node.firstChild.nodeValue;
+        return !/[\n\t\r]/.test(node.currentText);
+      }
+      return false;
+    }
+
+    // Handle a node. Add its successor to the continuation if there
+    // is one, find out whether the node is normalized. If it is,
+    // yield its content, otherwise, normalize it (writeNode will take
+    // care of yielding).
+    function scanNode(node, c){
+      if (node.nextSibling)
+        c = push(scanNode, node.nextSibling, c);
+
+      if (partNode(node)){
+        nodeQueue.push(node);
+        return yield(node.currentText, c);
+      }
+      else if (node.nodeName == "BR") {
+        nodeQueue.push(node);
+        return yield("\n", c);
+      }
+      else {
+        point = pointAt(node);
+        removeElement(node);
+        return writeNode(node, c);
+      }
+    }
+
+    // MochiKit iterators are objects with a next function that
+    // returns the next value or throws StopIteration when there are
+    // no more values.
+    return {next: function(){return cc();}, nodes: nodeQueue};
+  }
+
+  // Determine the text size of a processed node.
+  function nodeSize(node) {
+    if (node.nodeName == "BR")
+      return 1;
+    else
+      return node.currentText.length;
+  }
+
+  // Search backwards through the top-level nodes until the next BR or
+  // the start of the frame.
+  function startOfLine(node) {
+    while (node &amp;&amp; node.nodeName != "BR") node = node.previousSibling;
+    return node;
+  }
+  function endOfLine(node, container) {
+    if (!node) node = container.firstChild;
+    else if (node.nodeName == "BR") node = node.nextSibling;
+
+    while (node &amp;&amp; node.nodeName != "BR") node = node.nextSibling;
+    return node;
+  }
+
+  // Replace all DOM nodes in the current selection with new ones.
+  // Needed to prevent issues in IE where the old DOM nodes can be
+  // pasted back into the document, still holding their old undo
+  // information.
+  function scrubPasted(container, start, start2) {
+    var end = select.selectionTopNode(container, true),
+        doc = container.ownerDocument;
+    if (start != null &amp;&amp; start.parentNode != container) start = start2;
+    if (start === false) start = null;
+    if (start == end || !end || !container.firstChild) return;
+
+    var clear = traverseDOM(start ? start.nextSibling : container.firstChild);
+    while (end.parentNode == container) try{clear.next();}catch(e){break;}
+    forEach(clear.nodes, function(node) {
+      var newNode = node.nodeName == "BR" ? doc.createElement("BR") : makePartSpan(node.currentText, doc);
+      container.replaceChild(newNode, node);
+    });
+  }
+
+  // Client interface for searching the content of the editor. Create
+  // these by calling CodeMirror.getSearchCursor. To use, call
+  // findNext on the resulting object -- this returns a boolean
+  // indicating whether anything was found, and can be called again to
+  // skip to the next find. Use the select and replace methods to
+  // actually do something with the found locations.
+  function SearchCursor(editor, string, fromCursor) {
+    this.editor = editor;
+    this.history = editor.history;
+    this.history.commit();
+
+    // Are we currently at an occurrence of the search string?
+    this.atOccurrence = false;
+    // The object stores a set of nodes coming after its current
+    // position, so that when the current point is taken out of the
+    // DOM tree, we can still try to continue.
+    this.fallbackSize = 15;
+    var cursor;
+    // Start from the cursor when specified and a cursor can be found.
+    if (fromCursor &amp;&amp; (cursor = select.cursorPos(this.editor.container))) {
+      this.line = cursor.node;
+      this.offset = cursor.offset;
+    }
+    else {
+      this.line = null;
+      this.offset = 0;
+    }
+    this.valid = !!string;
+
+    // Create a matcher function based on the kind of string we have.
+    var target = string.split("\n"), self = this;;
+    this.matches = (target.length == 1) ?
+      // For one-line strings, searching can be done simply by calling
+      // indexOf on the current line.
+      function() {
+        var match = cleanText(self.history.textAfter(self.line).slice(self.offset)).indexOf(string);
+        if (match > -1)
+          return {from: {node: self.line, offset: self.offset + match},
+                  to: {node: self.line, offset: self.offset + match + string.length}};
+      } :
+      // Multi-line strings require internal iteration over lines, and
+      // some clunky checks to make sure the first match ends at the
+      // end of the line and the last match starts at the start.
+      function() {
+        var firstLine = cleanText(self.history.textAfter(self.line).slice(self.offset));
+        var match = firstLine.lastIndexOf(target[0]);
+        if (match == -1 || match != firstLine.length - target[0].length)
+          return false;
+        var startOffset = self.offset + match;
+
+        var line = self.history.nodeAfter(self.line);
+        for (var i = 1; i &lt; target.length - 1; i++) {
+          if (cleanText(self.history.textAfter(line)) != target[i])
+            return false;
+          line = self.history.nodeAfter(line);
+        }
+
+        if (cleanText(self.history.textAfter(line)).indexOf(target[target.length - 1]) != 0)
+          return false;
+
+        return {from: {node: self.line, offset: startOffset},
+                to: {node: line, offset: target[target.length - 1].length}};
+      };
+  }
+
+  SearchCursor.prototype = {
+    findNext: function() {
+      if (!this.valid) return false;
+      this.atOccurrence = false;
+      var self = this;
+
+      // Go back to the start of the document if the current line is
+      // no longer in the DOM tree.
+      if (this.line &amp;&amp; !this.line.parentNode) {
+        this.line = null;
+        this.offset = 0;
+      }
+
+      // Set the cursor's position one character after the given
+      // position.
+      function saveAfter(pos) {
+        if (self.history.textAfter(pos.node).length &lt; pos.offset) {
+          self.line = pos.node;
+          self.offset = pos.offset + 1;
+        }
+        else {
+          self.line = self.history.nodeAfter(pos.node);
+          self.offset = 0;
+        }
+      }
+
+      while (true) {
+        var match = this.matches();
+        // Found the search string.
+        if (match) {
+          this.atOccurrence = match;
+          saveAfter(match.from);
+          return true;
+        }
+        this.line = this.history.nodeAfter(this.line);
+        this.offset = 0;
+        // End of document.
+        if (!this.line) {
+          this.valid = false;
+          return false;
+        }
+      }
+    },
+
+    select: function() {
+      if (this.atOccurrence) {
+        select.setCursorPos(this.editor.container, this.atOccurrence.from, this.atOccurrence.to);
+        select.scrollToCursor(this.editor.container);
+      }
+    },
+
+    replace: function(string) {
+      if (this.atOccurrence) {
+        var end = this.editor.replaceRange(this.atOccurrence.from, this.atOccurrence.to, string);
+        this.line = end.node;
+        this.offset = end.offset;
+        this.atOccurrence = false;
+      }
+    }
+  };
+
+  // The Editor object is the main inside-the-iframe interface.
+  function Editor(options) {
+    this.options = options;
+    window.indentUnit = options.indentUnit;
+    this.parent = parent;
+    this.doc = document;
+    var container = this.container = this.doc.body;
+    this.win = window;
+    this.history = new History(container, options.undoDepth, options.undoDelay,
+                               this, options.onChange);
+    var self = this;
+
+    if (!Editor.Parser)
+      throw "No parser loaded.";
+    if (options.parserConfig &amp;&amp; Editor.Parser.configure)
+      Editor.Parser.configure(options.parserConfig);
+
+    if (!options.readOnly)
+      select.setCursorPos(container, {node: null, offset: 0});
+
+    this.dirty = [];
+    if (options.content)
+      this.importCode(options.content);
+    else // FF acts weird when the editable document is completely empty
+      container.appendChild(this.doc.createElement("BR"));
+
+    if (!options.readOnly) {
+      if (options.continuousScanning !== false) {
+        this.scanner = this.documentScanner(options.linesPerPass);
+        this.delayScanning();
+      }
+
+      function setEditable() {
+        // In IE, designMode frames can not run any scripts, so we use
+        // contentEditable instead.
+        if (document.body.contentEditable != undefined &amp;&amp; internetExplorer)
+          document.body.contentEditable = "true";
+        else
+          document.designMode = "on";
+
+        document.documentElement.style.borderWidth = "0";
+        if (!options.textWrapping)
+          container.style.whiteSpace = "nowrap";
+      }
+
+      // If setting the frame editable fails, try again when the user
+      // focus it (happens when the frame is not visible on
+      // initialisation, in Firefox).
+      try {
+        setEditable();
+      }
+      catch(e) {
+        var focusEvent = addEventHandler(document, "focus", function() {
+          focusEvent();
+          setEditable();
+        }, true);
+      }
+
+      addEventHandler(document, "keydown", method(this, "keyDown"));
+      addEventHandler(document, "keypress", method(this, "keyPress"));
+      addEventHandler(document, "keyup", method(this, "keyUp"));
+
+      function cursorActivity() {self.cursorActivity(false);}
+      addEventHandler(document.body, "mouseup", cursorActivity);
+      addEventHandler(document.body, "paste", function(event) {
+        cursorActivity();
+        if (internetExplorer) {
+          var text = null;
+          try {text = window.clipboardData.getData("Text");}catch(e){}
+          if (text != null) {
+            self.replaceSelection(text);
+            event.stop();
+          }
+          else {
+            var start = select.selectionTopNode(self.container, true),
+                start2 = start &amp;&amp; start.previousSibling;
+            setTimeout(function(){scrubPasted(self.container, start, start2);}, 0);
+          }
+        }
+      });
+      addEventHandler(document.body, "cut", cursorActivity);
+
+      if (this.options.autoMatchParens)
+        addEventHandler(document.body, "click", method(this, "scheduleParenBlink"));
+    }
+  }
+
+  function isSafeKey(code) {
+    return (code >= 16 &amp;&amp; code &lt;= 18) || // shift, control, alt
+           (code >= 33 &amp;&amp; code &lt;= 40); // arrows, home, end
+  }
+
+  Editor.prototype = {
+    // Import a piece of code into the editor.
+    importCode: function(code) {
+      this.history.push(null, null, asEditorLines(code));
+      this.history.reset();
+    },
+
+    // Extract the code from the editor.
+    getCode: function() {
+      if (!this.container.firstChild)
+        return "";
+
+      var accum = [];
+      select.markSelection(this.win);
+      forEach(traverseDOM(this.container.firstChild), method(accum, "push"));
+      webkitLastLineHack(this.container);
+      select.selectMarked();
+      return cleanText(accum.join(""));
+    },
+
+    checkLine: function(node) {
+      if (node === false || !(node == null || node.parentNode == this.container))
+        throw parent.CodeMirror.InvalidLineHandle;
+    },
+
+    cursorPosition: function(start) {
+      if (start == null) start = true;
+      var pos = select.cursorPos(this.container, start);
+      if (pos) return {line: pos.node, character: pos.offset};
+      else return {line: null, character: 0};
+    },
+
+    firstLine: function() {
+      return null;
+    },
+
+    lastLine: function() {
+      if (this.container.lastChild) return startOfLine(this.container.lastChild);
+      else return null;
+    },
+
+    nextLine: function(line) {
+      this.checkLine(line);
+      var end = endOfLine(line, this.container);
+      return end || false;
+    },
+
+    prevLine: function(line) {
+      this.checkLine(line);
+      if (line == null) return false;
+      return startOfLine(line.previousSibling);
+    },
+
+    selectLines: function(startLine, startOffset, endLine, endOffset) {
+      this.checkLine(startLine);
+      var start = {node: startLine, offset: startOffset}, end = null;
+      if (endOffset !== undefined) {
+        this.checkLine(endLine);
+        end = {node: endLine, offset: endOffset};
+      }
+      select.setCursorPos(this.container, start, end);
+      select.scrollToCursor(this.container);
+    },
+
+    lineContent: function(line) {
+      this.checkLine(line);
+      var accum = [];
+      for (line = line ? line.nextSibling : this.container.firstChild;
+           line &amp;&amp; line.nodeName != "BR"; line = line.nextSibling)
+        accum.push(nodeText(line));
+      return cleanText(accum.join(""));
+    },
+
+    setLineContent: function(line, content) {
+      this.history.commit();
+      this.replaceRange({node: line, offset: 0},
+                        {node: line, offset: this.history.textAfter(line).length},
+                        content);
+      this.addDirtyNode(line);
+      this.scheduleHighlight();
+    },
+
+    insertIntoLine: function(line, position, content) {
+      var before = null;
+      if (position == "end") {
+        before = endOfLine(line, this.container);
+      }
+      else {
+        for (var cur = line ? line.nextSibling : this.container.firstChild; cur; cur = cur.nextSibling) {
+          if (position == 0) {
+            before = cur;
+            break;
+          }
+          var text = (cur.innerText || cur.textContent || cur.nodeValue || "");
+          if (text.length > position) {
+            before = cur.nextSibling;
+            content = text.slice(0, position) + content + text.slice(position);
+            removeElement(cur);
+            break;
+          }
+          position -= text.length;
+        }
+      }
+
+      var lines = asEditorLines(content), doc = this.container.ownerDocument;
+      for (var i = 0; i &lt; lines.length; i++) {
+        if (i > 0) this.container.insertBefore(doc.createElement("BR"), before);
+        this.container.insertBefore(makePartSpan(lines[i], doc), before);
+      }
+      this.addDirtyNode(line);
+      this.scheduleHighlight();
+    },
+
+    // Retrieve the selected text.
+    selectedText: function() {
+      var h = this.history;
+      h.commit();
+
+      var start = select.cursorPos(this.container, true),
+          end = select.cursorPos(this.container, false);
+      if (!start || !end) return "";
+
+      if (start.node == end.node)
+        return h.textAfter(start.node).slice(start.offset, end.offset);
+
+      var text = [h.textAfter(start.node).slice(start.offset)];
+      for (pos = h.nodeAfter(start.node); pos != end.node; pos = h.nodeAfter(pos))
+        text.push(h.textAfter(pos));
+      text.push(h.textAfter(end.node).slice(0, end.offset));
+      return cleanText(text.join("\n"));
+    },
+
+    // Replace the selection with another piece of text.
+    replaceSelection: function(text) {
+      this.history.commit();
+      var start = select.cursorPos(this.container, true),
+          end = select.cursorPos(this.container, false);
+      if (!start || !end) return;
+
+      end = this.replaceRange(start, end, text);
+      select.setCursorPos(this.container, start, end);
+    },
+
+    replaceRange: function(from, to, text) {
+      var lines = asEditorLines(text);
+      lines[0] = this.history.textAfter(from.node).slice(0, from.offset) + lines[0];
+      var lastLine = lines[lines.length - 1];
+      lines[lines.length - 1] = lastLine + this.history.textAfter(to.node).slice(to.offset);
+      var end = this.history.nodeAfter(to.node);
+      this.history.push(from.node, end, lines);
+      return {node: this.history.nodeBefore(end),
+              offset: lastLine.length};
+    },
+
+    getSearchCursor: function(string, fromCursor) {
+      return new SearchCursor(this, string, fromCursor);
+    },
+
+    // Re-indent the whole buffer
+    reindent: function() {
+      if (this.container.firstChild)
+        this.indentRegion(null, this.container.lastChild);
+    },
+
+    grabKeys: function(eventHandler, filter) {
+      this.frozen = eventHandler;
+      this.keyFilter = filter;
+    },
+    ungrabKeys: function() {
+      this.frozen = "leave";
+      this.keyFilter = null;
+    },
+
+    // Intercept enter and tab, and assign their new functions.
+    keyDown: function(event) {
+      if (this.frozen == "leave") this.frozen = null;
+      if (this.frozen &amp;&amp; (!this.keyFilter || this.keyFilter(event.keyCode))) {
+        event.stop();
+        this.frozen(event);
+        return;
+      }
+
+      var code = event.keyCode;
+      // Don't scan when the user is typing.
+      this.delayScanning();
+      // Schedule a paren-highlight event, if configured.
+      if (this.options.autoMatchParens)
+        this.scheduleParenBlink();
+
+      if (code == 13) { // enter
+        if (event.ctrlKey) {
+          this.reparseBuffer();
+        }
+        else {
+          select.insertNewlineAtCursor(this.win);
+          this.indentAtCursor();
+          select.scrollToCursor(this.container);
+        }
+        event.stop();
+      }
+      else if (code == 9 &amp;&amp; this.options.tabMode != "default") { // tab
+        this.handleTab(!event.ctrlKey &amp;&amp; !event.shiftKey);
+        event.stop();
+      }
+      else if (code == 32 &amp;&amp; event.shiftKey &amp;&amp; this.options.tabMode == "default") { // space
+        this.handleTab(true);
+        event.stop();
+      }
+      else if ((code == 219 || code == 221) &amp;&amp; event.ctrlKey) {
+        this.blinkParens(event.shiftKey);
+        event.stop();
+      }
+      else if (event.metaKey &amp;&amp; (code == 37 || code == 39)) { // Meta-left/right
+        var cursor = select.selectionTopNode(this.container);
+        if (cursor === false || !this.container.firstChild) return;
+
+        if (code == 37) select.focusAfterNode(startOfLine(cursor), this.container);
+        else {
+          end = endOfLine(cursor, this.container);
+          select.focusAfterNode(end ? end.previousSibling : this.container.lastChild, this.container);
+        }
+        event.stop();
+      }
+      else if (event.ctrlKey || event.metaKey) {
+        if ((event.shiftKey &amp;&amp; code == 90) || code == 89) { // shift-Z, Y
+          select.scrollToNode(this.history.redo());
+          event.stop();
+        }
+        else if (code == 90 || code == 8) { // Z, backspace
+          select.scrollToNode(this.history.undo());
+          event.stop();
+        }
+        else if (code == 83 &amp;&amp; this.options.saveFunction) { // S
+          this.options.saveFunction();
+          event.stop();
+        }
+      }
+    },
+
+    // Check for characters that should re-indent the current line,
+    // and prevent Opera from handling enter and tab anyway.
+    keyPress: function(event) {
+      var electric = /indent|default/.test(this.options.tabMode) &amp;&amp; Editor.Parser.electricChars;
+      // Hack for Opera, and Firefox on OS X, in which stopping a
+      // keydown event does not prevent the associated keypress event
+      // from happening, so we have to cancel enter and tab again
+      // here.
+      if ((this.frozen &amp;&amp; (!this.keyFilter || this.keyFilter(event.keyCode))) ||
+          event.code == 13 || (event.code == 9 &amp;&amp; this.options.tabMode != "default") ||
+          (event.keyCode == 32 &amp;&amp; event.shiftKey &amp;&amp; this.options.tabMode == "default"))
+        event.stop();
+      else if (electric &amp;&amp; electric.indexOf(event.character) != -1)
+        this.parent.setTimeout(method(this, "indentAtCursor"), 0);
+    },
+
+    // Mark the node at the cursor dirty when a non-safe key is
+    // released.
+    keyUp: function(event) {
+      this.cursorActivity(isSafeKey(event.keyCode));
+    },
+
+    // Indent the line following a given &lt;br>, or null for the first
+    // line. If given a &lt;br> element, this must have been highlighted
+    // so that it has an indentation method. Returns the whitespace
+    // element that has been modified or created (if any).
+    indentLineAfter: function(start, direction) {
+      // whiteSpace is the whitespace span at the start of the line,
+      // or null if there is no such node.
+      var whiteSpace = start ? start.nextSibling : this.container.firstChild;
+      if (whiteSpace &amp;&amp; !hasClass(whiteSpace, "whitespace"))
+        whiteSpace = null;
+
+      // Sometimes the start of the line can influence the correct
+      // indentation, so we retrieve it.
+      var firstText = whiteSpace ? whiteSpace.nextSibling : (start ? start.nextSibling : this.container.firstChild);
+      var nextChars = (start &amp;&amp; firstText &amp;&amp; firstText.currentText) ? firstText.currentText : "";
+
+      // Ask the lexical context for the correct indentation, and
+      // compute how much this differs from the current indentation.
+      var newIndent = 0, curIndent = whiteSpace ? whiteSpace.currentText.length : 0;
+      if (direction != null &amp;&amp; this.options.tabMode == "shift")
+        newIndent = direction ? curIndent + indentUnit : Math.max(0, curIndent - indentUnit)
+      else if (start)
+        newIndent = start.indentation(nextChars, curIndent, direction);
+      else if (Editor.Parser.firstIndentation)
+        newIndent = Editor.Parser.firstIndentation(nextChars, curIndent, direction);
+      var indentDiff = newIndent - curIndent;
+
+      // If there is too much, this is just a matter of shrinking a span.
+      if (indentDiff &lt; 0) {
+        if (newIndent == 0) {
+          if (firstText) select.snapshotMove(whiteSpace.firstChild, firstText.firstChild, 0);
+          removeElement(whiteSpace);
+          whiteSpace = null;
+        }
+        else {
+          select.snapshotMove(whiteSpace.firstChild, whiteSpace.firstChild, indentDiff, true);
+          whiteSpace.currentText = makeWhiteSpace(newIndent);
+          whiteSpace.firstChild.nodeValue = whiteSpace.currentText;
+        }
+      }
+      // Not enough...
+      else if (indentDiff > 0) {
+        // If there is whitespace, we grow it.
+        if (whiteSpace) {
+          whiteSpace.currentText = makeWhiteSpace(newIndent);
+          whiteSpace.firstChild.nodeValue = whiteSpace.currentText;
+        }
+        // Otherwise, we have to add a new whitespace node.
+        else {
+          whiteSpace = makePartSpan(makeWhiteSpace(newIndent), this.doc);
+          whiteSpace.className = "whitespace";
+          if (start) insertAfter(whiteSpace, start);
+          else this.container.insertBefore(whiteSpace, this.container.firstChild);
+        }
+        if (firstText) select.snapshotMove(firstText.firstChild, whiteSpace.firstChild, curIndent, false, true);
+      }
+      if (indentDiff != 0) this.addDirtyNode(start);
+      return whiteSpace;
+    },
+
+    // Re-highlight the selected part of the document.
+    highlightAtCursor: function() {
+      var pos = select.selectionTopNode(this.container, true);
+      var to = select.selectionTopNode(this.container, false);
+      if (pos === false || to === false) return;
+
+      select.markSelection(this.win);
+      if (this.highlight(pos, endOfLine(to, this.container), true, 20) === false)
+        return false;
+      select.selectMarked();
+      return true;
+    },
+
+    // When tab is pressed with text selected, the whole selection is
+    // re-indented, when nothing is selected, the line with the cursor
+    // is re-indented.
+    handleTab: function(direction) {
+      if (this.options.tabMode == "spaces") {
+        select.insertTabAtCursor(this.win);
+      }
+      else if (!select.somethingSelected(this.win)) {
+        this.indentAtCursor(direction);
+      }
+      else {
+        var start = select.selectionTopNode(this.container, true),
+            end = select.selectionTopNode(this.container, false);
+        if (start === false || end === false) return;
+        this.indentRegion(start, end, direction);
+      }
+    },
+
+    // Delay (or initiate) the next paren blink event.
+    scheduleParenBlink: function() {
+      if (this.parenEvent) this.parent.clearTimeout(this.parenEvent);
+      var self = this;
+      this.parenEvent = this.parent.setTimeout(function(){self.blinkParens();}, 300);
+    },
+
+    // Take the token before the cursor. If it contains a character in
+    // '()[]{}', search for the matching paren/brace/bracket, and
+    // highlight them in green for a moment, or red if no proper match
+    // was found.
+    blinkParens: function(jump) {
+      // Clear the event property.
+      if (this.parenEvent) this.parent.clearTimeout(this.parenEvent);
+      this.parenEvent = null;
+
+      // Extract a 'paren' from a piece of text.
+      function paren(node) {
+        if (node.currentText) {
+          var match = node.currentText.match(/^[\s\u00a0]*([\(\)\[\]{}])[\s\u00a0]*$/);
+          return match &amp;&amp; match[1];
+        }
+      }
+      // Determine the direction a paren is facing.
+      function forward(ch) {
+        return /[\(\[\{]/.test(ch);
+      }
+
+      var ch, self = this, cursor = select.selectionTopNode(this.container, true);
+      if (!cursor || !this.highlightAtCursor()) return;
+      cursor = select.selectionTopNode(this.container, true);
+      if (!(cursor &amp;&amp; ((ch = paren(cursor)) || (cursor = cursor.nextSibling) &amp;&amp; (ch = paren(cursor)))))
+        return;
+      // We only look for tokens with the same className.
+      var className = cursor.className, dir = forward(ch), match = matching[ch];
+
+      // Since parts of the document might not have been properly
+      // highlighted, and it is hard to know in advance which part we
+      // have to scan, we just try, and when we find dirty nodes we
+      // abort, parse them, and re-try.
+      function tryFindMatch() {
+        var stack = [], ch, ok = true;;
+        for (var runner = cursor; runner; runner = dir ? runner.nextSibling : runner.previousSibling) {
+          if (runner.className == className &amp;&amp; runner.nodeName == "SPAN" &amp;&amp; (ch = paren(runner))) {
+            if (forward(ch) == dir)
+              stack.push(ch);
+            else if (!stack.length)
+              ok = false;
+            else if (stack.pop() != matching[ch])
+              ok = false;
+            if (!stack.length) break;
+          }
+          else if (runner.dirty || runner.nodeName != "SPAN" &amp;&amp; runner.nodeName != "BR") {
+            return {node: runner, status: "dirty"};
+          }
+        }
+        return {node: runner, status: runner &amp;&amp; ok};
+      }
+      // Temporarily give the relevant nodes a colour.
+      function blink(node, ok) {
+        node.style.fontWeight = "bold";
+        node.style.color = ok ? "#8F8" : "#F88";
+        self.parent.setTimeout(function() {node.style.fontWeight = ""; node.style.color = "";}, 500);
+      }
+
+      while (true) {
+        var found = tryFindMatch();
+        if (found.status == "dirty") {
+          this.highlight(found.node, 1);
+          // Needed because in some corner cases a highlight does not
+          // reach a node.
+          found.node.dirty = false;
+          continue;
+        }
+        else {
+          blink(cursor, found.status);
+          if (found.node) {
+            blink(found.node, found.status);
+            if (jump) select.focusAfterNode(found.node.previousSibling, this.container);
+          }
+          break;
+        }
+      }
+    },
+
+    // Adjust the amount of whitespace at the start of the line that
+    // the cursor is on so that it is indented properly.
+    indentAtCursor: function(direction) {
+      if (!this.container.firstChild) return;
+      // The line has to have up-to-date lexical information, so we
+      // highlight it first.
+      if (!this.highlightAtCursor()) return;
+      var cursor = select.selectionTopNode(this.container, false);
+      // If we couldn't determine the place of the cursor,
+      // there's nothing to indent.
+      if (cursor === false)
+        return;
+      var lineStart = startOfLine(cursor);
+      var whiteSpace = this.indentLineAfter(lineStart, direction);
+      if (cursor == lineStart &amp;&amp; whiteSpace)
+          cursor = whiteSpace;
+      // This means the indentation has probably messed up the cursor.
+      if (cursor == whiteSpace)
+        select.focusAfterNode(cursor, this.container);
+    },
+
+    // Indent all lines whose start falls inside of the current
+    // selection.
+    indentRegion: function(start, end, direction) {
+      var current = (start = startOfLine(start)), before = start &amp;&amp; startOfLine(start.previousSibling);
+      if (end.nodeName != "BR") end = endOfLine(end, this.container);
+
+      do {
+        if (current) this.highlight(before, current, true);
+        this.indentLineAfter(current, direction);
+        before = current;
+        current = endOfLine(current, this.container);
+      } while (current != end);
+      select.setCursorPos(this.container, {node: start, offset: 0}, {node: end, offset: 0});
+    },
+
+    // Find the node that the cursor is in, mark it as dirty, and make
+    // sure a highlight pass is scheduled.
+    cursorActivity: function(safe) {
+      if (internetExplorer) {
+        this.container.createTextRange().execCommand("unlink");
+        this.selectionSnapshot = select.selectionCoords(this.win);
+      }
+
+      var activity = this.options.cursorActivity;
+      if (!safe || activity) {
+        var cursor = select.selectionTopNode(this.container, false);
+        if (cursor === false || !this.container.firstChild) return;
+        cursor = cursor || this.container.firstChild;
+        if (activity) activity(cursor);
+        if (!safe) {
+          this.scheduleHighlight();
+          this.addDirtyNode(cursor);
+        }
+      }
+    },
+
+    reparseBuffer: function() {
+      forEach(this.container.childNodes, function(node) {node.dirty = true;});
+      if (this.container.firstChild)
+        this.addDirtyNode(this.container.firstChild);
+    },
+
+    // Add a node to the set of dirty nodes, if it isn't already in
+    // there.
+    addDirtyNode: function(node) {
+      node = node || this.container.firstChild;
+      if (!node) return;
+
+      for (var i = 0; i &lt; this.dirty.length; i++)
+        if (this.dirty[i] == node) return;
+
+      if (node.nodeType != 3)
+        node.dirty = true;
+      this.dirty.push(node);
+    },
+
+    // Cause a highlight pass to happen in options.passDelay
+    // milliseconds. Clear the existing timeout, if one exists. This
+    // way, the passes do not happen while the user is typing, and
+    // should as unobtrusive as possible.
+    scheduleHighlight: function() {
+      // Timeouts are routed through the parent window, because on
+      // some browsers designMode windows do not fire timeouts.
+      var self = this;
+      this.parent.clearTimeout(this.highlightTimeout);
+      this.highlightTimeout = this.parent.setTimeout(function(){self.highlightDirty();}, this.options.passDelay);
+    },
+
+    // Fetch one dirty node, and remove it from the dirty set.
+    getDirtyNode: function() {
+      while (this.dirty.length > 0) {
+        var found = this.dirty.pop();
+        // IE8 sometimes throws an unexplainable 'invalid argument'
+        // exception for found.parentNode
+        try {
+          // If the node has been coloured in the meantime, or is no
+          // longer in the document, it should not be returned.
+          while (found &amp;&amp; found.parentNode != this.container)
+            found = found.parentNode
+          if (found &amp;&amp; (found.dirty || found.nodeType == 3))
+            return found;
+        } catch (e) {}
+      }
+      return null;
+    },
+
+    // Pick dirty nodes, and highlight them, until
+    // options.linesPerPass lines have been highlighted. The highlight
+    // method will continue to next lines as long as it finds dirty
+    // nodes. It returns an object indicating the amount of lines
+    // left, and information about the place where it stopped. If
+    // there are dirty nodes left after this function has spent all
+    // its lines, it shedules another highlight to finish the job.
+    highlightDirty: function(force) {
+      // Prevent FF from raising an error when it is firing timeouts
+      // on a page that's no longer loaded.
+      if (!window.select) return;
+
+      var lines = force ? Infinity : this.options.linesPerPass;
+      if (!this.options.readOnly) select.markSelection(this.win);
+      var start;
+      while (lines > 0 &amp;&amp; (start = this.getDirtyNode())){
+        var result = this.highlight(start, lines);
+        if (result) {
+          lines = result.left;
+          if (result.node &amp;&amp; result.dirty)
+            this.addDirtyNode(result.node);
+        }
+      }
+      if (!this.options.readOnly) select.selectMarked();
+      if (start)
+        this.scheduleHighlight();
+      return this.dirty.length == 0;
+    },
+
+    // Creates a function that, when called through a timeout, will
+    // continuously re-parse the document.
+    documentScanner: function(linesPer) {
+      var self = this, pos = null;
+      return function() {
+        // If the current node is no longer in the document... oh
+        // well, we start over.
+        if (pos &amp;&amp; pos.parentNode != self.container)
+          pos = null;
+        select.markSelection(self.win);
+        var result = self.highlight(pos, linesPer, true);
+        select.selectMarked();
+        var newPos = result ? (result.node &amp;&amp; result.node.nextSibling) : null;
+        pos = (pos == newPos) ? null : newPos;
+        self.delayScanning();
+      };
+    },
+
+    // Starts the continuous scanning process for this document after
+    // a given interval.
+    delayScanning: function() {
+      if (this.scanner) {
+        this.parent.clearTimeout(this.documentScan);
+        this.documentScan = this.parent.setTimeout(this.scanner, this.options.continuousScanning);
+      }
+    },
+
+    // The function that does the actual highlighting/colouring (with
+    // help from the parser and the DOM normalizer). Its interface is
+    // rather overcomplicated, because it is used in different
+    // situations: ensuring that a certain line is highlighted, or
+    // highlighting up to X lines starting from a certain point. The
+    // 'from' argument gives the node at which it should start. If
+    // this is null, it will start at the beginning of the document.
+    // When a number of lines is given with the 'target' argument, it
+    // will highlight no more than that amount of lines. If this
+    // argument holds a DOM node, it will highlight until it reaches
+    // that node. If at any time it comes across a 'clean' line (no
+    // dirty nodes), it will stop, except when 'cleanLines' is true.
+    highlight: function(from, target, cleanLines, maxBacktrack){
+      var container = this.container, self = this, active = this.options.activeTokens;
+      var lines = (typeof target == "number" ? target : null);
+
+      if (!container.firstChild)
+        return;
+      // Backtrack to the first node before from that has a partial
+      // parse stored.
+      while (from &amp;&amp; (!from.parserFromHere || from.dirty)) {
+        from = from.previousSibling;
+        if (maxBacktrack != null &amp;&amp; from.nodeName == "BR" &amp;&amp; (--maxBacktrack) &lt; 0)
+          return false;
+      }
+      // If we are at the end of the document, do nothing.
+      if (from &amp;&amp; !from.nextSibling)
+        return;
+
+      // Check whether a part (&lt;span> node) and the corresponding token
+      // match.
+      function correctPart(token, part){
+        return !part.reduced &amp;&amp; part.currentText == token.value &amp;&amp; part.className == token.style;
+      }
+      // Shorten the text associated with a part by chopping off
+      // characters from the front. Note that only the currentText
+      // property gets changed. For efficiency reasons, we leave the
+      // nodeValue alone -- we set the reduced flag to indicate that
+      // this part must be replaced.
+      function shortenPart(part, minus){
+        part.currentText = part.currentText.substring(minus);
+        part.reduced = true;
+      }
+      // Create a part corresponding to a given token.
+      function tokenPart(token){
+        var part = makePartSpan(token.value, self.doc);
+        part.className = token.style;
+        return part;
+      }
+
+      function maybeTouch(node) {
+        if (node) {
+          if (node.nextSibling != node.oldNextSibling) {
+            self.history.touch(node);
+            node.oldNextSibling = node.nextSibling;
+          }
+        }
+        else {
+          if (self.container.firstChild != self.container.oldFirstChild) {
+            self.history.touch(node);
+            self.container.oldFirstChild = self.container.firstChild;
+          }
+        }
+      }
+
+      // Get the token stream. If from is null, we start with a new
+      // parser from the start of the frame, otherwise a partial parse
+      // is resumed.
+      var traversal = traverseDOM(from ? from.nextSibling : container.firstChild),
+          stream = stringStream(traversal),
+          parsed = from ? from.parserFromHere(stream) : Editor.Parser.make(stream);
+
+      // parts is an interface to make it possible to 'delay' fetching
+      // the next DOM node until we are completely done with the one
+      // before it. This is necessary because often the next node is
+      // not yet available when we want to proceed past the current
+      // one.
+      var parts = {
+        current: null,
+        // Fetch current node.
+        get: function(){
+          if (!this.current)
+            this.current = traversal.nodes.shift();
+          return this.current;
+        },
+        // Advance to the next part (do not fetch it yet).
+        next: function(){
+          this.current = null;
+        },
+        // Remove the current part from the DOM tree, and move to the
+        // next.
+        remove: function(){
+          container.removeChild(this.get());
+          this.current = null;
+        },
+        // Advance to the next part that is not empty, discarding empty
+        // parts.
+        getNonEmpty: function(){
+          var part = this.get();
+          // Allow empty nodes when they are alone on a line, needed
+          // for the FF cursor bug workaround (see select.js,
+          // insertNewlineAtCursor).
+          while (part &amp;&amp; part.nodeName == "SPAN" &amp;&amp; part.currentText == "") {
+            var old = part;
+            this.remove();
+            part = this.get();
+            // Adjust selection information, if any. See select.js for details.
+            select.snapshotMove(old.firstChild, part &amp;&amp; (part.firstChild || part), 0);
+          }
+          return part;
+        }
+      };
+
+      var lineDirty = false, prevLineDirty = true, lineNodes = 0;
+
+      // This forEach loops over the tokens from the parsed stream, and
+      // at the same time uses the parts object to proceed through the
+      // corresponding DOM nodes.
+      forEach(parsed, function(token){
+        var part = parts.getNonEmpty();
+
+        if (token.value == "\n"){
+          // The idea of the two streams actually staying synchronized
+          // is such a long shot that we explicitly check.
+          if (part.nodeName != "BR")
+            throw "Parser out of sync. Expected BR.";
+
+          if (part.dirty || !part.indentation) lineDirty = true;
+          maybeTouch(from);
+          from = part;
+
+          // Every &lt;br> gets a copy of the parser state and a lexical
+          // context assigned to it. The first is used to be able to
+          // later resume parsing from this point, the second is used
+          // for indentation.
+          part.parserFromHere = parsed.copy();
+          part.indentation = token.indentation;
+          part.dirty = false;
+
+          // If the target argument wasn't an integer, go at least
+          // until that node.
+          if (lines == null &amp;&amp; part == target) throw StopIteration;
+
+          // A clean line with more than one node means we are done.
+          // Throwing a StopIteration is the way to break out of a
+          // MochiKit forEach loop.
+          if ((lines != null &amp;&amp; --lines &lt;= 0) || (!lineDirty &amp;&amp; !prevLineDirty &amp;&amp; lineNodes > 1 &amp;&amp; !cleanLines))
+            throw StopIteration;
+          prevLineDirty = lineDirty; lineDirty = false; lineNodes = 0;
+          parts.next();
+        }
+        else {
+          if (part.nodeName != "SPAN")
+            throw "Parser out of sync. Expected SPAN.";
+          if (part.dirty)
+            lineDirty = true;
+          lineNodes++;
+
+          // If the part matches the token, we can leave it alone.
+          if (correctPart(token, part)){
+            part.dirty = false;
+            parts.next();
+          }
+          // Otherwise, we have to fix it.
+          else {
+            lineDirty = true;
+            // Insert the correct part.
+            var newPart = tokenPart(token);
+            container.insertBefore(newPart, part);
+            if (active) active(newPart, token, self);
+            var tokensize = token.value.length;
+            var offset = 0;
+            // Eat up parts until the text for this token has been
+            // removed, adjusting the stored selection info (see
+            // select.js) in the process.
+            while (tokensize > 0) {
+              part = parts.get();
+              var partsize = part.currentText.length;
+              select.snapshotReplaceNode(part.firstChild, newPart.firstChild, tokensize, offset);
+              if (partsize > tokensize){
+                shortenPart(part, tokensize);
+                tokensize = 0;
+              }
+              else {
+                tokensize -= partsize;
+                offset += partsize;
+                parts.remove();
+              }
+            }
+          }
+        }
+      });
+      maybeTouch(from);
+      webkitLastLineHack(this.container);
+
+      // The function returns some status information that is used by
+      // hightlightDirty to determine whether and where it has to
+      // continue.
+      return {left: lines,
+              node: parts.getNonEmpty(),
+              dirty: lineDirty};
+    }
+  };
+
+  return Editor;
+})();
+
+  addEventHandler(window, "load", function() {
+      var CodeMirror = window.frameElement.CodeMirror;
+      CodeMirror.editor = new Editor(CodeMirror.options);
+      this.parent.setTimeout(method(CodeMirror, "init"), 0);
+  });
+</textarea>
+</div>
+
+<script type="text/javascript">
+  var textarea = document.getElementById('code');
+  var editor = new CodeMirror(CodeMirror.replace(textarea), {
+    height: "750px",
+    width: "100%",
+    content: textarea.value,
+    parserfile: ["tokenizejavascript.js", "parsejavascript.js"],
+    stylesheet: "css/jscolors.css",
+    path: "js/",
+    autoMatchParens: true,
+    initCallback: function(editor){editor.win.document.body.lastChild.scrollIntoView();}
+  });
+</script>
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/compress.html b/typo3/contrib/codemirror/compress.html
new file mode 100644 (file)
index 0000000..86d4f2d
--- /dev/null
@@ -0,0 +1,139 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+    <title>CodeMirror: Compression Helper</title>
+    <link rel="stylesheet" type="text/css" href="css/docs.css"/>
+    <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Droid+Sans:bold"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <style type="text/css">
+      .field {border: 1px solid black; padding: .4em;}
+      button {border: 1px solid black; background-color: #eee;}
+    </style>
+  </head>
+  <body>
+
+<h1><span class="logo-braces">{ }</span> CodeMirror</h1>
+
+<pre class="grey">
+/* Script compression */
+</pre>
+
+    <p>The CodeMirror scripts, as distributed, are many, and full of
+    comments. To optimize page loading, it is recommended to
+    concatenate the scripts loaded in the CodeMirror frame, and
+    compress them. This page may be useful if you intend to do this:
+    it provides an interface to Google's <a
+    href="http://closure-compiler.appspot.com/">Closure compiler</a>,
+    allowing you to easily load in CodeMirror scripts.</p>
+
+    <p>You will have to compress <code>codemirror.js</code>
+    separately, since that will be loaded into the top-level page from
+    which you use CodeMirror. Inside the frame, the
+    <code>parserfile</code> and <code>basefiles</code> options control
+    which files are loaded. If you combine the parser(s) you need with
+    the basefiles, you can set <code>basefiles</code> to point at your
+    compressed file, and leave <code>parserfiles</code> at
+    <code>[]</code>.</p>
+
+    <p>For example, you have a page that uses CodeMirror to edit some
+    JavaScript code. You could save a minimized version of
+    <code>codemirror.js</code> as <code>codemirror_min.js</code>, and
+    include that (with a <code>&lt;script></code> tag) in your page.
+    Next, you compress all the files under "In-frame base code", plus
+    <code>tokenizejavascript.js</code> and
+    <code>parsejavascript.js</code> into
+    <code>codemirror_base.js</code>, and load the editor like
+    this:</p>
+
+    <pre class="code">CodeMirror.fromTextArea("mytextarea", {
+  basefiles: ["js/codemirror_base.js"],
+  lineNumbers: true
+});</pre>
+
+    <p>Clicking the "Compress" buttons below will take you to a file
+    containing the compressed code. Copy-paste this into your script
+    file. ("Save as" for that page is broken on some browsers, so be
+    careful).</p>
+
+    <script type="text/javascript">
+      function setVersion(ver) {
+        var urlprefix = ver.options[ver.selectedIndex].value;
+        console.log(urlprefix);
+        var select = document.getElementById("files"), m;
+        for (var optgr = select.firstChild; optgr; optgr = optgr.nextSibling)
+          for (var opt = optgr.firstChild; opt; opt = opt.nextSibling) {
+            if (opt.nodeName != "OPTION")
+              continue;
+            else if (m = opt.value.match(/^http:\/\/codemirror.net\/(.*)$/))
+              opt.value = urlprefix + m[1];
+            else if (m = opt.value.match(/http:\/\/marijn.haverbeke.nl\/git\/codemirror\?a=blob_plain;hb=[^;]+;f=(.*)$/))
+              opt.value = urlprefix + m[1];
+          }
+      }
+      function verify() {
+        document.getElementById("output").value="warnings";
+        document.getElementById("form").submit();
+        document.getElementById("output").value="compiled_code";
+      }
+    </script>
+
+    <form id="form" action="http://closure-compiler.appspot.com/compile" method="post" id="form">
+      <p>Version: <select id="version" onchange="setVersion(this);" class="field" style="padding: 1px">
+        <option value="http://codemirror.net/" selected>Development head</option>
+        <option value="http://marijn.haverbeke.nl/git/codemirror?a=blob_plain;hb=v0.8;f=">v0.8</option>
+        <option value="http://marijn.haverbeke.nl/git/codemirror?a=blob_plain;hb=v0.7;f=">v0.7</option>
+        <option value="http://marijn.haverbeke.nl/git/codemirror?a=blob_plain;hb=v0.67;f=">v0.67</option>
+        <option value="http://marijn.haverbeke.nl/git/codemirror?a=blob_plain;hb=v0.66;f=">v0.66</option>
+      </select></p>
+
+      <p><input type="hidden" value="compiled_code" name="output_info" id="output"/>
+
+      <select multiple="multiple" name="code_url" style="width: 40em;" class="field" id="files">
+        <optgroup label="CodeMirror Library">
+          <option value="http://codemirror.net/js/codemirror.js">codemirror.js</option>
+        </optgroup>
+        <optgroup label="In-frame base files">
+          <option value="http://codemirror.net/js/util.js">util.js</option>
+          <option value="http://codemirror.net/js/stringstream.js">stringstream.js</option>
+          <option value="http://codemirror.net/js/select.js">select.js</option>
+          <option value="http://codemirror.net/js/undo.js">undo.js</option>
+          <option value="http://codemirror.net/js/editor.js">editor.js</option>
+          <option value="http://codemirror.net/js/tokenize.js">tokenize.js</option>
+        </optgroup>
+        <optgroup label="Parsers">
+          <option value="http://codemirror.net/js/tokenizejavascript.js">tokenizejavascript.js</option>
+          <option value="http://codemirror.net/js/parsejavascript.js">parsejavascript.js</option>
+          <option value="http://codemirror.net/js/parsexml.js">parsexml.js</option>
+          <option value="http://codemirror.net/js/parsecss.js">parsecss.js</option>
+          <option value="http://codemirror.net/js/parsesparql.js">parsesparql.js</option>
+          <option value="http://codemirror.net/js/parsehtmlmixed.js">parsehtmlmixed.js</option>
+          <option value="http://codemirror.net/js/parsedummy.js">parsedummy.js</option>
+        </optgroup>
+        <optgroup label="Contributed parsers">
+          <option value="http://codemirror.net/contrib/lua/js/parselua.js">parselua.js</option>
+          <option value="http://codemirror.net/contrib/python/js/parsepython.js">parsepython.js</option>
+          <option value="http://codemirror.net/contrib/php/js/tokenizephp.js">tokenizephp.js</option>
+          <option value="http://codemirror.net/contrib/php/js/parsephp.js">parsephp.js</option>
+          <option value="http://codemirror.net/contrib/php/js/parsephphtmlmixed.js">parsephphtmlmixed.js</option>
+          <option value="http://codemirror.net/contrib/csharp/js/tokenizecsharp.js">tokenizecsharp.js</option>
+          <option value="http://codemirror.net/contrib/csharp/js/parsecsharp.js">parsecsharp.js</option>
+          <option value="http://codemirror.net/contrib/sql/js/parsesql.js">parsesql.js</option>
+          <option value="http://codemirror.net/contrib/plsql/js/parseplsql.js">parseplsql.js</option>
+          <option value="http://codemirror.net/contrib/scheme/js/tokenizescheme.js">tokenizescheme.js</option>
+          <option value="http://codemirror.net/contrib/seheme/js/parsescheme.js">parsescheme.js</option>
+          <option value="http://codemirror.net/contrib/ometa/js/tokenizeometa.js">tokenizeometa.js</option>
+          <option value="http://codemirror.net/contrib/ometa/js/parseometa.js">parseometa.js</option>
+          <option value="http://codemirror.net/contrib/xquery/js/tokenizexquery.js">tokenizexquery.js</option>
+          <option value="http://codemirror.net/contrib/xquery/js/parsexquery.js">parsexquery.js</option>
+          <option value="http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/tokenizegroovy.js">tokenizegroovy.js</option>
+          <option value="http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/parsegroovy.js">parsegroovy.js</option>
+        </optgroup>
+      </select></p>
+
+      <p><button type="submit">Compress!</button> <button type="button" onclick="verify();">Check for errors</button></p>
+
+      <p>Custom code to add to the compressed file:<textarea name="js_code" style="width: 100%; height: 15em;" class="field"></textarea></p>
+    </form>
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/csharp/._index.html b/typo3/contrib/codemirror/contrib/csharp/._index.html
new file mode 100644 (file)
index 0000000..eb0419b
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/csharp/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/csharp/css/._csharpcolors.css b/typo3/contrib/codemirror/contrib/csharp/css/._csharpcolors.css
new file mode 100644 (file)
index 0000000..114b546
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/csharp/css/._csharpcolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/csharp/css/csharpcolors.css b/typo3/contrib/codemirror/contrib/csharp/css/csharpcolors.css
new file mode 100644 (file)
index 0000000..234f1ad
--- /dev/null
@@ -0,0 +1,60 @@
+html {
+  cursor: text;
+}
+
+.editbox {
+  margin: .4em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  color: black;
+}
+
+pre.code, .editbox {
+  color: #666666;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.csharp-punctuation {
+  color: green;
+}
+
+span.csharp-operator {
+  color: purple;
+}
+
+span.csharp-keyword {
+  color: blue;
+}
+
+span.csharp-atom {
+  color: brown;
+}
+
+span.csharp-variable {
+  color: black;
+}
+
+span.csharp-variabledef {
+  color: #0000FF;
+}
+
+span.csharp-localvariable {
+  color: #004499;
+}
+
+span.csharp-property {
+  color: black;
+}
+
+span.csharp-comment {
+  color: green;
+}
+
+span.csharp-string {
+  color: red;
+}
+
diff --git a/typo3/contrib/codemirror/contrib/csharp/index.html b/typo3/contrib/codemirror/contrib/csharp/index.html
new file mode 100644 (file)
index 0000000..3b128f3
--- /dev/null
@@ -0,0 +1,61 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: C# demonstration</title>
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/>
+  </head>
+  <body style="padding: 20px;">
+
+<p>Demonstration of <a href="../../index.html">CodeMirror</a>'s C# highlighter.</p>
+
+<p>Written by <a href="http://skilltesting.com/">Boris Gaber and Christopher Buchino</a> (<a
+href="http://skilltesting.com/codemirror-parser-license/">license</a>).</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="50">
+using System;
+
+namespace Example
+{
+    /// &lt;summary>
+    /// Represents a person employed at the company
+    /// &lt;/summary>
+    public class Employee : Person
+    {
+        #region Properties
+        
+        /// &lt;summary>
+        /// Gets or sets the first name.
+        /// &lt;/summary>
+        /// &lt;value>The first name.&lt;/value>
+        public string FirstName { get; set; }
+
+        #endregion
+
+        /// &lt;summary>
+        /// Calculates the salary.
+        /// &lt;/summary>
+        /// &lt;param name="grade">The grade.&lt;/param>
+        /// &lt;returns>&lt;/returns>
+        public decimal CalculateSalary(int grade)
+        {
+            if (grade > 10)
+                return 1000;
+            return 500;
+        }
+    }
+}
+</textarea>
+</div>
+
+<script type="text/javascript">
+  var editor = CodeMirror.fromTextArea('code', {
+    parserfile: ["../contrib/csharp/js/tokenizecsharp.js", "../contrib/csharp/js/parsecsharp.js"],
+    stylesheet: "css/csharpcolors.css",
+    path: "../../js/",
+    height: "500px"
+  });
+</script>
+
+</body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/csharp/js/._parsecsharp.js b/typo3/contrib/codemirror/contrib/csharp/js/._parsecsharp.js
new file mode 100644 (file)
index 0000000..c1aa9e0
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/csharp/js/._parsecsharp.js differ
diff --git a/typo3/contrib/codemirror/contrib/csharp/js/._tokenizecsharp.js b/typo3/contrib/codemirror/contrib/csharp/js/._tokenizecsharp.js
new file mode 100644 (file)
index 0000000..7ef718b
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/csharp/js/._tokenizecsharp.js differ
diff --git a/typo3/contrib/codemirror/contrib/csharp/js/parsecsharp.js b/typo3/contrib/codemirror/contrib/csharp/js/parsecsharp.js
new file mode 100644 (file)
index 0000000..10dcb41
--- /dev/null
@@ -0,0 +1,328 @@
+/* Parse function for JavaScript. Makes use of the tokenizer from
+ * tokenizecsharp.js. Note that your parsers do not have to be
+ * this complicated -- if you don't want to recognize local variables,
+ * in many languages it is enough to just look for braces, semicolons,
+ * parentheses, etc, and know when you are inside a string or comment.
+ *
+ * See manual.html for more info about the parser interface.
+ */
+
+var JSParser = Editor.Parser = (function() {
+  // Token types that can be considered to be atoms.
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
+  // Setting that can be used to have JSON data indent properly.
+  var json = false;
+  // Constructor for the lexical context objects.
+  function CSharpLexical(indented, column, type, align, prev, info) {
+    // indentation at start of this line
+    this.indented = indented;
+    // column at which this scope was opened
+    this.column = column;
+    // type of scope ('vardef', 'stat' (statement), 'form' (special form), '[', '{', or '(')
+    this.type = type;
+    // '[', '{', or '(' blocks that have any text after their opening
+    // character are said to be 'aligned' -- any lines below are
+    // indented all the way to the opening character.
+    if (align != null)
+      this.align = align;
+    // Parent scope, if any.
+    this.prev = prev;
+    this.info = info;
+  }
+
+  // CSharp indentation rules.
+  function indentCSharp(lexical) {
+    return function(firstChars) {
+      var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
+      var closing = firstChar == type;
+      if (type == "vardef")
+        return lexical.indented + 4;
+      else if (type == "form" && firstChar == "{")
+        return lexical.indented;
+      else if (type == "stat" || type == "form")
+        return lexical.indented + indentUnit;
+      else if (lexical.info == "switch" && !closing)
+        return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align)
+        return lexical.column - (closing ? 1 : 0);
+      else
+        return lexical.indented + (closing ? 0 : indentUnit);
+    };
+  }
+
+  // The parser-iterator-producing function itself.
+  function parseCSharp(input, basecolumn) {
+    // Wrap the input in a token stream
+    var tokens = tokenizeCSharp(input);
+    // The parser state. cc is a stack of actions that have to be
+    // performed to finish the current statement. For example we might
+    // know that we still need to find a closing parenthesis and a
+    // semicolon. Actions at the end of the stack go first. It is
+    // initialized with an infinitely looping action that consumes
+    // whole statements.
+    var cc = [statements];
+    // The lexical scope, used mostly for indentation.
+    var lexical = new CSharpLexical((basecolumn || 0) - indentUnit, 0, "block", false);
+    // Current column, and the indentation at the start of the current
+    // line. Used to create lexical scope objects.
+    var column = 0;
+    var indented = 0;
+    // Variables which are used by the mark, cont, and pass functions
+    // below to communicate with the driver loop in the 'next'
+    // function.
+    var consume, marked;
+  
+    // The iterator object.
+    var parser = {next: next, copy: copy};
+
+    function next(){
+      // Start by performing any 'lexical' actions (adjusting the
+      // lexical variable), or the operations below will be working
+      // with the wrong lexical state.
+      while(cc[cc.length - 1].lex)
+        cc.pop()();
+
+      // Fetch a token.
+      var token = tokens.next();
+
+      // Adjust column and indented.
+      if (token.type == "whitespace" && column == 0)
+        indented = token.value.length;
+      column += token.value.length;
+      if (token.content == "\n"){
+        indented = column = 0;
+        // If the lexical scope's align property is still undefined at
+        // the end of the line, it is an un-aligned scope.
+        if (!("align" in lexical))
+          lexical.align = false;
+        // Newline tokens get an indentation function associated with
+        // them.
+        token.indentation = indentCSharp(lexical);
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "comment")
+        return token;
+      // When a meaningful token is found and the lexical scope's
+      // align is undefined, it is an aligned scope.
+      if (!("align" in lexical))
+        lexical.align = true;
+
+      // Execute actions until one 'consumes' the token and we can
+      // return it.
+      while(true) {
+        consume = marked = false;
+        // Take and execute the topmost action.
+        cc.pop()(token.type, token.content);
+        if (consume){
+          // Marked is used to change the style of the current token.
+          if (marked)
+            token.style = marked;
+          return token;
+        }
+      }
+    }
+
+    // This makes a copy of the parser state. It stores all the
+    // stateful variables in a closure, and returns a function that
+    // will restore them when called with a new input stream. Note
+    // that the cc array has to be copied, because it is contantly
+    // being modified. Lexical objects are not mutated, and context
+    // objects are not mutated in a harmful way, so they can be shared
+    // between runs of the parser.
+    function copy(){
+      var _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
+  
+      return function copyParser(input){
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizeCSharp(input, _tokenState);
+        return parser;
+      };
+    }
+
+    // Helper function for pushing a number of actions onto the cc
+    // stack in reverse order.
+    function push(fs){
+      for (var i = fs.length - 1; i >= 0; i--)
+        cc.push(fs[i]);
+    }
+    // cont and pass are used by the action functions to add other
+    // actions to the stack. cont will cause the current token to be
+    // consumed, pass will leave it for the next action.
+    function cont(){
+      push(arguments);
+      consume = true;
+    }
+    function pass(){
+      push(arguments);
+      consume = false;
+    }
+    // Used to change the style of the current token.
+    function mark(style){
+      marked = style;
+    }
+
+    // Push a new lexical context of the given type.
+    function pushlex(type, info) {
+      var result = function(){
+        lexical = new CSharpLexical(indented, column, type, null, lexical, info)
+      };
+      result.lex = true;
+      return result;
+    }
+    // Pop off the current lexical context.
+    function poplex(){
+      lexical = lexical.prev;
+    }
+    poplex.lex = true;
+    // The 'lex' flag on these actions is used by the 'next' function
+    // to know they can (and have to) be ran before moving on to the
+    // next token.
+  
+    // Creates an action that discards tokens until it finds one of
+    // the given type.
+    function expect(wanted){
+      return function expecting(type){
+        if (type == wanted) cont();
+        else cont(arguments.callee);
+      };
+    }
+
+    // Looks for a statement, and then calls itself.
+    function statements(type){
+      return pass(statement, statements);
+    }
+    // Dispatches various types of statements based on the type of the
+    // current token.
+    function statement(type){
+      if (type == "var") cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+      else if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
+      else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
+      else if (type == "{" && json) cont(pushlex("}"), commasep(objprop, "}"), poplex);
+      else if (type == "{") cont(pushlex("}"), block, poplex);
+      else if (type == "function") cont(functiondef);
+      else if (type == "for") cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
+      else if (type == "variable") cont(pushlex("stat"), maybelabel);
+      else if (type == "switch") cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), block, poplex, poplex);
+      else if (type == "case") cont(expression, expect(":"));
+      else if (type == "default") cont(expect(":"));
+      else if (type == "catch") cont(pushlex("form"), expect("("), funarg, expect(")"), statement, poplex);
+      
+      else if (type == "class") cont(classdef);
+      else if (type == "keyword d") cont(statement);
+      
+      else pass(pushlex("stat"), expression, expect(";"), poplex);
+    }
+    // Dispatch expression types.
+    function expression(type){
+      if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
+      else if (type == "function") cont(functiondef);
+      else if (type == "keyword c") cont(expression);
+      else if (type == "(") cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
+      else if (type == "operator") cont(expression);
+      else if (type == "[") cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
+      else if (type == "{") cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
+    }
+    // Called for places where operators, function calls, or
+    // subscripts are valid. Will skip on to the next action if none
+    // is found.
+    function maybeoperator(type){
+      if (type == "operator") cont(expression);
+      else if (type == "(") cont(pushlex(")"), expression, commasep(expression, ")"), poplex, maybeoperator);
+      else if (type == ".") cont(property, maybeoperator);
+      else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
+    }
+    // When a statement starts with a variable name, it might be a
+    // label. If no colon follows, it's a regular statement.
+    function maybelabel(type){
+      if (type == ":") cont(poplex, statement);
+      else if (type == "(") cont(commasep(funarg, ")"), poplex, statement); // method definition
+      else if (type == "{") cont(poplex, pushlex("}"), block, poplex); // property definition
+      else pass(maybeoperator, expect(";"), poplex);
+    }
+    // Property names need to have their style adjusted -- the
+    // tokenizer thinks they are variables.
+    function property(type){
+      if (type == "variable") {mark("csharp-property"); cont();}
+    }
+    // This parses a property and its value in an object literal.
+    function objprop(type){
+      if (type == "variable") mark("csharp-property");
+      if (atomicTypes.hasOwnProperty(type)) cont(expect(":"), expression);
+    }
+    // Parses a comma-separated list of the things that are recognized
+    // by the 'what' argument.
+    function commasep(what, end){
+      function proceed(type) {
+        if (type == ",") cont(what, proceed);
+        else if (type == end) cont();
+        else cont(expect(end));
+      };
+      return function commaSeparated(type) {
+        if (type == end) cont();
+        else pass(what, proceed);
+      };
+    }
+    // Look for statements until a closing brace is found.
+    function block(type){
+      if (type == "}") cont();
+      else pass(statement, block);
+    }
+    // Variable definitions are split into two actions -- 1 looks for
+    // a name or the end of the definition, 2 looks for an '=' sign or
+    // a comma.
+    function vardef1(type, value){
+      if (type == "variable"){cont(vardef2);}
+      else cont();
+    }
+    function vardef2(type, value){
+      if (value == "=") cont(expression, vardef2);
+      else if (type == ",") cont(vardef1);
+    }
+    // For loops.
+    function forspec1(type){
+      if (type == "var") cont(vardef1, forspec2);
+      else if (type == ";") pass(forspec2);
+      else if (type == "variable") cont(formaybein);
+      else pass(forspec2);
+    }
+    function formaybein(type, value){
+      if (value == "in") cont(expression);
+      else cont(maybeoperator, forspec2);
+    }
+    function forspec2(type, value){
+      if (type == ";") cont(forspec3);
+      else if (value == "in") cont(expression);
+      else cont(expression, expect(";"), forspec3);
+    }
+    function forspec3(type) {
+      if (type == ")") pass();
+      else cont(expression);
+    }
+    // A function definition creates a new context, and the variables
+    // in its argument list have to be added to this context.
+    function functiondef(type, value){
+      if (type == "variable") cont(functiondef);
+      else if (type == "(") cont(commasep(funarg, ")"), statement);
+    }
+    function funarg(type, value){
+      if (type == "variable"){cont();}
+    }
+    
+    function classdef(type) {
+        if (type == "variable") cont(classdef, statement);
+        else if (type == ":") cont(classdef, statement);
+    }
+  
+    return parser;
+  }
+
+  return {
+    make: parseCSharp,
+    electricChars: "{}:",
+    configure: function(obj) {
+      if (obj.json != null) json = obj.json;
+    }
+  };
+})();
diff --git a/typo3/contrib/codemirror/contrib/csharp/js/tokenizecsharp.js b/typo3/contrib/codemirror/contrib/csharp/js/tokenizecsharp.js
new file mode 100644 (file)
index 0000000..5d89e26
--- /dev/null
@@ -0,0 +1,196 @@
+/* Tokenizer for CSharp code */
+
+var tokenizeCSharp = (function() {
+  // Advance the stream until the given character (not preceded by a
+  // backslash) is encountered, or the end of the line is reached.
+  function nextUntilUnescaped(source, end) {
+    var escaped = false;
+    var next;
+    while (!source.endOfLine()) {
+      var next = source.next();
+      if (next == end && !escaped)
+        return false;
+      escaped = !escaped && next == "\\";
+    }
+    return escaped;
+  }
+
+  // A map of JavaScript's keywords. The a/b/c keyword distinction is
+  // very rough, but it gives the parser enough information to parse
+  // correct code correctly (we don't care that much how we parse
+  // incorrect code). The style information included in these objects
+  // is used by the highlighter to pick the correct CSS style for a
+  // token.
+  var keywords = function(){
+    function result(type, style){
+      return {type: type, style: "csharp-" + style};
+    }
+    // keywords that take a parenthised expression, and then a
+    // statement (if)
+    var keywordA = result("keyword a", "keyword");
+    // keywords that take just a statement (else)
+    var keywordB = result("keyword b", "keyword");
+    // keywords that optionally take an expression, and form a
+    // statement (return)
+    var keywordC = result("keyword c", "keyword");
+    var operator = result("operator", "keyword");
+    var atom = result("atom", "atom");
+    // just a keyword with no indentation implications
+    var keywordD = result("keyword d", "keyword"); 
+    
+    return {
+      "if": keywordA, "while": keywordA, "with": keywordA,
+      "else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB,
+      "return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "delete": keywordC, "throw": keywordC,
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "var": result("var", "keyword"), "function": result("function", "keyword"), "catch": result("catch", "keyword"),
+      "for": result("for", "keyword"), "switch": result("switch", "keyword"),
+      "case": result("case", "keyword"), "default": result("default", "keyword"),
+      "true": atom, "false": atom, "null": atom,
+      
+      "class": result("class", "keyword"), "namespace": result("class", "keyword"),
+      
+      "public": keywordD, "private": keywordD, "protected": keywordD, "internal": keywordD,
+      "extern": keywordD, "override": keywordD, "virtual": keywordD, "abstract": keywordD, 
+      "static": keywordD, "out": keywordD, "ref": keywordD, "const": keywordD,
+      
+      "foreach": result("for", "keyword"), "using": keywordC,
+      
+      "int": keywordD, "double": keywordD, "long": keywordD, "bool": keywordD, "char": keywordD, 
+      "void": keywordD, "string": keywordD, "byte": keywordD, "sbyte": keywordD, "decimal": keywordD,
+      "float": keywordD, "uint": keywordD, "ulong": keywordD, "object": keywordD,
+      "short": keywordD, "ushort": keywordD,
+      
+      "get": keywordD, "set": keywordD, "value": keywordD      
+    };
+  }();
+
+  // Some helper regexps
+  var isOperatorChar = /[+\-*&%=<>!?|]/;
+  var isHexDigit = /[0-9A-Fa-f]/;
+  var isWordChar = /[\w\$_]/;
+
+  // Wrapper around jsToken that helps maintain parser state (whether
+  // we are inside of a multi-line comment and whether the next token
+  // could be a regular expression).
+  function jsTokenState(inside, regexp) {
+    return function(source, setState) {
+      var newInside = inside;
+      var type = jsToken(inside, regexp, source, function(c) {newInside = c;});
+      var newRegexp = type.type == "operator" || type.type == "keyword c" || type.type.match(/^[\[{}\(,;:]$/);
+      if (newRegexp != regexp || newInside != inside)
+        setState(jsTokenState(newInside, newRegexp));
+      return type;
+    };
+  }
+
+  // The token reader, inteded to be used by the tokenizer from
+  // tokenize.js (through jsTokenState). Advances the source stream
+  // over a token, and returns an object containing the type and style
+  // of that token.
+  function jsToken(inside, regexp, source, setInside) {
+    function readHexNumber(){
+      source.next(); // skip the 'x'
+      source.nextWhileMatches(isHexDigit);
+      return {type: "number", style: "csharp-atom"};
+    }
+
+    function readNumber() {
+      source.nextWhileMatches(/[0-9]/);
+      if (source.equals(".")){
+        source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      if (source.equals("e") || source.equals("E")){
+        source.next();
+        if (source.equals("-"))
+          source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      return {type: "number", style: "csharp-atom"};
+    }
+    // Read a word, look it up in keywords. If not found, it is a
+    // variable, otherwise it is a keyword of the type found.
+    function readWord() {
+      source.nextWhileMatches(isWordChar);
+      var word = source.get();
+      var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
+      return known ? {type: known.type, style: known.style, content: word} :
+      {type: "variable", style: "csharp-variable", content: word};
+    }
+    function readRegexp() {
+      nextUntilUnescaped(source, "/");
+      source.nextWhileMatches(/[gi]/);
+      return {type: "regexp", style: "csharp-string"};
+    }
+    // Mutli-line comments are tricky. We want to return the newlines
+    // embedded in them as regular newline tokens, and then continue
+    // returning a comment token for every line of the comment. So
+    // some state has to be saved (inside) to indicate whether we are
+    // inside a /* */ sequence.
+    function readMultilineComment(start){
+      var newInside = "/*";
+      var maybeEnd = (start == "*");
+      while (true) {
+        if (source.endOfLine())
+          break;
+        var next = source.next();
+        if (next == "/" && maybeEnd){
+          newInside = null;
+          break;
+        }
+        maybeEnd = (next == "*");
+      }
+      setInside(newInside);
+      return {type: "comment", style: "csharp-comment"};
+    }
+    function readOperator() {
+      source.nextWhileMatches(isOperatorChar);
+      return {type: "operator", style: "csharp-operator"};
+    }
+    function readString(quote) {
+      var endBackSlash = nextUntilUnescaped(source, quote);
+      setInside(endBackSlash ? quote : null);
+      return {type: "string", style: "csharp-string"};
+    }
+
+    // Fetch the next token. Dispatches on first character in the
+    // stream, or first two characters when the first is a slash.
+    if (inside == "\"" || inside == "'")
+      return readString(inside);
+    var ch = source.next();
+    if (inside == "/*")
+      return readMultilineComment(ch);
+    else if (ch == "\"" || ch == "'")
+      return readString(ch);
+    // with punctuation, the type of the token is the symbol itself
+    else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+      return {type: ch, style: "csharp-punctuation"};
+    else if (ch == "0" && (source.equals("x") || source.equals("X")))
+      return readHexNumber();
+    else if (/[0-9]/.test(ch))
+      return readNumber();
+    else if (ch == "/"){
+      if (source.equals("*"))
+      { source.next(); return readMultilineComment(ch); }
+      else if (source.equals("/"))
+      { nextUntilUnescaped(source, null); return {type: "comment", style: "csharp-comment"};}
+      else if (regexp)
+        return readRegexp();
+      else
+        return readOperator();
+    }
+    else if (ch == "#") {  // treat c# regions like comments
+        nextUntilUnescaped(source, null); return {type: "comment", style: "csharp-comment"};
+    }
+    else if (isOperatorChar.test(ch))
+      return readOperator();
+    else
+      return readWord();
+  }
+
+  // The external interface to the tokenizer.
+  return function(source, startState) {
+    return tokenizer(source, startState || jsTokenState(false, true));
+  };
+})();
diff --git a/typo3/contrib/codemirror/contrib/groovy/._index.html b/typo3/contrib/codemirror/contrib/groovy/._index.html
new file mode 100644 (file)
index 0000000..276955b
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/groovy/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/groovy/index.html b/typo3/contrib/codemirror/contrib/groovy/index.html
new file mode 100644 (file)
index 0000000..16dce47
--- /dev/null
@@ -0,0 +1,57 @@
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+  <head>\r
+    <script src="../../js/codemirror.js" type="text/javascript"></script>\r
+    <title>CodeMirror: Groovy demonstration</title>\r
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/>\r
+  </head>\r
+  <body style="padding: 20px;">\r
+\r
+<p>Demonstration of <a href="../../index.html">CodeMirror</a>'s Groovy highlighter.</p>\r
+\r
+<p>Created by eXo Platform SAS (<a href="http://www.opensource.org/licenses/lgpl-2.1.php">license</a>).</p>\r
+\r
+<p>Note that the files for this parser aren't included in the CodeMirror repository, but have to fetched from <a href="http://svn.exoplatform.org/">svn.exoplatform.org</a>:</p>\r
+\r
+<ul>\r
+ <li><a href="http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/tokenizegroovy.js">tokenizegroovy.js</a></li>\r
+ <li><a href="http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/parsegroovy.js">parsegroovy.js</a></li>\r
+ <li><a href="http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/css/groovycolors.css">groovy.colors.css</a></li>\r
+</ul>\r
+\r
+<div class="border">\r
+<textarea id="code" cols="120" rows="50">\r
+// simple groovy script\r
+import javax.ws.rs.Path\r
+import javax.ws.rs.GET\r
+import javax.ws.rs.PathParam\r
+import javax.ws.rs.POST\r
+\r
+@Path("/")\r
+public class HelloWorld {\r
+  @GET\r
+  @Path("helloworld/{name}")\r
+  public String hello(@PathParam("name") String name) {\r
+    return "Hello " + name\r
+  }\r
+  \r
+  @POST\r
+  @Path("helloworld/{name}")\r
+  public String hello2(@PathParam("name") String name) {\r
+    return "Hello " + name\r
+  }\r
+}\r
+</textarea>\r
+</div>\r
+\r
+<script type="text/javascript">\r
+  var editor = CodeMirror.fromTextArea('code', {\r
+    height: "450px",\r
+    parserfile: ["http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/parsegroovy.js", "http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/js/tokenizegroovy.js"],\r
+    stylesheet: "http://svn.exoplatform.org/projects/gwt/trunk/exo-gwtframework-editor/src/main/resources/org/exoplatform/gwtframework/editor/public/codemirror/css/groovycolors.css",\r
+    path: "../../js/",\r
+    textWrapping: false\r
+  });\r
+</script>\r
+\r
+</body>\r
+</html>\r
diff --git a/typo3/contrib/codemirror/contrib/lua/._LICENSE b/typo3/contrib/codemirror/contrib/lua/._LICENSE
new file mode 100644 (file)
index 0000000..fae2894
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/lua/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/lua/._index.html b/typo3/contrib/codemirror/contrib/lua/._index.html
new file mode 100644 (file)
index 0000000..046560d
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/lua/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/lua/LICENSE b/typo3/contrib/codemirror/contrib/lua/LICENSE
new file mode 100644 (file)
index 0000000..5b867cd
--- /dev/null
@@ -0,0 +1,32 @@
+Copyright (c) 2009, Franciszek Wawrzak
+All rights reserved.
+
+This software is provided for use in connection with the
+CodeMirror suite of modules and utilities, hosted and maintained
+at http://codemirror.net/.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/typo3/contrib/codemirror/contrib/lua/css/._luacolors.css b/typo3/contrib/codemirror/contrib/lua/css/._luacolors.css
new file mode 100644 (file)
index 0000000..073d1df
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/lua/css/._luacolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/lua/css/luacolors.css b/typo3/contrib/codemirror/contrib/lua/css/luacolors.css
new file mode 100644 (file)
index 0000000..e901529
--- /dev/null
@@ -0,0 +1,63 @@
+html {
+  cursor: text;
+}
+
+.editbox {
+  margin: .4em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  color: black;
+}
+
+pre.code, .editbox {
+  color: #666666;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.lua-comment {
+  color: #BB9977;
+}
+
+span.lua-keyword {
+  font-weight: bold;
+  color: blue;
+}
+
+span.lua-string {
+  color: #AA2222;
+}
+
+span.lua-stdfunc {
+  font-weight: bold;
+  color: #077;
+}
+span.lua-customfunc {
+  font-weight: bold;
+  color: #0AA;
+}
+
+
+span.lua-identifier {
+  color: black;
+}
+
+span.lua-number {
+  color: #3A3;
+}
+
+span.lua-token {
+  color: #151;
+}
+
+span.lua-error {
+  color: #FFF;
+  background-color: #F00;
+}
+
+
+
+
diff --git a/typo3/contrib/codemirror/contrib/lua/index.html b/typo3/contrib/codemirror/contrib/lua/index.html
new file mode 100644 (file)
index 0000000..03a3229
--- /dev/null
@@ -0,0 +1,68 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: Lua demonstration</title>
+  </head>
+  <body style="padding: 20px;">
+
+<p>This page demonstrates <a href="../../index.html">CodeMirror</a>'s
+Lua parser. Written by <a href="http://francio.pl/">Franciszek
+Wawrzak</a>, released under a BSD-style <a
+href="LICENSE">license</a>.</p>
+
+<div style="border: 1px solid black; padding: 0px;">
+<textarea id="code" cols="120" rows="30">
+--[[
+example useless code to show lua syntax highlighting
+this is multiline comment
+]]
+
+function blahblahblah(x)
+
+  local table = {
+    "asd" = 123,
+    "x" = 0.34,  
+  }
+  if x ~= 3 then
+    print( x )
+  elseif x == "string"
+    my_custom_function( 0x34 )
+  else
+    unknown_function( "some string" )
+  end
+
+  --single line comment
+  
+end
+
+function blablabla3()
+
+  for k,v in ipairs( table ) do
+    --abcde..
+    y=[=[
+  x=[[
+      x is a multi line string
+   ]]
+  but its definition is iside a highest level string!
+  ]=]
+    print(" \"\" ")
+  --this marks a parser error:
+  s = [== asdasdasd]]
+
+    s = math.sin( x )
+  end
+
+end
+</textarea>
+</div>
+
+<script type="text/javascript">
+  var editor = CodeMirror.fromTextArea('code', {
+    height: "350px",
+    parserfile: "../contrib/lua/js/parselua.js",
+    stylesheet: "css/luacolors.css",
+    path: "../../js/"
+  });
+</script>
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/lua/js/._parselua.js b/typo3/contrib/codemirror/contrib/lua/js/._parselua.js
new file mode 100644 (file)
index 0000000..7dbc994
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/lua/js/._parselua.js differ
diff --git a/typo3/contrib/codemirror/contrib/lua/js/parselua.js b/typo3/contrib/codemirror/contrib/lua/js/parselua.js
new file mode 100644 (file)
index 0000000..5d508b2
--- /dev/null
@@ -0,0 +1,254 @@
+/* 
+ Simple parser for LUA 
+ Written for Lua 5.1, based on parsecss and other parsers. 
+ features: highlights keywords, strings, comments (no leveling supported! ("[==[")),tokens, basic indenting
+
+ to make this parser highlight your special functions pass table with this functions names to parserConfig argument of creator,
+       
+ parserConfig: ["myfunction1","myfunction2"],
+ */
+
+function findFirstRegexp(words) {
+    return new RegExp("^(?:" + words.join("|") + ")", "i");
+}
+
+function matchRegexp(words) {
+    return new RegExp("^(?:" + words.join("|") + ")$", "i");
+}
+
+
+var luaCustomFunctions= matchRegexp([]);
+function configureLUA(parserConfig){
+       if(parserConfig)
+       luaCustomFunctions= matchRegexp(parserConfig);
+}
+
+
+//long list of standard functions from lua manual
+var luaStdFunctions = matchRegexp([
+"_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load","loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require","select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall",
+
+"coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield",
+
+"debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable","debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable","debug.setupvalue","debug.traceback",
+
+"close","flush","lines","read","seek","setvbuf","write",
+
+"io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin","io.stdout","io.tmpfile","io.type","io.write",
+
+"math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg","math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max","math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh","math.sqrt","math.tan","math.tanh",
+
+"os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale","os.time","os.tmpname",
+
+"package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload","package.seeall",
+
+"string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub","string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper",
+
+"table.concat","table.insert","table.maxn","table.remove","table.sort"
+]);
+
+
+
+ var luaKeywords = matchRegexp(["and","break","elseif","false","nil","not","or","return",
+                               "true","function", "end", "if", "then", "else", "do", 
+                               "while", "repeat", "until", "for", "in", "local" ]);
+
+ var luaIndentKeys = matchRegexp(["function", "if","repeat","for","while", "[\(]", "{"]);
+ var luaUnindentKeys = matchRegexp(["end", "until", "[\)]", "}"]);
+
+ var luaUnindentKeys2 = findFirstRegexp(["end", "until", "[\)]", "}"]);
+ var luaMiddleKeys = findFirstRegexp(["else","elseif"]);
+
+
+
+var LUAParser = Editor.Parser = (function() {
+  var tokenizeLUA = (function() {
+    function normal(source, setState) {
+      var ch = source.next();
+
+   if (ch == "-" && source.equals("-")) {
+        source.next();
+               setState(inSLComment);
+        return null;
+      } 
+       else if (ch == "\"" || ch == "'") {
+        setState(inString(ch));
+        return null;
+      }
+    if (ch == "[" && (source.equals("[") || source.equals("="))) {
+        var level = 0;
+               while(source.equals("=")){
+                       level ++;
+                       source.next();
+               }
+               if(! source.equals("[") )
+                       return "lua-error";             
+               setState(inMLSomething(level,"lua-string"));
+        return null;
+      } 
+           
+      else if (ch == "=") {
+       if (source.equals("="))
+               source.next();
+        return "lua-token";
+      }
+       
+      else if (ch == ".") {
+       if (source.equals("."))
+               source.next();
+       if (source.equals("."))
+               source.next();
+        return "lua-token";
+      }
+     
+      else if (ch == "+" || ch == "-" || ch == "*" || ch == "/" || ch == "%" || ch == "^" || ch == "#" ) {
+        return "lua-token";
+      }
+      else if (ch == ">" || ch == "<" || ch == "(" || ch == ")" || ch == "{" || ch == "}" || ch == "[" ) {
+        return "lua-token";
+      }
+      else if (ch == "]" || ch == ";" || ch == ":" || ch == ",") {
+        return "lua-token";
+      }
+      else if (source.equals("=") && (ch == "~" || ch == "<" || ch == ">")) {
+        source.next();
+        return "lua-token";
+      }
+
+     else if (/\d/.test(ch)) {
+        source.nextWhileMatches(/[\w.%]/);
+        return "lua-number";
+      }
+      else {
+        source.nextWhileMatches(/[\w\\\-_.]/);
+        return "lua-identifier";
+      }
+    }
+function inSLComment(source, setState) {
+      var start = true;
+       var count=0;
+      while (!source.endOfLine()) {
+               var ch = source.next();
+               var level = 0;
+               if ((ch =="[") && start){
+                       while(source.equals("=")){
+                       source.next();
+                       level++;
+                       }
+                       if (source.equals("[")){
+                                       setState(inMLSomething(level,"lua-comment"));
+                               return null;
+                               }
+                }
+                start = false; 
+       }
+       setState(normal);               
+     return "lua-comment";
+       
+    }
+
+    function inMLSomething(level,what) {
+       //wat sholud be "lua-string" or "lua-comment", level is the number of "=" in opening mark.
+       return function(source, setState){
+      var dashes = 0;
+      while (!source.endOfLine()) {
+        var ch = source.next();
+        if (dashes == level+1 && ch == "]" ) {
+          setState(normal);
+          break;
+        }
+               if (dashes == 0) 
+                       dashes = (ch == "]") ? 1:0;
+               else
+                       dashes = (ch == "=") ? dashes + 1 : 0;
+        }
+      return what;
+        }
+    }
+
+
+    function inString(quote) {
+      return function(source, setState) {
+        var escaped = false;
+        while (!source.endOfLine()) {
+          var ch = source.next();
+          if (ch == quote && !escaped)
+            break;
+          escaped = !escaped && ch == "\\";
+        }
+        if (!escaped)
+          setState(normal);
+        return "lua-string";
+      };
+    }
+
+    return function(source, startState) {
+      return tokenizer(source, startState || normal);
+    };
+  })();
+
+  function indentLUA(indentDepth, base) {
+    return function(nextChars) {
+
+      var closing = (luaUnindentKeys2.test(nextChars) || luaMiddleKeys.test(nextChars));
+
+       
+       return base + ( indentUnit * (indentDepth - (closing?1:0)) );
+    };
+  }
+
+  
+function parseLUA(source,basecolumn) {
+     basecolumn = basecolumn || 0;
+    
+       var tokens = tokenizeLUA(source);
+    var indentDepth = 0;
+
+    var iter = {
+      next: function() {
+        var token = tokens.next(), style = token.style, content = token.content;
+
+       
+       if (style == "lua-identifier" && luaKeywords.test(content)){
+         token.style = "lua-keyword";
+       }       
+       if (style == "lua-identifier" && luaStdFunctions.test(content)){
+         token.style = "lua-stdfunc";
+       }
+       if (style == "lua-identifier" && luaCustomFunctions.test(content)){
+         token.style = "lua-customfunc";
+       }
+
+       if (luaIndentKeys.test(content))
+       indentDepth++;
+       else if (luaUnindentKeys.test(content))
+               indentDepth--;
+        
+
+        if (content == "\n")
+          token.indentation = indentLUA( indentDepth, basecolumn);
+
+        return token;
+      },
+
+      copy: function() {
+        var  _tokenState = tokens.state, _indentDepth = indentDepth;
+        return function(source) {
+          tokens = tokenizeLUA(source, _tokenState);
+      
+         indentDepth = _indentDepth;
+          return iter;
+        };
+      }
+    };
+    return iter;
+  }
+
+  return {make: parseLUA, configure:configureLUA, electricChars: "delf})"};   //en[d] els[e] unti[l] elsei[f]  // this should be taken from Keys keywords
+})();
+
diff --git a/typo3/contrib/codemirror/contrib/ometa/._LICENSE b/typo3/contrib/codemirror/contrib/ometa/._LICENSE
new file mode 100644 (file)
index 0000000..e2f550b
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/ometa/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/ometa/._index.html b/typo3/contrib/codemirror/contrib/ometa/._index.html
new file mode 100644 (file)
index 0000000..64457a5
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/ometa/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/ometa/LICENSE b/typo3/contrib/codemirror/contrib/ometa/LICENSE
new file mode 100644 (file)
index 0000000..44ceed6
--- /dev/null
@@ -0,0 +1,23 @@
+ Copyright (c) 2007-2009 Marijn Haverbeke
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
+ damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
+ redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+    not claim that you wrote the original software. If you use this
+    software in a product, an acknowledgment in the product
+    documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+    not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+    distribution.
+
+ Marijn Haverbeke
+ marijnh at gmail
diff --git a/typo3/contrib/codemirror/contrib/ometa/css/._ometacolors.css b/typo3/contrib/codemirror/contrib/ometa/css/._ometacolors.css
new file mode 100644 (file)
index 0000000..3eccef1
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/ometa/css/._ometacolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/ometa/css/ometacolors.css b/typo3/contrib/codemirror/contrib/ometa/css/ometacolors.css
new file mode 100644 (file)
index 0000000..f797b45
--- /dev/null
@@ -0,0 +1,63 @@
+html {
+  cursor: text;
+}
+
+.editbox {
+  margin: .4em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  color: black;
+}
+
+pre.code, .editbox {
+  color: #666666;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.js-punctuation {
+  color: #666666;
+}
+
+span.js-operator {
+  color: #E1570F;
+}
+
+span.js-keyword {
+  color: #770088;
+}
+
+span.js-atom {
+  color: #228811;
+}
+
+span.js-variable {
+  color: black;
+}
+
+span.js-variabledef {
+  color: #0000FF;
+}
+
+span.js-localvariable {
+  color: #004499;
+}
+
+span.js-property {
+  color: black;
+}
+
+span.js-comment {
+  color: #AA7700;
+}
+
+span.js-string {
+  color: #AA2222;
+}
+
+span.ometa-binding {
+  color: #FF0000;
+}
diff --git a/typo3/contrib/codemirror/contrib/ometa/index.html b/typo3/contrib/codemirror/contrib/ometa/index.html
new file mode 100644 (file)
index 0000000..7bf59fd
--- /dev/null
@@ -0,0 +1,77 @@
+<html xmlns="http://www.w3.org/1999/xhtml"> 
+  <head> 
+    <script src="../../js/codemirror.js" type="text/javascript"></script> 
+    <title>CodeMirror: OmetaJS demonstration</title> 
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/> 
+  </head> 
+  <body style="padding: 20px;"> 
+
+<p>This page demonstrates <a href="../../index.html">CodeMirror</a>'s <a
+      href="http://www.tinlizzie.org/ometa">OmetaJS</a> parser.</p>
+
+<p>Adapted from the official Javascript parser by Eric KEDJI
+  &lt;<a href="mailto:eric.kedji@gmail.com">eric.kedji@gmail.com</a>&gt;.</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="30">
+// Source: http://www.tinlizzie.org/ometa-js/#Lisp
+// Inspired by McCarthy's meta-circular lisp
+
+ometa Lisp {
+  ev     = string:a                                         -> self.env[a]
+         | [#lambda :fs :body]                              -> [#lambda, fs, body]
+         | [#quote  :ans]                                   -> ans
+         | [#cond   evCond:ans]                             -> ans
+         | [ev:f    ev*:xs]     app(f, xs):ans              -> ans,
+
+  evCond = condF* condT:ans anything*                       -> x,
+  condT  = [ev:x ?x ev:ans]                                 -> ans,
+  condF  = ~condT anything,
+
+  app    = #car                [[:hd anything*]]            -> hd
+         | #cdr                [[:hd anything*:tl]]         -> tl
+         | #cons               [:hd :tl]                    -> [hd].concat(tl)
+         | #atom               [:x]                         -> (!(x instanceof Array))
+         | #eq                 [:x :y]                      -> (x == y)
+         | [#lambda :fs :body] :args
+             enter bind(fs, args) ev(body):ans leave        -> ans,
+  enter  =                                                  -> (self.env = self.env.delegated({_p: self.env})),
+  bind   = []                []
+         | [:f anything*:fs] [:a anything*:as] bind(fs, as) -> (self.env[f] = a),
+  leave  =                                                  -> (self.env = self.env._p)
+}
+Lisp.initialize = function() { this.env = {car: "car", cdr: "cdr", cons: "cons", atom: "atom", eq: "eq", nil: null, T: "T"} }
+lispEval = function(x) { return Lisp.match(x, "ev") }
+
+lispEval([`quote, [1, 2, 3]])
+lispEval([`car, [`quote, [1, 2, 3]]])
+lispEval([`cdr, [`quote, [1, 2, 3]]])
+lispEval([`cons, [`quote, `x], [`quote, `y]])
+lispEval([`eq, [`quote, `x], [`quote, `x]])
+lispEval([[`lambda, [`x], [`cons, `x, `x]], [`quote, `boo]])
+</textarea>
+</div>
+
+<script type="text/javascript">
+/*  var textarea = document.getElementById('code');
+  var editor = new MirrorFrame(CodeMirror.replace(textarea), {
+    height: "350px",
+    content: textarea.value,
+    parserfile: ["tokenizeometa.js", "parseometa.js"],
+    stylesheet: "css/ometacolors.css",
+    path: "js/",
+    autoMatchParens: true
+  });
+*/
+  var editor = CodeMirror.fromTextArea('code', {
+    height: "450px",
+    parserfile: ["../contrib/ometa/js/tokenizeometa.js",
+      "../contrib/ometa/js/parseometa.js"],
+    stylesheet: "css/ometacolors.css",
+    path: "../../js/",
+    textWrapping: false
+  });
+</script>
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/ometa/js/._parseometa.js b/typo3/contrib/codemirror/contrib/ometa/js/._parseometa.js
new file mode 100644 (file)
index 0000000..9935096
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/ometa/js/._parseometa.js differ
diff --git a/typo3/contrib/codemirror/contrib/ometa/js/._tokenizeometa.js b/typo3/contrib/codemirror/contrib/ometa/js/._tokenizeometa.js
new file mode 100644 (file)
index 0000000..55558f3
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/ometa/js/._tokenizeometa.js differ
diff --git a/typo3/contrib/codemirror/contrib/ometa/js/parseometa.js b/typo3/contrib/codemirror/contrib/ometa/js/parseometa.js
new file mode 100644 (file)
index 0000000..efb715e
--- /dev/null
@@ -0,0 +1,364 @@
+/* Parse function for JavaScript. Makes use of the tokenizer from
+ * tokenizejavascript.js. Note that your parsers do not have to be
+ * this complicated -- if you don't want to recognize local variables,
+ * in many languages it is enough to just look for braces, semicolons,
+ * parentheses, etc, and know when you are inside a string or comment.
+ *
+ * See manual.html for more info about the parser interface.
+ */
+
+var JSParser = Editor.Parser = (function() {
+  // Token types that can be considered to be atoms.
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
+  // Setting that can be used to have JSON data indent properly.
+  var json = false;
+  // Constructor for the lexical context objects.
+  function JSLexical(indented, column, type, align, prev, info) {
+    // indentation at start of this line
+    this.indented = indented;
+    // column at which this scope was opened
+    this.column = column;
+    // type of scope ('vardef', 'stat' (statement), 'form' (special form), '[', '{', or '(')
+    this.type = type;
+    // '[', '{', or '(' blocks that have any text after their opening
+    // character are said to be 'aligned' -- any lines below are
+    // indented all the way to the opening character.
+    if (align != null)
+      this.align = align;
+    // Parent scope, if any.
+    this.prev = prev;
+    this.info = info;
+  }
+
+  // My favourite JavaScript indentation rules.
+  function indentJS(lexical) {
+    return function(firstChars) {
+      var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
+      var closing = firstChar == type;
+      if (type == "vardef")
+        return lexical.indented + 4;
+      else if (type == "form" && firstChar == "{")
+        return lexical.indented;
+      else if (type == "stat" || type == "form")
+        return lexical.indented + indentUnit;
+      else if (lexical.info == "switch" && !closing)
+        return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align)
+        return lexical.column - (closing ? 1 : 0);
+      else
+        return lexical.indented + (closing ? 0 : indentUnit);
+    };
+  }
+
+  // The parser-iterator-producing function itself.
+  function parseJS(input, basecolumn) {
+    // Wrap the input in a token stream
+    var tokens = tokenizeJavaScript(input);
+    // The parser state. cc is a stack of actions that have to be
+    // performed to finish the current statement. For example we might
+    // know that we still need to find a closing parenthesis and a
+    // semicolon. Actions at the end of the stack go first. It is
+    // initialized with an infinitely looping action that consumes
+    // whole statements.
+    var cc = [json ? expressions : statements];
+    // Context contains information about the current local scope, the
+    // variables defined in that, and the scopes above it.
+    var context = null;
+    // The lexical scope, used mostly for indentation.
+    var lexical = new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false);
+    // Current column, and the indentation at the start of the current
+    // line. Used to create lexical scope objects.
+    var column = 0;
+    var indented = 0;
+    // Variables which are used by the mark, cont, and pass functions
+    // below to communicate with the driver loop in the 'next'
+    // function.
+    var consume, marked;
+  
+    // The iterator object.
+    var parser = {next: next, copy: copy};
+
+    function next(){
+      // Start by performing any 'lexical' actions (adjusting the
+      // lexical variable), or the operations below will be working
+      // with the wrong lexical state.
+      while(cc[cc.length - 1].lex)
+        cc.pop()();
+
+      // Fetch a token.
+      var token = tokens.next();
+
+      // Adjust column and indented.
+      if (token.type == "whitespace" && column == 0)
+        indented = token.value.length;
+      column += token.value.length;
+      if (token.content == "\n"){
+        indented = column = 0;
+        // If the lexical scope's align property is still undefined at
+        // the end of the line, it is an un-aligned scope.
+        if (!("align" in lexical))
+          lexical.align = false;
+        // Newline tokens get an indentation function associated with
+        // them.
+        token.indentation = indentJS(lexical);
+        // special handling for multiline strings: keep everything in the first
+        // column, as spaces at the start of a multiline string are significant
+        if (lexical.info == "multilineString") {
+          lexical.align = false;
+          token.indentation = function () { return 0; };
+        }
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "comment")
+        return token;
+      // Take note when a multiline string is found, so as to
+      // correctly handle indentation at the end of the line
+      // (see above, line 95)
+      if (token.type == "multilineString")
+        lexical.info = 'multilineString';
+      // When a meaningful token is found and the lexical scope's
+      // align is undefined, it is an aligned scope.
+      if (!("align" in lexical))
+        lexical.align = true;
+
+      // Execute actions until one 'consumes' the token and we can
+      // return it.
+      while(true) {
+        consume = marked = false;
+        // Take and execute the topmost action.
+        cc.pop()(token.type, token.content);
+        if (consume){
+          // Marked is used to change the style of the current token.
+          if (marked)
+            token.style = marked;
+          // Here we differentiate between local and global variables.
+          else if (token.type == "variable" && inScope(token.content))
+            token.style = "js-localvariable";
+          return token;
+        }
+      }
+    }
+
+    // This makes a copy of the parser state. It stores all the
+    // stateful variables in a closure, and returns a function that
+    // will restore them when called with a new input stream. Note
+    // that the cc array has to be copied, because it is contantly
+    // being modified. Lexical objects are not mutated, and context
+    // objects are not mutated in a harmful way, so they can be shared
+    // between runs of the parser.
+    function copy(){
+      var _context = context, _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
+  
+      return function copyParser(input){
+        context = _context;
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizeJavaScript(input, _tokenState);
+        return parser;
+      };
+    }
+
+    // Helper function for pushing a number of actions onto the cc
+    // stack in reverse order.
+    function push(fs){
+      for (var i = fs.length - 1; i >= 0; i--)
+        cc.push(fs[i]);
+    }
+    // cont and pass are used by the action functions to add other
+    // actions to the stack. cont will cause the current token to be
+    // consumed, pass will leave it for the next action.
+    function cont(){
+      push(arguments);
+      consume = true;
+    }
+    function pass(){
+      push(arguments);
+      consume = false;
+    }
+    // Used to change the style of the current token.
+    function mark(style){
+      marked = style;
+    }
+
+    // Push a new scope. Will automatically link the current scope.
+    function pushcontext(){
+      context = {prev: context, vars: {"this": true, "arguments": true}};
+    }
+    // Pop off the current scope.
+    function popcontext(){
+      context = context.prev;
+    }
+    // Register a variable in the current scope.
+    function register(varname){
+      if (context){
+        mark("js-variabledef");
+        context.vars[varname] = true;
+      }
+    }
+    // Check whether a variable is defined in the current scope.
+    function inScope(varname){
+      var cursor = context;
+      while (cursor) {
+        if (cursor.vars[varname])
+          return true;
+        cursor = cursor.prev;
+      }
+      return false;
+    }
+  
+    // Push a new lexical context of the given type.
+    function pushlex(type, info) {
+      var result = function(){
+        lexical = new JSLexical(indented, column, type, null, lexical, info)
+      };
+      result.lex = true;
+      return result;
+    }
+    // Pop off the current lexical context.
+    function poplex(){
+      lexical = lexical.prev;
+    }
+    poplex.lex = true;
+    // The 'lex' flag on these actions is used by the 'next' function
+    // to know they can (and have to) be ran before moving on to the
+    // next token.
+  
+    // Creates an action that discards tokens until it finds one of
+    // the given type.
+    function expect(wanted){
+      return function expecting(type){
+        if (type == wanted) cont();
+        else cont(arguments.callee);
+      };
+    }
+
+    // Looks for a statement, and then calls itself.
+    function statements(type){
+      return pass(statement, statements);
+    }
+    function expressions(type){
+      return pass(expression, expressions);
+    }
+    // Dispatches various types of statements based on the type of the
+    // current token.
+    function statement(type){
+      if (type == "var") cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+      else if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
+      else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
+      else if (type == "{") cont(pushlex("}"), block, poplex);
+      else if (type == "function") cont(functiondef);
+      else if (type == "for") cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
+      else if (type == "variable") cont(pushlex("stat"), maybelabel);
+      else if (type == "switch") cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), block, poplex, poplex);
+      else if (type == "case") cont(expression, expect(":"));
+      else if (type == "default") cont(expect(":"));
+      else if (type == "catch") cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext);
+      else pass(pushlex("stat"), expression, expect(";"), poplex);
+    }
+    // Dispatch expression types.
+    function expression(type){
+      if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
+      else if (type == "function") cont(functiondef);
+      else if (type == "keyword c") cont(expression);
+      else if (type == "(") cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
+      else if (type == "operator") cont(expression);
+      else if (type == "[") cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
+      else if (type == "{") cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
+      else cont();
+    }
+    // Called for places where operators, function calls, or
+    // subscripts are valid. Will skip on to the next action if none
+    // is found.
+    function maybeoperator(type){
+      if (type == "operator") cont(expression);
+      else if (type == "(") cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
+      else if (type == ".") cont(property, maybeoperator);
+      else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
+    }
+    // When a statement starts with a variable name, it might be a
+    // label. If no colon follows, it's a regular statement.
+    function maybelabel(type){
+      if (type == ":") cont(poplex, statement);
+      else pass(maybeoperator, expect(";"), poplex);
+    }
+    // Property names need to have their style adjusted -- the
+    // tokenizer thinks they are variables.
+    function property(type){
+      if (type == "variable") {mark("js-property"); cont();}
+    }
+    // This parses a property and its value in an object literal.
+    function objprop(type){
+      if (type == "variable") mark("js-property");
+      if (atomicTypes.hasOwnProperty(type)) cont(expect(":"), expression);
+    }
+    // Parses a comma-separated list of the things that are recognized
+    // by the 'what' argument.
+    function commasep(what, end){
+      function proceed(type) {
+        if (type == ",") cont(what, proceed);
+        else if (type == end) cont();
+        else cont(expect(end));
+      }
+      return function commaSeparated(type) {
+        if (type == end) cont();
+        else pass(what, proceed);
+      };
+    }
+    // Look for statements until a closing brace is found.
+    function block(type){
+      if (type == "}") cont();
+      else pass(statement, block);
+    }
+    // Variable definitions are split into two actions -- 1 looks for
+    // a name or the end of the definition, 2 looks for an '=' sign or
+    // a comma.
+    function vardef1(type, value){
+      if (type == "variable"){register(value); cont(vardef2);}
+      else cont();
+    }
+    function vardef2(type, value){
+      if (value == "=") cont(expression, vardef2);
+      else if (type == ",") cont(vardef1);
+    }
+    // For loops.
+    function forspec1(type){
+      if (type == "var") cont(vardef1, forspec2);
+      else if (type == ";") pass(forspec2);
+      else if (type == "variable") cont(formaybein);
+      else pass(forspec2);
+    }
+    function formaybein(type, value){
+      if (value == "in") cont(expression);
+      else cont(maybeoperator, forspec2);
+    }
+    function forspec2(type, value){
+      if (type == ";") cont(forspec3);
+      else if (value == "in") cont(expression);
+      else cont(expression, expect(";"), forspec3);
+    }
+    function forspec3(type) {
+      if (type == ")") pass();
+      else cont(expression);
+    }
+    // A function definition creates a new context, and the variables
+    // in its argument list have to be added to this context.
+    function functiondef(type, value){
+      if (type == "variable"){register(value); cont(functiondef);}
+      else if (type == "(") cont(pushcontext, commasep(funarg, ")"), statement, popcontext);
+    }
+    function funarg(type, value){
+      if (type == "variable"){register(value); cont();}
+    }
+  
+    return parser;
+  }
+
+  return {
+    make: parseJS,
+    electricChars: "{}:",
+    configure: function(obj) {
+      if (obj.json != null) json = obj.json;
+    }
+  };
+})();
diff --git a/typo3/contrib/codemirror/contrib/ometa/js/tokenizeometa.js b/typo3/contrib/codemirror/contrib/ometa/js/tokenizeometa.js
new file mode 100644 (file)
index 0000000..430206c
--- /dev/null
@@ -0,0 +1,209 @@
+/* Tokenizer for JavaScript code */
+
+var tokenizeJavaScript = (function() {
+  // Advance the stream until the given character (not preceded by a
+  // backslash) is encountered, or the end of the line is reached.
+  function nextUntilUnescaped(source, end) {
+    var escaped = false;
+    while (!source.endOfLine()) {
+      var next = source.next();
+      if (next == end && !escaped)
+        return false;
+      escaped = !escaped && next == "\\";
+    }
+    return escaped;
+  }
+
+  // A map of JavaScript's keywords. The a/b/c keyword distinction is
+  // very rough, but it gives the parser enough information to parse
+  // correct code correctly (we don't care that much how we parse
+  // incorrect code). The style information included in these objects
+  // is used by the highlighter to pick the correct CSS style for a
+  // token.
+  var keywords = function(){
+    function result(type, style){
+      return {type: type, style: "js-" + style};
+    }
+    // keywords that take a parenthised expression, and then a
+    // statement (if)
+    var keywordA = result("keyword a", "keyword");
+    // keywords that take just a statement (else)
+    var keywordB = result("keyword b", "keyword");
+    // keywords that optionally take an expression, and form a
+    // statement (return)
+    var keywordC = result("keyword c", "keyword");
+    var operator = result("operator", "keyword");
+    var atom = result("atom", "atom");
+    return {
+      "if": keywordA, "while": keywordA, "with": keywordA,
+      "else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB,
+      "return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "delete": keywordC, "throw": keywordC,
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "var": result("var", "keyword"), "function": result("function", "keyword"), "catch": result("catch", "keyword"),
+      "for": result("for", "keyword"), "switch": result("switch", "keyword"),
+      "case": result("case", "keyword"), "default": result("default", "keyword"),
+      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
+      "ometa": keywordB
+    };
+  }();
+
+  // Some helper regexps
+  var isOperatorChar = /[+\-*&%=<>!?|~]/;
+  var isHexDigit = /[0-9A-Fa-f]/;
+  var isWordChar = /[\w\$_]/;
+
+  // Wrapper around jsToken that helps maintain parser state (whether
+  // we are inside of a multi-line comment and whether the next token
+  // could be a regular expression).
+  function jsTokenState(inside, regexp) {
+    return function(source, setState) {
+      var newInside = inside;
+      var type = jsToken(inside, regexp, source, function(c) {newInside = c;});
+      var newRegexp = type.type == "operator" || type.type == "keyword c" || type.type.match(/^[\[{}\(,;:]$/);
+      if (newRegexp != regexp || newInside != inside)
+        setState(jsTokenState(newInside, newRegexp));
+      return type;
+    };
+  }
+
+  // The token reader, intended to be used by the tokenizer from
+  // tokenize.js (through jsTokenState). Advances the source stream
+  // over a token, and returns an object containing the type and style
+  // of that token.
+  function jsToken(inside, regexp, source, setInside) {
+    function readHexNumber(){
+      source.next(); // skip the 'x'
+      source.nextWhileMatches(isHexDigit);
+      return {type: "number", style: "js-atom"};
+    }
+
+    function readNumber() {
+      source.nextWhileMatches(/[0-9]/);
+      if (source.equals(".")){
+        source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      if (source.equals("e") || source.equals("E")){
+        source.next();
+        if (source.equals("-"))
+          source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      return {type: "number", style: "js-atom"};
+    }
+    // Read a word, look it up in keywords. If not found, it is a
+    // variable, otherwise it is a keyword of the type found.
+    function readWord() {
+      source.nextWhileMatches(isWordChar);
+      var word = source.get();
+      var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
+      return known ? {type: known.type, style: known.style, content: word} :
+      {type: "variable", style: "js-variable", content: word};
+    }
+    function readRegexp() {
+      nextUntilUnescaped(source, "/");
+      source.nextWhileMatches(/[gi]/);
+      return {type: "regexp", style: "js-string"};
+    }
+    // Mutli-line comments are tricky. We want to return the newlines
+    // embedded in them as regular newline tokens, and then continue
+    // returning a comment token for every line of the comment. So
+    // some state has to be saved (inside) to indicate whether we are
+    // inside a /* */ sequence.
+    function readMultilineComment(start){
+      var newInside = "/*";
+      var maybeEnd = (start == "*");
+      while (true) {
+        if (source.endOfLine())
+          break;
+        var next = source.next();
+        if (next == "/" && maybeEnd){
+          newInside = null;
+          break;
+        }
+        maybeEnd = (next == "*");
+      }
+      setInside(newInside);
+      return {type: "comment", style: "js-comment"};
+    }
+    function readMultilineString(start, quotes) {
+      var newInside = quotes;
+      var quote = quotes.charAt(0);
+      var maybeEnd = (start == quote);
+      while (true) {
+        if (source.endOfLine())
+          break;
+        var next = source.next();
+        if (next == quote && source.peek() == quote && maybeEnd) {
+          source.next();
+          newInside = null;
+          break;
+        }
+        maybeEnd = (next == quote);
+      }
+      setInside(newInside);
+      return {type: "multilineString", style: "js-string"};
+    }
+    function readOperator() {
+      source.nextWhileMatches(isOperatorChar);
+      return {type: "operator", style: "js-operator"};
+    }
+    function readString(quote) {
+      var endBackSlash = nextUntilUnescaped(source, quote);
+      setInside(endBackSlash ? quote : null);
+      return {type: "string", style: "js-string"};
+    }
+    function readOmetaIdentifierString() {
+      source.nextWhileMatches(isWordChar);
+      return {type: "string", style: "js-string"};
+    }
+    function readOmetaBinding() {
+      source.nextWhileMatches(isWordChar);
+      return {type: "variable", style: "ometa-binding"};
+    }
+
+    // Fetch the next token. Dispatches on first character in the
+    // stream, or first two characters when the first is a slash.
+    if (inside == "\"" || inside == "'")
+      return readString(inside);
+    var ch = source.next();
+    if (inside == "/*")
+      return readMultilineComment(ch);
+    if (inside == '"""' || inside == "'''")
+      return readMultilineString(ch, inside);
+    if (ch == '"' && source.lookAhead('""', true) || ch == "'" && source.lookAhead("''", true))
+      return readMultilineString('-', ch+ch+ch); // work as far as '-' is not '"' nor "'"
+    else if (ch == "\"" || ch == "'")
+      return readString(ch);
+    else if (ch == "`" || ch == "#" )
+      return readOmetaIdentifierString();
+    else if (ch == ':' && isWordChar.test(source.peek())) 
+      return readOmetaBinding();
+    // with punctuation, the type of the token is the symbol itself
+    else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+      return {type: ch, style: "js-punctuation"};
+    else if (ch == "0" && (source.equals("x") || source.equals("X")))
+      return readHexNumber();
+    else if (/[0-9]/.test(ch))
+      return readNumber();
+    else if (ch == "/"){
+      if (source.equals("*"))
+      { source.next(); return readMultilineComment(ch); }
+      else if (source.equals("/"))
+      { nextUntilUnescaped(source, null); return {type: "comment", style: "js-comment"};}
+      else if (regexp)
+        return readRegexp();
+      else
+        return readOperator();
+    }
+    else if (isOperatorChar.test(ch))
+      return readOperator();
+    else
+      return readWord();
+  }
+
+  // The external interface to the tokenizer.
+  return function(source, startState) {
+    return tokenizer(source, startState || jsTokenState(false, true));
+  };
+})();
diff --git a/typo3/contrib/codemirror/contrib/php/._LICENSE b/typo3/contrib/codemirror/contrib/php/._LICENSE
new file mode 100644 (file)
index 0000000..8d85e4d
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/php/._index.html b/typo3/contrib/codemirror/contrib/php/._index.html
new file mode 100644 (file)
index 0000000..4d6bed7
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/php/LICENSE b/typo3/contrib/codemirror/contrib/php/LICENSE
new file mode 100644 (file)
index 0000000..32f48ca
--- /dev/null
@@ -0,0 +1,37 @@
+Copyright (c) 2008-2009, Yahoo! Inc.
+All rights reserved.
+
+This software is provided for use in connection with the
+CodeMirror suite of modules and utilities, hosted and maintained
+at http://codemirror.net/.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/typo3/contrib/codemirror/contrib/php/css/._phpcolors.css b/typo3/contrib/codemirror/contrib/php/css/._phpcolors.css
new file mode 100644 (file)
index 0000000..60c8bca
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/css/._phpcolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/php/css/phpcolors.css b/typo3/contrib/codemirror/contrib/php/css/phpcolors.css
new file mode 100644 (file)
index 0000000..43d4057
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
+The copyrights embodied in the content of this file are licensed by
+Yahoo! Inc. under the BSD (revised) open source license
+
+@author Dan Vlad Dascalescu <dandv@yahoo-inc.com>
+*/
+
+html {
+  cursor: text;
+}
+
+.editbox {
+  margin: .4em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+}
+
+/*We should define specific styles for every element of the syntax.
+  the setting below will cause some annoying color to show through if we missed
+  defining a style for a token. This is also the "color" of the whitespace and
+  of the cursor.
+*/
+pre.code, .editbox {
+  color: red;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.php-punctuation {
+  color: blue;
+}
+
+span.php-keyword {
+  color: #770088;
+  font-weight: bold;
+}
+
+span.php-operator {
+  color: blue;
+}
+
+/* __FILE__ etc.; http://php.net/manual/en/reserved.php */
+span.php-compile-time-constant {
+  color: #776088;
+  font-weight: bold;
+}
+
+/* output of get_defined_constants(). Differs from http://php.net/manual/en/reserved.constants.php */
+span.php-predefined-constant {
+  color: darkgreen;
+  font-weight: bold;
+}
+
+/* PHP reserved "language constructs"... echo() etc.; http://php.net/manual/en/reserved.php */
+span.php-reserved-language-construct {
+  color: green;
+  font-weight: bold;
+}
+
+/* PHP built-in functions: glob(), chr() etc.; output of get_defined_functions()["internal"] */
+span.php-predefined-function {
+  color: green;
+}
+
+/* PHP predefined classes: PDO, Exception etc.; output of get_declared_classes() and different from http://php.net/manual/en/reserved.classes.php */
+span.php-predefined-class {
+  color: green;
+}
+
+span.php-atom {
+  color: #228811;
+}
+
+/* class, interface, namespace or function names, but not $variables */
+span.php-t_string {
+  color: black;
+}
+
+span.php-variable {
+  color: black;
+  font-weight: bold;
+}
+
+
+span.js-localvariable {
+  color: #004499;
+}
+
+span.php-comment {
+  color: #AA7700;
+  font-stretch: condensed;
+/*  font-style: italic;  This causes line height to slightly change, getting line numbers out of sync */
+}
+
+span.php-string-single-quoted {
+  color: #AA2222;
+}
+/* double quoted strings allow interpolation */
+span.php-string-double-quoted {
+  color: #AA2222;
+  font-weight: bold;
+}
+
+span.syntax-error {
+  background-color: red;
+}
+
+span.deprecated {
+  font-size: smaller;
+}
diff --git a/typo3/contrib/codemirror/contrib/php/index.html b/typo3/contrib/codemirror/contrib/php/index.html
new file mode 100644 (file)
index 0000000..006cb56
--- /dev/null
@@ -0,0 +1,310 @@
+<!--
+Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
+The copyrights embodied in the content of this file are licensed by
+Yahoo! Inc. under the BSD (revised) open source license
+
+@author Dan Vlad Dascalescu <dandv@yahoo-inc.com>
+
+-->
+
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: PHP+HTML+JavaScript+CSS mixed-mode demonstration</title>
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/>
+  </head>
+  <body style="padding: 20px;">
+
+    <p>This is a complex demonstration of the <b>PHP+HTML+JavaScript+CSS mixed-mode
+    syntax highlight</b> capabilities of <a href="../../index.html">CodeMirror</a>.
+    &lt;?php ... ?> tags use the PHP parser, &lt;script> tags use the JavaScript
+    parser, and &lt;style> tags use the CSS parser. The rest of the content is
+    parsed using the XML parser in HTML mode.</p>
+
+    <p>Features of the PHP parser:
+    <ul>
+      <li>special "deprecated" style for PHP4 keywords like 'var'
+      <li>support for PHP 5.3 keywords: 'namespace', 'use'
+      <li>911 predefined constants, 1301 predefined functions, 105 predeclared classes
+        from a typical PHP installation in a LAMP environment
+      <li>new feature: syntax error flagging, thus enabling strict parsing of:
+        <ol>
+          <li>function definitions with explicitly or implicitly typed arguments and default values
+          <li>modifiers (public, static etc.) applied to method and member definitions
+          <li>foreach(array_expression as $key [=> $value]) loops
+        </ol>
+      <li>differentiation between single-quoted strings and double-quoted interpolating strings
+    </ul>
+
+    <div style="border: 1px solid black; padding: 3px; background-color: #F8F8F8">
+    <textarea id="code" cols="120" rows="30">
+The "root" parser is XML in HTML mode.
+Next, we can switch into PHP mode, for example. This is
+<?php echo 'text output by';
+?>
+PHP. </b>
+On the line above, we just had an XML syntax error due to the </b> tag not being opened.
+
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>   HTML text will follow
+<html>
+  <head>
+    <title>Similarly, the 'script' tag will switch to the JavaScript parser:</title>
+    <script type="text/javascript">
+       // Press enter inside the object and your new line will be suitably
+       // indented.
+       var keyBindings = {
+         enter: "newline-and-indent",
+         tab: "reindent-selection",
+         ctrl_enter: "reparse-buffer",
+         ctrl_z: "undo",
+         ctrl_y: "redo",
+         ctrl_backspace: "undo-for-safari-which-stupidly-enough-blocks-ctrl-z"
+       };
+
+       // Press tab on the next line and the wrong indentation will be fixed.
+             var regex = /foo|bar/i;
+
+       function example(x) {
+         // Local variables get a different colour than global ones.
+         var y = 44.4;
+         return x + y - z;
+       }
+    </script>
+    <style>
+      /* Some example CSS */
+
+      @import url("something.css");
+
+      body {
+        margin: 0;
+        padding: 3em 6em;
+        font-family: tahoma, arial, sans-serif;
+        color: #000;
+      }
+
+      #navigation a {
+        font-weight: bold;
+        text-decoration: none !important;
+      }
+
+      h1 {
+        font-size: 2.5em;
+      }
+
+      h1:before, h2:before {
+        content: "::";
+      }
+
+      code {
+        font-family: courier, monospace;
+        font-size: 80%;
+        color: #418A8A;
+      }
+    </style>
+  </head>
+
+  <body>
+
+  The PHP code below contains some deliberate errors. Play with the editor by fixing them
+  and observing how the highlight changes.
+
+    <?php
+    namespace A;
+    namespace A::B::C;
+    namespace A::::B;
+    namespace A::B::C::;
+    namespace A::B::C::D x;
+    self::range($row['lft'], $row['rgt']));  // error: extra ')'
+    $a = (b() + 4) 5 foo;  // error: missing operators
+    self::$var;
+    $parent = self::range($max + 1, $max + 1);
+    $row[attributes][$attribute_name] = $attribute_value;
+    $row[attributes()][$attribute_name] = $attribute_value;
+    $row[attributes(5)][$attribute_name] = $attribute_value;
+    $row[$attributes()][$attribute_name] = $attribute_value;
+    abstract class 5 extends foo implements echo {
+        private function domainObjectBuilder() {
+            return $this->use_domain_object_builder
+                   ? $this->domain()->objectBuilder()
+                   : null;
+        }
+
+        const $myconst = 'some string';
+        $array[myconst] = 4;
+        // this is a single-line C++-style comment
+        # this is a single-line shell-style comment
+        private var $a = __FILE__;
+        protected static $b = timezone_transitions_get('some parameter here');
+        global $g = isset("string");
+        static $s = hash_update_file;  // warning: predefined function non-call
+        function mike ($var) $foo;
+        mike(A::func(param));
+        func($b $c);  // error: function parameters must be comma-separated
+        foo bar;  // error: no operator
+        $baz $quux;  // error: no operator
+        public abstract function loadPageXML(util_FilePath $filename, $merge=0+$foo, $x, $y=3) {
+            $newrow[$key] = $val;
+            $newresult[] = $row;
+            $state = $row['c'] == 1;
+            $attribute_values[$attribute_name] = null;
+            $row['attributes'][$attribute_name] = $attribute_value;
+            $result[$row['element']][$row['attribute']] = $row['value'];
+            $sql = "multiline string
+line2 is special - it'll interpolate variables like $state and method calls
+{$this->cache->add($key, 5)} and maybe \"more\"
+
+line5";
+            $sql = 'multiline string
+single quoting means no \'interpolation\' like "$start" or method call
+{$this->cache->add($key, 5)} will happen
+
+line5';
+            $bitpattern = 1 << 2;
+            $bitpattern <<= 3;
+            $incorrect = <<< 5 EOSTRING  // FIXME: CodeMirror update bug: add a letter before 5 and notice that syntax is not updated until EOF, even with continuousScanning: 500
+error: the identifier must conform to the identifier rules
+EOSTRING;
+            $sql = <<< EOSQL
+                SELECT attribute, element, value
+                FROM attribute_values
+                WHERE dimension = ?
+EOSQL;
+            $this->lr_cache->add($key, self::range($row['lft'], $row['rgt']));
+            $composite_string = <<<EOSTRING
+some lines here
+EOSTRING
+. 'something extra';
+            $page_lft = ($domain->name() == 'page') ? $start + 1 : $page_start + 1;
+            echo "This is class foo";
+            echo "a = ".$this ->a[2+3*$array["foo"]]."";
+            echo "b = {$this->b}";  // FIXME: highlight interpolation in strings
+        }
+        final function makecoffee error($types = array("cappuccino"), $coffeeMaker = NULL) {
+            $out_of_way_amount = $max - $child->left() + 1;
+            $absolute_pos = $child->left() - $move->width();
+            $varfunc(1, 'x');
+            $varfunc(1, 'x') + foo() - 5;
+            $funcarray[$i]('param1', $param2);
+                $lr[$domain_name] = $this->get_left_and_right($domain,
+                                                              $dimension_name,
+                                                              $element_name);
+            $domain_list = is_null($domain) ?
+                           r3_Domain::names() :
+                           array($domain->name());
+            foreach (r3_Domain::names() as $domain_name) {
+                $placeholders = 'distance LIKE '
+                            . implode(array_fill(1, $num_distances, '?'),
+                                      ' OR distance LIKE ');
+
+            }
+            return $this->target*$this->trans+myfunc(__METHOD__);
+            /*
+            echo 'This is a test'; /* This comment will cause a problem */
+            */
+        }
+        switch( $type ) {
+            case "r3core_AddTemplateToTargetEvent":
+                $this->notifyAddTemplateToTarget( $genevent );
+                break;
+            case "r3core_GenerateTargetEvent" $this:
+                for($i=0; $i<=this->method(); $i++) {
+                    echo 'Syntax "highlighting"';
+                }
+                try {
+                    foreach($array xor $loader->parse_fn($filename) as $key => value) {
+                        namespace r3;
+                    }
+                } catch( Exception $e ) {
+                    /** restore the backup
+                    */
+                    $this->loadAll($tmp, $event, true);
+                    // `php -l` doesn't complain at all at this (it assumes string constants):
+                    this + makes * no - sense;
+                }
+
+                break;
+
+            default moo:
+                throw new r3_util_Exception( get_class( $genevent ) . " does not map" );
+        }
+
+
+    };
+    
+    if($something==true):
+       $test = 'something';
+    endif;
+    
+    for($i=0;$i<2000;$i++):
+       echo $i;
+       $k = $k + 1;
+    endfor;
+    
+    foreach(array('one','two') as $key => $value):
+       echo $number . ' = '. $key;
+    endforeach;
+
+    /* fails if nested */
+    if($nested < 0):
+       if($fail > 1):
+               echo 'This fails....';
+       endif;
+    endif;
+    ?>
+
+    <r3:cphp>
+        php("works", $here, 2);
+    </r3:cphp>
+
+    <r4:cphp>
+    class foo {
+        // a comment
+        var $a;
+        var $b;
+    };
+    </r4:cphp>
+
+  <h1>This is an <?php # echo 'simple';?> example.</h1>
+  <p>The header above will say 'This is an  example'.</p>
+  <h1>This is an <?php // echo 'simple';?> example.</h1>
+
+  <?php echo; ?>
+    <body>
+
+<?php echo "<html>
+  <head>
+    <script>
+    var foo = 'bar';
+    </script>
+    <style>
+      span.test {font-family: arial, 'lucida console', sans-serif}
+    </style>
+  </head>
+  <body>
+    <!-- comment -->
+  </body>
+</html>"; ?>
+
+</body>
+</html>
+
+
+    </textarea>
+    </div>
+
+    <script type="text/javascript">
+      var editor = CodeMirror.fromTextArea('code', {
+        height: "350px",
+        parserfile: ["parsexml.js", "parsecss.js", "tokenizejavascript.js", "parsejavascript.js",
+                     "../contrib/php/js/tokenizephp.js", "../contrib/php/js/parsephp.js",
+                     "../contrib/php/js/parsephphtmlmixed.js"],
+        stylesheet: ["../../css/xmlcolors.css", "../../css/jscolors.css", "../../css/csscolors.css", "css/phpcolors.css"],
+        path: "../../js/",
+        continuousScanning: 500
+      });
+    </script>
+
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/php/js/._parsephp.js b/typo3/contrib/codemirror/contrib/php/js/._parsephp.js
new file mode 100644 (file)
index 0000000..41197bc
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/js/._parsephp.js differ
diff --git a/typo3/contrib/codemirror/contrib/php/js/._parsephphtmlmixed.js b/typo3/contrib/codemirror/contrib/php/js/._parsephphtmlmixed.js
new file mode 100644 (file)
index 0000000..2cdbeaa
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/js/._parsephphtmlmixed.js differ
diff --git a/typo3/contrib/codemirror/contrib/php/js/._tokenizephp.js b/typo3/contrib/codemirror/contrib/php/js/._tokenizephp.js
new file mode 100644 (file)
index 0000000..ad0df8e
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/php/js/._tokenizephp.js differ
diff --git a/typo3/contrib/codemirror/contrib/php/js/parsephp.js b/typo3/contrib/codemirror/contrib/php/js/parsephp.js
new file mode 100644 (file)
index 0000000..9823195
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
+The copyrights embodied in the content of this file are licensed by
+Yahoo! Inc. under the BSD (revised) open source license
+
+@author Dan Vlad Dascalescu <dandv@yahoo-inc.com>
+
+
+Parse function for PHP. Makes use of the tokenizer from tokenizephp.js.
+Based on parsejavascript.js by Marijn Haverbeke.
+
+
+Features:
+ + special "deprecated" style for PHP4 keywords like 'var'
+ + support for PHP 5.3 keywords: 'namespace', 'use'
+ + 911 predefined constants, 1301 predefined functions, 105 predeclared classes
+   from a typical PHP installation in a LAMP environment
+ + new feature: syntax error flagging, thus enabling strict parsing of:
+   + function definitions with explicitly or implicitly typed arguments and default values
+   + modifiers (public, static etc.) applied to method and member definitions
+   + foreach(array_expression as $key [=> $value]) loops
+ + differentiation between single-quoted strings and double-quoted interpolating strings
+
+*/
+
+
+// add the Array.indexOf method for JS engines that don't support it (e.g. IE)
+// code from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array/IndexOf
+if (!Array.prototype.indexOf)
+{
+  Array.prototype.indexOf = function(elt /*, from*/)
+  {
+    var len = this.length;
+
+    var from = Number(arguments[1]) || 0;
+    from = (from < 0)
+         ? Math.ceil(from)
+         : Math.floor(from);
+    if (from < 0)
+      from += len;
+
+    for (; from < len; from++)
+    {
+      if (from in this &&
+          this[from] === elt)
+        return from;
+    }
+    return -1;
+  };
+}
+
+
+var PHPParser = Editor.Parser = (function() {
+  // Token types that can be considered to be atoms, part of operator expressions
+  var atomicTypes = {
+    "atom": true, "number": true, "variable": true, "string": true
+  };
+  // Constructor for the lexical context objects.
+  function PHPLexical(indented, column, type, align, prev, info) {
+    // indentation at start of this line
+    this.indented = indented;
+    // column at which this scope was opened
+    this.column = column;
+    // type of scope ('stat' (statement), 'form' (special form), '[', '{', or '(')
+    this.type = type;
+    // '[', '{', or '(' blocks that have any text after their opening
+    // character are said to be 'aligned' -- any lines below are
+    // indented all the way to the opening character.
+    if (align != null)
+      this.align = align;
+    // Parent scope, if any.
+    this.prev = prev;
+    this.info = info;
+  }
+
+  // PHP indentation rules
+  function indentPHP(lexical) {
+    return function(firstChars) {
+      var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
+      var closing = firstChar == type;
+      if (type == "form" && firstChar == "{")
+        return lexical.indented;
+      else if (type == "stat" || type == "form")
+        return lexical.indented + indentUnit;
+      else if (lexical.info == "switch" && !closing)
+        return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align)
+        return lexical.column - (closing ? 1 : 0);
+      else
+        return lexical.indented + (closing ? 0 : indentUnit);
+    };
+  }
+
+  // The parser-iterator-producing function itself.
+  function parsePHP(input, basecolumn) {
+    // Wrap the input in a token stream
+    var tokens = tokenizePHP(input);
+    // The parser state. cc is a stack of actions that have to be
+    // performed to finish the current statement. For example we might
+    // know that we still need to find a closing parenthesis and a
+    // semicolon. Actions at the end of the stack go first. It is
+    // initialized with an infinitely looping action that consumes
+    // whole statements.
+    var cc = [statements];
+    // The lexical scope, used mostly for indentation.
+    var lexical = new PHPLexical((basecolumn || 0) - indentUnit, 0, "block", false);
+    // Current column, and the indentation at the start of the current
+    // line. Used to create lexical scope objects.
+    var column = 0;
+    var indented = 0;
+    // Variables which are used by the mark, cont, and pass functions
+    // below to communicate with the driver loop in the 'next' function.
+    var consume, marked;
+
+    // The iterator object.
+    var parser = {next: next, copy: copy};
+
+    // parsing is accomplished by calling next() repeatedly
+    function next(){
+      // Start by performing any 'lexical' actions (adjusting the
+      // lexical variable), or the operations below will be working
+      // with the wrong lexical state.
+      while(cc[cc.length - 1].lex)
+        cc.pop()();
+
+      // Fetch the next token.
+      var token = tokens.next();
+
+      // Adjust column and indented.
+      if (token.type == "whitespace" && column == 0)
+        indented = token.value.length;
+      column += token.value.length;
+      if (token.content == "\n"){
+        indented = column = 0;
+        // If the lexical scope's align property is still undefined at
+        // the end of the line, it is an un-aligned scope.
+        if (!("align" in lexical))
+          lexical.align = false;
+        // Newline tokens get an indentation function associated with
+        // them.
+        token.indentation = indentPHP(lexical);
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "comment"
+        || token.type == "string_not_terminated" )
+        return token;
+      // When a meaningful token is found and the lexical scope's
+      // align is undefined, it is an aligned scope.
+      if (!("align" in lexical))
+        lexical.align = true;
+
+      // Execute actions until one 'consumes' the token and we can
+      // return it. 'marked' is used to change the style of the current token.
+      while(true) {
+        consume = marked = false;
+        // Take and execute the topmost action.
+        var action = cc.pop();
+        action(token);
+
+        if (consume){
+          if (marked)
+            token.style = marked;
+          // Here we differentiate between local and global variables.
+          return token;
+        }
+      }
+      return 1; // Firebug workaround for http://code.google.com/p/fbug/issues/detail?id=1239#c1
+    }
+
+    // This makes a copy of the parser state. It stores all the
+    // stateful variables in a closure, and returns a function that
+    // will restore them when called with a new input stream. Note
+    // that the cc array has to be copied, because it is contantly
+    // being modified. Lexical objects are not mutated, so they can
+    // be shared between runs of the parser.
+    function copy(){
+      var _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
+
+      return function copyParser(input){
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizePHP(input, _tokenState);
+        return parser;
+      };
+    }
+
+    // Helper function for pushing a number of actions onto the cc
+    // stack in reverse order.
+    function push(fs){
+      for (var i = fs.length - 1; i >= 0; i--)
+        cc.push(fs[i]);
+    }
+    // cont and pass are used by the action functions to add other
+    // actions to the stack. cont will cause the current token to be
+    // consumed, pass will leave it for the next action.
+    function cont(){
+      push(arguments);
+      consume = true;
+    }
+    function pass(){
+      push(arguments);
+      consume = false;
+    }
+    // Used to change the style of the current token.
+    function mark(style){
+      marked = style;
+    }
+    // Add a lyer of style to the current token, for example syntax-error
+    function mark_add(style){
+      marked = marked + ' ' + style;
+    }
+
+    // Push a new lexical context of the given type.
+    function pushlex(type, info) {
+      var result = function pushlexing() {
+        lexical = new PHPLexical(indented, column, type, null, lexical, info)
+      };
+      result.lex = true;
+      return result;
+    }
+    // Pop off the current lexical context.
+    function poplex(){
+      lexical = lexical.prev;
+    }
+    poplex.lex = true;
+    // The 'lex' flag on these actions is used by the 'next' function
+    // to know they can (and have to) be ran before moving on to the
+    // next token.
+
+    // Creates an action that discards tokens until it finds one of
+    // the given type. This will ignore (and recover from) syntax errors.
+    function expect(wanted){
+      return function expecting(token){
+        if (token.type == wanted) cont();  // consume the token
+        else {
+          cont(arguments.callee);  // continue expecting() - call itself
+        }
+      };
+    }
+
+    // Require a specific token type, or one of the tokens passed in the 'wanted' array
+    // Used to detect blatant syntax errors. 'execute' is used to pass extra code
+    // to be executed if the token is matched. For example, a '(' match could
+    // 'execute' a cont( compasep(funcarg), require(")") )
+    function require(wanted, execute){
+      return function requiring(token){
+        var ok;
+        var type = token.type;
+        if (typeof(wanted) == "string")
+          ok = (type == wanted) -1;
+        else
+          ok = wanted.indexOf(type);
+        if (ok >= 0) {
+          if (execute && typeof(execute[ok]) == "function")
+            execute[ok](token);
+            cont();  // just consume the token
+        }
+        else {
+          if (!marked) mark(token.style);
+          mark_add("syntax-error");
+          cont(arguments.callee);
+        }
+      };
+    }
+
+    // Looks for a statement, and then calls itself.
+    function statements(token){
+      return pass(statement, statements);
+    }
+    // Dispatches various types of statements based on the type of the current token.
+    function statement(token){
+      var type = token.type;
+      if (type == "keyword a") cont(pushlex("form"), expression, altsyntax, statement, poplex);
+      else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
+      else if (type == "{") cont(pushlex("}"), block, poplex);
+      else if (type == "function") funcdef();
+      // technically, "class implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function
+      else if (type == "class") classdef();
+      else if (type == "foreach") cont(pushlex("form"), require("("), pushlex(")"), expression, require("as"), require("variable"), /* => $value */ expect(")"), altsyntax, poplex, statement, poplex);
+      else if (type == "for") cont(pushlex("form"), require("("), pushlex(")"), expression, require(";"), expression, require(";"), expression, require(")"), altsyntax, poplex, statement, poplex);
+      // public final function foo(), protected static $bar;
+      else if (type == "modifier") cont(require(["modifier", "variable", "function", "abstract"], [null, null, funcdef, absfun]));
+      else if (type == "abstract") abs();
+      else if (type == "switch") cont(pushlex("form"), require("("), expression, require(")"), pushlex("}", "switch"), require([":", "{"]), block, poplex, poplex);
+      else if (type == "case") cont(expression, require(":"));
+      else if (type == "default") cont(require(":"));
+      else if (type == "catch") cont(pushlex("form"), require("("), require("t_string"), require("variable"), require(")"), statement, poplex);
+      else if (type == "const") cont(require("t_string"));  // 'const static x=5' is a syntax error
+      // technically, "namespace implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function
+      else if (type == "namespace") cont(namespacedef, require(";"));
+      // $variables may be followed by operators, () for variable function calls, or [] subscripts
+      else pass(pushlex("stat"), expression, require(";"), poplex);
+    }
+    // Dispatch expression types.
+    function expression(token){
+      var type = token.type;
+      if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
+      else if (type == "<<<") cont(require("string"), maybeoperator);  // heredoc/nowdoc
+      else if (type == "t_string") cont(maybe_double_colon, maybeoperator);
+      else if (type == "keyword c" || type == "operator") cont(expression);
+      // lambda
+      else if (type == "function") lambdadef();
+      // function call or parenthesized expression: $a = ($b + 1) * 2;
+      else if (type == "(") cont(pushlex(")"), commasep(expression), require(")"), poplex, maybeoperator);
+    }
+    // Called for places where operators, function calls, or subscripts are
+    // valid. Will skip on to the next action if none is found.
+    function maybeoperator(token){
+      var type = token.type;
+      if (type == "operator") {
+        if (token.content == "?") cont(expression, require(":"), expression);  // ternary operator
+        else cont(expression);
+      }
+      else if (type == "(") cont(pushlex(")"), expression, commasep(expression), require(")"), poplex, maybeoperator /* $varfunc() + 3 */);
+      else if (type == "[") cont(pushlex("]"), expression, require("]"), maybeoperator /* for multidimensional arrays, or $func[$i]() */, poplex);
+    }
+    // A regular use of the double colon to specify a class, as in self::func() or myclass::$var;
+    // Differs from `namespace` or `use` in that only one class can be the parent; chains (A::B::$var) are a syntax error.
+    function maybe_double_colon(token) {
+      if (token.type == "t_double_colon")
+        // A::$var, A::func(), A::const
+        cont(require(["t_string", "variable"]), maybeoperator);
+      else {
+        // a t_string wasn't followed by ::, such as in a function call: foo()
+        pass(expression)
+      }
+    }
+    // the declaration or definition of a function
+    function funcdef() {
+      cont(require("t_string"), require("("), pushlex(")"), commasep(funcarg), require(")"), poplex, block);
+    }
+    // the declaration or definition of a lambda
+    function lambdadef() {
+      cont(require("("), pushlex(")"), commasep(funcarg), require(")"), maybe_lambda_use, poplex, require("{"), pushlex("}"), block, poplex);
+    }
+    // optional lambda 'use' statement
+    function maybe_lambda_use(token) {
+      if(token.type == "namespace") {
+        cont(require('('), commasep(funcarg), require(')'));
+      }
+      else {
+        pass(expression);
+      }
+    }
+    // the definition of a class
+    function classdef() {
+      cont(require("t_string"), expect("{"), pushlex("}"), block, poplex);
+    }
+    // either funcdef if the current token is "function", or the keyword "function" + funcdef
+    function absfun(token) {
+      if(token.type == "function") funcdef();
+      else cont(require(["function"], [funcdef]));
+    }
+    // the abstract class or function (with optional modifier)
+    function abs(token) {
+      cont(require(["modifier", "function", "class"], [absfun, funcdef, classdef]));
+    }
+    // Parses a comma-separated list of the things that are recognized
+    // by the 'what' argument.
+    function commasep(what){
+      function proceed(token) {
+        if (token.type == ",") cont(what, proceed);
+      }
+      return function commaSeparated() {
+        pass(what, proceed);
+      };
+    }
+    // Look for statements until a closing brace is found.
+    function block(token) {
+      if (token.type == "}") cont();
+      else pass(statement, block);
+    }
+    function empty_parens_if_array(token) {
+      if(token.content == "array")
+        cont(require("("), require(")"));
+    }
+    function maybedefaultparameter(token){
+      if (token.content == "=") cont(require(["t_string", "string", "number", "atom"], [empty_parens_if_array, null, null]));
+    }
+    function var_or_reference(token) {
+      if(token.type == "variable") cont(maybedefaultparameter);
+      else if(token.content == "&") cont(require("variable"), maybedefaultparameter);
+    }
+    // support for default arguments: http://us.php.net/manual/en/functions.arguments.php#functions.arguments.default
+    function funcarg(token){
+      // function foo(myclass $obj) {...} or function foo(myclass &objref) {...}
+      if (token.type == "t_string") cont(var_or_reference);
+      // function foo($var) {...} or function foo(&$ref) {...}
+      else var_or_reference(token);
+    }
+
+    // A namespace definition or use
+    function maybe_double_colon_def(token) {
+      if (token.type == "t_double_colon")
+        cont(namespacedef);
+    }
+    function namespacedef(token) {
+      pass(require("t_string"), maybe_double_colon_def);
+    }
+    
+    function altsyntax(token){
+       if(token.content==':')
+               cont(altsyntaxBlock,poplex);
+    }
+    
+    function altsyntaxBlock(token){
+       if (token.type == "altsyntaxend") cont(require(';'));
+      else pass(statement, altsyntaxBlock);
+    }
+
+
+    return parser;
+  }
+
+  return {make: parsePHP, electricChars: "{}:"};
+
+})();
diff --git a/typo3/contrib/codemirror/contrib/php/js/parsephphtmlmixed.js b/typo3/contrib/codemirror/contrib/php/js/parsephphtmlmixed.js
new file mode 100644 (file)
index 0000000..fa189c1
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
+The copyrights embodied in the content of this file are licensed by
+Yahoo! Inc. under the BSD (revised) open source license
+
+@author Dan Vlad Dascalescu <dandv@yahoo-inc.com>
+
+Based on parsehtmlmixed.js by Marijn Haverbeke.
+*/
+
+var PHPHTMLMixedParser = Editor.Parser = (function() {
+  var processingInstructions = ["<?php"];
+
+  if (!(PHPParser && CSSParser && JSParser && XMLParser))
+    throw new Error("PHP, CSS, JS, and XML parsers must be loaded for PHP+HTML mixed mode to work.");
+  XMLParser.configure({useHTMLKludges: true});
+
+  function parseMixed(stream) {
+    var htmlParser = XMLParser.make(stream), localParser = null,
+        inTag = false, lastAtt = null, phpParserState = null;
+    var iter = {next: top, copy: copy};
+
+    function top() {
+      var token = htmlParser.next();
+      if (token.content == "<")
+        inTag = true;
+      else if (token.style == "xml-tagname" && inTag === true)
+        inTag = token.content.toLowerCase();
+      else if (token.style == "xml-attname")
+        lastAtt = token.content;
+      else if (token.type == "xml-processing") {
+        // see if this opens a PHP block
+        for (var i = 0; i < processingInstructions.length; i++)
+          if (processingInstructions[i] == token.content) {
+            iter.next = local(PHPParser, "?>");
+            break;
+          }
+      }
+      else if (token.style == "xml-attribute" && token.content == "\"php\"" && inTag == "script" && lastAtt == "language")
+        inTag = "script/php";
+      // "xml-processing" tokens are ignored, because they should be handled by a specific local parser
+      else if (token.content == ">") {
+        if (inTag == "script/php")
+          iter.next = local(PHPParser, "</script>");
+        else if (inTag == "script")
+          iter.next = local(JSParser, "</script");
+        else if (inTag == "style")
+          iter.next = local(CSSParser, "</style");
+        lastAtt = null;
+        inTag = false;
+      }
+      return token;
+    }
+    function local(parser, tag) {
+      var baseIndent = htmlParser.indentation();
+      if (parser == PHPParser && phpParserState)
+        localParser = phpParserState(stream);
+      else
+        localParser = parser.make(stream, baseIndent + indentUnit);
+
+      return function() {
+        if (stream.lookAhead(tag, false, false, true)) {
+          if (parser == PHPParser) phpParserState = localParser.copy();
+          localParser = null;
+          iter.next = top;
+          return top();  // pass the ending tag to the enclosing parser
+        }
+
+        var token = localParser.next();
+        var lt = token.value.lastIndexOf("<"), sz = Math.min(token.value.length - lt, tag.length);
+        if (lt != -1 && token.value.slice(lt, lt + sz).toLowerCase() == tag.slice(0, sz) &&
+            stream.lookAhead(tag.slice(sz), false, false, true)) {
+          stream.push(token.value.slice(lt));
+          token.value = token.value.slice(0, lt);
+        }
+
+        if (token.indentation) {
+          var oldIndent = token.indentation;
+          token.indentation = function(chars) {
+            if (chars == "</")
+              return baseIndent;
+            else
+              return oldIndent(chars);
+          }
+        }
+
+        return token;
+      };
+    }
+
+    function copy() {
+      var _html = htmlParser.copy(), _local = localParser && localParser.copy(),
+          _next = iter.next, _inTag = inTag, _lastAtt = lastAtt, _php = phpParserState;
+      return function(_stream) {
+        stream = _stream;
+        htmlParser = _html(_stream);
+        localParser = _local && _local(_stream);
+        phpParserState = _php;
+        iter.next = _next;
+        inTag = _inTag;
+        lastAtt = _lastAtt;
+        return iter;
+      };
+    }
+    return iter;
+  }
+
+  return {
+    make: parseMixed,
+    electricChars: "{}/:",
+    configure: function(conf) {
+      if (conf.opening != null) processingInstructions = conf.opening;
+    }
+  };
+
+})();
diff --git a/typo3/contrib/codemirror/contrib/php/js/tokenizephp.js b/typo3/contrib/codemirror/contrib/php/js/tokenizephp.js
new file mode 100644 (file)
index 0000000..8b14458
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+Copyright (c) 2008-2009 Yahoo! Inc.  All rights reserved.
+The copyrights embodied in the content of this file are licensed by
+Yahoo! Inc. under the BSD (revised) open source license
+
+@author Vlad Dan Dascalescu <dandv@yahoo-inc.com>
+
+
+Tokenizer for PHP code
+
+References:
+  + http://php.net/manual/en/reserved.php
+  + http://php.net/tokens
+  + get_defined_constants(), get_defined_functions(), get_declared_classes()
+      executed on a realistic (not vanilla) PHP installation with typical LAMP modules.
+      Specifically, the PHP bundled with the Uniform Web Server (www.uniformserver.com).
+
+*/
+
+
+// add the forEach method for JS engines that don't support it (e.g. IE)
+// code from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:forEach
+if (!Array.prototype.forEach)
+{
+  Array.prototype.forEach = function(fun /*, thisp*/)
+  {
+    var len = this.length;
+    if (typeof fun != "function")
+      throw new TypeError();
+
+    var thisp = arguments[1];
+    for (var i = 0; i < len; i++)
+    {
+      if (i in this)
+        fun.call(thisp, this[i], i, this);
+    }
+  };
+}
+
+
+var tokenizePHP = (function() {
+  /* A map of PHP's reserved words (keywords, predefined classes, functions and
+     constants. Each token has a type ('keyword', 'operator' etc.) and a style.
+     The style corresponds to the CSS span class in phpcolors.css.
+
+     Keywords can be of three types:
+     a - takes an expression and forms a statement - e.g. if
+     b - takes just a statement - e.g. else
+     c - takes an optinoal expression, but no statement - e.g. return
+     This distinction gives the parser enough information to parse
+     correct code correctly (we don't care that much how we parse
+     incorrect code).
+
+     Reference: http://us.php.net/manual/en/reserved.php
+  */
+  var keywords = function(){
+    function token(type, style){
+      return {type: type, style: style};
+    }
+    var result = {};
+
+    // for each(var element in ["...", "..."]) can pick up elements added to
+    // Array.prototype, so we'll use the loop structure below. See also
+    // http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for_each...in
+
+    // keywords that take an expression and form a statement
+    ["if", "elseif", "while", "declare"].forEach(function(element, index, array) {
+      result[element] = token("keyword a", "php-keyword");
+    });
+
+    // keywords that take just a statement
+    ["do", "else", "try" ].forEach(function(element, index, array) {
+      result[element] = token("keyword b", "php-keyword");
+    });
+
+    // keywords that take an optional expression, but no statement
+    ["return", "break", "continue",  // the expression is optional
+      "new", "clone", "throw"  // the expression is mandatory
+    ].forEach(function(element, index, array) {
+      result[element] = token("keyword c", "php-keyword");
+    });
+
+    ["__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__", "__METHOD__", "__NAMESPACE__"].forEach(function(element, index, array) {
+      result[element] = token("atom", "php-compile-time-constant");
+    });
+
+    ["true", "false", "null"].forEach(function(element, index, array) {
+      result[element] = token("atom", "php-atom");
+    });
+
+    ["and", "or", "xor", "instanceof"].forEach(function(element, index, array) {
+      result[element] = token("operator", "php-keyword php-operator");
+    });
+
+    ["class", "interface"].forEach(function(element, index, array) {
+      result[element] = token("class", "php-keyword");
+    });
+    ["namespace", "use", "extends", "implements"].forEach(function(element, index, array) {
+      result[element] = token("namespace", "php-keyword");
+    });
+
+    // reserved "language constructs"... http://php.net/manual/en/reserved.php
+    [ "die", "echo", "empty", "exit", "eval", "include", "include_once", "isset",
+      "list", "require", "require_once", "return", "print", "unset",
+      "array" // a keyword rather, but mandates a parenthesized parameter list
+    ].forEach(function(element, index, array) {
+      result[element] = token("t_string", "php-reserved-language-construct");
+    });
+
+    result["switch"] = token("switch", "php-keyword");
+    result["case"] = token("case", "php-keyword");
+    result["default"] = token("default", "php-keyword");
+    result["catch"] = token("catch", "php-keyword");
+    result["function"] = token("function", "php-keyword");
+
+    // http://php.net/manual/en/control-structures.alternative-syntax.php must be followed by a ':'
+    ["endif", "endwhile", "endfor", "endforeach", "endswitch", "enddeclare"].forEach(function(element, index, array) {
+      result[element] = token("altsyntaxend", "php-keyword");
+    });
+
+    result["const"] = token("const", "php-keyword");
+
+    ["final", "private", "protected", "public", "global", "static"].forEach(function(element, index, array) {
+      result[element] = token("modifier", "php-keyword");
+    });
+    result["var"] = token("modifier", "php-keyword deprecated");
+    result["abstract"] = token("abstract", "php-keyword");
+
+    result["foreach"] = token("foreach", "php-keyword");
+    result["as"] = token("as", "php-keyword");
+    result["for"] = token("for", "php-keyword");
+
+    // PHP built-in functions - output of get_defined_functions()["internal"]
+    [ "zend_version", "func_num_args", "func_get_arg", "func_get_args", "strlen",
+      "strcmp", "strncmp", "strcasecmp", "strncasecmp", "each", "error_reporting",
+      "define", "defined", "get_class", "get_parent_class", "method_exists",
+      "property_exists", "class_exists", "interface_exists", "function_exists",
+      "get_included_files", "get_required_files", "is_subclass_of", "is_a",
+      "get_class_vars", "get_object_vars", "get_class_methods", "trigger_error",
+      "user_error", "set_error_handler", "restore_error_handler",
+      "set_exception_handler", "restore_exception_handler", "get_declared_classes",
+      "get_declared_interfaces", "get_defined_functions", "get_defined_vars",
+      "create_function", "get_resource_type", "get_loaded_extensions",
+      "extension_loaded", "get_extension_funcs", "get_defined_constants",
+      "debug_backtrace", "debug_print_backtrace", "bcadd", "bcsub", "bcmul", "bcdiv",
+      "bcmod", "bcpow", "bcsqrt", "bcscale", "bccomp", "bcpowmod", "jdtogregorian",
+      "gregoriantojd", "jdtojulian", "juliantojd", "jdtojewish", "jewishtojd",
+      "jdtofrench", "frenchtojd", "jddayofweek", "jdmonthname", "easter_date",
+      "easter_days", "unixtojd", "jdtounix", "cal_to_jd", "cal_from_jd",
+      "cal_days_in_month", "cal_info", "variant_set", "variant_add", "variant_cat",
+      "variant_sub", "variant_mul", "variant_and", "variant_div", "variant_eqv",
+      "variant_idiv", "variant_imp", "variant_mod", "variant_or", "variant_pow",
+      "variant_xor", "variant_abs", "variant_fix", "variant_int", "variant_neg",
+      "variant_not", "variant_round", "variant_cmp", "variant_date_to_timestamp",
+      "variant_date_from_timestamp", "variant_get_type", "variant_set_type",
+      "variant_cast", "com_create_guid", "com_event_sink", "com_print_typeinfo",
+      "com_message_pump", "com_load_typelib", "com_get_active_object", "ctype_alnum",
+      "ctype_alpha", "ctype_cntrl", "ctype_digit", "ctype_lower", "ctype_graph",
+      "ctype_print", "ctype_punct", "ctype_space", "ctype_upper", "ctype_xdigit",
+      "strtotime", "date", "idate", "gmdate", "mktime", "gmmktime", "checkdate",
+      "strftime", "gmstrftime", "time", "localtime", "getdate", "date_create",
+      "date_parse", "date_format", "date_modify", "date_timezone_get",
+      "date_timezone_set", "date_offset_get", "date_time_set", "date_date_set",
+      "date_isodate_set", "timezone_open", "timezone_name_get",
+      "timezone_name_from_abbr", "timezone_offset_get", "timezone_transitions_get",
+      "timezone_identifiers_list", "timezone_abbreviations_list",
+      "date_default_timezone_set", "date_default_timezone_get", "date_sunrise",
+      "date_sunset", "date_sun_info", "filter_input", "filter_var",
+      "filter_input_array", "filter_var_array", "filter_list", "filter_has_var",
+      "filter_id", "ftp_connect", "ftp_login", "ftp_pwd", "ftp_cdup", "ftp_chdir",
+      "ftp_exec", "ftp_raw", "ftp_mkdir", "ftp_rmdir", "ftp_chmod", "ftp_alloc",
+      "ftp_nlist", "ftp_rawlist", "ftp_systype", "ftp_pasv", "ftp_get", "ftp_fget",
+      "ftp_put", "ftp_fput", "ftp_size", "ftp_mdtm", "ftp_rename", "ftp_delete",
+      "ftp_site", "ftp_close", "ftp_set_option", "ftp_get_option", "ftp_nb_fget",
+      "ftp_nb_get", "ftp_nb_continue", "ftp_nb_put", "ftp_nb_fput", "ftp_quit",
+      "hash", "hash_file", "hash_hmac", "hash_hmac_file", "hash_init", "hash_update",
+      "hash_update_stream", "hash_update_file", "hash_final", "hash_algos", "iconv",
+      "ob_iconv_handler", "iconv_get_encoding", "iconv_set_encoding", "iconv_strlen",
+      "iconv_substr", "iconv_strpos", "iconv_strrpos", "iconv_mime_encode",
+      "iconv_mime_decode", "iconv_mime_decode_headers", "json_encode", "json_decode",
+      "odbc_autocommit", "odbc_binmode", "odbc_close", "odbc_close_all",
+      "odbc_columns", "odbc_commit", "odbc_connect", "odbc_cursor",
+      "odbc_data_source", "odbc_execute", "odbc_error", "odbc_errormsg", "odbc_exec",
+      "odbc_fetch_array", "odbc_fetch_object", "odbc_fetch_row", "odbc_fetch_into",
+      "odbc_field_len", "odbc_field_scale", "odbc_field_name", "odbc_field_type",
+      "odbc_field_num", "odbc_free_result", "odbc_gettypeinfo", "odbc_longreadlen",
+      "odbc_next_result", "odbc_num_fields", "odbc_num_rows", "odbc_pconnect",
+      "odbc_prepare", "odbc_result", "odbc_result_all", "odbc_rollback",
+      "odbc_setoption", "odbc_specialcolumns", "odbc_statistics", "odbc_tables",
+      "odbc_primarykeys", "odbc_columnprivileges", "odbc_tableprivileges",
+      "odbc_foreignkeys", "odbc_procedures", "odbc_procedurecolumns", "odbc_do",
+      "odbc_field_precision", "preg_match", "preg_match_all", "preg_replace",
+      "preg_replace_callback", "preg_split", "preg_quote", "preg_grep",
+      "preg_last_error", "session_name", "session_module_name", "session_save_path",
+      "session_id", "session_regenerate_id", "session_decode", "session_register",
+      "session_unregister", "session_is_registered", "session_encode",
+      "session_start", "session_destroy", "session_unset",
+      "session_set_save_handler", "session_cache_limiter", "session_cache_expire",
+      "session_set_cookie_params", "session_get_cookie_params",
+      "session_write_close", "session_commit", "spl_classes", "spl_autoload",
+      "spl_autoload_extensions", "spl_autoload_register", "spl_autoload_unregister",
+      "spl_autoload_functions", "spl_autoload_call", "class_parents",
+      "class_implements", "spl_object_hash", "iterator_to_array", "iterator_count",
+      "iterator_apply", "constant", "bin2hex", "sleep", "usleep", "flush",
+      "wordwrap", "htmlspecialchars", "htmlentities", "html_entity_decode",
+      "htmlspecialchars_decode", "get_html_translation_table", "sha1", "sha1_file",
+      "md5", "md5_file", "crc32", "iptcparse", "iptcembed", "getimagesize",
+      "image_type_to_mime_type", "image_type_to_extension", "phpinfo", "phpversion",
+      "phpcredits", "php_logo_guid", "php_real_logo_guid", "php_egg_logo_guid",
+      "zend_logo_guid", "php_sapi_name", "php_uname", "php_ini_scanned_files",
+      "strnatcmp", "strnatcasecmp", "substr_count", "strspn", "strcspn", "strtok",
+      "strtoupper", "strtolower", "strpos", "stripos", "strrpos", "strripos",
+      "strrev", "hebrev", "hebrevc", "nl2br", "basename", "dirname", "pathinfo",
+      "stripslashes", "stripcslashes", "strstr", "stristr", "strrchr", "str_shuffle",
+      "str_word_count", "str_split", "strpbrk", "substr_compare", "strcoll",
+      "substr", "substr_replace", "quotemeta", "ucfirst", "ucwords", "strtr",
+      "addslashes", "addcslashes", "rtrim", "str_replace", "str_ireplace",
+      "str_repeat", "count_chars", "chunk_split", "trim", "ltrim", "strip_tags",
+      "similar_text", "explode", "implode", "setlocale", "localeconv", "soundex",
+      "levenshtein", "chr", "ord", "parse_str", "str_pad", "chop", "strchr",
+      "sprintf", "printf", "vprintf", "vsprintf", "fprintf", "vfprintf", "sscanf",
+      "fscanf", "parse_url", "urlencode", "urldecode", "rawurlencode",
+      "rawurldecode", "http_build_query", "unlink", "exec", "system",
+      "escapeshellcmd", "escapeshellarg", "passthru", "shell_exec", "proc_open",
+      "proc_close", "proc_terminate", "proc_get_status", "rand", "srand",
+      "getrandmax", "mt_rand", "mt_srand", "mt_getrandmax", "getservbyname",
+      "getservbyport", "getprotobyname", "getprotobynumber", "getmyuid", "getmygid",
+      "getmypid", "getmyinode", "getlastmod", "base64_decode", "base64_encode",
+      "convert_uuencode", "convert_uudecode", "abs", "ceil", "floor", "round", "sin",
+      "cos", "tan", "asin", "acos", "atan", "atan2", "sinh", "cosh", "tanh", "pi",
+      "is_finite", "is_nan", "is_infinite", "pow", "exp", "log", "log10", "sqrt",
+      "hypot", "deg2rad", "rad2deg", "bindec", "hexdec", "octdec", "decbin",
+      "decoct", "dechex", "base_convert", "number_format", "fmod", "ip2long",
+      "long2ip", "getenv", "putenv", "microtime", "gettimeofday", "uniqid",
+      "quoted_printable_decode", "convert_cyr_string", "get_current_user",
+      "set_time_limit", "get_cfg_var", "magic_quotes_runtime",
+      "set_magic_quotes_runtime", "get_magic_quotes_gpc", "get_magic_quotes_runtime",
+      "import_request_variables", "error_log", "error_get_last", "call_user_func",
+      "call_user_func_array", "call_user_method", "call_user_method_array",
+      "serialize", "unserialize", "var_dump", "var_export", "debug_zval_dump",
+      "print_r", "memory_get_usage", "memory_get_peak_usage",
+      "register_shutdown_function", "register_tick_function",
+      "unregister_tick_function", "highlight_file", "show_source",
+      "highlight_string", "php_strip_whitespace", "ini_get", "ini_get_all",
+      "ini_set", "ini_alter", "ini_restore", "get_include_path", "set_include_path",
+      "restore_include_path", "setcookie", "setrawcookie", "header", "headers_sent",
+      "headers_list", "connection_aborted", "connection_status", "ignore_user_abort",
+      "parse_ini_file", "is_uploaded_file", "move_uploaded_file", "gethostbyaddr",
+      "gethostbyname", "gethostbynamel", "intval", "floatval", "doubleval", "strval",
+      "gettype", "settype", "is_null", "is_resource", "is_bool", "is_long",
+      "is_float", "is_int", "is_integer", "is_double", "is_real", "is_numeric",
+      "is_string", "is_array", "is_object", "is_scalar", "is_callable", "ereg",
+      "ereg_replace", "eregi", "eregi_replace", "split", "spliti", "join",
+      "sql_regcase", "dl", "pclose", "popen", "readfile", "rewind", "rmdir", "umask",
+      "fclose", "feof", "fgetc", "fgets", "fgetss", "fread", "fopen", "fpassthru",
+      "ftruncate", "fstat", "fseek", "ftell", "fflush", "fwrite", "fputs", "mkdir",
+      "rename", "copy", "tempnam", "tmpfile", "file", "file_get_contents",
+      "file_put_contents", "stream_select", "stream_context_create",
+      "stream_context_set_params", "stream_context_set_option",
+      "stream_context_get_options", "stream_context_get_default",
+      "stream_filter_prepend", "stream_filter_append", "stream_filter_remove",
+      "stream_socket_client", "stream_socket_server", "stream_socket_accept",
+      "stream_socket_get_name", "stream_socket_recvfrom", "stream_socket_sendto",
+      "stream_socket_enable_crypto", "stream_socket_shutdown",
+      "stream_copy_to_stream", "stream_get_contents", "fgetcsv", "fputcsv", "flock",
+      "get_meta_tags", "stream_set_write_buffer", "set_file_buffer",
+      "set_socket_blocking", "stream_set_blocking", "socket_set_blocking",
+      "stream_get_meta_data", "stream_get_line", "stream_wrapper_register",
+      "stream_register_wrapper", "stream_wrapper_unregister",
+      "stream_wrapper_restore", "stream_get_wrappers", "stream_get_transports",
+      "get_headers", "stream_set_timeout", "socket_set_timeout", "socket_get_status",
+      "realpath", "fsockopen", "pfsockopen", "pack", "unpack", "get_browser",
+      "crypt", "opendir", "closedir", "chdir", "getcwd", "rewinddir", "readdir",
+      "dir", "scandir", "glob", "fileatime", "filectime", "filegroup", "fileinode",
+      "filemtime", "fileowner", "fileperms", "filesize", "filetype", "file_exists",
+      "is_writable", "is_writeable", "is_readable", "is_executable", "is_file",
+      "is_dir", "is_link", "stat", "lstat", "chown", "chgrp", "chmod", "touch",
+      "clearstatcache", "disk_total_space", "disk_free_space", "diskfreespace",
+      "mail", "ezmlm_hash", "openlog", "syslog", "closelog",
+      "define_syslog_variables", "lcg_value", "metaphone", "ob_start", "ob_flush",
+      "ob_clean", "ob_end_flush", "ob_end_clean", "ob_get_flush", "ob_get_clean",
+      "ob_get_length", "ob_get_level", "ob_get_status", "ob_get_contents",
+      "ob_implicit_flush", "ob_list_handlers", "ksort", "krsort", "natsort",
+      "natcasesort", "asort", "arsort", "sort", "rsort", "usort", "uasort", "uksort",
+      "shuffle", "array_walk", "array_walk_recursive", "count", "end", "prev",
+      "next", "reset", "current", "key", "min", "max", "in_array", "array_search",
+      "extract", "compact", "array_fill", "array_fill_keys", "range",
+      "array_multisort", "array_push", "array_pop", "array_shift", "array_unshift",
+      "array_splice", "array_slice", "array_merge", "array_merge_recursive",
+      "array_keys", "array_values", "array_count_values", "array_reverse",
+      "array_reduce", "array_pad", "array_flip", "array_change_key_case",
+      "array_rand", "array_unique", "array_intersect", "array_intersect_key",
+      "array_intersect_ukey", "array_uintersect", "array_intersect_assoc",
+      "array_uintersect_assoc", "array_intersect_uassoc", "array_uintersect_uassoc",
+      "array_diff", "array_diff_key", "array_diff_ukey", "array_udiff",
+      "array_diff_assoc", "array_udiff_assoc", "array_diff_uassoc",
+      "array_udiff_uassoc", "array_sum", "array_product", "array_filter",
+      "array_map", "array_chunk", "array_combine", "array_key_exists", "pos",
+      "sizeof", "key_exists", "assert", "assert_options", "version_compare",
+      "str_rot13", "stream_get_filters", "stream_filter_register",
+      "stream_bucket_make_writeable", "stream_bucket_prepend",
+      "stream_bucket_append", "stream_bucket_new", "output_add_rewrite_var",
+      "output_reset_rewrite_vars", "sys_get_temp_dir", "token_get_all", "token_name",
+      "readgzfile", "gzrewind", "gzclose", "gzeof", "gzgetc", "gzgets", "gzgetss",
+      "gzread", "gzopen", "gzpassthru", "gzseek", "gztell", "gzwrite", "gzputs",
+      "gzfile", "gzcompress", "gzuncompress", "gzdeflate", "gzinflate", "gzencode",
+      "ob_gzhandler", "zlib_get_coding_type", "libxml_set_streams_context",
+      "libxml_use_internal_errors", "libxml_get_last_error", "libxml_clear_errors",
+      "libxml_get_errors", "dom_import_simplexml", "simplexml_load_file",
+      "simplexml_load_string", "simplexml_import_dom", "wddx_serialize_value",
+      "wddx_serialize_vars", "wddx_packet_start", "wddx_packet_end", "wddx_add_vars",
+      "wddx_deserialize", "xml_parser_create", "xml_parser_create_ns",
+      "xml_set_object", "xml_set_element_handler", "xml_set_character_data_handler",
+      "xml_set_processing_instruction_handler", "xml_set_default_handler",
+      "xml_set_unparsed_entity_decl_handler", "xml_set_notation_decl_handler",
+      "xml_set_external_entity_ref_handler", "xml_set_start_namespace_decl_handler",
+      "xml_set_end_namespace_decl_handler", "xml_parse", "xml_parse_into_struct",
+      "xml_get_error_code", "xml_error_string", "xml_get_current_line_number",
+      "xml_get_current_column_number", "xml_get_current_byte_index",
+      "xml_parser_free", "xml_parser_set_option", "xml_parser_get_option",
+      "utf8_encode", "utf8_decode", "xmlwriter_open_uri", "xmlwriter_open_memory",
+      "xmlwriter_set_indent", "xmlwriter_set_indent_string",
+      "xmlwriter_start_comment", "xmlwriter_end_comment",
+      "xmlwriter_start_attribute", "xmlwriter_end_attribute",
+      "xmlwriter_write_attribute", "xmlwriter_start_attribute_ns",
+      "xmlwriter_write_attribute_ns", "xmlwriter_start_element",
+      "xmlwriter_end_element", "xmlwriter_full_end_element",
+      "xmlwriter_start_element_ns", "xmlwriter_write_element",
+      "xmlwriter_write_element_ns", "xmlwriter_start_pi", "xmlwriter_end_pi",
+      "xmlwriter_write_pi", "xmlwriter_start_cdata", "xmlwriter_end_cdata",
+      "xmlwriter_write_cdata", "xmlwriter_text", "xmlwriter_write_raw",
+      "xmlwriter_start_document", "xmlwriter_end_document",
+      "xmlwriter_write_comment", "xmlwriter_start_dtd", "xmlwriter_end_dtd",
+      "xmlwriter_write_dtd", "xmlwriter_start_dtd_element",
+      "xmlwriter_end_dtd_element", "xmlwriter_write_dtd_element",
+      "xmlwriter_start_dtd_attlist", "xmlwriter_end_dtd_attlist",
+      "xmlwriter_write_dtd_attlist", "xmlwriter_start_dtd_entity",
+      "xmlwriter_end_dtd_entity", "xmlwriter_write_dtd_entity",
+      "xmlwriter_output_memory", "xmlwriter_flush", "gd_info", "imagearc",
+      "imageellipse", "imagechar", "imagecharup", "imagecolorat",
+      "imagecolorallocate", "imagepalettecopy", "imagecreatefromstring",
+      "imagecolorclosest", "imagecolordeallocate", "imagecolorresolve",
+      "imagecolorexact", "imagecolorset", "imagecolortransparent",
+      "imagecolorstotal", "imagecolorsforindex", "imagecopy", "imagecopymerge",
+      "imagecopymergegray", "imagecopyresized", "imagecreate",
+      "imagecreatetruecolor", "imageistruecolor", "imagetruecolortopalette",
+      "imagesetthickness", "imagefilledarc", "imagefilledellipse",
+      "imagealphablending", "imagesavealpha", "imagecolorallocatealpha",
+      "imagecolorresolvealpha", "imagecolorclosestalpha", "imagecolorexactalpha",
+      "imagecopyresampled", "imagegrabwindow", "imagegrabscreen", "imagerotate",
+      "imageantialias", "imagesettile", "imagesetbrush", "imagesetstyle",
+      "imagecreatefrompng", "imagecreatefromgif", "imagecreatefromjpeg",
+      "imagecreatefromwbmp", "imagecreatefromxbm", "imagecreatefromgd",
+      "imagecreatefromgd2", "imagecreatefromgd2part", "imagepng", "imagegif",
+      "imagejpeg", "imagewbmp", "imagegd", "imagegd2", "imagedestroy",
+      "imagegammacorrect", "imagefill", "imagefilledpolygon", "imagefilledrectangle",
+      "imagefilltoborder", "imagefontwidth", "imagefontheight", "imageinterlace",
+      "imageline", "imageloadfont", "imagepolygon", "imagerectangle",
+      "imagesetpixel", "imagestring", "imagestringup", "imagesx", "imagesy",
+      "imagedashedline", "imagettfbbox", "imagettftext", "imageftbbox",
+      "imagefttext", "imagepsloadfont", "imagepsfreefont", "imagepsencodefont",
+      "imagepsextendfont", "imagepsslantfont", "imagepstext", "imagepsbbox",
+      "imagetypes", "jpeg2wbmp", "png2wbmp", "image2wbmp", "imagelayereffect",
+      "imagecolormatch", "imagexbm", "imagefilter", "imageconvolution",
+      "mb_convert_case", "mb_strtoupper", "mb_strtolower", "mb_language",
+      "mb_internal_encoding", "mb_http_input", "mb_http_output", "mb_detect_order",
+      "mb_substitute_character", "mb_parse_str", "mb_output_handler",
+      "mb_preferred_mime_name", "mb_strlen", "mb_strpos", "mb_strrpos", "mb_stripos",
+      "mb_strripos", "mb_strstr", "mb_strrchr", "mb_stristr", "mb_strrichr",
+      "mb_substr_count", "mb_substr", "mb_strcut", "mb_strwidth", "mb_strimwidth",
+      "mb_convert_encoding", "mb_detect_encoding", "mb_list_encodings",
+      "mb_convert_kana", "mb_encode_mimeheader", "mb_decode_mimeheader",
+      "mb_convert_variables", "mb_encode_numericentity", "mb_decode_numericentity",
+      "mb_send_mail", "mb_get_info", "mb_check_encoding", "mb_regex_encoding",
+      "mb_regex_set_options", "mb_ereg", "mb_eregi", "mb_ereg_replace",
+      "mb_eregi_replace", "mb_split", "mb_ereg_match", "mb_ereg_search",
+      "mb_ereg_search_pos", "mb_ereg_search_regs", "mb_ereg_search_init",
+      "mb_ereg_search_getregs", "mb_ereg_search_getpos", "mb_ereg_search_setpos",
+      "mbregex_encoding", "mbereg", "mberegi", "mbereg_replace", "mberegi_replace",
+      "mbsplit", "mbereg_match", "mbereg_search", "mbereg_search_pos",
+      "mbereg_search_regs", "mbereg_search_init", "mbereg_search_getregs",
+      "mbereg_search_getpos", "mbereg_search_setpos", "mysql_connect",
+      "mysql_pconnect", "mysql_close", "mysql_select_db", "mysql_query",
+      "mysql_unbuffered_query", "mysql_db_query", "mysql_list_dbs",
+      "mysql_list_tables", "mysql_list_fields", "mysql_list_processes",
+      "mysql_error", "mysql_errno", "mysql_affected_rows", "mysql_insert_id",
+      "mysql_result", "mysql_num_rows", "mysql_num_fields", "mysql_fetch_row",
+      "mysql_fetch_array", "mysql_fetch_assoc", "mysql_fetch_object",
+      "mysql_data_seek", "mysql_fetch_lengths", "mysql_fetch_field",
+      "mysql_field_seek", "mysql_free_result", "mysql_field_name",
+      "mysql_field_table", "mysql_field_len", "mysql_field_type",
+      "mysql_field_flags", "mysql_escape_string", "mysql_real_escape_string",
+      "mysql_stat", "mysql_thread_id", "mysql_client_encoding", "mysql_ping",
+      "mysql_get_client_info", "mysql_get_host_info", "mysql_get_proto_info",
+      "mysql_get_server_info", "mysql_info", "mysql_set_charset", "mysql",
+      "mysql_fieldname", "mysql_fieldtable", "mysql_fieldlen", "mysql_fieldtype",
+      "mysql_fieldflags", "mysql_selectdb", "mysql_freeresult", "mysql_numfields",
+      "mysql_numrows", "mysql_listdbs", "mysql_listtables", "mysql_listfields",
+      "mysql_db_name", "mysql_dbname", "mysql_tablename", "mysql_table_name",
+      "mysqli_affected_rows", "mysqli_autocommit", "mysqli_change_user",
+      "mysqli_character_set_name", "mysqli_close", "mysqli_commit", "mysqli_connect",
+      "mysqli_connect_errno", "mysqli_connect_error", "mysqli_data_seek",
+      "mysqli_debug", "mysqli_disable_reads_from_master", "mysqli_disable_rpl_parse",
+      "mysqli_dump_debug_info", "mysqli_enable_reads_from_master",
+      "mysqli_enable_rpl_parse", "mysqli_embedded_server_end",
+      "mysqli_embedded_server_start", "mysqli_errno", "mysqli_error",
+      "mysqli_stmt_execute", "mysqli_execute", "mysqli_fetch_field",
+      "mysqli_fetch_fields", "mysqli_fetch_field_direct", "mysqli_fetch_lengths",
+      "mysqli_fetch_array", "mysqli_fetch_assoc", "mysqli_fetch_object",
+      "mysqli_fetch_row", "mysqli_field_count", "mysqli_field_seek",
+      "mysqli_field_tell", "mysqli_free_result", "mysqli_get_charset",
+      "mysqli_get_client_info", "mysqli_get_client_version", "mysqli_get_host_info",
+      "mysqli_get_proto_info", "mysqli_get_server_info", "mysqli_get_server_version",
+      "mysqli_get_warnings", "mysqli_init", "mysqli_info", "mysqli_insert_id",
+      "mysqli_kill", "mysqli_set_local_infile_default",
+      "mysqli_set_local_infile_handler", "mysqli_master_query",
+      "mysqli_more_results", "mysqli_multi_query", "mysqli_next_result",
+      "mysqli_num_fields", "mysqli_num_rows", "mysqli_options", "mysqli_ping",
+      "mysqli_prepare", "mysqli_report", "mysqli_query", "mysqli_real_connect",
+      "mysqli_real_escape_string", "mysqli_real_query", "mysqli_rollback",
+      "mysqli_rpl_parse_enabled", "mysqli_rpl_probe", "mysqli_rpl_query_type",
+      "mysqli_select_db", "mysqli_set_charset", "mysqli_stmt_attr_get",
+      "mysqli_stmt_attr_set", "mysqli_stmt_field_count", "mysqli_stmt_init",
+      "mysqli_stmt_prepare", "mysqli_stmt_result_metadata",
+      "mysqli_stmt_send_long_data", "mysqli_stmt_bind_param",
+      "mysqli_stmt_bind_result", "mysqli_stmt_fetch", "mysqli_stmt_free_result",
+      "mysqli_stmt_get_warnings", "mysqli_stmt_insert_id", "mysqli_stmt_reset",
+      "mysqli_stmt_param_count", "mysqli_send_query", "mysqli_slave_query",
+      "mysqli_sqlstate", "mysqli_ssl_set", "mysqli_stat",
+      "mysqli_stmt_affected_rows", "mysqli_stmt_close", "mysqli_stmt_data_seek",
+      "mysqli_stmt_errno", "mysqli_stmt_error", "mysqli_stmt_num_rows",
+      "mysqli_stmt_sqlstate", "mysqli_store_result", "mysqli_stmt_store_result",
+      "mysqli_thread_id", "mysqli_thread_safe", "mysqli_use_result",
+      "mysqli_warning_count", "mysqli_bind_param", "mysqli_bind_result",
+      "mysqli_client_encoding", "mysqli_escape_string", "mysqli_fetch",
+      "mysqli_param_count", "mysqli_get_metadata", "mysqli_send_long_data",
+      "mysqli_set_opt", "pdo_drivers", "socket_select", "socket_create",
+      "socket_create_listen", "socket_accept", "socket_set_nonblock",
+      "socket_set_block", "socket_listen", "socket_close", "socket_write",
+      "socket_read", "socket_getsockname", "socket_getpeername", "socket_connect",
+      "socket_strerror", "socket_bind", "socket_recv", "socket_send",
+      "socket_recvfrom", "socket_sendto", "socket_get_option", "socket_set_option",
+      "socket_shutdown", "socket_last_error", "socket_clear_error", "socket_getopt",
+      "socket_setopt", "eaccelerator_put", "eaccelerator_get", "eaccelerator_rm",
+      "eaccelerator_gc", "eaccelerator_lock", "eaccelerator_unlock",
+      "eaccelerator_caching", "eaccelerator_optimizer", "eaccelerator_clear",
+      "eaccelerator_clean", "eaccelerator_info", "eaccelerator_purge",
+      "eaccelerator_cached_scripts", "eaccelerator_removed_scripts",
+      "eaccelerator_list_keys", "eaccelerator_encode", "eaccelerator_load",
+      "_eaccelerator_loader_file", "_eaccelerator_loader_line",
+      "eaccelerator_set_session_handlers", "_eaccelerator_output_handler",
+      "eaccelerator_cache_page", "eaccelerator_rm_page", "eaccelerator_cache_output",
+      "eaccelerator_cache_result", "xdebug_get_stack_depth",
+      "xdebug_get_function_stack", "xdebug_print_function_stack",
+      "xdebug_get_declared_vars", "xdebug_call_class", "xdebug_call_function",
+      "xdebug_call_file", "xdebug_call_line", "xdebug_var_dump", "xdebug_debug_zval",
+      "xdebug_debug_zval_stdout", "xdebug_enable", "xdebug_disable",
+      "xdebug_is_enabled", "xdebug_break", "xdebug_start_trace", "xdebug_stop_trace",
+      "xdebug_get_tracefile_name", "xdebug_get_profiler_filename",
+      "xdebug_dump_aggr_profiling_data", "xdebug_clear_aggr_profiling_data",
+      "xdebug_memory_usage", "xdebug_peak_memory_usage", "xdebug_time_index",
+      "xdebug_start_error_collection", "xdebug_stop_error_collection",
+      "xdebug_get_collected_errors", "xdebug_start_code_coverage",
+      "xdebug_stop_code_coverage", "xdebug_get_code_coverage",
+      "xdebug_get_function_count", "xdebug_dump_superglobals",
+      "_" // alias for gettext()
+    ].forEach(function(element, index, array) {
+      result[element] = token("t_string", "php-predefined-function");
+    });
+
+    // output of get_defined_constants(). Differs significantly from http://php.net/manual/en/reserved.constants.php
+    [ "E_ERROR", "E_RECOVERABLE_ERROR", "E_WARNING", "E_PARSE", "E_NOTICE",
+      "E_STRICT", "E_CORE_ERROR", "E_CORE_WARNING", "E_COMPILE_ERROR",
+      "E_COMPILE_WARNING", "E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE",
+      "E_ALL", "TRUE", "FALSE", "NULL", "ZEND_THREAD_SAFE", "PHP_VERSION", "PHP_OS",
+      "PHP_SAPI", "DEFAULT_INCLUDE_PATH", "PEAR_INSTALL_DIR", "PEAR_EXTENSION_DIR",
+      "PHP_EXTENSION_DIR", "PHP_PREFIX", "PHP_BINDIR", "PHP_LIBDIR", "PHP_DATADIR",
+      "PHP_SYSCONFDIR", "PHP_LOCALSTATEDIR", "PHP_CONFIG_FILE_PATH",
+      "PHP_CONFIG_FILE_SCAN_DIR", "PHP_SHLIB_SUFFIX", "PHP_EOL", "PHP_EOL",
+      "PHP_INT_MAX", "PHP_INT_SIZE", "PHP_OUTPUT_HANDLER_START",
+      "PHP_OUTPUT_HANDLER_CONT", "PHP_OUTPUT_HANDLER_END", "UPLOAD_ERR_OK",
+      "UPLOAD_ERR_INI_SIZE", "UPLOAD_ERR_FORM_SIZE", "UPLOAD_ERR_PARTIAL",
+      "UPLOAD_ERR_NO_FILE", "UPLOAD_ERR_NO_TMP_DIR", "UPLOAD_ERR_CANT_WRITE",
+      "UPLOAD_ERR_EXTENSION", "CAL_GREGORIAN", "CAL_JULIAN", "CAL_JEWISH",
+      "CAL_FRENCH", "CAL_NUM_CALS", "CAL_DOW_DAYNO", "CAL_DOW_SHORT", "CAL_DOW_LONG",
+      "CAL_MONTH_GREGORIAN_SHORT", "CAL_MONTH_GREGORIAN_LONG",
+      "CAL_MONTH_JULIAN_SHORT", "CAL_MONTH_JULIAN_LONG", "CAL_MONTH_JEWISH",
+      "CAL_MONTH_FRENCH", "CAL_EASTER_DEFAULT", "CAL_EASTER_ROMAN",
+      "CAL_EASTER_ALWAYS_GREGORIAN", "CAL_EASTER_ALWAYS_JULIAN",
+      "CAL_JEWISH_ADD_ALAFIM_GERESH", "CAL_JEWISH_ADD_ALAFIM",
+      "CAL_JEWISH_ADD_GERESHAYIM", "CLSCTX_INPROC_SERVER", "CLSCTX_INPROC_HANDLER",
+      "CLSCTX_LOCAL_SERVER", "CLSCTX_REMOTE_SERVER", "CLSCTX_SERVER", "CLSCTX_ALL",
+      "VT_NULL", "VT_EMPTY", "VT_UI1", "VT_I1", "VT_UI2", "VT_I2", "VT_UI4", "VT_I4",
+      "VT_R4", "VT_R8", "VT_BOOL", "VT_ERROR", "VT_CY", "VT_DATE", "VT_BSTR",
+      "VT_DECIMAL", "VT_UNKNOWN", "VT_DISPATCH", "VT_VARIANT", "VT_INT", "VT_UINT",
+      "VT_ARRAY", "VT_BYREF", "CP_ACP", "CP_MACCP", "CP_OEMCP", "CP_UTF7", "CP_UTF8",
+      "CP_SYMBOL", "CP_THREAD_ACP", "VARCMP_LT", "VARCMP_EQ", "VARCMP_GT",
+      "VARCMP_NULL", "NORM_IGNORECASE", "NORM_IGNORENONSPACE", "NORM_IGNORESYMBOLS",
+      "NORM_IGNOREWIDTH", "NORM_IGNOREKANATYPE", "DISP_E_DIVBYZERO",
+      "DISP_E_OVERFLOW", "DISP_E_BADINDEX", "MK_E_UNAVAILABLE", "INPUT_POST",
+      "INPUT_GET", "INPUT_COOKIE", "INPUT_ENV", "INPUT_SERVER", "INPUT_SESSION",
+      "INPUT_REQUEST", "FILTER_FLAG_NONE", "FILTER_REQUIRE_SCALAR",
+      "FILTER_REQUIRE_ARRAY", "FILTER_FORCE_ARRAY", "FILTER_NULL_ON_FAILURE",
+      "FILTER_VALIDATE_INT", "FILTER_VALIDATE_BOOLEAN", "FILTER_VALIDATE_FLOAT",
+      "FILTER_VALIDATE_REGEXP", "FILTER_VALIDATE_URL", "FILTER_VALIDATE_EMAIL",
+      "FILTER_VALIDATE_IP", "FILTER_DEFAULT", "FILTER_UNSAFE_RAW",
+      "FILTER_SANITIZE_STRING", "FILTER_SANITIZE_STRIPPED",
+      "FILTER_SANITIZE_ENCODED", "FILTER_SANITIZE_SPECIAL_CHARS",
+      "FILTER_SANITIZE_EMAIL", "FILTER_SANITIZE_URL", "FILTER_SANITIZE_NUMBER_INT",
+      "FILTER_SANITIZE_NUMBER_FLOAT", "FILTER_SANITIZE_MAGIC_QUOTES",
+      "FILTER_CALLBACK", "FILTER_FLAG_ALLOW_OCTAL", "FILTER_FLAG_ALLOW_HEX",
+      "FILTER_FLAG_STRIP_LOW", "FILTER_FLAG_STRIP_HIGH", "FILTER_FLAG_ENCODE_LOW",
+      "FILTER_FLAG_ENCODE_HIGH", "FILTER_FLAG_ENCODE_AMP",
+      "FILTER_FLAG_NO_ENCODE_QUOTES", "FILTER_FLAG_EMPTY_STRING_NULL",
+      "FILTER_FLAG_ALLOW_FRACTION", "FILTER_FLAG_ALLOW_THOUSAND",
+      "FILTER_FLAG_ALLOW_SCIENTIFIC", "FILTER_FLAG_SCHEME_REQUIRED",
+      "FILTER_FLAG_HOST_REQUIRED", "FILTER_FLAG_PATH_REQUIRED",
+      "FILTER_FLAG_QUERY_REQUIRED", "FILTER_FLAG_IPV4", "FILTER_FLAG_IPV6",
+      "FILTER_FLAG_NO_RES_RANGE", "FILTER_FLAG_NO_PRIV_RANGE", "FTP_ASCII",
+      "FTP_TEXT", "FTP_BINARY", "FTP_IMAGE", "FTP_AUTORESUME", "FTP_TIMEOUT_SEC",
+      "FTP_AUTOSEEK", "FTP_FAILED", "FTP_FINISHED", "FTP_MOREDATA", "HASH_HMAC",
+      "ICONV_IMPL", "ICONV_VERSION", "ICONV_MIME_DECODE_STRICT",
+      "ICONV_MIME_DECODE_CONTINUE_ON_ERROR", "ODBC_TYPE", "ODBC_BINMODE_PASSTHRU",
+      "ODBC_BINMODE_RETURN", "ODBC_BINMODE_CONVERT", "SQL_ODBC_CURSORS",
+      "SQL_CUR_USE_DRIVER", "SQL_CUR_USE_IF_NEEDED", "SQL_CUR_USE_ODBC",
+      "SQL_CONCURRENCY", "SQL_CONCUR_READ_ONLY", "SQL_CONCUR_LOCK",
+      "SQL_CONCUR_ROWVER", "SQL_CONCUR_VALUES", "SQL_CURSOR_TYPE",
+      "SQL_CURSOR_FORWARD_ONLY", "SQL_CURSOR_KEYSET_DRIVEN", "SQL_CURSOR_DYNAMIC",
+      "SQL_CURSOR_STATIC", "SQL_KEYSET_SIZE", "SQL_FETCH_FIRST", "SQL_FETCH_NEXT",
+      "SQL_CHAR", "SQL_VARCHAR", "SQL_LONGVARCHAR", "SQL_DECIMAL", "SQL_NUMERIC",
+      "SQL_BIT", "SQL_TINYINT", "SQL_SMALLINT", "SQL_INTEGER", "SQL_BIGINT",
+      "SQL_REAL", "SQL_FLOAT", "SQL_DOUBLE", "SQL_BINARY", "SQL_VARBINARY",
+      "SQL_LONGVARBINARY", "SQL_DATE", "SQL_TIME", "SQL_TIMESTAMP",
+      "PREG_PATTERN_ORDER", "PREG_SET_ORDER", "PREG_OFFSET_CAPTURE",
+      "PREG_SPLIT_NO_EMPTY", "PREG_SPLIT_DELIM_CAPTURE", "PREG_SPLIT_OFFSET_CAPTURE",
+      "PREG_GREP_INVERT", "PREG_NO_ERROR", "PREG_INTERNAL_ERROR",
+      "PREG_BACKTRACK_LIMIT_ERROR", "PREG_RECURSION_LIMIT_ERROR",
+      "PREG_BAD_UTF8_ERROR", "DATE_ATOM", "DATE_COOKIE", "DATE_ISO8601",
+      "DATE_RFC822", "DATE_RFC850", "DATE_RFC1036", "DATE_RFC1123", "DATE_RFC2822",
+      "DATE_RFC3339", "DATE_RSS", "DATE_W3C", "SUNFUNCS_RET_TIMESTAMP",
+      "SUNFUNCS_RET_STRING", "SUNFUNCS_RET_DOUBLE", "LIBXML_VERSION",
+      "LIBXML_DOTTED_VERSION", "LIBXML_NOENT", "LIBXML_DTDLOAD", "LIBXML_DTDATTR",
+      "LIBXML_DTDVALID", "LIBXML_NOERROR", "LIBXML_NOWARNING", "LIBXML_NOBLANKS",
+      "LIBXML_XINCLUDE", "LIBXML_NSCLEAN", "LIBXML_NOCDATA", "LIBXML_NONET",
+      "LIBXML_COMPACT", "LIBXML_NOXMLDECL", "LIBXML_NOEMPTYTAG", "LIBXML_ERR_NONE",
+      "LIBXML_ERR_WARNING", "LIBXML_ERR_ERROR", "LIBXML_ERR_FATAL",
+      "CONNECTION_ABORTED", "CONNECTION_NORMAL", "CONNECTION_TIMEOUT", "INI_USER",
+      "INI_PERDIR", "INI_SYSTEM", "INI_ALL", "PHP_URL_SCHEME", "PHP_URL_HOST",
+      "PHP_URL_PORT", "PHP_URL_USER", "PHP_URL_PASS", "PHP_URL_PATH",
+      "PHP_URL_QUERY", "PHP_URL_FRAGMENT", "M_E", "M_LOG2E", "M_LOG10E", "M_LN2",
+      "M_LN10", "M_PI", "M_PI_2", "M_PI_4", "M_1_PI", "M_2_PI", "M_SQRTPI",
+      "M_2_SQRTPI", "M_LNPI", "M_EULER", "M_SQRT2", "M_SQRT1_2", "M_SQRT3", "INF",
+      "NAN", "INFO_GENERAL", "INFO_CREDITS", "INFO_CONFIGURATION", "INFO_MODULES",
+      "INFO_ENVIRONMENT", "INFO_VARIABLES", "INFO_LICENSE", "INFO_ALL",
+      "CREDITS_GROUP", "CREDITS_GENERAL", "CREDITS_SAPI", "CREDITS_MODULES",
+      "CREDITS_DOCS", "CREDITS_FULLPAGE", "CREDITS_QA", "CREDITS_ALL",
+      "HTML_SPECIALCHARS", "HTML_ENTITIES", "ENT_COMPAT", "ENT_QUOTES",
+      "ENT_NOQUOTES", "STR_PAD_LEFT", "STR_PAD_RIGHT", "STR_PAD_BOTH",
+      "PATHINFO_DIRNAME", "PATHINFO_BASENAME", "PATHINFO_EXTENSION",
+      "PATHINFO_FILENAME", "CHAR_MAX", "LC_CTYPE", "LC_NUMERIC", "LC_TIME",
+      "LC_COLLATE", "LC_MONETARY", "LC_ALL", "SEEK_SET", "SEEK_CUR", "SEEK_END",
+      "LOCK_SH", "LOCK_EX", "LOCK_UN", "LOCK_NB", "STREAM_NOTIFY_CONNECT",
+      "STREAM_NOTIFY_AUTH_REQUIRED", "STREAM_NOTIFY_AUTH_RESULT",
+      "STREAM_NOTIFY_MIME_TYPE_IS", "STREAM_NOTIFY_FILE_SIZE_IS",
+      "STREAM_NOTIFY_REDIRECTED", "STREAM_NOTIFY_PROGRESS", "STREAM_NOTIFY_FAILURE",
+      "STREAM_NOTIFY_COMPLETED", "STREAM_NOTIFY_RESOLVE",
+      "STREAM_NOTIFY_SEVERITY_INFO", "STREAM_NOTIFY_SEVERITY_WARN",
+      "STREAM_NOTIFY_SEVERITY_ERR", "STREAM_FILTER_READ", "STREAM_FILTER_WRITE",
+      "STREAM_FILTER_ALL", "STREAM_CLIENT_PERSISTENT", "STREAM_CLIENT_ASYNC_CONNECT",
+      "STREAM_CLIENT_CONNECT", "STREAM_CRYPTO_METHOD_SSLv2_CLIENT",
+      "STREAM_CRYPTO_METHOD_SSLv3_CLIENT", "STREAM_CRYPTO_METHOD_SSLv23_CLIENT",
+      "STREAM_CRYPTO_METHOD_TLS_CLIENT", "STREAM_CRYPTO_METHOD_SSLv2_SERVER",
+      "STREAM_CRYPTO_METHOD_SSLv3_SERVER", "STREAM_CRYPTO_METHOD_SSLv23_SERVER",
+      "STREAM_CRYPTO_METHOD_TLS_SERVER", "STREAM_SHUT_RD", "STREAM_SHUT_WR",
+      "STREAM_SHUT_RDWR", "STREAM_PF_INET", "STREAM_PF_INET6", "STREAM_PF_UNIX",
+      "STREAM_IPPROTO_IP", "STREAM_IPPROTO_TCP", "STREAM_IPPROTO_UDP",
+      "STREAM_IPPROTO_ICMP", "STREAM_IPPROTO_RAW", "STREAM_SOCK_STREAM",
+      "STREAM_SOCK_DGRAM", "STREAM_SOCK_RAW", "STREAM_SOCK_SEQPACKET",
+      "STREAM_SOCK_RDM", "STREAM_PEEK", "STREAM_OOB", "STREAM_SERVER_BIND",
+      "STREAM_SERVER_LISTEN", "FILE_USE_INCLUDE_PATH", "FILE_IGNORE_NEW_LINES",
+      "FILE_SKIP_EMPTY_LINES", "FILE_APPEND", "FILE_NO_DEFAULT_CONTEXT",
+      "PSFS_PASS_ON", "PSFS_FEED_ME", "PSFS_ERR_FATAL", "PSFS_FLAG_NORMAL",
+      "PSFS_FLAG_FLUSH_INC", "PSFS_FLAG_FLUSH_CLOSE", "CRYPT_SALT_LENGTH",
+      "CRYPT_STD_DES", "CRYPT_EXT_DES", "CRYPT_MD5", "CRYPT_BLOWFISH",
+      "DIRECTORY_SEPARATOR", "PATH_SEPARATOR", "GLOB_BRACE", "GLOB_MARK",
+      "GLOB_NOSORT", "GLOB_NOCHECK", "GLOB_NOESCAPE", "GLOB_ERR", "GLOB_ONLYDIR",
+      "LOG_EMERG", "LOG_ALERT", "LOG_CRIT", "LOG_ERR", "LOG_WARNING", "LOG_NOTICE",
+      "LOG_INFO", "LOG_DEBUG", "LOG_KERN", "LOG_USER", "LOG_MAIL", "LOG_DAEMON",
+      "LOG_AUTH", "LOG_SYSLOG", "LOG_LPR", "LOG_NEWS", "LOG_UUCP", "LOG_CRON",
+      "LOG_AUTHPRIV", "LOG_PID", "LOG_CONS", "LOG_ODELAY", "LOG_NDELAY",
+      "LOG_NOWAIT", "LOG_PERROR", "EXTR_OVERWRITE", "EXTR_SKIP", "EXTR_PREFIX_SAME",
+      "EXTR_PREFIX_ALL", "EXTR_PREFIX_INVALID", "EXTR_PREFIX_IF_EXISTS",
+      "EXTR_IF_EXISTS", "EXTR_REFS", "SORT_ASC", "SORT_DESC", "SORT_REGULAR",
+      "SORT_NUMERIC", "SORT_STRING", "SORT_LOCALE_STRING", "CASE_LOWER",
+      "CASE_UPPER", "COUNT_NORMAL", "COUNT_RECURSIVE", "ASSERT_ACTIVE",
+      "ASSERT_CALLBACK", "ASSERT_BAIL", "ASSERT_WARNING", "ASSERT_QUIET_EVAL",
+      "STREAM_USE_PATH", "STREAM_IGNORE_URL", "STREAM_ENFORCE_SAFE_MODE",
+      "STREAM_REPORT_ERRORS", "STREAM_MUST_SEEK", "STREAM_URL_STAT_LINK",
+      "STREAM_URL_STAT_QUIET", "STREAM_MKDIR_RECURSIVE", "IMAGETYPE_GIF",
+      "IMAGETYPE_JPEG", "IMAGETYPE_PNG", "IMAGETYPE_SWF", "IMAGETYPE_PSD",
+      "IMAGETYPE_BMP", "IMAGETYPE_TIFF_II", "IMAGETYPE_TIFF_MM", "IMAGETYPE_JPC",
+      "IMAGETYPE_JP2", "IMAGETYPE_JPX", "IMAGETYPE_JB2", "IMAGETYPE_SWC",
+      "IMAGETYPE_IFF", "IMAGETYPE_WBMP", "IMAGETYPE_JPEG2000", "IMAGETYPE_XBM",
+      "T_INCLUDE", "T_INCLUDE_ONCE", "T_EVAL", "T_REQUIRE", "T_REQUIRE_ONCE",
+      "T_LOGICAL_OR", "T_LOGICAL_XOR", "T_LOGICAL_AND", "T_PRINT", "T_PLUS_EQUAL",
+      "T_MINUS_EQUAL", "T_MUL_EQUAL", "T_DIV_EQUAL", "T_CONCAT_EQUAL", "T_MOD_EQUAL",
+      "T_AND_EQUAL", "T_OR_EQUAL", "T_XOR_EQUAL", "T_SL_EQUAL", "T_SR_EQUAL",
+      "T_BOOLEAN_OR", "T_BOOLEAN_AND", "T_IS_EQUAL", "T_IS_NOT_EQUAL",
+      "T_IS_IDENTICAL", "T_IS_NOT_IDENTICAL", "T_IS_SMALLER_OR_EQUAL",
+      "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "T_INC", "T_DEC", "T_INT_CAST",
+      "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST",
+      "T_BOOL_CAST", "T_UNSET_CAST", "T_NEW", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE",
+      "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME",
+      "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_CHARACTER",
+      "T_BAD_CHARACTER", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING",
+      "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH",
+      "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_ENDSWITCH",
+      "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_FUNCTION", "T_CONST",
+      "T_RETURN", "T_USE", "T_GLOBAL", "T_STATIC", "T_VAR", "T_UNSET", "T_ISSET",
+      "T_EMPTY", "T_CLASS", "T_EXTENDS", "T_INTERFACE", "T_IMPLEMENTS",
+      "T_OBJECT_OPERATOR", "T_DOUBLE_ARROW", "T_LIST", "T_ARRAY", "T_CLASS_C",
+      "T_FUNC_C", "T_METHOD_C", "T_LINE", "T_FILE", "T_COMMENT", "T_DOC_COMMENT",
+      "T_OPEN_TAG", "T_OPEN_TAG_WITH_ECHO", "T_CLOSE_TAG", "T_WHITESPACE",
+      "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES",
+      "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_DOUBLE_COLON", "T_ABSTRACT",
+      "T_CATCH", "T_FINAL", "T_INSTANCEOF", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC",
+      "T_THROW", "T_TRY", "T_CLONE", "T_HALT_COMPILER", "FORCE_GZIP",
+      "FORCE_DEFLATE", "XML_ELEMENT_NODE", "XML_ATTRIBUTE_NODE", "XML_TEXT_NODE",
+      "XML_CDATA_SECTION_NODE", "XML_ENTITY_REF_NODE", "XML_ENTITY_NODE",
+      "XML_PI_NODE", "XML_COMMENT_NODE", "XML_DOCUMENT_NODE",
+      "XML_DOCUMENT_TYPE_NODE", "XML_DOCUMENT_FRAG_NODE", "XML_NOTATION_NODE",
+      "XML_HTML_DOCUMENT_NODE", "XML_DTD_NODE", "XML_ELEMENT_DECL_NODE",
+      "XML_ATTRIBUTE_DECL_NODE", "XML_ENTITY_DECL_NODE", "XML_NAMESPACE_DECL_NODE",
+      "XML_LOCAL_NAMESPACE", "XML_ATTRIBUTE_CDATA", "XML_ATTRIBUTE_ID",
+      "XML_ATTRIBUTE_IDREF", "XML_ATTRIBUTE_IDREFS", "XML_ATTRIBUTE_ENTITY",
+      "XML_ATTRIBUTE_NMTOKEN", "XML_ATTRIBUTE_NMTOKENS", "XML_ATTRIBUTE_ENUMERATION",
+      "XML_ATTRIBUTE_NOTATION", "DOM_PHP_ERR", "DOM_INDEX_SIZE_ERR",
+      "DOMSTRING_SIZE_ERR", "DOM_HIERARCHY_REQUEST_ERR", "DOM_WRONG_DOCUMENT_ERR",
+      "DOM_INVALID_CHARACTER_ERR", "DOM_NO_DATA_ALLOWED_ERR",
+      "DOM_NO_MODIFICATION_ALLOWED_ERR", "DOM_NOT_FOUND_ERR",
+      "DOM_NOT_SUPPORTED_ERR", "DOM_INUSE_ATTRIBUTE_ERR", "DOM_INVALID_STATE_ERR",
+      "DOM_SYNTAX_ERR", "DOM_INVALID_MODIFICATION_ERR", "DOM_NAMESPACE_ERR",
+      "DOM_INVALID_ACCESS_ERR", "DOM_VALIDATION_ERR", "XML_ERROR_NONE",
+      "XML_ERROR_NO_MEMORY", "XML_ERROR_SYNTAX", "XML_ERROR_NO_ELEMENTS",
+      "XML_ERROR_INVALID_TOKEN", "XML_ERROR_UNCLOSED_TOKEN",
+      "XML_ERROR_PARTIAL_CHAR", "XML_ERROR_TAG_MISMATCH",
+      "XML_ERROR_DUPLICATE_ATTRIBUTE", "XML_ERROR_JUNK_AFTER_DOC_ELEMENT",
+      "XML_ERROR_PARAM_ENTITY_REF", "XML_ERROR_UNDEFINED_ENTITY",
+      "XML_ERROR_RECURSIVE_ENTITY_REF", "XML_ERROR_ASYNC_ENTITY",
+      "XML_ERROR_BAD_CHAR_REF", "XML_ERROR_BINARY_ENTITY_REF",
+      "XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF", "XML_ERROR_MISPLACED_XML_PI",
+      "XML_ERROR_UNKNOWN_ENCODING", "XML_ERROR_INCORRECT_ENCODING",
+      "XML_ERROR_UNCLOSED_CDATA_SECTION", "XML_ERROR_EXTERNAL_ENTITY_HANDLING",
+      "XML_OPTION_CASE_FOLDING", "XML_OPTION_TARGET_ENCODING",
+      "XML_OPTION_SKIP_TAGSTART", "XML_OPTION_SKIP_WHITE", "XML_SAX_IMPL", "IMG_GIF",
+      "IMG_JPG", "IMG_JPEG", "IMG_PNG", "IMG_WBMP", "IMG_XPM", "IMG_COLOR_TILED",
+      "IMG_COLOR_STYLED", "IMG_COLOR_BRUSHED", "IMG_COLOR_STYLEDBRUSHED",
+      "IMG_COLOR_TRANSPARENT", "IMG_ARC_ROUNDED", "IMG_ARC_PIE", "IMG_ARC_CHORD",
+      "IMG_ARC_NOFILL", "IMG_ARC_EDGED", "IMG_GD2_RAW", "IMG_GD2_COMPRESSED",
+      "IMG_EFFECT_REPLACE", "IMG_EFFECT_ALPHABLEND", "IMG_EFFECT_NORMAL",
+      "IMG_EFFECT_OVERLAY", "GD_BUNDLED", "IMG_FILTER_NEGATE",
+      "IMG_FILTER_GRAYSCALE", "IMG_FILTER_BRIGHTNESS", "IMG_FILTER_CONTRAST",
+      "IMG_FILTER_COLORIZE", "IMG_FILTER_EDGEDETECT", "IMG_FILTER_GAUSSIAN_BLUR",
+      "IMG_FILTER_SELECTIVE_BLUR", "IMG_FILTER_EMBOSS", "IMG_FILTER_MEAN_REMOVAL",
+      "IMG_FILTER_SMOOTH", "PNG_NO_FILTER", "PNG_FILTER_NONE", "PNG_FILTER_SUB",
+      "PNG_FILTER_UP", "PNG_FILTER_AVG", "PNG_FILTER_PAETH", "PNG_ALL_FILTERS",
+      "MB_OVERLOAD_MAIL", "MB_OVERLOAD_STRING", "MB_OVERLOAD_REGEX", "MB_CASE_UPPER",
+      "MB_CASE_LOWER", "MB_CASE_TITLE", "MYSQL_ASSOC", "MYSQL_NUM", "MYSQL_BOTH",
+      "MYSQL_CLIENT_COMPRESS", "MYSQL_CLIENT_SSL", "MYSQL_CLIENT_INTERACTIVE",
+      "MYSQL_CLIENT_IGNORE_SPACE", "MYSQLI_READ_DEFAULT_GROUP",
+      "MYSQLI_READ_DEFAULT_FILE", "MYSQLI_OPT_CONNECT_TIMEOUT",
+      "MYSQLI_OPT_LOCAL_INFILE", "MYSQLI_INIT_COMMAND", "MYSQLI_CLIENT_SSL",
+      "MYSQLI_CLIENT_COMPRESS", "MYSQLI_CLIENT_INTERACTIVE",
+      "MYSQLI_CLIENT_IGNORE_SPACE", "MYSQLI_CLIENT_NO_SCHEMA",
+      "MYSQLI_CLIENT_FOUND_ROWS", "MYSQLI_STORE_RESULT", "MYSQLI_USE_RESULT",
+      "MYSQLI_ASSOC", "MYSQLI_NUM", "MYSQLI_BOTH",
+      "MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH", "MYSQLI_STMT_ATTR_CURSOR_TYPE",
+      "MYSQLI_CURSOR_TYPE_NO_CURSOR", "MYSQLI_CURSOR_TYPE_READ_ONLY",
+      "MYSQLI_CURSOR_TYPE_FOR_UPDATE", "MYSQLI_CURSOR_TYPE_SCROLLABLE",
+      "MYSQLI_STMT_ATTR_PREFETCH_ROWS", "MYSQLI_NOT_NULL_FLAG",
+      "MYSQLI_PRI_KEY_FLAG", "MYSQLI_UNIQUE_KEY_FLAG", "MYSQLI_MULTIPLE_KEY_FLAG",
+      "MYSQLI_BLOB_FLAG", "MYSQLI_UNSIGNED_FLAG", "MYSQLI_ZEROFILL_FLAG",
+      "MYSQLI_AUTO_INCREMENT_FLAG", "MYSQLI_TIMESTAMP_FLAG", "MYSQLI_SET_FLAG",
+      "MYSQLI_NUM_FLAG", "MYSQLI_PART_KEY_FLAG", "MYSQLI_GROUP_FLAG",
+      "MYSQLI_TYPE_DECIMAL", "MYSQLI_TYPE_TINY", "MYSQLI_TYPE_SHORT",
+      "MYSQLI_TYPE_LONG", "MYSQLI_TYPE_FLOAT", "MYSQLI_TYPE_DOUBLE",
+      "MYSQLI_TYPE_NULL", "MYSQLI_TYPE_TIMESTAMP", "MYSQLI_TYPE_LONGLONG",
+      "MYSQLI_TYPE_INT24", "MYSQLI_TYPE_DATE", "MYSQLI_TYPE_TIME",
+      "MYSQLI_TYPE_DATETIME", "MYSQLI_TYPE_YEAR", "MYSQLI_TYPE_NEWDATE",
+      "MYSQLI_TYPE_ENUM", "MYSQLI_TYPE_SET", "MYSQLI_TYPE_TINY_BLOB",
+      "MYSQLI_TYPE_MEDIUM_BLOB", "MYSQLI_TYPE_LONG_BLOB", "MYSQLI_TYPE_BLOB",
+      "MYSQLI_TYPE_VAR_STRING", "MYSQLI_TYPE_STRING", "MYSQLI_TYPE_CHAR",
+      "MYSQLI_TYPE_INTERVAL", "MYSQLI_TYPE_GEOMETRY", "MYSQLI_TYPE_NEWDECIMAL",
+      "MYSQLI_TYPE_BIT", "MYSQLI_RPL_MASTER", "MYSQLI_RPL_SLAVE", "MYSQLI_RPL_ADMIN",
+      "MYSQLI_NO_DATA", "MYSQLI_DATA_TRUNCATED", "MYSQLI_REPORT_INDEX",
+      "MYSQLI_REPORT_ERROR", "MYSQLI_REPORT_STRICT", "MYSQLI_REPORT_ALL",
+      "MYSQLI_REPORT_OFF", "AF_UNIX", "AF_INET", "AF_INET6", "SOCK_STREAM",
+      "SOCK_DGRAM", "SOCK_RAW", "SOCK_SEQPACKET", "SOCK_RDM", "MSG_OOB",
+      "MSG_WAITALL", "MSG_PEEK", "MSG_DONTROUTE", "SO_DEBUG", "SO_REUSEADDR",
+      "SO_KEEPALIVE", "SO_DONTROUTE", "SO_LINGER", "SO_BROADCAST", "SO_OOBINLINE",
+      "SO_SNDBUF", "SO_RCVBUF", "SO_SNDLOWAT", "SO_RCVLOWAT", "SO_SNDTIMEO",
+      "SO_RCVTIMEO", "SO_TYPE", "SO_ERROR", "SOL_SOCKET", "SOMAXCONN",
+      "PHP_NORMAL_READ", "PHP_BINARY_READ", "SOCKET_EINTR", "SOCKET_EBADF",
+      "SOCKET_EACCES", "SOCKET_EFAULT", "SOCKET_EINVAL", "SOCKET_EMFILE",
+      "SOCKET_EWOULDBLOCK", "SOCKET_EINPROGRESS", "SOCKET_EALREADY",
+      "SOCKET_ENOTSOCK", "SOCKET_EDESTADDRREQ", "SOCKET_EMSGSIZE",
+      "SOCKET_EPROTOTYPE", "SOCKET_ENOPROTOOPT", "SOCKET_EPROTONOSUPPORT",
+      "SOCKET_ESOCKTNOSUPPORT", "SOCKET_EOPNOTSUPP", "SOCKET_EPFNOSUPPORT",
+      "SOCKET_EAFNOSUPPORT", "SOCKET_EADDRINUSE", "SOCKET_EADDRNOTAVAIL",
+      "SOCKET_ENETDOWN", "SOCKET_ENETUNREACH", "SOCKET_ENETRESET",
+      "SOCKET_ECONNABORTED", "SOCKET_ECONNRESET", "SOCKET_ENOBUFS", "SOCKET_EISCONN",
+      "SOCKET_ENOTCONN", "SOCKET_ESHUTDOWN", "SOCKET_ETOOMANYREFS",
+      "SOCKET_ETIMEDOUT", "SOCKET_ECONNREFUSED", "SOCKET_ELOOP",
+      "SOCKET_ENAMETOOLONG", "SOCKET_EHOSTDOWN", "SOCKET_EHOSTUNREACH",
+      "SOCKET_ENOTEMPTY", "SOCKET_EPROCLIM", "SOCKET_EUSERS", "SOCKET_EDQUOT",
+      "SOCKET_ESTALE", "SOCKET_EREMOTE", "SOCKET_EDISCON", "SOCKET_SYSNOTREADY",
+      "SOCKET_VERNOTSUPPORTED", "SOCKET_NOTINITIALISED", "SOCKET_HOST_NOT_FOUND",
+      "SOCKET_TRY_AGAIN", "SOCKET_NO_RECOVERY", "SOCKET_NO_DATA",
+      "SOCKET_NO_ADDRESS", "SOL_TCP", "SOL_UDP", "EACCELERATOR_VERSION",
+      "EACCELERATOR_SHM_AND_DISK", "EACCELERATOR_SHM", "EACCELERATOR_SHM_ONLY",
+      "EACCELERATOR_DISK_ONLY", "EACCELERATOR_NONE", "XDEBUG_TRACE_APPEND",
+      "XDEBUG_TRACE_COMPUTERIZED", "XDEBUG_TRACE_HTML", "XDEBUG_CC_UNUSED",
+      "XDEBUG_CC_DEAD_CODE", "STDIN", "STDOUT", "STDERR"
+    ].forEach(function(element, index, array) {
+      result[element] = token("atom", "php-predefined-constant");
+    });
+
+    // PHP declared classes - output of get_declared_classes(). Differs from http://php.net/manual/en/reserved.classes.php
+    [  "stdClass", "Exception", "ErrorException", "COMPersistHelper", "com_exception",
+      "com_safearray_proxy", "variant", "com", "dotnet", "ReflectionException",
+      "Reflection", "ReflectionFunctionAbstract", "ReflectionFunction",
+      "ReflectionParameter", "ReflectionMethod", "ReflectionClass",
+      "ReflectionObject", "ReflectionProperty", "ReflectionExtension", "DateTime",
+      "DateTimeZone", "LibXMLError", "__PHP_Incomplete_Class", "php_user_filter",
+      "Directory", "SimpleXMLElement", "DOMException", "DOMStringList",
+      "DOMNameList", "DOMImplementationList", "DOMImplementationSource",
+      "DOMImplementation", "DOMNode", "DOMNameSpaceNode", "DOMDocumentFragment",
+      "DOMDocument", "DOMNodeList", "DOMNamedNodeMap", "DOMCharacterData", "DOMAttr",
+      "DOMElement", "DOMText", "DOMComment", "DOMTypeinfo", "DOMUserDataHandler",
+      "DOMDomError", "DOMErrorHandler", "DOMLocator", "DOMConfiguration",
+      "DOMCdataSection", "DOMDocumentType", "DOMNotation", "DOMEntity",
+      "DOMEntityReference", "DOMProcessingInstruction", "DOMStringExtend",
+      "DOMXPath", "RecursiveIteratorIterator", "IteratorIterator", "FilterIterator",
+      "RecursiveFilterIterator", "ParentIterator", "LimitIterator",
+      "CachingIterator", "RecursiveCachingIterator", "NoRewindIterator",
+      "AppendIterator", "InfiniteIterator", "RegexIterator",
+      "RecursiveRegexIterator", "EmptyIterator", "ArrayObject", "ArrayIterator",
+      "RecursiveArrayIterator", "SplFileInfo", "DirectoryIterator",
+      "RecursiveDirectoryIterator", "SplFileObject", "SplTempFileObject",
+      "SimpleXMLIterator", "LogicException", "BadFunctionCallException",
+      "BadMethodCallException", "DomainException", "InvalidArgumentException",
+      "LengthException", "OutOfRangeException", "RuntimeException",
+      "OutOfBoundsException", "OverflowException", "RangeException",
+      "UnderflowException", "UnexpectedValueException", "SplObjectStorage",
+      "XMLReader", "XMLWriter", "mysqli_sql_exception", "mysqli_driver", "mysqli",
+      "mysqli_warning", "mysqli_result", "mysqli_stmt", "PDOException", "PDO",
+      "PDOStatement", "PDORow"
+    ].forEach(function(element, index, array) {
+      result[element] = token("t_string", "php-predefined-class");
+    });
+
+    return result;
+
+  }();
+
+  // Helper regexps
+  var isOperatorChar = /[+*&%\/=<>!?.|-]/;
+  var isHexDigit = /[0-9A-Fa-f]/;
+  var isWordChar = /[\w\$_\\]/;
+
+  // Wrapper around phpToken that helps maintain parser state (whether
+  // we are inside of a multi-line comment)
+  function phpTokenState(inside) {
+    return function(source, setState) {
+      var newInside = inside;
+      var type = phpToken(inside, source, function(c) {newInside = c;});
+      if (newInside != inside)
+        setState(phpTokenState(newInside));
+      return type;
+    };
+  }
+
+  // The token reader, inteded to be used by the tokenizer from
+  // tokenize.js (through phpTokenState). Advances the source stream
+  // over a token, and returns an object containing the type and style
+  // of that token.
+  function phpToken(inside, source, setInside) {
+    function readHexNumber(){
+      source.next();  // skip the 'x'
+      source.nextWhileMatches(isHexDigit);
+      return {type: "number", style: "php-atom"};
+    }
+
+    function readNumber() {
+      source.nextWhileMatches(/[0-9]/);
+      if (source.equals(".")){
+        source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      if (source.equals("e") || source.equals("E")){
+        source.next();
+        if (source.equals("-"))
+          source.next();
+        source.nextWhileMatches(/[0-9]/);
+      }
+      return {type: "number", style: "php-atom"};
+    }
+    // Read a word and look it up in the keywords array. If found, it's a
+    // keyword of that type; otherwise it's a PHP T_STRING.
+    function readWord() {
+      source.nextWhileMatches(isWordChar);
+      var word = source.get();
+      var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
+      // since we called get(), tokenize::take won't get() anything. Thus, we must set token.content
+      return known ? {type: known.type, style: known.style, content: word} :
+      {type: "t_string", style: "php-t_string", content: word};
+    }
+    function readVariable() {
+      source.nextWhileMatches(isWordChar);
+      var word = source.get();
+      // in PHP, '$this' is a reserved word, but 'this' isn't. You can have function this() {...}
+      if (word == "$this")
+        return {type: "variable", style: "php-keyword", content: word};
+      else
+        return {type: "variable", style: "php-variable", content: word};
+    }
+
+    // Advance the stream until the given character (not preceded by a
+    // backslash) is encountered, or the end of the line is reached.
+    function nextUntilUnescaped(source, end) {
+      var escaped = false;
+      while(!source.endOfLine()){
+        var next = source.next();
+        if (next == end && !escaped)
+          return false;
+        escaped = next == "\\" && !escaped;
+      }
+      return escaped;
+    }
+
+    function readSingleLineComment() {
+      // read until the end of the line or until ?>, which terminates single-line comments
+      // `<?php echo 1; // comment ?> foo` will display "1 foo"
+      while(!source.lookAhead("?>") && !source.endOfLine())
+        source.next();
+      return {type: "comment", style: "php-comment"};
+    }
+    /* For multi-line comments, we want to return a comment token for
+       every line of the comment, but we also want to return the newlines
+       in them as regular newline tokens. We therefore need to save a
+       state variable ("inside") to indicate whether we are inside a
+       multi-line comment.
+    */
+
+    function readMultilineComment(start){
+      var newInside = "/*";
+      var maybeEnd = (start == "*");
+      while (true) {
+        if (source.endOfLine())
+          break;
+        var next = source.next();
+        if (next == "/" && maybeEnd){
+          newInside = null;
+          break;
+        }
+        maybeEnd = (next == "*");
+      }
+      setInside(newInside);
+      return {type: "comment", style: "php-comment"};
+    }
+
+    // similar to readMultilineComment and nextUntilUnescaped
+    // unlike comments, strings are not stopped by ?>
+    function readMultilineString(start){
+      var newInside = start;
+      var escaped = false;
+      while (true) {
+        if (source.endOfLine())
+          break;
+        var next = source.next();
+        if (next == start && !escaped){
+          newInside = null;  // we're outside of the string now
+          break;
+        }
+        escaped = (next == "\\" && !escaped);
+      }
+      setInside(newInside);
+      return {
+        type: newInside == null? "string" : "string_not_terminated",
+        style: (start == "'"? "php-string-single-quoted" : "php-string-double-quoted")
+      };
+    }
+
+    // http://php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
+    // See also 'nowdoc' on the page. Heredocs are not interrupted by the '?>' token.
+    function readHeredoc(identifier){
+      var token = {};
+      if (identifier == "<<<") {
+        // on our first invocation after reading the <<<, we must determine the closing identifier
+        if (source.equals("'")) {
+          // nowdoc
+          source.nextWhileMatches(isWordChar);
+          identifier = "'" + source.get() + "'";
+          source.next();  // consume the closing "'"
+        } else if (source.matches(/[A-Za-z_]/)) {
+          // heredoc
+          source.nextWhileMatches(isWordChar);
+          identifier = source.get();
+        } else {
+          // syntax error
+          setInside(null);
+          return { type: "error", style: "syntax-error" };
+        }
+        setInside(identifier);
+        token.type = "string_not_terminated";
+        token.style = identifier.charAt(0) == "'"? "php-string-single-quoted" : "php-string-double-quoted";
+        token.content = identifier;
+      } else {
+        token.style = identifier.charAt(0) == "'"? "php-string-single-quoted" : "php-string-double-quoted";
+        // consume a line of heredoc and check if it equals the closing identifier plus an optional semicolon
+        if (source.lookAhead(identifier, true) && (source.lookAhead(";\n") || source.endOfLine())) {
+          // the closing identifier can only appear at the beginning of the line
+          // note that even whitespace after the ";" is forbidden by the PHP heredoc syntax
+          token.type = "string";
+          token.content = source.get();  // don't get the ";" if there is one
+          setInside(null);
+        } else {
+          token.type = "string_not_terminated";
+          source.nextWhileMatches(/[^\n]/);
+          token.content = source.get();
+        }
+      }
+      return token;
+    }
+
+    function readOperator() {
+      source.nextWhileMatches(isOperatorChar);
+      return {type: "operator", style: "php-operator"};
+    }
+    function readStringSingleQuoted() {
+      var endBackSlash = nextUntilUnescaped(source, "'", false);
+      setInside(endBackSlash ? "'" : null);
+      return {type: "string", style: "php-string-single-quoted"};
+    }
+    function readStringDoubleQuoted() {
+      var endBackSlash = nextUntilUnescaped(source, "\"", false);
+      setInside(endBackSlash ? "\"": null);
+      return {type: "string", style: "php-string-double-quoted"};
+    }
+
+    // Fetch the next token. Dispatches on first character in the
+    // stream, or first two characters when the first is a slash.
+    switch (inside) {
+      case null:
+      case false: break;
+      case "'":
+      case "\"": return readMultilineString(inside);
+      case "/*": return readMultilineComment(source.next());
+      default: return readHeredoc(inside);
+    }
+    var ch = source.next();
+    if (ch == "'" || ch == "\"")
+      return readMultilineString(ch);
+    else if (ch == "#")
+      return readSingleLineComment();
+    else if (ch == "$")
+      return readVariable();
+    else if (ch == ":" && source.equals(":")) {
+      source.next();
+      // the T_DOUBLE_COLON can only follow a T_STRING (class name)
+      return {type: "t_double_colon", style: "php-operator"}
+    }
+    // with punctuation, the type of the token is the symbol itself
+    else if (/[\[\]{}\(\),;:]/.test(ch)) {
+      return {type: ch, style: "php-punctuation"};
+    }
+    else if (ch == "0" && (source.equals("x") || source.equals("X")))
+      return readHexNumber();
+    else if (/[0-9]/.test(ch))
+      return readNumber();
+    else if (ch == "/") {
+      if (source.equals("*"))
+      { source.next(); return readMultilineComment(ch); }
+      else if (source.equals("/"))
+        return readSingleLineComment();
+      else
+        return readOperator();
+    }
+    else if (ch == "<") {
+      if (source.lookAhead("<<", true)) {
+        setInside("<<<");
+        return {type: "<<<", style: "php-punctuation"};
+      }
+      else
+        return readOperator();
+    }
+    else if (isOperatorChar.test(ch))
+      return readOperator();
+    else
+      return readWord();
+  }
+
+  // The external interface to the tokenizer.
+  return function(source, startState) {
+    return tokenizer(source, startState || phpTokenState(false, true));
+  };
+})();
diff --git a/typo3/contrib/codemirror/contrib/plsql/._LICENSE b/typo3/contrib/codemirror/contrib/plsql/._LICENSE
new file mode 100644 (file)
index 0000000..30473e0
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/plsql/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/plsql/._index.html b/typo3/contrib/codemirror/contrib/plsql/._index.html
new file mode 100644 (file)
index 0000000..17793ba
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/plsql/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/plsql/LICENSE b/typo3/contrib/codemirror/contrib/plsql/LICENSE
new file mode 100644 (file)
index 0000000..b9ae48b
--- /dev/null
@@ -0,0 +1,22 @@
+ Copyright (c) 2010 Peter Raganitsch
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
+ damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
+ redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+    not claim that you wrote the original software. If you use this
+    software in a product, an acknowledgment in the product
+    documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+    not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+    distribution.
+
+ Peter Raganitsch
diff --git a/typo3/contrib/codemirror/contrib/plsql/css/._plsqlcolors.css b/typo3/contrib/codemirror/contrib/plsql/css/._plsqlcolors.css
new file mode 100644 (file)
index 0000000..8dc1ee9
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/plsql/css/._plsqlcolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/plsql/css/plsqlcolors.css b/typo3/contrib/codemirror/contrib/plsql/css/plsqlcolors.css
new file mode 100644 (file)
index 0000000..bc64c20
--- /dev/null
@@ -0,0 +1,57 @@
+html {
+  cursor: text;
+}
+
+.editbox {
+  margin: .4em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  color: black;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.plsql-keyword {
+  color: blue;
+}
+
+span.plsql-var {
+  color: red;
+}
+
+span.plsql-comment {
+  color: #AA7700;
+}
+
+span.plsql-literal {
+  color: green;
+}
+
+span.plsql-operator {
+  color: blue;
+}
+
+span.plsql-word {
+  color: black;
+}
+
+span.plsql-function {
+  color: darkorange;
+}
+
+span.plsql-type {
+  color: purple;
+}
+
+span.plsql-separator {
+  color: #666666;
+}
+
+span.plsql-number {
+  color: darkcyan;
+}
+
+
diff --git a/typo3/contrib/codemirror/contrib/plsql/index.html b/typo3/contrib/codemirror/contrib/plsql/index.html
new file mode 100644 (file)
index 0000000..28919e8
--- /dev/null
@@ -0,0 +1,67 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: PLSQL demonstration</title>
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/>
+  </head>
+  <body style="padding: 20px;">
+
+<p>Demonstration of <a href="../../index.html">CodeMirror</a>'s PLSQL
+highlighter.</p>
+
+<p>Written by Peter Raganitsch (<a href="LICENSE">license</a>), based
+on John Benediktsson <a href="../sql/index.html">SQL parser</a>.</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="50">
+PROCEDURE generateResult
+  ( pRoutineType   IN VARCHAR2
+  , pReferenceType IN VARCHAR2
+  , pReferenceId   IN NUMBER
+  )
+IS
+    ROUTINE_NAME      CONSTANT VARCHAR2(30) := 'generateResult';
+    --
+    vDisplayAs        APEXLIB_V_PAGE_ITEM.DISPLAY_AS      %TYPE;
+    vLovQuery         APEXLIB_V_PAGE_ITEM.LOV_QUERY       %TYPE;
+    vDisplayNullValue APEXLIB_V_PAGE_ITEM.LOV_DISPLAY_NULL%TYPE;
+    vLovNullText      APEXLIB_V_PAGE_ITEM.LOV_NULL_TEXT   %TYPE;
+    vLovNullValue     APEXLIB_V_PAGE_ITEM.LOV_NULL_VALUE  %TYPE;
+    vApplicationId    APEXLIB_V_PAGE_ITEM.APPLICATION_ID  %TYPE;
+    vPageId           APEXLIB_V_PAGE_ITEM.PAGE_ID         %TYPE;
+BEGIN
+    ----------------------------------------------------------------------------
+    -- Determine which routine to call and pass parameters
+    ----------------------------------------------------------------------------
+    CASE pRoutineType
+    WHEN 'LOV'
+    THEN
+        ApexLib_Lov.generateLovResult( pReferenceType, pReferenceId );
+    --
+    WHEN 'COMPUTATION'
+    THEN
+        ApexLib_Computation.generateComputationResult( pReferenceType, pReferenceId );
+    --
+    ELSE
+        Apexlib_Error.raiseImplError('Unsupported routine type "'||pRoutineType||'"!');
+    END CASE;
+    --
+EXCEPTION WHEN OTHERS THEN
+    HTP.prn('Error: '||SQLERRM);
+    -- RAISE; no raise, because APEX doesn't care anyway.
+END generateResult;
+</textarea>
+</div>
+
+<script type="text/javascript">
+  var editor = CodeMirror.fromTextArea('code', {
+    height: "450px",
+    parserfile: "../contrib/plsql/js/parseplsql.js",
+    stylesheet: "css/plsqlcolors.css",
+    path: "../../js/",
+    textWrapping: false
+  });
+</script>
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/plsql/js/._parseplsql.js b/typo3/contrib/codemirror/contrib/plsql/js/._parseplsql.js
new file mode 100644 (file)
index 0000000..8a25885
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/plsql/js/._parseplsql.js differ
diff --git a/typo3/contrib/codemirror/contrib/plsql/js/parseplsql.js b/typo3/contrib/codemirror/contrib/plsql/js/parseplsql.js
new file mode 100644 (file)
index 0000000..cc35c8c
--- /dev/null
@@ -0,0 +1,233 @@
+var PlsqlParser = Editor.Parser = (function() {
+
+  function wordRegexp(words) {
+    return new RegExp("^(?:" + words.join("|") + ")$", "i");
+  }
+
+  var functions = wordRegexp([
+"abs","acos","add_months","ascii","asin","atan","atan2","average",
+"bfilename",
+"ceil","chartorowid","chr","concat","convert","cos","cosh","count",
+"decode","deref","dual","dump","dup_val_on_index",
+"empty","error","exp",
+"false","floor","found",
+"glb","greatest",
+"hextoraw",
+"initcap","instr","instrb","isopen",
+"last_day","least","lenght","lenghtb","ln","lower","lpad","ltrim","lub",
+"make_ref","max","min","mod","months_between",
+"new_time","next_day","nextval","nls_charset_decl_len","nls_charset_id","nls_charset_name","nls_initcap","nls_lower",
+"nls_sort","nls_upper","nlssort","no_data_found","notfound","null","nvl",
+"others",
+"power",
+"rawtohex","reftohex","round","rowcount","rowidtochar","rpad","rtrim",
+"sign","sin","sinh","soundex","sqlcode","sqlerrm","sqrt","stddev","substr","substrb","sum","sysdate",
+"tan","tanh","to_char","to_date","to_label","to_multi_byte","to_number","to_single_byte","translate","true","trunc",
+"uid","upper","user","userenv",
+"variance","vsize"
+
+  ]);
+
+  var keywords = wordRegexp([
+"abort","accept","access","add","all","alter","and","any","array","arraylen","as","asc","assert","assign","at","attributes","audit",
+"authorization","avg",
+"base_table","begin","between","binary_integer","body","boolean","by",
+"case","cast","char","char_base","check","close","cluster","clusters","colauth","column","comment","commit","compress","connect",
+"connected","constant","constraint","crash","create","current","currval","cursor",
+"data_base","database","date","dba","deallocate","debugoff","debugon","decimal","declare","default","definition","delay","delete",
+"desc","digits","dispose","distinct","do","drop",
+"else","elsif","enable","end","entry","escape","exception","exception_init","exchange","exclusive","exists","exit","external",
+"fast","fetch","file","for","force","form","from","function",
+"generic","goto","grant","group",
+"having",
+"identified","if","immediate","in","increment","index","indexes","indicator","initial","initrans","insert","interface","intersect",
+"into","is",
+"key",
+"level","library","like","limited","local","lock","log","logging","long","loop",
+"master","maxextents","maxtrans","member","minextents","minus","mislabel","mode","modify","multiset",
+"new","next","no","noaudit","nocompress","nologging","noparallel","not","nowait","number_base",
+"object","of","off","offline","on","online","only","open","option","or","order","out",
+"package","parallel","partition","pctfree","pctincrease","pctused","pls_integer","positive","positiven","pragma","primary","prior",
+"private","privileges","procedure","public",
+"raise","range","raw","read","rebuild","record","ref","references","refresh","release","rename","replace","resource","restrict","return",
+"returning","reverse","revoke","rollback","row","rowid","rowlabel","rownum","rows","run",
+"savepoint","schema","segment","select","separate","session","set","share","snapshot","some","space","split","sql","start","statement",
+"storage","subtype","successful","synonym",
+"tabauth","table","tables","tablespace","task","terminate","then","to","trigger","truncate","type",
+"union","unique","unlimited","unrecoverable","unusable","update","use","using",
+"validate","value","values","variable","view","views",
+"when","whenever","where","while","with","work"
+  ]);
+
+  var types = wordRegexp([
+"bfile","blob",
+"character","clob",
+"dec",
+"float",
+"int","integer",
+"mlslabel",
+"natural","naturaln","nchar","nclob","number","numeric","nvarchar2",
+"real","rowtype",
+"signtype","smallint","string",
+"varchar","varchar2"
+  ]);
+
+  var operators = wordRegexp([
+    ":=", "<", "<=", "==", "!=", "<>", ">", ">=", "like", "rlike", "in", "xor", "between"
+  ]);
+
+  var operatorChars = /[*+\-<>=&|:\/]/;
+
+  var tokenizeSql = (function() {
+    function normal(source, setState) {
+      var ch = source.next();
+      if (ch == "@" || ch == "$") {
+        source.nextWhileMatches(/[\w\d]/);
+        return "plsql-var";
+      }
+      else if (ch == "\"" || ch == "'" || ch == "`") {
+        setState(inLiteral(ch));
+        return null;
+      }
+      else if (ch == "," || ch == ";") {
+        return "plsql-separator"
+      }
+      else if (ch == '-') {
+        if (source.peek() == "-") {
+          while (!source.endOfLine()) source.next();
+          return "plsql-comment";
+        }
+        else if (/\d/.test(source.peek())) {
+          source.nextWhileMatches(/\d/);
+          if (source.peek() == '.') {
+            source.next();
+            source.nextWhileMatches(/\d/);
+          }
+          return "plsql-number";
+        }
+        else
+          return "plsql-operator";
+      }
+      else if (operatorChars.test(ch)) {
+        source.nextWhileMatches(operatorChars);
+        return "plsql-operator";
+      }
+      else if (/\d/.test(ch)) {
+        source.nextWhileMatches(/\d/);
+        if (source.peek() == '.') {
+          source.next();
+          source.nextWhileMatches(/\d/);
+        }
+        return "plsql-number";
+      }
+      else if (/[()]/.test(ch)) {
+        return "plsql-punctuation";
+      }
+      else {
+        source.nextWhileMatches(/[_\w\d]/);
+        var word = source.get(), type;
+        if (operators.test(word))
+          type = "plsql-operator";
+        else if (keywords.test(word))
+          type = "plsql-keyword";
+        else if (functions.test(word))
+          type = "plsql-function";
+        else if (types.test(word))
+          type = "plsql-type";
+        else
+          type = "plsql-word";
+        return {style: type, content: word};
+      }
+    }
+
+    function inLiteral(quote) {
+      return function(source, setState) {
+        var escaped = false;
+        while (!source.endOfLine()) {
+          var ch = source.next();
+          if (ch == quote && !escaped) {
+            setState(normal);
+            break;
+          }
+          escaped = !escaped && ch == "\\";
+        }
+        return quote == "`" ? "plsql-word" : "plsql-literal";
+      };
+    }
+
+    return function(source, startState) {
+      return tokenizer(source, startState || normal);
+    };
+  })();
+
+  function indentSql(context) {
+    return function(nextChars) {
+      var firstChar = nextChars && nextChars.charAt(0);
+      var closing = context && firstChar == context.type;
+      if (!context)
+        return 0;
+      else if (context.align)
+        return context.col - (closing ? context.width : 0);
+      else
+        return context.indent + (closing ? 0 : indentUnit);
+    }
+  }
+
+  function parseSql(source) {
+    var tokens = tokenizeSql(source);
+    var context = null, indent = 0, col = 0;
+    function pushContext(type, width, align) {
+      context = {prev: context, indent: indent, col: col, type: type, width: width, align: align};
+    }
+    function popContext() {
+      context = context.prev;
+    }
+
+    var iter = {
+      next: function() {
+        var token = tokens.next();
+        var type = token.style, content = token.content, width = token.value.length;
+
+        if (content == "\n") {
+          token.indentation = indentSql(context);
+          indent = col = 0;
+          if (context && context.align == null) context.align = false;
+        }
+        else if (type == "whitespace" && col == 0) {
+          indent = width;
+        }
+        else if (!context && type != "plsql-comment") {
+          pushContext(";", 0, false);
+        }
+
+        if (content != "\n") col += width;
+
+        if (type == "plsql-punctuation") {
+          if (content == "(")
+            pushContext(")", width);
+          else if (content == ")")
+            popContext();
+        }
+        else if (type == "plsql-separator" && content == ";" && context && !context.prev) {
+          popContext();
+        }
+
+        return token;
+      },
+
+      copy: function() {
+        var _context = context, _indent = indent, _col = col, _tokenState = tokens.state;
+        return function(source) {
+          tokens = tokenizeSql(source, _tokenState);
+          context = _context;
+          indent = _indent;
+          col = _col;
+          return iter;
+        };
+      }
+    };
+    return iter;
+  }
+
+  return {make: parseSql, electricChars: ")"};
+})();
diff --git a/typo3/contrib/codemirror/contrib/python/._LICENSE b/typo3/contrib/codemirror/contrib/python/._LICENSE
new file mode 100644 (file)
index 0000000..f74230d
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/python/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/python/._index.html b/typo3/contrib/codemirror/contrib/python/._index.html
new file mode 100644 (file)
index 0000000..7e5844d
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/python/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/python/LICENSE b/typo3/contrib/codemirror/contrib/python/LICENSE
new file mode 100644 (file)
index 0000000..9512de2
--- /dev/null
@@ -0,0 +1,32 @@
+Copyright (c) 2009, Timothy Farrell\r
+All rights reserved.\r
+\r
+This software is provided for use in connection with the\r
+CodeMirror suite of modules and utilities, hosted and maintained\r
+at http://codemirror.net/.\r
+\r
+Redistribution and use of this software in source and binary forms,\r
+with or without modification, are permitted provided that the\r
+following conditions are met:\r
+\r
+* Redistributions of source code must retain the above\r
+  copyright notice, this list of conditions and the\r
+  following disclaimer.\r
+\r
+* Redistributions in binary form must reproduce the above\r
+  copyright notice, this list of conditions and the\r
+  following disclaimer in the documentation and/or other\r
+  materials provided with the distribution.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGE.\r
diff --git a/typo3/contrib/codemirror/contrib/python/css/._pythoncolors.css b/typo3/contrib/codemirror/contrib/python/css/._pythoncolors.css
new file mode 100644 (file)
index 0000000..62fdc8c
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/python/css/._pythoncolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/python/css/pythoncolors.css b/typo3/contrib/codemirror/contrib/python/css/pythoncolors.css
new file mode 100644 (file)
index 0000000..fb9cea4
--- /dev/null
@@ -0,0 +1,58 @@
+html {
+  cursor: text;
+}
+
+.editbox {
+  padding: .4em;
+  margin: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  line-height: 1.1em;
+  color: black;
+}
+
+pre.code, .editbox {
+  color: #666666;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.py-delimiter, span.py-special {
+  color: #666666;
+}
+
+span.py-operator {
+  color: #666666;
+}
+
+span.py-error {
+  background-color: #660000;
+  color: #FFFFFF;
+}
+
+span.py-keyword {
+  color: #770088;
+  font-weight: bold;
+}
+
+span.py-literal {
+  color: #228811;
+}
+
+span.py-identifier, span.py-func  {
+  color: black;
+}
+
+span.py-type, span.py-decorator {
+  color: #0000FF;
+}
+
+span.py-comment {
+  color: #AA7700;
+}
+
+span.py-string, span.py-bytes, span.py-raw, span.py-unicode {
+  color: #AA2222;
+}
diff --git a/typo3/contrib/codemirror/contrib/python/index.html b/typo3/contrib/codemirror/contrib/python/index.html
new file mode 100644 (file)
index 0000000..31d2f0a
--- /dev/null
@@ -0,0 +1,141 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <title>CodeMirror: Python demonstration</title>
+    <style type="text/css">
+      .CodeMirror-line-numbers {
+        width: 2.2em;
+        color: #aaa;
+        background-color: #eee;
+        text-align: right;
+        padding: .4em;
+        margin: 0;
+        font-family: monospace;
+        font-size: 10pt;
+        line-height: 1.1em;
+      }
+    </style>
+</head>
+<body style="padding: 20px;">
+<p>
+    This is a simple demonstration of the Python syntax highlighting module
+    for <a href="index.html">CodeMirror</a>.
+</p>
+<p>
+    Features of this parser include:
+</p>
+<ul>
+    <li>Token-based syntax highlighting - currently very little lexical analysis happens.  Few lexical errors will be detected.</li>
+    <li>Use the normal indentation mode to enforce regular indentation, otherwise the "shift" indentation mode will give you more flexibility.</li>
+    <li>Parser Options:
+        <ul>
+            <li>pythonVersion (Integer) - 2 or 3 to indicate which version of Python to parse.  Default = 2</li>
+            <li>strictErrors (Bool) - true to highlight errors that may not be Python errors but cause confusion for this parser. Default = true</li>
+        </ul>
+    </li>
+</ul>
+<p>Written by Timothy Farrell (<a href="LICENSE">license</a>). Special
+thanks to Adam Brand and Marijn Haverbeke for their help in debugging
+and providing for this parser.</p>
+
+<div style="border: 1px solid black; padding: 0px;">
+<textarea id="code" cols="100" rows="20" style="width:100%">
+# Literals
+1234
+0.0e101
+.123
+0b01010011100
+0o01234567
+0x0987654321abcdef
+# Error Literals
+.0b000
+0.0e
+0e
+
+# String Literals
+'For\''
+"God\""
+"""so loved
+the world"""
+'''that he gave
+his only begotten\' '''
+'that whosoever believeth \
+in him'
+''
+
+# Identifiers
+__a__
+a.b
+a.b.c
+# Error Identifiers
+a.
+
+# Operators
++ - * / % & | ^ ~ < >
+== != <= >= <> << >> // **
+and or not in is
+
+# Delimiters
+() [] {} , : ` = ; @ . # At-signs and periods require context
++= -= *= /= %= &= |= ^=
+//= >>= <<= **=
+
+# Keywords
+as assert break class continue def del elif else except
+finally for from global if import lambda pass raise
+return try while with yield
+
+# Python 2 Keywords (otherwise Identifiers)
+exec print
+
+# Python 3 Keywords (otherwise Identifiers)
+nonlocal
+
+# Types
+bool classmethod complex dict enumerate float frozenset int list object
+property reversed set slice staticmethod str super tuple type
+
+# Python 2 Types (otherwise Identifiers)
+basestring buffer file long unicode xrange
+
+# Python 3 Types (otherwise Identifiers)
+bytearray bytes filter map memoryview open range zip
+
+# Example Strict Errors
+def doesNothing():
+   pass # indentUnit is set to 4 but this line is indented 3
+
+# Some Example code
+import os
+from package import ParentClass
+
+@nonsenseDecorator
+def doesNothing():
+    pass
+
+class ExampleClass(ParentClass):
+    @staticmethod
+    def example(inputStr):
+        a = list(inputStr)
+        a.reverse()
+        return ''.join(a)
+
+    def __init__(self, mixin = 'Hello'):
+        self.mixin = mixin
+
+</textarea>
+</div>
+
+<script type="text/javascript">
+    var editor = CodeMirror.fromTextArea('code', {
+        parserfile: ["../contrib/python/js/parsepython.js"],
+        stylesheet: "css/pythoncolors.css",
+        path: "../../js/",
+        lineNumbers: true,
+        textWrapping: false,
+        indentUnit: 4,
+        parserConfig: {'pythonVersion': 2, 'strictErrors': true}
+    });
+</script>
+</body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/python/js/._parsepython.js b/typo3/contrib/codemirror/contrib/python/js/._parsepython.js
new file mode 100644 (file)
index 0000000..a21b0eb
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/python/js/._parsepython.js differ
diff --git a/typo3/contrib/codemirror/contrib/python/js/parsepython.js b/typo3/contrib/codemirror/contrib/python/js/parsepython.js
new file mode 100644 (file)
index 0000000..0bd6d5c
--- /dev/null
@@ -0,0 +1,542 @@
+var PythonParser = Editor.Parser = (function() {
+    function wordRegexp(words) {
+        return new RegExp("^(?:" + words.join("|") + ")$");
+    }
+    var DELIMITERCLASS = 'py-delimiter';
+    var LITERALCLASS = 'py-literal';
+    var ERRORCLASS = 'py-error';
+    var OPERATORCLASS = 'py-operator';
+    var IDENTIFIERCLASS = 'py-identifier';
+    var STRINGCLASS = 'py-string';
+    var BYTESCLASS = 'py-bytes';
+    var UNICODECLASS = 'py-unicode';
+    var RAWCLASS = 'py-raw';
+    var NORMALCONTEXT = 'normal';
+    var STRINGCONTEXT = 'string';
+    var singleOperators = '+-*/%&|^~<>';
+    var doubleOperators = wordRegexp(['==', '!=', '\\<=', '\\>=', '\\<\\>',
+                                      '\\<\\<', '\\>\\>', '\\/\\/', '\\*\\*']);
+    var singleDelimiters = '()[]{}@,:`=;';
+    var doubleDelimiters = ['\\+=', '\\-=', '\\*=', '/=', '%=', '&=', '\\|=',
+                            '\\^='];
+    var tripleDelimiters = wordRegexp(['//=','\\>\\>=','\\<\\<=','\\*\\*=']);
+    var singleStarters = singleOperators + singleDelimiters + '=!';
+    var doubleStarters = '=<>*/';
+    var identifierStarters = /[_A-Za-z]/;
+
+    var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
+    var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
+                          'def', 'del', 'elif', 'else', 'except', 'finally',
+                          'for', 'from', 'global', 'if', 'import',
+                          'lambda', 'pass', 'raise', 'return',
+                          'try', 'while', 'with', 'yield'];
+    var commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
+                       'float', 'frozenset', 'int', 'list', 'object',
+                       'property', 'reversed', 'set', 'slice', 'staticmethod',
+                       'str', 'super', 'tuple', 'type'];
+    var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
+                         'xrange'],
+               'keywords': ['exec', 'print'],
+               'version': 2 };
+    var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
+                         'open', 'range', 'zip'],
+               'keywords': ['nonlocal'],
+               'version': 3};
+
+    var py, keywords, types, stringStarters, stringTypes, config;
+
+    function configure(conf) {
+        if (!conf.hasOwnProperty('pythonVersion')) {
+            conf.pythonVersion = 2;
+        }
+        if (!conf.hasOwnProperty('strictErrors')) {
+            conf.strictErrors = true;
+        }
+        if (conf.pythonVersion != 2 && conf.pythonVersion != 3) {
+            alert('CodeMirror: Unknown Python Version "' +
+                  conf.pythonVersion +
+                  '", defaulting to Python 2.x.');
+            conf.pythonVersion = 2;
+        }
+        if (conf.pythonVersion == 3) {
+            py = py3;
+            stringStarters = /[\'\"rbRB]/;
+            stringTypes = /[rb]/;
+            doubleDelimiters.push('\\-\\>');
+        } else {
+            py = py2;
+            stringStarters = /[\'\"RUru]/;
+            stringTypes = /[ru]/;
+        }
+        config = conf;
+        keywords = wordRegexp(commonkeywords.concat(py.keywords));
+        types = wordRegexp(commontypes.concat(py.types));
+        doubleDelimiters = wordRegexp(doubleDelimiters);
+    }
+
+    var tokenizePython = (function() {
+        function normal(source, setState) {
+            var stringDelim, threeStr, temp, type, word, possible = {};
+            var ch = source.next();
+            
+            function filterPossible(token, styleIfPossible) {
+                if (!possible.style && !possible.content) {
+                    return token;
+                } else if (typeof(token) == STRINGCONTEXT) {
+                    token = {content: source.get(), style: token};
+                }
+                if (possible.style || styleIfPossible) {
+                    token.style = styleIfPossible ? styleIfPossible : possible.style;
+                }
+                if (possible.content) {
+                    token.content = possible.content + token.content;
+                }
+                possible = {};
+                return token;
+            }
+
+            // Handle comments
+            if (ch == '#') {
+                while (!source.endOfLine()) {
+                    source.next();
+                }
+                return 'py-comment';
+            }
+            // Handle special chars
+            if (ch == '\\') {
+                if (!source.endOfLine()) {
+                    var whitespace = true;
+                    while (!source.endOfLine()) {
+                        if(!(/[\s\u00a0]/.test(source.next()))) {
+                            whitespace = false;
+                        }
+                    }
+                    if (!whitespace) {
+                        return ERRORCLASS;
+                    }
+                }
+                return 'py-special';
+            }
+            // Handle operators and delimiters
+            if (singleStarters.indexOf(ch) != -1 || (ch == "." && !source.matches(/\d/))) {
+                if (doubleStarters.indexOf(source.peek()) != -1) {
+                    temp = ch + source.peek();
+                    // It must be a double delimiter or operator or triple delimiter
+                    if (doubleOperators.test(temp)) {
+                        source.next();
+                        var nextChar = source.peek();
+                        if (nextChar && tripleDelimiters.test(temp + nextChar)) {
+                            source.next();
+                            return DELIMITERCLASS;
+                        } else {
+                            return OPERATORCLASS;
+                        }
+                    } else if (doubleDelimiters.test(temp)) {
+                        source.next();
+                        return DELIMITERCLASS;
+                    }
+                }
+                // It must be a single delimiter or operator
+                if (singleOperators.indexOf(ch) != -1 || ch == ".") {
+                    return OPERATORCLASS;
+                } else if (singleDelimiters.indexOf(ch) != -1) {
+                    if (ch == '@' && source.matches(/\w/)) {
+                        source.nextWhileMatches(/[\w\d_]/);
+                        return {style:'py-decorator',
+                                content: source.get()};
+                    } else {
+                        return DELIMITERCLASS;
+                    }
+                } else {
+                    return ERRORCLASS;
+                }
+            }
+            // Handle number literals
+            if (/\d/.test(ch) || (ch == "." && source.matches(/\d/))) {
+                if (ch === '0' && !source.endOfLine()) {
+                    switch (source.peek()) {
+                        case 'o':
+                        case 'O':
+                            source.next();
+                            source.nextWhileMatches(/[0-7]/);
+                            return filterPossible(LITERALCLASS, ERRORCLASS);
+                        case 'x':
+                        case 'X':
+                            source.next();
+                            source.nextWhileMatches(/[0-9A-Fa-f]/);
+                            return filterPossible(LITERALCLASS, ERRORCLASS);
+                        case 'b':
+                        case 'B':
+                            source.next();
+                            source.nextWhileMatches(/[01]/);
+                            return filterPossible(LITERALCLASS, ERRORCLASS);
+                    }
+                }
+                source.nextWhileMatches(/\d/);
+                if (ch != '.' && source.peek() == '.') {
+                    source.next();
+                    source.nextWhileMatches(/\d/);
+                }
+                // Grab an exponent
+                if (source.matches(/e/i)) {
+                    source.next();
+                    if (source.peek() == '+' || source.peek() == '-') {
+                        source.next();
+                    }
+                    if (source.matches(/\d/)) {
+                        source.nextWhileMatches(/\d/);
+                    } else {
+                        return filterPossible(ERRORCLASS);
+                    }
+                }
+                // Grab a complex number
+                if (source.matches(/j/i)) {
+                    source.next();
+                }
+
+                return filterPossible(LITERALCLASS);
+            }
+            // Handle strings
+            if (stringStarters.test(ch)) {
+                var peek = source.peek();
+                var stringType = STRINGCLASS;
+                if ((stringTypes.test(ch)) && (peek == '"' || peek == "'")) {
+                    switch (ch.toLowerCase()) {
+                        case 'b':
+                            stringType = BYTESCLASS;
+                            break;
+                        case 'r':
+                            stringType = RAWCLASS;
+                            break;
+                        case 'u':
+                            stringType = UNICODECLASS;
+                            break;
+                    }
+                    ch = source.next();
+                    stringDelim = ch;
+                    if (source.peek() != stringDelim) {
+                        setState(inString(stringType, stringDelim));
+                        return null;
+                    } else {
+                        source.next();
+                        if (source.peek() == stringDelim) {
+                            source.next();
+                            threeStr = stringDelim + stringDelim + stringDelim;
+                            setState(inString(stringType, threeStr));
+                            return null;
+                        } else {
+                            return stringType;
+                        }
+                    }
+                } else if (ch == "'" || ch == '"') {
+                    stringDelim = ch;
+                    if (source.peek() != stringDelim) {
+                        setState(inString(stringType, stringDelim));
+                        return null;
+                    } else {
+                        source.next();
+                        if (source.peek() == stringDelim) {
+                            source.next();
+                            threeStr = stringDelim + stringDelim + stringDelim;
+                            setState(inString(stringType, threeStr));
+                            return null;
+                        } else {
+                            return stringType;
+                        }
+                    }
+                }
+            }
+            // Handle Identifier
+            if (identifierStarters.test(ch)) {
+                source.nextWhileMatches(/[\w\d_]/);
+                word = source.get();
+                if (wordOperators.test(word)) {
+                    type = OPERATORCLASS;
+                } else if (keywords.test(word)) {
+                    type = 'py-keyword';
+                } else if (types.test(word)) {
+                    type = 'py-type';
+                } else {
+                    type = IDENTIFIERCLASS;
+                    while (source.peek() == '.') {
+                        source.next();
+                        if (source.matches(identifierStarters)) {
+                            source.nextWhileMatches(/[\w\d]/);
+                        } else {
+                            type = ERRORCLASS;
+                            break;
+                        }
+                    }
+                    word = word + source.get();
+                }
+                return filterPossible({style: type, content: word});
+            }
+
+            // Register Dollar sign and Question mark as errors. Always!
+            if (/\$\?/.test(ch)) {
+                return filterPossible(ERRORCLASS);
+            }
+
+            return filterPossible(ERRORCLASS);
+        }
+
+        function inString(style, terminator) {
+            return function(source, setState) {
+                var matches = [];
+                var found = false;
+                while (!found && !source.endOfLine()) {
+                    var ch = source.next(), newMatches = [];
+                    // Skip escaped characters
+                    if (ch == '\\') {
+                        if (source.peek() == '\n') {
+                            break;
+                        }
+                        ch = source.next();
+                        ch = source.next();
+                    }
+                    if (ch == terminator.charAt(0)) {
+                        matches.push(terminator);
+                    }
+                    for (var i = 0; i < matches.length; i++) {
+                        var match = matches[i];
+                        if (match.charAt(0) == ch) {
+                            if (match.length == 1) {
+                                setState(normal);
+                                found = true;
+                                break;
+                            } else {
+                                newMatches.push(match.slice(1));
+                            }
+                        }
+                    }
+                    matches = newMatches;
+                }
+                return style;
+            };
+        }
+
+        return function(source, startState) {
+            return tokenizer(source, startState || normal);
+        };
+    })();
+
+    function parsePython(source, basecolumn) {
+        if (!keywords) {
+            configure({});
+        }
+        basecolumn = basecolumn || 0;
+
+        var tokens = tokenizePython(source);
+        var lastToken = null;
+        var column = basecolumn;
+        var context = {prev: null,
+                       endOfScope: false,
+                       startNewScope: false,
+                       level: basecolumn,
+                       next: null,
+                       type: NORMALCONTEXT
+                       };
+
+        function pushContext(level, type) {
+            type = type ? type : NORMALCONTEXT;
+            context = {prev: context,
+                       endOfScope: false,
+                       startNewScope: false,
+                       level: level,
+                       next: null,
+                       type: type
+                       };
+        }
+
+        function popContext(remove) {
+            remove = remove ? remove : false;
+            if (context.prev) {
+                if (remove) {
+                    context = context.prev;
+                    context.next = null;
+                } else {
+                    context.prev.next = context;
+                    context = context.prev;
+                }
+            }
+        }
+
+        function indentPython(context) {
+            var temp;
+            return function(nextChars, currentLevel, direction) {
+                if (direction === null || direction === undefined) {
+                    if (nextChars) {
+                        while (context.next) {
+                            context = context.next;
+                        }
+                    }
+                    return context.level;
+                }
+                else if (direction === true) {
+                    if (currentLevel == context.level) {
+                        if (context.next) {
+                            return context.next.level;
+                        } else {
+                            return context.level;
+                        }
+                    } else {
+                        temp = context;
+                        while (temp.prev && temp.prev.level > currentLevel) {
+                            temp = temp.prev;
+                        }
+                        return temp.level;
+                    }
+                } else if (direction === false) {
+                    if (currentLevel > context.level) {
+                        return context.level;
+                    } else if (context.prev) {
+                        temp = context;
+                        while (temp.prev && temp.prev.level >= currentLevel) {
+                            temp = temp.prev;
+                        }
+                        if (temp.prev) {
+                            return temp.prev.level;
+                        } else {
+                            return temp.level;
+                        }
+                    }
+                }
+                return context.level;
+            };
+        }
+
+        var iter = {
+            next: function() {
+                var token = tokens.next();
+                var type = token.style;
+                var content = token.content;
+
+                if (lastToken) {
+                    if (lastToken.content == 'def' && type == IDENTIFIERCLASS) {
+                        token.style = 'py-func';
+                    }
+                    if (lastToken.content == '\n') {
+                        var tempCtx = context;
+                        // Check for a different scope
+                        if (type == 'whitespace' && context.type == NORMALCONTEXT) {
+                            if (token.value.length < context.level) {
+                                while (token.value.length < context.level) {
+                                    popContext();
+                                }
+
+                                if (token.value.length != context.level) {
+                                    context = tempCtx;
+                                    if (config.strictErrors) {
+                                        token.style = ERRORCLASS;
+                                    }
+                                } else {
+                                    context.next = null;
+                                }
+                            }
+                        } else if (context.level !== basecolumn &&
+                                   context.type == NORMALCONTEXT) {
+                            while (basecolumn !== context.level) {
+                                popContext();
+                            }
+
+                            if (context.level !== basecolumn) {
+                                context = tempCtx;
+                                if (config.strictErrors) {
+                                    token.style = ERRORCLASS;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // Handle Scope Changes
+                switch(type) {
+                    case STRINGCLASS:
+                    case BYTESCLASS:
+                    case RAWCLASS:
+                    case UNICODECLASS:
+                        if (context.type !== STRINGCONTEXT) {
+                            pushContext(context.level + 1, STRINGCONTEXT);
+                        }
+                        break;
+                    default:
+                        if (context.type === STRINGCONTEXT) {
+                            popContext(true);
+                        }
+                        break;
+                }
+                switch(content) {
+                    case '.':
+                    case '@':
+                        // These delimiters don't appear by themselves
+                        if (content !== token.value) {
+                            token.style = ERRORCLASS;
+                        }
+                        break;
+                    case ':':
+                        // Colons only delimit scope inside a normal scope
+                        if (context.type === NORMALCONTEXT) {
+                            context.startNewScope = context.level+indentUnit;
+                        }
+                        break;
+                    case '(':
+                    case '[':
+                    case '{':
+                        // These start a sequence scope
+                        pushContext(column + content.length, 'sequence');
+                        break;
+                    case ')':
+                    case ']':
+                    case '}':
+                        // These end a sequence scope
+                        popContext(true);
+                        break;
+                    case 'pass':
+                    case 'return':
+                        // These end a normal scope
+                        if (context.type === NORMALCONTEXT) {
+                            context.endOfScope = true;
+                        }
+                        break;
+                    case '\n':
+                        // Reset our column
+                        column = basecolumn;
+                        // Make any scope changes
+                        if (context.endOfScope) {
+                            context.endOfScope = false;
+                            popContext();
+                        } else if (context.startNewScope !== false) {
+                            var temp = context.startNewScope;
+                            context.startNewScope = false;
+                            pushContext(temp, NORMALCONTEXT);
+                        }
+                        // Newlines require an indentation function wrapped in a closure for proper context.
+                        token.indentation = indentPython(context);
+                        break;
+                }
+
+                // Keep track of current column for certain scopes.
+                if (content != '\n') {
+                    column += token.value.length;
+                }
+
+                lastToken = token;
+                return token;
+            },
+
+            copy: function() {
+                var _context = context, _tokenState = tokens.state;
+                return function(source) {
+                    tokens = tokenizePython(source, _tokenState);
+                    context = _context;
+                    return iter;
+                };
+            }
+        };
+        return iter;
+    }
+
+    return {make: parsePython,
+            electricChars: "",
+            configure: configure};
+})();
diff --git a/typo3/contrib/codemirror/contrib/scheme/._LICENSE b/typo3/contrib/codemirror/contrib/scheme/._LICENSE
new file mode 100644 (file)
index 0000000..14db923
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/scheme/._LICENSE differ
diff --git a/typo3/contrib/codemirror/contrib/scheme/._index.html b/typo3/contrib/codemirror/contrib/scheme/._index.html
new file mode 100644 (file)
index 0000000..b4ab44e
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/scheme/._index.html differ
diff --git a/typo3/contrib/codemirror/contrib/scheme/LICENSE b/typo3/contrib/codemirror/contrib/scheme/LICENSE
new file mode 100644 (file)
index 0000000..9f8a9f3
--- /dev/null
@@ -0,0 +1,23 @@
+ Copyright (c) 2010 Danny Yoo
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any
+ damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any
+ purpose, including commercial applications, and to alter it and
+ redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+    not claim that you wrote the original software. If you use this
+    software in a product, an acknowledgment in the product
+    documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+    not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+    distribution.
+
+ Danny Yoo
+ dyoo@cs.wpi.edu
diff --git a/typo3/contrib/codemirror/contrib/scheme/css/._schemecolors.css b/typo3/contrib/codemirror/contrib/scheme/css/._schemecolors.css
new file mode 100644 (file)
index 0000000..0b046fa
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/scheme/css/._schemecolors.css differ
diff --git a/typo3/contrib/codemirror/contrib/scheme/css/schemecolors.css b/typo3/contrib/codemirror/contrib/scheme/css/schemecolors.css
new file mode 100644 (file)
index 0000000..7283510
--- /dev/null
@@ -0,0 +1,45 @@
+html {
+  cursor: text;
+  width: 100%;
+  height: 100%;
+  background-color: white;
+}
+
+.editbox {
+  width: 100%;
+  height: 100%;
+  margin: 0pt;
+  padding: 0;
+  font-family: monospace;
+  font-size: 10pt;
+  color: black;
+}
+
+
+
+pre.code, .editbox {
+  color: #666666;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+span.scheme-string     {color: green;}
+span.scheme-number     {color: blue;}
+span.scheme-boolean     {color: darkred;}
+span.scheme-character  {color: orange;}
+span.scheme-symbol     {color: steelblue;}
+span.scheme-punctuation {color: black;}
+span.scheme-lparen      {color: black;}
+span.scheme-rparen      {color: black;}
+span.scheme-comment     { color: orange; }
+
+span.good-matching-paren { 
+    font-weight: bold;
+    color: #3399FF;  
+}
+span.bad-matching-paren {
+    font-weight: bold;
+    color: red;
+}
diff --git a/typo3/contrib/codemirror/contrib/scheme/index.html b/typo3/contrib/codemirror/contrib/scheme/index.html
new file mode 100644 (file)
index 0000000..ae00974
--- /dev/null
@@ -0,0 +1,81 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="../../js/codemirror.js" type="text/javascript"></script>
+    <script src="../../js/mirrorframe.js" type="text/javascript"></script>
+    <title>CodeMirror: Scheme demonstration</title>
+    <link rel="stylesheet" type="text/css" href="../../css/docs.css"/>
+
+    <style type="text/css">
+      .CodeMirror-line-numbers {
+        width: 2.2em;
+        color: #aaa;
+        background-color: #eee;
+        text-align: right;
+        padding-right: .3em;
+        font-size: 10pt;
+        font-family: monospace;
+        padding-top: .4em;
+      }
+    </style>
+  </head>
+  <body style="padding: 20px;">
+
+<p>This page demonstrates <a href="index.html">CodeMirror</a>'s
+Scheme parser. (<a href="LICENSE">license</a>)</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="30">
+(define (factorial x)
+  (cond
+    [(= x 0)
+     1]
+    [else
+     (* x (factorial (sub1 x)))]))
+
+(list "This is a string"
+      'boolean
+      true
+      3.14)
+
+(local [(define x 42)]
+  (printf "ok~n"))
+</textarea>
+</div>
+
+<script type="text/javascript">
+  function addClass(element, className) {
+    if (!editor.win.hasClass(element, className)) {
+      element.className = ((element.className.split(" ")).concat([className])).join(" ");
+    }
+  }
+
+  function removeClass(element, className) {
+    if (editor.win.hasClass(element, className)) {
+      var classes = element.className.split(" ");
+      for (var i = classes.length - 1 ; i >= 0; i--) {
+        if (classes[i] === className) {
+            classes.splice(i, 1);
+        }
+      }
+      element.className = classes.join(" ");
+    }
+  }
+
+  var textarea = document.getElementById('code');
+  var editor = new CodeMirror(CodeMirror.replace(textarea), {
+    height: "350px",
+    content: textarea.value,
+    path: "../../js/",
+    parserfile: ["../contrib/scheme/js/tokenizescheme.js",
+                 "../contrib/scheme/js/parsescheme.js"],
+    stylesheet:  "css/schemecolors.css",
+    autoMatchParens: true,
+    disableSpellcheck: true,
+    lineNumbers: true,
+    markParen: function(span, good) {addClass(span, good ? "good-matching-paren" : "bad-matching-paren");},
+    unmarkParen: function(span) {removeClass(span, "good-matching-paren"); removeClass(span, "bad-matching-paren");}
+  });
+</script>
+
+  </body>
+</html>
diff --git a/typo3/contrib/codemirror/contrib/scheme/js/._parsescheme.js b/typo3/contrib/codemirror/contrib/scheme/js/._parsescheme.js
new file mode 100644 (file)
index 0000000..a9e7793
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/scheme/js/._parsescheme.js differ
diff --git a/typo3/contrib/codemirror/contrib/scheme/js/._tokenizescheme.js b/typo3/contrib/codemirror/contrib/scheme/js/._tokenizescheme.js
new file mode 100644 (file)
index 0000000..4452413
Binary files /dev/null and b/typo3/contrib/codemirror/contrib/scheme/js/._tokenizescheme.js differ
diff --git a/typo3/contrib/codemirror/contrib/scheme/js/parsescheme.js b/typo3/contrib/codemirror/contrib/scheme/js/parsescheme.js
new file mode 100644 (file)
index 0000000..6b1ffba
--- /dev/null
@@ -0,0 +1,428 @@
+var SchemeParser = Editor.Parser = (function() {
+
+
+    // isLparen: char -> boolean
+    var isLparen = function(ch) {
+       return ch === '(' || ch === '[' || ch === '{';
+    };
+
+    // isRparen: char -> boolean
+    var isRparen = function(ch) {
+       return ch === ')' || ch === ']' || ch === '}';
+    };
+
+    // isMatchingParens: char char -> boolean
+    var isMatchingParens = function(lparen, rparen) {
+       return ((lparen === '(' && rparen === ')') ||
+               (lparen === '[' && rparen === ']') ||
+               (lparen === '{' && rparen === '}'));
+    };
+
+
+    // Compute the indentation context enclosing the end of the token
+    // sequence tokens.
+    // The context is the token sequence of the enclosing s-expression,
+    // augmented with column information.
+    var getIndentationContext = function(tokenStack) {
+       var EMPTY_CONTEXT = [];
+
+       var pendingParens = [], i = 0, j, line, column, context;
+       var tokens = [];
+
+       // Scan for the start of the indentation context, accumulating tokens.
+       while (! isEmptyPair(tokenStack)) {
+           i++;
+           tokens.push(pairFirst(tokenStack));
+           if (isLparen(pairFirst(tokenStack).type)) {
+               if (pendingParens.length === 0) {
+                   break;
+               } else {
+                   if (isMatchingParens(pairFirst(tokenStack).value,
+                                        pendingParens[pendingParens.length - 1])) {
+                       pendingParens.pop();
+                   } else {
+                       // Error condition: we see mismatching parens,
+                       // so we exit with no known indentation context.
+                       return EMPTY_CONTEXT;
+                   }
+               }
+           } else if (isRparen(pairFirst(tokenStack).type))  {
+               pendingParens.push(pairFirst(tokenStack).type);
+           }
+           tokenStack = pairRest(tokenStack);
+       }
+
+       // If we scanned backward too far, we couldn't find a context.  Just
+       // return the empty context.
+       if (isEmptyPair(tokenStack)) { 
+           return EMPTY_CONTEXT; 
+       }
+
+       // Position tokenStack to the next token beyond.
+       tokenStack = pairRest(tokenStack);
+
+       // We now scan backwards to closest newline to figure out the column
+       // number:
+       while (! isEmptyPair(tokenStack)) {
+           if(pairFirst(tokenStack).type === 'whitespace' && 
+              pairFirst(tokenStack).value === '\n') {
+               break;
+           }
+           tokens.push(pairFirst(tokenStack));
+           tokenStack = pairRest(tokenStack);
+       }
+
+       line = 0;
+       column = 0;
+       context = [];
+       // Start generating the context, walking forward.
+       for (j = tokens.length-1; j >= 0; j--) {
+           if (j < i) {
+               context.push({ type: tokens[j].type,
+                              value: tokens[j].value,
+                              line: line,
+                              column: column });
+           }
+
+           if (tokens[j].type === 'whitespace' && 
+               tokens[j].value === '\n') {
+               column = 0;
+               line++;
+           } else {
+               column += tokens[j].value.length;
+           }
+       }
+       return context;
+
+
+    };
+
+
+
+
+
+    // calculateIndentationFromContext: indentation-context number -> number
+    var calculateIndentationFromContext = function(context, currentIndentation) {
+       if (context.length === 0) {
+           return 0;
+       }
+       if (isBeginLikeContext(context)) {
+           return beginLikeIndentation(context);
+       }
+       if (isDefineLikeContext(context)) {
+           return defineLikeIndentation(context);
+       }
+       if (isLambdaLikeContext(context)) {
+           return lambdaLikeIndentation(context);
+       }
+       return beginLikeIndentation(context, 0);
+    };
+
+
+
+    // findContextElement: indentation-context number -> index or -1
+    var findContextElement = function(context, index) {
+       var depth = 0;
+       for(var i = 0; i < context.length; i++) {
+           if (context[i].type !== 'whitespace' && depth === 1) {
+               if (index === 0)
+                   return i;
+               else
+                   index--;
+           }
+
+           if (isLparen(context[i].type)) {
+               depth++;
+           }
+           if (isRparen(context[i].type)) {
+               depth = Math.max(depth - 1, 0);
+           }
+       }
+       return -1;
+    };
+
+    // contextElement: context -> (arrayof index)
+    var contextElements = function(context) {
+       var i = 0, index, results = [];
+       
+       while ((index = findContextElement(context, i++)) != -1) {
+           results.push(index);
+       }
+       return results;
+    };
+
+
+
+    //////////////////////////////////////////////////////////////////////
+
+    var BEGIN_LIKE_KEYWORDS = ["case-lambda", 
+                              "compound-unit",
+                              "compound-unit/sig",
+                              "cond",
+                              "delay",
+                              "inherit",
+                              "match-lambda",
+                              "match-lambda*",
+                              "override",
+                              "private",
+                              "public",
+                              "sequence",
+                              "unit"];
+
+    var isBeginLikeContext = function(context) {
+       var j = findContextElement(context, 0);
+       if (j === -1) { return false; }
+       return (/^begin/.test(context[j].value) ||
+               isMember(context[j].value, BEGIN_LIKE_KEYWORDS));
+    };
+
+
+    // Begin: if there's no elements within the begin context,
+    // the indentation is that of the begin keyword's column + offset.
+    // Otherwise, find the leading element on the last line.
+    // Also used for default indentation.
+    var beginLikeIndentation = function(context, offset) {
+       if (typeof(offset) === 'undefined') { offset = 1; }
+
+       var indices = contextElements(context), j;
+       if (indices.length === 0) {
+           return context[0].column + 1;
+       } else if (indices.length === 1) {
+           // if we only see the begin keyword, indentation is based
+           // off the keyword.
+           return context[indices[0]].column + offset;
+       } else {
+           // Otherwise, we scan for the contextElement of the last line
+           for (j = indices.length -1; j > 1; j--) {
+               if (context[indices[j]].line !==
+                   context[indices[j-1]].line) {
+                   return context[indices[j]].column;
+               }
+           }
+           return context[indices[j]].column;
+       }
+    };
+
+
+
+    //////////////////////////////////////////////////////////////////////
+
+
+    var DEFINE_LIKE_KEYWORDS = ["local"];
+
+    var isDefineLikeContext = function(context) {
+       var j = findContextElement(context, 0);
+       if (j === -1) { return false; }
+       return (/^def/.test(context[j].value) ||
+               isMember(context[j].value, DEFINE_LIKE_KEYWORDS));
+    };
+
+
+    var defineLikeIndentation = function(context) {
+       var i = findContextElement(context, 0);
+       if (i === -1) { return 0; }
+       return context[i].column +1; 
+    };
+
+    //////////////////////////////////////////////////////////////////////
+
+    var LAMBDA_LIKE_KEYWORDS = ["cases",
+                               "instantiate",
+                               "super-instantiate",
+                               "syntax/loc",
+                               "quasisyntax/loc",
+                               "lambda",
+                               "let",
+                               "let*",
+                               "letrec",
+                               "recur",
+                               "lambda/kw",
+                               "letrec-values",
+                               "with-syntax",
+                               "with-continuation-mark",
+                               "module",
+                               "match",
+                               "match-let",
+                               "match-let*",
+                               "match-letrec",
+                               "let/cc",
+                               "let/ec",
+                               "letcc",
+                               "catch",
+                               "let-syntax",
+                               "letrec-syntax",
+                               "fluid-let-syntax",
+                               "letrec-syntaxes+values",
+                               "for",
+                               "for/list",
+                               "for/hash",
+                               "for/hasheq",
+                               "for/and",
+                               "for/or",
+                               "for/lists",
+                               "for/first",
+                               "for/last",
+                               "for/fold",
+                               "for*",
+                               "for*/list",
+                               "for*/hash",
+                               "for*/hasheq",
+                               "for*/and",
+                               "for*/or",
+                               "for*/lists",
+                               "for*/first",
+                               "for*/last",
+                               "for*/fold",
+                               "kernel-syntax-case",
+                               "syntax-case",
+                               "syntax-case*",
+                               "syntax-rules",
+                               "syntax-id-rules",
+                               "let-signature",
+                               "fluid-let",
+                               "let-struct",
+                               "let-macro",
+                               "let-values",
+                               "let*-values",
+                               "case",
+                               "when",
+                               "unless",
+                               "let-enumerate",
+                               "class",
+                               "class*",
+                               "class-asi",
+                               "class-asi*",
+                               "class*/names",
+                               "class100",
+                               "class100*",
+                               "class100-asi",
+                               "class100-asi*",
+                               "class100*/names",
+                               "rec",
+                               "make-object",
+                               "mixin",
+                               "define-some",