File Index
+ + +<rot.js>
+ +-
+
+
+
+
+
+ + +
diff --git a/.gitattributes b/.gitattributes index c7d9f3332a950355d5a77d85000f05e6f45435ea..669e9ba17c56825a7fd26e47a4bca3d80d6a9b0a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -32,3 +32,37 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +music/(((stereofect)))_Winter_Solstice_2012.mp3 filter=lfs diff=lfs merge=lfs -text +music/Adversity.mp3 filter=lfs diff=lfs merge=lfs -text +music/Adversity.wav filter=lfs diff=lfs merge=lfs -text +music/all_ages_bitcrusher.mp3 filter=lfs diff=lfs merge=lfs -text +music/Ant_Neely_-_07_-_Not_Fit_For_Human_Consumption.mp3 filter=lfs diff=lfs merge=lfs -text +music/BLEO_-_02_-_Tart_Pts_1__2_feat_KeFF.mp3 filter=lfs diff=lfs merge=lfs -text +music/BLEO_-_04_-_Death_Destroyer_Radio_Edit_feat_Rhinostrich.mp3 filter=lfs diff=lfs merge=lfs -text +music/Boss[[:space:]]Loop[[:space:]]1.mp3 filter=lfs diff=lfs merge=lfs -text +music/Boss[[:space:]]Loop[[:space:]]1.wav filter=lfs diff=lfs merge=lfs -text +music/Broke_For_Free_-_01_-_Night_Owl.mp3 filter=lfs diff=lfs merge=lfs -text +music/conspiracy_bitcrusher_final.mp3 filter=lfs diff=lfs merge=lfs -text +music/Eric_Skiff_-_06_-_Searching.mp3 filter=lfs diff=lfs merge=lfs -text +music/Eric_Skiff_-_09_-_Come_and_Find_Me_-_B_mix.mp3 filter=lfs diff=lfs merge=lfs -text +music/Fex_coming_soon.mp3 filter=lfs diff=lfs merge=lfs -text +music/gurh.mp3 filter=lfs diff=lfs merge=lfs -text +music/intricate_cloudy_sin.mp3 filter=lfs diff=lfs merge=lfs -text +music/Jackson_D_Zero_One.mp3 filter=lfs diff=lfs merge=lfs -text +music/Obsibilo_-_02_-_Comme_Des_Orages.mp3 filter=lfs diff=lfs merge=lfs -text +music/Obsibilo_-_Soixante-8.mp3 filter=lfs diff=lfs merge=lfs -text +music/Revolution_Void_-_08_-_Obscure_Terrain.mp3 filter=lfs diff=lfs merge=lfs -text +music/RoccoW_-_Messeah.mp3 filter=lfs diff=lfs merge=lfs -text +music/Rolemusic_-_07_-_Beach_Wedding_Dance.mp3 filter=lfs diff=lfs merge=lfs -text +music/Roots[[:space:]]of[[:space:]]Supremacy.mp3 filter=lfs diff=lfs merge=lfs -text +music/Roots[[:space:]]of[[:space:]]Supremacy.wav filter=lfs diff=lfs merge=lfs -text +music/Skizofonik_System.mp3 filter=lfs diff=lfs merge=lfs -text +music/Spectrofuzz_Sunset_84.mp3 filter=lfs diff=lfs merge=lfs -text +music/Sycamore_Drive_-_03_-_The_Waves_Call_Her_Name.mp3 filter=lfs diff=lfs merge=lfs -text +music/ThatAndyGuy-Chip-loop.mp3 filter=lfs diff=lfs merge=lfs -text +music/ThatAndyGuy-Chip.mp3 filter=lfs diff=lfs merge=lfs -text +music/Tortue_Super_Sonic_-_11_-_Y.mp3 filter=lfs diff=lfs merge=lfs -text +music/Various_Artists_-_15_-_Slimeball_vomit.mp3 filter=lfs diff=lfs merge=lfs -text +music/Vernon_Lenoir_-_Brazilicon_alley.mp3 filter=lfs diff=lfs merge=lfs -text +music/what.mp3 filter=lfs diff=lfs merge=lfs -text +music/Yonnie_The_Green.mp3 filter=lfs diff=lfs merge=lfs -text diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ebaba6dc5bdf6f104c396fc89087a793a9ac9ad1 --- /dev/null +++ b/Makefile @@ -0,0 +1,137 @@ +# Partially based off of: +# http://nefariousdesigns.co.uk/website-builds-using-make.html + +# if a mod is specified but doesn't exist, raise an error +err:=$(shell if [ ! -z '$(mod)' ] && [ ! -d 'mods/$(mod)' ]; then echo 'Mod [$(mod)] not found!'; fi) +ifneq '$(err)' '' +$(error $(err)) +endif + +mod-dir=$(shell if [ -z '$(mod)' ]; then echo 'default'; else echo $(mod); fi) + +err:=$(shell if [ ! -f 'mods/$(mod-dir)/intro.js' ]; then echo 'File mods/$(mod-dir)/intro.js not found!'; fi) +ifneq '$(err)' '' +$(error $(err)) +endif + +js-target = scripts/build/untrusted.js +js-target-min = scripts/build/untrusted.min.js + +js-modules = scripts/util.js \ + mods/$(mod-dir)/intro.js\ + scripts/_head.js \ + scripts/game.js \ + scripts/codeEditor.js \ + scripts/display.js \ + scripts/dynamicObject.js \ + scripts/inventory.js \ + scripts/map.js \ + scripts/objects.js \ + scripts/player.js \ + scripts/reference.js \ + scripts/sound.js \ + scripts/validate.js \ + scripts/ui.js \ + levels/levels.js \ + scripts/_launcher_release.js \ + scripts/_tail.js + +js-modules-debug = scripts/util.js \ + mods/$(mod-dir)/intro.js\ + scripts/_head.js \ + scripts/game.js \ + scripts/codeEditor.js \ + scripts/display.js \ + scripts/dynamicObject.js \ + scripts/inventory.js \ + scripts/map.js \ + scripts/objects.js \ + scripts/player.js \ + scripts/reference.js \ + scripts/sound.js \ + scripts/validate.js \ + scripts/ui.js \ + levels/levels.js \ + scripts/_launcher_debug.js \ + scripts/_tail.js + +yui-jar = tools/yuicompressor-2.4.8pre.jar + +# `make` or `make debug` merges scripts (using debug launcher) +debug: + @echo "Building level file…\t\t\t\c" + @./compile_levels.sh $(mod-dir) + @echo "[ Done ]" + @echo "Merging JS files…\t\t\t\c" + @cat $(js-modules-debug) > $(js-target) + @./parse_target.sh $(js-target) $(mod-dir) + @echo "[ Done ]" + +# `make release` merges and compresses scripts (using release launcher) +release: + @rm -f $(js-target-min) + @echo "Building level file…\t\t\t\c" + @./compile_levels.sh $(mod-dir) + @echo "[ Done ]" + @echo "Merging JS files…\t\t\t\c" + @cat $(js-modules) > $(js-target) + @./parse_target.sh $(js-target) $(mod-dir) + @echo "[ Done ]" + @echo "Compressing merged JS…\t\t\t\c" + @java -jar $(yui-jar) -o $(js-target-min) $(js-target) + @echo "[ Done ]" + +# `make clean` removes built scripts +clean: + @rm -f $(js-target) $(js-target-min) + +# to use `make deploy` to deploy Untrusted to your own server, create +# a deploy.sh script (ncftpput is helpful for uploading via FTP). +deploy: release + @echo "Deploying to server…\t\t\t\c" + @rm -rf _site + @mkdir _site + @cp -R levels scripts styles images sound index.html _site + @./deploy.sh /untrusted _site + @rm -rf _site + @echo "[ Done ]" + +# `make deploy-full` also deploys music and libs +deploy-full: release + @echo "Deploying to server…\t\t\t\c" + @rm -rf _site + @mkdir _site + @cp -R levels scripts styles images sound music lib index.html _site + @./deploy.sh /untrusted _site + @rm -rf _site + @echo "[ Done ]" + +# `make deploy-debug` deploys the debug version to /debug +deploy-debug: debug + @echo "Deploying to server…\t\t\t\c" + @rm -rf _site + @mkdir _site + @cp -R levels scripts styles images sound index.html _site + @./deploy.sh /untrusted/debug _site + @rm -rf _site + @echo "[ Done ]" + +# `make deploy-debug` deploys the debug version to /debug +deploy-debug-full: debug + @echo "Deploying to server…\t\t\t\c" + @rm -rf _site + @mkdir _site + @cp -R levels scripts styles images sound music lib index.html _site + @./deploy.sh /untrusted/debug _site + @rm -rf _site + @echo "[ Done ]" + +deploy-github: + @git checkout gh-pages && git merge master --no-commit && make release && git commit -am "build" && git push origin gh-pages; git checkout master && make + +# run-local will start a mini python webserver and host a local +# instance of the game will run on an available port +# the option -c-1 disables caching +runlocal: debug + @echo "Running local instance" + ./node_modules/http-server/bin/http-server -c-1 diff --git a/README.md b/README.md index e3024567b392f4e1a9a3ddda549aef95cf8ac5ab..ca8c8c1fd57e9c1d5ce83591cc5b0b0095242082 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,115 @@ ---- -title: Untrusted Test Only -emoji: 🌖 -colorFrom: purple -colorTo: yellow -sdk: static -pinned: false -license: cc-by-nc-sa-3.0 ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +**Untrusted —or— the Continuing Adventures of Dr. Eval** is an exciting Meta-JavaScript Adventure Game wherein you guide the dashing, steadfast Dr. Eval through a mysterious MACHINE CONTINUUM, wherein, using only his trusty computer and the TURING-COMPLETE power of JavaScript, he must literally ALTER HIS REALITY in order to find his freedom! You must literally edit and re-execute the very JavaScript running the game in your browser to save Dr. Eval from this dark and confusing reality! + +### Overview + +The game presents you with a roguelike-like playing environment and a console window with the JavaScript code generating each level. As loaded, each level is unbeatable, and most of the JavaScript is blocked from editing. The challenge is to open a path to the next level using only the limited tools left open to you. + +### Development + +Run +``` +make +``` +to merge the JavaScript files into `scripts/build/untrusted.js` (and enables debug features). + +``` +make release +``` +merges and minifies the JavaScript files into `scripts/build/untrusted.min.js` (and disables debug features). + +To run the game locally, you need to set up a local server to serve `index.html` (this step is necessary due to Access-Control-Allow-Origin restrictions). + +First install [http-server](https://github.com/nodeapps/http-server/#installing-globally) if you haven't already: + +``` +npm install http-server +``` + +Then run: + +``` +make runlocal +``` + +Build your own mod in the `mods` directory: + +``` +make mod=example_mod +``` + +### Contributing Levels + +To add a new level, create a jsx file in [/levels/bonus](https://github.com/AlexNisnevich/untrusted/tree/master/levels/bonus) and add the level filename to the `bonusLevels` array in [game.js](https://github.com/AlexNisnevich/untrusted/blob/master/scripts/game.js#L40). + +If you are adding any new commands that the player can use, make sure to add them to `reference.js`. + +#### The .jsx file format + +jsx files are like regular JavaScript files, but have some additional syntax: +- `#BEGIN_EDITABLE#` and `#END_EDITABLE#` surround editable lines +- `#{#` and `#}#` wrap editable sections (parts of lines) +- `#BEGIN_PROPERTIES#` and `#END_PROPERTIES#` surround the properties object at the start of the file. Available properties include: + - `commandsIntroduced`: array of new commands introduced in the level (see `reference.js`) + - `mapProperties`: optionally contains any of the following: + - `allowOverwrite`: if true, placed static objects can be overwritten by other objects + - `keyDelay`: specifies the lag, in milliseconds, between player keystrokes (default: 0) + - `refreshRate`: the refresh rate of the level, in milliseconds (required for dynamic objects with `interval` properties to work correctly) + - `showDrawingCanvas`: if true, the drawing canvas overlay is displayed + - `showDummyDom`: if true, a dummy DOM will be displayed instead of the regular map + - `music`: name of the background track for the level (see `sound.js`) + - `startingMessage`: message displayed at the bottom of the screen when the level starts (if any) + - `version`: increase the level version whenever you update a level + - `nextBonusLevel`: load another level automatically when this one is solved +- `#START_OF_START_LEVEL#` and `#END_OF_START_LEVEL#` should be the first and last line of the `startLevel` method, respectively + +#### Adding music + +To add a new background music track, add an MP3 file (that you have permission to use) to the [/music](https://github.com/AlexNisnevich/untrusted/tree/master/music) and add a new entry to the `tracks` array in [sound.js](https://github.com/AlexNisnevich/untrusted/blob/master/scripts/sound.js). + +### Acknowledgements + +Untrusted is a game by [Alex Nisnevich](http://alex.nisnevich.com/) and [Greg Shuflin](https://github.com/neunenak). + +We'd like to thank: + +- [Dmitry Mazin](https://github.com/dmazin) for design assistance and for the implementation of multiline editing +- [Jordan Arnesen](https://github.com/extrajordanary) for playtesting and design of lvl17 +- [Natasha Hull-Richter](http://nhull.com) for extensive playtesting and assistance in level design +- Alex Bolotov, Colin Curtin, Conrad Irwin, Devin C-R, Eugene Evans, Gilbert Hsyu, Jacob Nisnevich, James Silvey, Jason Jiang, Jimmy Hack, Philip Shao, Ryan Fitzgerald, Stephen Liu, Yayoi Ukai, and Yuval Gnessin for playtesting and feedback +- [Ondřej Žára](https://github.com/ondras) for his [rot.js](http://ondras.github.io/rot.js/) library +- [Marijn Haverbeke](https://github.com/marijnh) for his [CodeMirror](http://codemirror.net/) library +- [Brian Harvey](http://www.cs.berkeley.edu/~bh/) for allowing us to use his likeness in lvl19 + +#### Soundtrack + +You can [listen to the full soundtrack here](https://soundcloud.com/untrusted/sets/untrusted-soundtrack). + +The music that appears in Untrusted, in order, is: + +- "The Green" - [Jonathan Holliday](http://www.soundclick.com/bands/default.cfm?bandID=836578) (used with permission) +- "Dmitry's Thing #2" - [Dmitry Mazin](https://soundcloud.com/dmitry-mazin) (written for Untrusted) +- "Obscure Terrain" - [Revolution Void](http://revolutionvoid.com/) (CC-BY-NC-SA) +- "coming soon" - [Fex](http://artistserver.com/Fex) (public domain) +- "cloudy sin" - [iNTRICATE](https://soundcloud.com/stk13) (used with permission) +- "Dynamic Punctuality" - [Dmitry Mazin](https://soundcloud.com/dmitry-mazin) (written for Untrusted) +- "Y" - [Tortue Super Sonic](https://soundcloud.com/tss-tortue-super-sonic) (CC-BY-NC-SA) +- "Night Owl" - [Broke for Free](http://brokeforfree.com/) (CC-BY) +- "The Waves Call Her Name" - [Sycamore Drive](http://sycamoredrive.bandcamp.com/) (CC-BY-NC-SA) +- "Come and Find Me - B mix" - [Eric Skiff](http://ericskiff.com/) (CC-BY) +- "Conspiracy" - [Mike and Alan](https://www.facebook.com/MicAndAlan) (used with permission) +- "Messeah" - [RoccoW](https://soundcloud.com/roccow) (CC-BY) +- "Searching" - [Eric Skiff](http://ericskiff.com/) (CC-BY) +- "Da Funk Do You Know 'bout Chip?" - [That Andy Guy](https://soundcloud.com/that-andy-guy) (used with permission) +- "Soixante-8" - [Obsibilo](http://freemusicarchive.org/music/Obsibilo/) (CC-BY-NC-SA) +- "Tart (Pts 1 and 2)" - [BLEO feat KeFF](http://bleo.dummydrome.com/) (CC-BY-NC-SA) +- "Beach Wedding Dance" - [Rolemusic](https://soundcloud.com/rolemusic) (CC-BY-NC-SA) +- "Boss Loop 1" - [Essa](http://www.youtube.com/user/Essasmusic) (free to use) +- "Adversity" - [Seropard](https://soundcloud.com/seropard) (free to use) +- "Comme Des Orages" - [Obsibilo](http://freemusicarchive.org/music/Obsibilo/) (CC-BY-NC-SA) +- "Brazilicon Alley" - [Vernon Lenoir](http://vernonlenoir.wordpress.com/) (CC-BY-NC-SA), based on "Aquarela do Brazil" by Ary Barroso + +### License +This work is dual-licensed. + +- Untrusted and the Untrusted soundtrack are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License (CC-BY-NC-SA 3.0). In other words, you are free to use and modify Untrusted for non-commercial purposes, provided that you credit us and your work is also licensed under CC-BY-NC-SA. +- Additionally, the Untrusted code *without the soundtrack* is licenced under a commercial license. This means that you are able to use Untrusted for commercial purposes under some conditions, provided that you do not use any of the music. Please [contact us](mailto:alex.nisnevich@gmail.com,greg.shuflin@gmail.com) for details. diff --git a/compile_levels.sh b/compile_levels.sh new file mode 100644 index 0000000000000000000000000000000000000000..fccff78c24752b4f9a0d9735f0d4105f0c8c15b4 --- /dev/null +++ b/compile_levels.sh @@ -0,0 +1,14 @@ +echo "Game.prototype._levels = {" > levels/levels.js + +mod=$1 + +for lvl in mods/$mod/*.jsx +do + lvlfn=`basename $lvl` + printf %s " 'levels/$lvlfn': '" >> levels/levels.js + echo "$lvl" | xargs sed "s#\\\#\\\\\\\#g" | sed "s#'#\\\'#g" | tr '\n' '`' | sed "s/\`/\\\n/g" | sed -e "a\\ + ', + " | tr '\n' ' ' >> levels/levels.js + echo "" >> levels/levels.js # dummy newline for style +done +echo "};" >> levels/levels.js diff --git a/deploy.sh.example b/deploy.sh.example new file mode 100644 index 0000000000000000000000000000000000000000..559a05d20ded746abeeb03c1ece58688e14c06a4 --- /dev/null +++ b/deploy.sh.example @@ -0,0 +1,3 @@ +cd $2 +ncftpput -R -v -u [username] ftp.[domain].com [untrusted_root_path]$1 . +cd .. diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dcd42105598e542fabb28fb0137e02a08580d6d6 Binary files /dev/null and b/favicon.ico differ diff --git a/images/mute-off.png b/images/mute-off.png new file mode 100644 index 0000000000000000000000000000000000000000..a23ba306bae935bc58171aa80e8a02c1b84ae858 Binary files /dev/null and b/images/mute-off.png differ diff --git a/images/mute-on.png b/images/mute-on.png new file mode 100644 index 0000000000000000000000000000000000000000..893aff40d5517beb70beb530253679fb40f9c044 Binary files /dev/null and b/images/mute-on.png differ diff --git a/images/static.gif b/images/static.gif new file mode 100644 index 0000000000000000000000000000000000000000..b3f5efb05b350d132007f6dc3961de81915a55a7 Binary files /dev/null and b/images/static.gif differ diff --git a/index.html b/index.html index 58275de3b1c343a98420342baa076b9baaafa157..6fa76698e05a0e7df51d83c4b936b7d286874795 100644 --- a/index.html +++ b/index.html @@ -1,19 +1,124 @@ -
- - -You can modify this app directly by editing index.html in the Files and versions tab.
-- Also don't forget to check the - Spaces documentation. -
+ +" + + " | " +
+ "Cornelius Eval" + + "Associate Professor of Computer Science" + + "
About me" + + "I am an associate professor of computer science, attached to the Department of " + + "Theoretical Computation. My current research interests include the human-machine " + + "interface, NP complete problems, and parallelized mesh mathematics. " + + "I am also the current faculty advisor to the undergraduate Super Smash Bros. team. " + + "In my spare time I enjoy polka and dirtbiking. " + + " | " +
+ "
Monday | Tuesday | Wednesday | Thursday | Friday | " + + "
---|---|---|---|---|
CS145 - Semicolons | Nothing Planned | CS145 - Semicolons | CS199 - Practical Theorycrafting | CS145 - Semicolons | " + + "
" +
+ "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci " +
+ "velit, sed quia nonnumquam eiusmodi tempora incidunt ut labore et dolore magnam aliquam quaerat " +
+ "voluptatem.
" +
+ "" +
+ "
" +
+ "Styling the current cursor line.
+ + + diff --git a/lib/codemirror-3.1/demo/bidi.html b/lib/codemirror-3.1/demo/bidi.html new file mode 100644 index 0000000000000000000000000000000000000000..47feb8c5aa937fd538536fe063e7883443904099 --- /dev/null +++ b/lib/codemirror-3.1/demo/bidi.html @@ -0,0 +1,61 @@ + + + + +Demonstration of bi-directional text support. See + the related + blog post for more background.
+ + + diff --git a/lib/codemirror-3.1/demo/btree.html b/lib/codemirror-3.1/demo/btree.html new file mode 100644 index 0000000000000000000000000000000000000000..5e5ce0abf29a2434ee2009161c30fe3954181ceb --- /dev/null +++ b/lib/codemirror-3.1/demo/btree.html @@ -0,0 +1,87 @@ + + + + +Shows a visual representation of the b-tree that CodeMirror + uses to store its document. See + the corresponding + blog post for a description of this format. The gray blocks + under each leaf show the lines it holds (with their width + representing the line height). Add and remove content to see how + the nodes are split and merged to keep the tree balanced.
+ +Demonstration of
+ using linked documents
+ to provide a split view on a document, and
+ using swapDoc
+ to use a single editor to display multiple documents.
On changes to the content of the above editor, a (crude) script +tries to auto-detect the language used, and switches the editor to +either JavaScript or Scheme mode based on that.
+ + + + diff --git a/lib/codemirror-3.1/demo/closebrackets.html b/lib/codemirror-3.1/demo/closebrackets.html new file mode 100644 index 0000000000000000000000000000000000000000..58ba0330a1294a8b7c75df2c67bd41c5902013a4 --- /dev/null +++ b/lib/codemirror-3.1/demo/closebrackets.html @@ -0,0 +1,59 @@ + + + + +Type a bracket like '[', '(', '{', '"', or ''' + and the addon + will auto-close it. Type the closing variant when directly in + front of a matching character and it will overwrite it.
+ + + + + + diff --git a/lib/codemirror-3.1/demo/closetag.html b/lib/codemirror-3.1/demo/closetag.html new file mode 100644 index 0000000000000000000000000000000000000000..87f4f019f65f6b22b4442fd1c752232d2b1dd7dd --- /dev/null +++ b/lib/codemirror-3.1/demo/closetag.html @@ -0,0 +1,37 @@ + + + + +Click on the right side of the gutter, then click again below,
+ the code between will collapse. Click on either arrow to expand.
+ To use, simply include the collapserange.js file and
+ set collapseRange: true
in options.
Press ctrl-space to activate autocompletion. See +the code (here +and here) to figure out +how it works.
+ + + + diff --git a/lib/codemirror-3.1/demo/emacs.html b/lib/codemirror-3.1/demo/emacs.html new file mode 100644 index 0000000000000000000000000000000000000000..b37a46b0487b48216ee23cfe052417fde03294cc --- /dev/null +++ b/lib/codemirror-3.1/demo/emacs.html @@ -0,0 +1,60 @@ + + + + +The emacs keybindings are enabled by
+including keymap/emacs.js and setting
+the keyMap
option to "emacs"
. Because
+CodeMirror's internal API is quite different from Emacs, they are only
+a loose approximation of actual emacs bindings, though.
Also note that a lot of browsers disallow certain keys from being +captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the +result that idiomatic use of Emacs keys will constantly close your tab +or open a new window.
+ + + + + diff --git a/lib/codemirror-3.1/demo/folding.html b/lib/codemirror-3.1/demo/folding.html new file mode 100644 index 0000000000000000000000000000000000000000..f28e5af4692de0be941f8f40efa41d65037a9e52 --- /dev/null +++ b/lib/codemirror-3.1/demo/folding.html @@ -0,0 +1,67 @@ + + + + +Demonstration of code folding using the code
+ in foldcode.js
.
+ Press ctrl-q or click on the gutter to fold a block, again
+ to unfold.
Try the Range Colapse demo as well.
Note: The formatting addon receives a fair + amount of bug requests. I (the maintainer of CodeMirror) do not + intend to spend time on improving it. Pull requests (if clean and + intelligent) are welcome, but you should see this code as a + proof-of-concept (using CodeMirror's mode tokenizers to help + format code), not a finished, robust module.
+ + + +Select a piece of code and click one of the links below to apply automatic formatting to the selected text or comment/uncomment the selected text. Note that the formatting behavior depends on the current block's mode. +
+ + Autoformat Selected + + | ++ + Comment Selected + + | ++ + Uncomment Selected + + | +
Press F11 when cursor is in the editor to toggle full screen editing. Esc can also be used to exit full screen editing.
+ + diff --git a/lib/codemirror-3.1/demo/lint.html b/lib/codemirror-3.1/demo/lint.html new file mode 100644 index 0000000000000000000000000000000000000000..ece8b1cef7b205f973c06675b0f8846a68c879ca --- /dev/null +++ b/lib/codemirror-3.1/demo/lint.html @@ -0,0 +1,90 @@ + + + + ++ + + + diff --git a/lib/codemirror-3.1/demo/marker.html b/lib/codemirror-3.1/demo/marker.html new file mode 100644 index 0000000000000000000000000000000000000000..f0981e4d5f110892859f28475da295b846686936 --- /dev/null +++ b/lib/codemirror-3.1/demo/marker.html @@ -0,0 +1,59 @@ + + + + +
Click the line-number gutter to add or remove 'breakpoints'.
+ + + + + diff --git a/lib/codemirror-3.1/demo/markselection.html b/lib/codemirror-3.1/demo/markselection.html new file mode 100644 index 0000000000000000000000000000000000000000..e1c054869fcacf67774955cee582f71a49874527 --- /dev/null +++ b/lib/codemirror-3.1/demo/markselection.html @@ -0,0 +1,36 @@ + + + + +Simple addon to easily mark (and style) selected text.
+ + + diff --git a/lib/codemirror-3.1/demo/matchhighlighter.html b/lib/codemirror-3.1/demo/matchhighlighter.html new file mode 100644 index 0000000000000000000000000000000000000000..c574fbae815ebb15334d5e8171ce91af45266897 --- /dev/null +++ b/lib/codemirror-3.1/demo/matchhighlighter.html @@ -0,0 +1,38 @@ + + + + +Search and highlight occurences of the selected text.
+ + + diff --git a/lib/codemirror-3.1/demo/multiplex.html b/lib/codemirror-3.1/demo/multiplex.html new file mode 100644 index 0000000000000000000000000000000000000000..9ebe8f357b9555f1aad8faa8cc0374d144cfd338 --- /dev/null +++ b/lib/codemirror-3.1/demo/multiplex.html @@ -0,0 +1,60 @@ + + + + +Demonstration of a multiplexing mode, which, at certain
+ boundary strings, switches to one or more inner modes. The out
+ (HTML) mode does not get fed the content of the <<
+ >>
blocks. See
+ the manual and
+ the source for more
+ information.
Demonstration of a mode that parses HTML, highlighting
+ the Mustache templating
+ directives inside of it by using the code
+ in overlay.js
. View
+ source to see the 15 lines of code needed to accomplish this.
By setting a few CSS properties, CodeMirror can be made to +automatically resize to fit its content.
+ + + + + diff --git a/lib/codemirror-3.1/demo/runmode.html b/lib/codemirror-3.1/demo/runmode.html new file mode 100644 index 0000000000000000000000000000000000000000..dba808ba7a66cefedac922d5804d56c89c40e4e2 --- /dev/null +++ b/lib/codemirror-3.1/demo/runmode.html @@ -0,0 +1,50 @@ + + + + +Running a CodeMirror mode outside of the editor.
+ The CodeMirror.runMode
function, defined
+ in lib/runmode.js
takes the following arguments:
text (string)
mode (mode spec)
output (function or DOM node)
null
for unstyled tokens). If it is a DOM node,
+ the tokens will be converted to span
elements as in
+ an editor, and inserted into the node
+ (through innerHTML
).Demonstration of primitive search/replace functionality. The + keybindings (which can be overridden by custom keymaps) are:
+Searching is enabled by + including addon/search/search.js + and addon/search/searchcursor.js. + For good-looking input dialogs, you also want to include + addon/dialog/dialog.js + and addon/dialog/dialog.css.
+ + diff --git a/lib/codemirror-3.1/demo/theme.html b/lib/codemirror-3.1/demo/theme.html new file mode 100644 index 0000000000000000000000000000000000000000..42a1b0cde7554f9ee77628f8678fc8850f710329 --- /dev/null +++ b/lib/codemirror-3.1/demo/theme.html @@ -0,0 +1,85 @@ + + + + +Select a theme: +
+ + + + diff --git a/lib/codemirror-3.1/demo/variableheight.html b/lib/codemirror-3.1/demo/variableheight.html new file mode 100644 index 0000000000000000000000000000000000000000..b00f7e4542d4e30539795c2f631c6113e2f3b138 --- /dev/null +++ b/lib/codemirror-3.1/demo/variableheight.html @@ -0,0 +1,52 @@ + + + + +The vim keybindings are enabled by
+including keymap/vim.js and setting
+the keyMap
option to "vim"
. Because
+CodeMirror's internal API is quite different from Vim, they are only
+a loose approximation of actual vim bindings, though.
Tabs inside the editor are spans with the
+class cm-tab
, and can be styled.
+
+
+
+
+
diff --git a/lib/codemirror-3.1/demo/widget.html b/lib/codemirror-3.1/demo/widget.html
new file mode 100644
index 0000000000000000000000000000000000000000..a3b27a9e4774f5182bd47607fe1f4e589171f7f6
--- /dev/null
+++ b/lib/codemirror-3.1/demo/widget.html
@@ -0,0 +1,74 @@
+
+
+
This demo runs JSHint over the code +in the editor (which is the script used on this page), and +inserts line widgets to +display the warnings that JSHint comes up with.
+ + diff --git a/lib/codemirror-3.1/demo/xmlcomplete.html b/lib/codemirror-3.1/demo/xmlcomplete.html new file mode 100644 index 0000000000000000000000000000000000000000..28a50638f7fa12a7db5c0772e6c05eee428b6f1e --- /dev/null +++ b/lib/codemirror-3.1/demo/xmlcomplete.html @@ -0,0 +1,81 @@ + + + + +Type '<' or space inside tag or + press ctrl-space to activate autocompletion. See + the code (here + and here) to figure out how + it works.
+ + + + diff --git a/lib/codemirror-3.1/doc/baboon.png b/lib/codemirror-3.1/doc/baboon.png new file mode 100644 index 0000000000000000000000000000000000000000..55d97f70b817ff2b78ebb409bf34a5147fe40d07 Binary files /dev/null and b/lib/codemirror-3.1/doc/baboon.png differ diff --git a/lib/codemirror-3.1/doc/baboon_vector.svg b/lib/codemirror-3.1/doc/baboon_vector.svg new file mode 100644 index 0000000000000000000000000000000000000000..dc1667af91371787b979f9155061ff5d954f3ece --- /dev/null +++ b/lib/codemirror-3.1/doc/baboon_vector.svg @@ -0,0 +1,153 @@ + + + + \ No newline at end of file diff --git a/lib/codemirror-3.1/doc/compress.html b/lib/codemirror-3.1/doc/compress.html new file mode 100644 index 0000000000000000000000000000000000000000..7f3bc7f7ab05c94c760a32b2aea98d008982ceac --- /dev/null +++ b/lib/codemirror-3.1/doc/compress.html @@ -0,0 +1,194 @@ + + + + ++/* Script compression + helper */ ++
To optimize loading CodeMirror, especially when including a + bunch of different modes, it is recommended that you combine and + minify (and preferably also gzip) the scripts. This page makes + those first two steps very easy. Simply select the version and + scripts you need in the form below, and + click Compress to download the minified script + file.
+ + + + + + + diff --git a/lib/codemirror-3.1/doc/docs.css b/lib/codemirror-3.1/doc/docs.css new file mode 100644 index 0000000000000000000000000000000000000000..170cd412449fc460aa4489aab3e0362238960b51 --- /dev/null +++ b/lib/codemirror-3.1/doc/docs.css @@ -0,0 +1,167 @@ +body { + font-family: Droid Sans, Arial, sans-serif; + line-height: 1.5; + max-width: 64.3em; + margin: 3em auto; + padding: 0 1em; +} + +h1 { + letter-spacing: -3px; + font-size: 3.23em; + font-weight: bold; + margin: 0; +} + +h2 { + font-size: 1.23em; + font-weight: bold; + margin: .5em 0; + letter-spacing: -1px; +} + +h3 { + font-size: 1.1em; + font-weight: bold; + margin: .4em 0; +} + +pre { + background-color: #eee; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: 1em; +} + +pre.code { + margin: 0 1em; +} + +.grey { + background-color: #eee; + border-radius: 6px; + margin-bottom: 1.65em; + margin-top: 0.825em; + padding: 0.825em 1.65em; + position: relative; +} + +img.logo { + position: absolute; + right: -1em; + bottom: 4px; + max-width: 23.6875em; /* Scale image down with text to prevent clipping */ +} + +.grey > pre { + background:none; + border-radius:0; + padding:0; + margin:0; + font-size:2.2em; + line-height:1.2em; +} + +a:link, a:visited, .quasilink { + color: #df0019; + cursor: pointer; + text-decoration: none; +} + +a:hover, .quasilink:hover { + color: #800004; +} + +h1 a:link, h1 a:visited, h1 a:hover { + color: black; +} + +ul { + margin: 0; + padding-left: 1.2em; +} + +a.download { + color: white; + background-color: #df0019; + width: 100%; + display: block; + text-align: center; + font-size: 1.23em; + font-weight: bold; + text-decoration: none; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: .5em 0; + margin-bottom: 1em; +} + +a.download:hover { + background-color: #bb0010; +} + +.rel { + margin-bottom: 0; +} + +.rel-note { + color: #777; + font-size: .9em; + margin-top: .1em; +} + +.logo-braces { + color: #df0019; + position: relative; + top: -4px; +} + +.blk { + float: left; +} + +.left { + margin-right: 20.68em; + max-width: 37em; + padding-right: 6.53em; + padding-bottom: 1em; +} + +.left1 { + width: 15.24em; + padding-right: 6.45em; +} + +.left2 { + max-width: 15.24em; +} + +.right { + width: 20.68em; + margin-left: -20.68em; +} + +.leftbig { + width: 42.44em; + padding-right: 6.53em; +} + +.rightsmall { + width: 15.24em; +} + +.clear:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; +} +.clear { display: inline-block; } +/* start commented backslash hack \*/ +* html .clear { height: 1%; } +.clear { display: block; } +/* close commented backslash hack */ diff --git a/lib/codemirror-3.1/doc/internals.html b/lib/codemirror-3.1/doc/internals.html new file mode 100644 index 0000000000000000000000000000000000000000..9139528f3de75ca48a8f5b04a71511894ff42d9b --- /dev/null +++ b/lib/codemirror-3.1/doc/internals.html @@ -0,0 +1,505 @@ + + + + ++/* (Re-) Implementing A Syntax- + Highlighting Editor in JavaScript */ ++
+ Topic: JavaScript, code editor implementation
+ Author: Marijn Haverbeke
+ Date: March 2nd 2011 (updated November 13th 2011)
+
Caution: this text was written briefly after +version 2 was initially written. It no longer (even including the +update at the bottom) fully represents the current implementation. I'm +leaving it here as a historic document. For more up-to-date +information, look at the entries +tagged cm-internals +on my blog.
+ +This is a followup to +my Brutal Odyssey to the +Dark Side of the DOM Tree story. That one describes the +mind-bending process of implementing (what would become) CodeMirror 1. +This one describes the internals of CodeMirror 2, a complete rewrite +and rethink of the old code base. I wanted to give this piece another +Hunter Thompson copycat subtitle, but somehow that would be out of +place—the process this time around was one of straightforward +engineering, requiring no serious mind-bending whatsoever.
+ +So, what is wrong with CodeMirror 1? I'd estimate, by mailing list +activity and general search-engine presence, that it has been +integrated into about a thousand systems by now. The most prominent +one, since a few weeks, +being Google +code's project hosting. It works, and it's being used widely. + +
Still, I did not start replacing it because I was bored. CodeMirror
+1 was heavily reliant on designMode
+or contentEditable
(depending on the browser). Neither of
+these are well specified (HTML5 tries
+to specify
+their basics), and, more importantly, they tend to be one of the more
+obscure and buggy areas of browser functionality—CodeMirror, by using
+this functionality in a non-typical way, was constantly running up
+against browser bugs. WebKit wouldn't show an empty line at the end of
+the document, and in some releases would suddenly get unbearably slow.
+Firefox would show the cursor in the wrong place. Internet Explorer
+would insist on linkifying everything that looked like a URL or email
+address, a behaviour that can't be turned off. Some bugs I managed to
+work around (which was often a frustrating, painful process), others,
+such as the Firefox cursor placement, I gave up on, and had to tell
+user after user that they were known problems, but not something I
+could help.
Also, there is the fact that designMode
(which seemed
+to be less buggy than contentEditable
in Webkit and
+Firefox, and was thus used by CodeMirror 1 in those browsers) requires
+a frame. Frames are another tricky area. It takes some effort to
+prevent getting tripped up by domain restrictions, they don't
+initialize synchronously, behave strangely in response to the back
+button, and, on several browsers, can't be moved around the DOM
+without having them re-initialize. They did provide a very nice way to
+namespace the library, though—CodeMirror 1 could freely pollute the
+namespace inside the frame.
Finally, working with an editable document means working with
+selection in arbitrary DOM structures. Internet Explorer (8 and
+before) has an utterly different (and awkward) selection API than all
+of the other browsers, and even among the different implementations of
+document.selection
, details about how exactly a selection
+is represented vary quite a bit. Add to that the fact that Opera's
+selection support tended to be very buggy until recently, and you can
+imagine why CodeMirror 1 contains 700 lines of selection-handling
+code.
And that brings us to the main issue with the CodeMirror 1 +code base: The proportion of browser-bug-workarounds to real +application code was getting dangerously high. By building on top of a +few dodgy features, I put the system in a vulnerable position—any +incompatibility and bugginess in these features, I had to paper over +with my own code. Not only did I have to do some serious stunt-work to +get it to work on older browsers (as detailed in the +previous story), things +also kept breaking in newly released versions, requiring me to come up +with new scary hacks in order to keep up. This was starting +to lose its appeal.
+ +What CodeMirror 2 does is try to sidestep most of the hairy hacks +that came up in version 1. I owe a lot to the +ACE editor for inspiration on how to +approach this.
+ +I absolutely did not want to be completely reliant on key events to +generate my input. Every JavaScript programmer knows that key event +information is horrible and incomplete. Some people (most awesomely +Mihai Bazon with Ymacs) have been able +to build more or less functioning editors by directly reading key +events, but it takes a lot of work (the kind of never-ending, fragile +work I described earlier), and will never be able to properly support +things like multi-keystoke international character +input. [see below for caveat]
+ +So what I do is focus a hidden textarea, and let the browser +believe that the user is typing into that. What we show to the user is +a DOM structure we built to represent his document. If this is updated +quickly enough, and shows some kind of believable cursor, it feels +like a real text-input control.
+ +Another big win is that this DOM representation does not have to
+span the whole document. Some CodeMirror 1 users insisted that they
+needed to put a 30 thousand line XML document into CodeMirror. Putting
+all that into the DOM takes a while, especially since, for some
+reason, an editable DOM tree is slower than a normal one on most
+browsers. If we have full control over what we show, we must only
+ensure that the visible part of the document has been added, and can
+do the rest only when needed. (Fortunately, the onscroll
+event works almost the same on all browsers, and lends itself well to
+displaying things only as they are scrolled into view.)
ACE uses its hidden textarea only as a text input shim, and does +all cursor movement and things like text deletion itself by directly +handling key events. CodeMirror's way is to let the browser do its +thing as much as possible, and not, for example, define its own set of +key bindings. One way to do this would have been to have the whole +document inside the hidden textarea, and after each key event update +the display DOM to reflect what's in that textarea.
+ +That'd be simple, but it is not realistic. For even medium-sized +document the editor would be constantly munging huge strings, and get +terribly slow. What CodeMirror 2 does is put the current selection, +along with an extra line on the top and on the bottom, into the +textarea.
+ +This means that the arrow keys (and their ctrl-variations), home, +end, etcetera, do not have to be handled specially. We just read the +cursor position in the textarea, and update our cursor to match it. +Also, copy and paste work pretty much for free, and people get their +native key bindings, without any special work on my part. For example, +I have emacs key bindings configured for Chrome and Firefox. There is +no way for a script to detect this. [no longer the case]
+ +Of course, since only a small part of the document sits in the +textarea, keys like page up and ctrl-end won't do the right thing. +CodeMirror is catching those events and handling them itself.
+ +Getting and setting the selection range of a textarea in modern
+browsers is trivial—you just use the selectionStart
+and selectionEnd
properties. On IE you have to do some
+insane stuff with temporary ranges and compensating for the fact that
+moving the selection by a 'character' will treat \r\n as a single
+character, but even there it is possible to build functions that
+reliably set and get the selection range.
But consider this typical case: When I'm somewhere in my document, +press shift, and press the up arrow, something gets selected. Then, if +I, still holding shift, press the up arrow again, the top of my +selection is adjusted. The selection remembers where its head +and its anchor are, and moves the head when we shift-move. +This is a generally accepted property of selections, and done right by +every editing component built in the past twenty years.
+ +But not something that the browser selection APIs expose.
+ +Great. So when someone creates an 'upside-down' selection, the next +time CodeMirror has to update the textarea, it'll re-create the +selection as an 'upside-up' selection, with the anchor at the top, and +the next cursor motion will behave in an unexpected way—our second +up-arrow press in the example above will not do anything, since it is +interpreted in exactly the same way as the first.
+ +No problem. We'll just, ehm, detect that the selection is +upside-down (you can tell by the way it was created), and then, when +an upside-down selection is present, and a cursor-moving key is +pressed in combination with shift, we quickly collapse the selection +in the textarea to its start, allow the key to take effect, and then +combine its new head with its old anchor to get the real +selection.
+ +In short, scary hacks could not be avoided entirely in CodeMirror +2.
+ +And, the observant reader might ask, how do you even know that a +key combo is a cursor-moving combo, if you claim you support any +native key bindings? Well, we don't, but we can learn. The editor +keeps a set known cursor-movement combos (initialized to the +predictable defaults), and updates this set when it observes that +pressing a certain key had (only) the effect of moving the cursor. +This, of course, doesn't work if the first time the key is used was +for extending an inverted selection, but it works most of the +time.
+ +One thing that always comes up when you have a complicated internal +state that's reflected in some user-visible external representation +(in this case, the displayed code and the textarea's content) is +keeping the two in sync. The naive way is to just update the display +every time you change your state, but this is not only error prone +(you'll forget), it also easily leads to duplicate work on big, +composite operations. Then you start passing around flags indicating +whether the display should be updated in an attempt to be efficient +again and, well, at that point you might as well give up completely.
+ +I did go down that road, but then switched to a much simpler model: +simply keep track of all the things that have been changed during an +action, and then, only at the end, use this information to update the +user-visible display.
+ +CodeMirror uses a concept of operations, which start by
+calling a specific set-up function that clears the state and end by
+calling another function that reads this state and does the required
+updating. Most event handlers, and all the user-visible methods that
+change state are wrapped like this. There's a method
+called operation
that accepts a function, and returns
+another function that wraps the given function as an operation.
It's trivial to extend this (as CodeMirror does) to detect nesting, +and, when an operation is started inside an operation, simply +increment the nesting count, and only do the updating when this count +reaches zero again.
+ +If we have a set of changed ranges and know the currently shown +range, we can (with some awkward code to deal with the fact that +changes can add and remove lines, so we're dealing with a changing +coordinate system) construct a map of the ranges that were left +intact. We can then compare this map with the part of the document +that's currently visible (based on scroll offset and editor height) to +determine whether something needs to be updated.
+ +CodeMirror uses two update algorithms—a full refresh, where it just +discards the whole part of the DOM that contains the edited text and +rebuilds it, and a patch algorithm, where it uses the information +about changed and intact ranges to update only the out-of-date parts +of the DOM. When more than 30 percent (which is the current heuristic, +might change) of the lines need to be updated, the full refresh is +chosen (since it's faster to do than painstakingly finding and +updating all the changed lines), in the other case it does the +patching (so that, if you scroll a line or select another character, +the whole screen doesn't have to be +re-rendered). [the full-refresh +algorithm was dropped, it wasn't really faster than the patching +one]
+ +All updating uses innerHTML
rather than direct DOM
+manipulation, since that still seems to be by far the fastest way to
+build documents. There's a per-line function that combines the
+highlighting, marking, and
+selection info for that line into a snippet of HTML. The patch updater
+uses this to reset individual lines, the refresh updater builds an
+HTML chunk for the whole visible document at once, and then uses a
+single innerHTML
update to do the refresh.
When I wrote CodeMirror 1, I +thought interruptable +parsers were a hugely scary and complicated thing, and I used a +bunch of heavyweight abstractions to keep this supposed complexity +under control: parsers +were iterators +that consumed input from another iterator, and used funny +closure-resetting tricks to copy and resume themselves.
+ +This made for a rather nice system, in that parsers formed strictly +separate modules, and could be composed in predictable ways. +Unfortunately, it was quite slow (stacking three or four iterators on +top of each other), and extremely intimidating to people not used to a +functional programming style.
+ +With a few small changes, however, we can keep all those +advantages, but simplify the API and make the whole thing less +indirect and inefficient. CodeMirror +2's mode API uses explicit state +objects, and makes the parser/tokenizer a function that simply takes a +state and a character stream abstraction, advances the stream one +token, and returns the way the token should be styled. This state may +be copied, optionally in a mode-defined way, in order to be able to +continue a parse at a given point. Even someone who's never touched a +lambda in his life can understand this approach. Additionally, far +fewer objects are allocated in the course of parsing now.
+ +The biggest speedup comes from the fact that the parsing no longer +has to touch the DOM though. In CodeMirror 1, on an older browser, you +could see the parser work its way through the document, +managing some twenty lines in each 50-millisecond time slice it got. It +was reading its input from the DOM, and updating the DOM as it went +along, which any experienced JavaScript programmer will immediately +spot as a recipe for slowness. In CodeMirror 2, the parser usually +finishes the whole document in a single 100-millisecond time slice—it +manages some 1500 lines during that time on Chrome. All it has to do +is munge strings, so there is no real reason for it to be slow +anymore.
+ +Given all this, what can you expect from CodeMirror 2?
+ +iframe
nodes aren't
+really known for respecting document flow. Now that an editor instance
+is a plain div
element, it is much easier to size it to
+fit the surrounding elements. You don't even have to make it scroll if
+you do not want to.On the downside, a CodeMirror 2 instance is not a native +editable component. Though it does its best to emulate such a +component as much as possible, there is functionality that browsers +just do not allow us to hook into. Doing select-all from the context +menu, for example, is not currently detected by CodeMirror.
+ +[Updates from November 13th 2011] Recently, I've made +some changes to the codebase that cause some of the text above to no +longer be current. I've left the text intact, but added markers at the +passages that are now inaccurate. The new situation is described +below.
+ +The original implementation of CodeMirror 2 represented the
+document as a flat array of line objects. This worked well—splicing
+arrays will require the part of the array after the splice to be
+moved, but this is basically just a simple memmove
of a
+bunch of pointers, so it is cheap even for huge documents.
However, I recently added line wrapping and code folding (line +collapsing, basically). Once lines start taking up a non-constant +amount of vertical space, looking up a line by vertical position +(which is needed when someone clicks the document, and to determine +the visible part of the document during scrolling) can only be done +with a linear scan through the whole array, summing up line heights as +you go. Seeing how I've been going out of my way to make big documents +fast, this is not acceptable.
+ +The new representation is based on a B-tree. The leaves of the tree +contain arrays of line objects, with a fixed minimum and maximum size, +and the non-leaf nodes simply hold arrays of child nodes. Each node +stores both the amount of lines that live below them and the vertical +space taken up by these lines. This allows the tree to be indexed both +by line number and by vertical position, and all access has +logarithmic complexity in relation to the document size.
+ +I gave line objects and tree nodes parent pointers, to the node +above them. When a line has to update its height, it can simply walk +these pointers to the top of the tree, adding or subtracting the +difference in height from each node it encounters. The parent pointers +also make it cheaper (in complexity terms, the difference is probably +tiny in normal-sized documents) to find the current line number when +given a line object. In the old approach, the whole document array had +to be searched. Now, we can just walk up the tree and count the sizes +of the nodes coming before us at each level.
+ +I chose B-trees, not regular binary trees, mostly because they +allow for very fast bulk insertions and deletions. When there is a big +change to a document, it typically involves adding, deleting, or +replacing a chunk of subsequent lines. In a regular balanced tree, all +these inserts or deletes would have to be done separately, which could +be really expensive. In a B-tree, to insert a chunk, you just walk +down the tree once to find where it should go, insert them all in one +shot, and then break up the node if needed. This breaking up might +involve breaking up nodes further up, but only requires a single pass +back up the tree. For deletion, I'm somewhat lax in keeping things +balanced—I just collapse nodes into a leaf when their child count goes +below a given number. This means that there are some weird editing +patterns that may result in a seriously unbalanced tree, but even such +an unbalanced tree will perform well, unless you spend a day making +strangely repeating edits to a really big document.
+ +Above, I claimed that directly catching key +events for things like cursor movement is impractical because it +requires some browser-specific kludges. I then proceeded to explain +some awful hacks that were needed to make it +possible for the selection changes to be detected through the +textarea. In fact, the second hack is about as bad as the first.
+ +On top of that, in the presence of user-configurable tab sizes and +collapsed and wrapped lines, lining up cursor movement in the textarea +with what's visible on the screen becomes a nightmare. Thus, I've +decided to move to a model where the textarea's selection is no longer +depended on.
+ +So I moved to a model where all cursor movement is handled by my +own code. This adds support for a goal column, proper interaction of +cursor movement with collapsed lines, and makes it possible for +vertical movement to move through wrapped lines properly, instead of +just treating them like non-wrapped lines.
+ +The key event handlers now translate the key event into a string,
+something like Ctrl-Home
or Shift-Cmd-R
, and
+use that string to look up an action to perform. To make keybinding
+customizable, this lookup goes through
+a table, using a scheme that
+allows such tables to be chained together (for example, the default
+Mac bindings fall through to a table named 'emacsy', which defines
+basic Emacs-style bindings like Ctrl-F
, and which is also
+used by the custom Emacs bindings).
A new
+option extraKeys
+allows ad-hoc keybindings to be defined in a much nicer way than what
+was possible with the
+old onKeyEvent
+callback. You simply provide an object mapping key identifiers to
+functions, instead of painstakingly looking at raw key events.
Built-in commands map to strings, rather than functions, for
+example "goLineUp"
is the default action bound to the up
+arrow key. This allows new keymaps to refer to them without
+duplicating any code. New commands can be defined by assigning to
+the CodeMirror.commands
object, which maps such commands
+to functions.
The hidden textarea now only holds the current selection, with no +extra characters around it. This has a nice advantage: polling for +input becomes much, much faster. If there's a big selection, this text +does not have to be read from the textarea every time—when we poll, +just noticing that something is still selected is enough to tell us +that no new text was typed.
+ +The reason that cheap polling is important is that many browsers do
+not fire useful events on IME (input method engine) input, which is
+the thing where people inputting a language like Japanese or Chinese
+use multiple keystrokes to create a character or sequence of
+characters. Most modern browsers fire input
when the
+composing is finished, but many don't fire anything when the character
+is updated during composition. So we poll, whenever the
+editor is focused, to provide immediate updates of the display.
+/* User manual and + reference guide */ ++
CodeMirror is a code-editor component that can be embedded in + Web pages. The core library provides only the editor + component, no accompanying buttons, auto-completion, or other IDE + functionality. It does provide a rich API on top of which such + functionality can be straightforwardly implemented. See + the add-ons included in the distribution, + and + the CodeMirror + UI project, for reusable implementations of extra features.
+ +CodeMirror works with language-specific modes. Modes are
+ JavaScript programs that help color (and optionally indent) text
+ written in a given language. The distribution comes with a number
+ of modes (see the mode/
+ directory), and it isn't hard to write new
+ ones for other languages.
The easiest way to use CodeMirror is to simply load the script
+ and style sheet found under lib/
in the distribution,
+ plus a mode script from one of the mode/
directories.
+ (See the compression helper for an
+ easy way to combine scripts.) For example:
<script src="lib/codemirror.js"></script> +<link rel="stylesheet" href="../lib/codemirror.css"> +<script src="mode/javascript/javascript.js"></script>+ +
Having done this, an editor instance can be created like + this:
+ +var myCodeMirror = CodeMirror(document.body);+ +
The editor will be appended to the document body, will start
+ empty, and will use the mode that we loaded. To have more control
+ over the new editor, a configuration object can be passed
+ to CodeMirror
as a second argument:
var myCodeMirror = CodeMirror(document.body, { + value: "function myScript(){return 100;}\n", + mode: "javascript" +});+ +
This will initialize the editor with a piece of code already in + it, and explicitly tell it to use the JavaScript mode (which is + useful when multiple modes are loaded). + See below for a full discussion of the + configuration options that CodeMirror accepts.
+ +In cases where you don't want to append the editor to an
+ element, and need more control over the way it is inserted, the
+ first argument to the CodeMirror
function can also
+ be a function that, when given a DOM element, inserts it into the
+ document somewhere. This could be used to, for example, replace a
+ textarea with a real editor:
var myCodeMirror = CodeMirror(function(elt) { + myTextArea.parentNode.replaceChild(elt, myTextArea); +}, {value: myTextArea.value});+ +
However, for this use case, which is a common way to use + CodeMirror, the library provides a much more powerful + shortcut:
+ +var myCodeMirror = CodeMirror.fromTextArea(myTextArea);+ +
This will, among other things, ensure that the textarea's value + is updated with the editor's contents when the form (if it is part + of a form) is submitted. See the API + reference for a full description of this method.
+ +Both the CodeMirror
function and
+ its fromTextArea
method take as second (optional)
+ argument an object containing configuration options. Any option
+ not supplied like this will be taken
+ from CodeMirror.defaults
, an object containing the
+ default options. You can update this object to change the defaults
+ on your page.
Options are not checked in any way, so setting bogus option + values is bound to lead to odd errors.
+ +These are the supported options:
+ +value (string or Doc)
mode (string or object)
name
property that names the mode (for
+ example {name: "javascript", json: true}
). The demo
+ pages for each mode contain information about what configuration
+ parameters the mode supports. You can ask CodeMirror which modes
+ and MIME types have been defined by inspecting
+ the CodeMirror.modes
+ and CodeMirror.mimeModes
objects. The first maps
+ mode names to their constructors, and the second maps MIME types
+ to mode specs.theme (string)
.cm-s-[name]
+ styles is loaded (see
+ the theme
directory in the
+ distribution). The default is "default"
, for which
+ colors are included in codemirror.css
. It is
+ possible to use multiple theming classes at once—for
+ example "foo bar"
will assign both
+ the cm-s-foo
and the cm-s-bar
classes
+ to the editor.indentUnit (integer)
smartIndent (boolean)
tabSize (integer)
indentWithTabs (boolean)
tabSize
+ spaces should be replaced by N tabs. Default is false.electricChars (boolean)
rtlMoveVisually (boolean)
false
+ on Windows, and true
on other platforms.keyMap (string)
"default"
, which is the only keymap defined
+ in codemirror.js
itself. Extra keymaps are found in
+ the keymap
directory. See
+ the section on keymaps for more
+ information.extraKeys (object)
keyMap
. Should be
+ either null, or a valid keymap value.lineWrapping (boolean)
false
(scroll).lineNumbers (boolean)
firstLineNumber (integer)
lineNumberFormatter (function)
gutters (array)
width
(and optionally a
+ background), and which will be used to draw the background of
+ the gutters. May include
+ the CodeMirror-linenumbers
class, in order to
+ explicitly set the position of the line number gutter (it will
+ default to be to the right of all other gutters). These class
+ names are the keys passed
+ to setGutterMarker
.fixedGutter (boolean)
readOnly (boolean)
"nocursor"
is given (instead of
+ simply true
), focusing of the editor is also
+ disallowed.showCursorWhenSelecting (boolean)
undoDepth (integer)
tabindex (integer)
autofocus (boolean)
fromTextArea
is
+ used, and no explicit value is given for this option, it will be
+ set to true when either the source textarea is focused, or it
+ has an autofocus
attribute and no other element is
+ focused.Below this a few more specialized, low-level options are + listed. These are only useful in very specific situations, you + might want to skip them the first time you read this manual.
+ +dragDrop (boolean)
onDragEvent (function)
dragenter
, dragover
,
+ or drop
event. It will be passed the editor instance
+ and the event object as arguments. The callback can choose to
+ handle the event itself, in which case it should
+ return true
to indicate that CodeMirror should not
+ do anything further.onKeyEvent (function)
keydown
, keyup
,
+ and keypress
event that CodeMirror captures. It
+ will be passed two arguments, the editor instance and the key
+ event. This key event is pretty much the raw key event, except
+ that a stop()
method is always added to it. You
+ could feed it to, for example, jQuery.Event
to
+ further normalize it.keydown
does not stop
+ the keypress
from firing, whereas on others it
+ does. If you respond to an event, you should probably inspect
+ its type
property and only do something when it
+ is keydown
(or keypress
for actions
+ that need character data).cursorBlinkRate (number)
cursorHeight (number)
0.85
),
+ which causes the cursor to not reach all the way to the bottom
+ of the line, looks betterworkTime, workDelay (number)
workTime
milliseconds, and then use
+ timeout to sleep for workDelay
milliseconds. The
+ defaults are 200 and 300, you can change these options to make
+ the highlighting more or less aggressive.pollInterval (number)
flattenSpans (boolean)
viewportMargin (integer)
Infinity
to make sure the whole document is
+ always rendered, and thus the browser's text search works on it.
+ This will have bad effects on performance of big
+ documents.A CodeMirror instance emits a number of events, which allow
+ client code to react to various situations. These are registered
+ with the on
method (and
+ removed with the off
+ method). These are the events that fire on the instance object.
+ The name of the event is followed by the arguments that will be
+ passed to the handler. The instance
argument always
+ refers to the editor instance.
"change" (instance, changeObj)
changeObj
is a {from, to, text,
+ next}
object containing information about the changes
+ that occurred as second argument. from
+ and to
are the positions (in the pre-change
+ coordinate system) where the change started and ended (for
+ example, it might be {ch:0, line:18}
if the
+ position is at the beginning of line #19). text
is
+ an array of strings representing the text that replaced the
+ changed range (split by line). If multiple changes happened
+ during a single operation, the object will have
+ a next
property pointing to another change object
+ (which may point to another, etc)."beforeChange" (instance, change)
change
object
+ has from
, to
, and text
+ properties, as with
+ the "change"
event, but
+ never a next
property, since this is fired for each
+ individual change, and not batched per operation. It also
+ has update(from, to, text)
+ and cancel()
methods, which may be used to modify
+ or cancel the change. All three arguments to update
+ are optional, and can be left off to leave the existing value
+ for that field intact. Note: you may not do
+ anything from a "beforeChange"
handler that would
+ cause changes to the document or its visualization. Doing so
+ will, since this handler is called directly from the bowels of
+ the CodeMirror implementation, probably cause the editor to
+ become corrupted."cursorActivity" (instance)
"beforeSelectionChange" (instance, selection)
selection
parameter is an object
+ with head
and anchor
properties
+ holding {line, ch}
objects, which the handler can
+ read and update. Handlers for this event have the same
+ restriction
+ as "beforeChange"
+ handlers — they should not do anything to directly update the
+ state of the editor."viewportChange" (instance, from, to)
from
and to
arguments
+ give the new start and end of the viewport."gutterClick" (instance, line, gutter, clickEvent)
mousedown
event object as
+ fourth argument."focus", "blur" (instance)
"scroll" (instance)
"update" (instance)
It is also possible to register events on
+ other objects. Use CodeMirror.on(handle, "eventName",
+ func)
to register handlers on objects that don't have their
+ own on
method. Document objects (instances
+ of CodeMirror.Doc
) emit the
+ following events:
"change" (doc, changeObj)
changeObj
has a similar type as the
+ object passed to the
+ editor's "change"
+ event, but it never has a next
property, because
+ document change events are not batched (whereas editor change
+ events are)."beforeChange" (doc, change)
"cursorActivity" (doc)
"beforeSelectionChange" (doc, selection)
Line handles (as returned by, for
+ example, getLineHandle
)
+ support these events:
"delete" ()
"change" ()
Marked range handles, as returned
+ by markText
+ and setBookmark
, emit the
+ following events:
"clear" ()
clearOnEnter
+ or through a call to its clear()
method. Will only
+ be fired once per handle. Note that deleting the range through
+ text editing does not fire this event, because an undo
+ action might bring the range back into existence."hide" ()
"unhide" ()
Line widgets, returned
+ by addLineWidget
, fire
+ these events:
"redraw" ()
Keymaps are ways to associate keys with functionality. A keymap + is an object mapping strings that identify the keys to functions + that implement their functionality.
+ +Keys are identified either by name or by character.
+ The CodeMirror.keyNames
object defines names for
+ common keys and associates them with their key codes. Examples of
+ names defined here are Enter
, F5
,
+ and Q
. These can be prefixed
+ with Shift-
, Cmd-
, Ctrl-
,
+ and Alt-
(in that order!) to specify a modifier. So
+ for example, Shift-Ctrl-Space
would be a valid key
+ identifier.
Alternatively, a character can be specified directly by
+ surrounding it in single quotes, for example '$'
+ or 'q'
. Due to limitations in the way browsers fire
+ key events, these may not be prefixed with modifiers.
The CodeMirror.keyMap
object associates keymaps
+ with names. User code and keymap definitions can assign extra
+ properties to this object. Anywhere where a keymap is expected, a
+ string can be given, which will be looked up in this object. It
+ also contains the "default"
keymap holding the
+ default bindings.
The values of properties in keymaps can be either functions of
+ a single argument (the CodeMirror instance), strings, or
+ false
. Such strings refer to properties of the
+ CodeMirror.commands
object, which defines a number of
+ common commands that are used by the default keybindings, and maps
+ them to functions. If the property is set to false
,
+ CodeMirror leaves handling of the key up to the browser. A key
+ handler function may return CodeMirror.Pass
to indicate
+ that it has decided not to handle the key, and other handlers (or
+ the default behavior) should be given a turn.
Keys mapped to command names that start with the
+ characters "go"
(which should be used for
+ cursor-movement actions) will be fired even when an
+ extra Shift
modifier is present (i.e. "Up":
+ "goLineUp"
matches both up and shift-up). This is used to
+ easily implement shift-selection.
Keymaps can defer to each other by defining
+ a fallthrough
property. This indicates that when a
+ key is not found in the map itself, one or more other maps should
+ be searched. It can hold either a single keymap or an array of
+ keymaps.
When a keymap contains a nofallthrough
property
+ set to true
, keys matched against that map will be
+ ignored if they don't match any of the bindings in the map (no
+ further child maps will be tried, and the default effect of
+ inserting a character will not occur).
Up to a certain extent, CodeMirror's look can be changed by
+ modifying style sheet files. The style sheets supplied by modes
+ simply provide the colors for that mode, and can be adapted in a
+ very straightforward way. To style the editor itself, it is
+ possible to alter or override the styles defined
+ in codemirror.css
.
Some care must be taken there, since a lot of the rules in this + file are necessary to have CodeMirror function properly. Adjusting + colors should be safe, of course, and with some care a lot of + other things can be changed as well. The CSS classes defined in + this file serve the following roles:
+ +CodeMirror
CodeMirror-scroll
overflow: auto
+
+ fixed height). By default, it does. Setting
+ the CodeMirror
class to have height:
+ auto
and giving this class overflow-x: auto;
+ overflow-y: hidden;
will cause the editor
+ to resize to fit its
+ content.CodeMirror-focused
CodeMirror-gutters
CodeMirror-linenumbers
CodeMirror-linenumber
CodeMirror-linenumbers
+ (plural) element, but rather will be absolutely positioned to
+ overlay it. Use this to set alignment and text properties for
+ the line numbers.CodeMirror-lines
CodeMirror-cursor
CodeMirror-selected
span
elements
+ with this class.CodeMirror-matchingbracket
,
+ CodeMirror-nonmatchingbracket
If your page's style sheets do funky things to
+ all div
or pre
elements (you probably
+ shouldn't do that), you'll have to define rules to cancel these
+ effects out again for elements under the CodeMirror
+ class.
Themes are also simply CSS files, which define colors for
+ various syntactic elements. See the files in
+ the theme
directory.
A lot of CodeMirror features are only available through its + API. Thus, you need to write code (or + use add-ons) if you want to expose them to + your users.
+ +Whenever points in the document are represented, the API uses
+ objects with line
and ch
properties.
+ Both are zero-based. CodeMirror makes sure to 'clip' any positions
+ passed by client code so that they fit inside the document, so you
+ shouldn't worry too much about sanitizing your coordinates. If you
+ give ch
a value of null
, or don't
+ specify it, it will be replaced with the length of the specified
+ line.
Methods prefixed with doc.
can, unless otherwise
+ specified, be called both on CodeMirror
(editor)
+ instances and CodeMirror.Doc
instances. Methods
+ prefixed with cm.
are only available
+ on CodeMirror
instances.
doc.getValue() → string
"\n"
).doc.setValue(string)
doc.getRange(from, to) → string
{line, ch}
objects. An optional third
+ argument can be given to indicate the line separator string to
+ use (defaults to "\n"
).doc.replaceRange(string, from, to)
from
+ and to
with the given string. from
+ and to
must be {line, ch}
+ objects. to
can be left off to simply insert the
+ string at position from
.doc.getLine(n) → string
n
.doc.setLine(n, text)
n
.doc.removeLine(n)
doc.lineCount() → number
doc.firstLine() → number
doc.lastLine() → number
doc.lineCount() - 1
respectively,
+ but for linked sub-views,
+ or documents instantiated with a non-zero
+ first line, it might return other values.doc.getLineHandle(num) → lineHandle
doc.getLineNumber(handle) → integer
null
when it is no longer in the
+ document).doc.eachLine(f) | doc.eachLine(start, end, f)
start
+ and end
line numbers are given, the range
+ from start
up to (not including) end
,
+ and call f
for each line, passing the line handle.
+ This is a faster way to visit a range of line handlers than
+ calling getLineHandle
+ for each of them. Note that line handles have
+ a text
property containing the line's content (as a
+ string).doc.markClean()
doc.isClean() → boolean
markClean
).doc.getSelection() → string
doc.replaceSelection(string)
doc.getCursor(start) → object
start
is a an optional string indicating which
+ end of the selection to return. It may
+ be "start"
, "end"
, "head"
+ (the side of the selection that moves when you press
+ shift+arrow), or "anchor"
(the fixed side of the
+ selection). Omitting the argument is the same as
+ passing "head"
. A {line, ch}
object
+ will be returned.doc.somethingSelected() → boolean
doc.setCursor(pos)
{line, ch}
object, or the line and the
+ character as two separate parameters.doc.setSelection(anchor, head)
anchor
+ and head
should be {line, ch}
+ objects. head
defaults to anchor
when
+ not given.doc.extendSelection(pos, pos2)
setSelection
, but
+ will, if shift is held or
+ the extending flag is set, move the
+ head of the selection while leaving the anchor at its current
+ place. pos2
is optional, and can be passed to
+ ensure a region (for example a word or paragraph) will end up
+ selected (in addition to whatever lies between that region and
+ the current anchor).doc.setExtending(bool)
extendSelection
+ to leave the selection anchor in place.cm.findPosH(start, amount, unit, visually) → object
start
is a {line, ch}
+ object, amount
an integer (may be negative),
+ and unit
one of the
+ string "char"
, "column"
,
+ or "word"
. Will return a position that is produced
+ by moving amount
times the distance specified
+ by unit
. When visually
is true, motion
+ in right-to-left text will be visual rather than logical. When
+ the motion was clipped by hitting the end or start of the
+ document, the returned value will have a hitSide
+ property set to true.cm.findPosV(start, amount, unit) → object
findPosH
,
+ but used for vertical motion. unit
may
+ be "line"
or "page"
. The other
+ arguments and the returned value have the same interpretation as
+ they have in findPosH
.cm.setOption(option, value)
option
+ should the name of an option,
+ and value
should be a valid value for that
+ option.cm.getOption(option) → value
cm.addKeyMap(map)
extraKeys
+ option. Maps added in this way have a lower precedence
+ than extraKeys
, a higher precedence than the
+ base keyMap
, and
+ between them, the maps added earlier have a higher precedence
+ than those added later.cm.removeKeyMap(map)
addKeyMap
. Either
+ pass in the keymap object itself, or a string, which will be
+ compared against the name
property of the active
+ keymaps.cm.addOverlay(mode, options)
mode
can be a mode
+ spec or a mode object (an object with
+ a token
method).
+ The option
parameter is optional. If given it
+ should be an object. Currently, only the opaque
+ option is recognized. This defaults to off, but can be given to
+ allow the overlay styling, when not null
, to
+ override the styling of the base mode entirely, instead of the
+ two being applied together.cm.removeOverlay(mode)
mode
parameter
+ to addOverlay
to remove
+ an overlay again.cm.on(type, func)
CodeMirror.on(object, type, func)
version
+ that allows registering of events on any object.cm.off(type, func)
CodeMirror.off(object, type,
+ func)
also exists.Each editor is associated with an instance
+ of CodeMirror.Doc
, its document. A document
+ represents the editor content, plus a selection, an undo history,
+ and a mode. A document can only be
+ associated with a single editor at a time. You can create new
+ documents by calling the CodeMirror.Doc(text, mode,
+ firstLineNumber)
constructor. The last two arguments are
+ optional and can be used to set a mode for the document and make
+ it start at a line number other than 0, respectively.
cm.getDoc() → doc
doc.getEditor() → editor
null
.cm.swapDoc(doc) → doc
doc.copy(copyHistory) → doc
copyHistory
is true, the history will also be
+ copied. Can not be called directly on an editor.doc.linkedDoc(options) → doc
from, to (integer)
mode (mode spec)
doc.unlinkDoc(doc)
doc.iterLinkedDocs(function)
doc.undo()
doc.redo()
doc.historySize() → object
{undo, redo}
properties,
+ both of which hold integers, indicating the amount of stored
+ undo and redo operations.doc.clearHistory()
doc.getHistory() → object
doc.setHistory(object)
getHistory
. Note that
+ this will have entirely undefined results if the editor content
+ isn't also the same as it was when getHistory
was
+ called.doc.markText(from, to, options) → object
from
and to
should
+ be {line, ch}
objects. The options
+ parameter is optional. When given, it should be an object that
+ may contain the following configuration options:
+ className (string)
inclusiveLeft (boolean)
inclusiveRight
(boolean)inclusiveLeft
,
+ but for the right side.atomic (boolean)
inclusiveLeft
+ and inclusiveRight
have a different meaning—they
+ will prevent the cursor from being placed respectively
+ directly before and directly after the range.collapsed (boolean)
clearOnEnter (boolean)
"clear"
event
+ fired on the range handle can be used to be notified when this
+ happens.replacedWith (dom node)
readOnly
setValue
to reset
+ the whole document. Note: adding a read-only span
+ currently clears the undo history of the editor, because
+ existing undo events being partially nullified by read-only
+ spans would corrupt the history (in the current
+ implementation).startStyle
endStyle
startStyle
, but for the rightmost span.shared
to true to make the
+ marker appear in all documents. By default, a marker appears
+ only in its target document.CodeMirror.TextMarker
), which
+ exposes three methods:
+ clear()
, to remove the mark,
+ find()
, which returns a {from, to}
+ object (both holding document positions), indicating the current
+ position of the marked range, or undefined
if the
+ marker is no longer in the document, and
+ finally getOptions(copyWidget)
, which returns an
+ object representing the options for the marker.
+ If copyWidget
is given an true, it will clone the
+ value of
+ the replacedWith
+ option, if any.doc.setBookmark(pos, options) → object
find()
and clear()
. The first
+ returns the current position of the bookmark, if it is still in
+ the document, and the second explicitly removes the bookmark.
+ The options argument is optional. If given, the following
+ properties are recognized:
+ widget
replacedWith
+ option to markText
).insertLeft
doc.findMarksAt(pos) → array
doc.getAllMarks() → array
cm.setGutterMarker(line, gutterID, value) → lineHandle
gutters
option)
+ to the given value. Value can be either null
, to
+ clear the marker, or a DOM element, to set it. The DOM element
+ will be shown in the specified gutter next to the specified
+ line.cm.clearGutter(gutterID)
cm.addLineClass(line, where, class) → lineHandle
line
+ can be a number or a line handle. where
determines
+ to which element this class should be applied, can can be one
+ of "text"
(the text element, which lies in front of
+ the selection), "background"
(a background element
+ that will be behind the selection), or "wrap"
(the
+ wrapper node that wraps all of the line's elements, including
+ gutter elements). class
should be the name of the
+ class to apply.cm.removeLineClass(line, where, class) → lineHandle
line
can be a
+ line handle or number. where
should be one
+ of "text"
, "background"
,
+ or "wrap"
+ (see addLineClass
). class
+ can be left off to remove all classes for the specified node, or
+ be a string to remove only a specific class.cm.lineInfo(line) → object
{line, handle, text,
+ gutterMarkers, textClass, bgClass, wrapClass, widgets}
,
+ where gutterMarkers
is an object mapping gutter IDs
+ to marker elements, and widgets
is an array
+ of line widgets attached to this
+ line, and the various class properties refer to classes added
+ with addLineClass
.cm.addWidget(pos, node, scrollIntoView)
node
, which should be an absolutely
+ positioned DOM node, into the editor, positioned right below the
+ given {line, ch}
position.
+ When scrollIntoView
is true, the editor will ensure
+ that the entire node is visible (if possible). To remove the
+ widget again, simply use DOM methods (move it somewhere else, or
+ call removeChild
on its parent).cm.addLineWidget(line, node, options) → object
line
should be either an integer or a
+ line handle, and node
should be a DOM node, which
+ will be displayed below the given line. options
,
+ when given, should be an object that configures the behavior of
+ the widget. The following options are supported (all default to
+ false):
+ coverGutter (boolean)
noHScroll (boolean)
above (boolean)
showIfHidden (boolean)
line
property
+ pointing at the line handle that it is associated with, and the following methods:
+ clear()
changed()
cm.setSize(width, height)
width
and height
height
+ can be either numbers (interpreted as pixels) or CSS units
+ ("100%"
, for example). You can
+ pass null
for either of them to indicate that that
+ dimension should not be changed.cm.scrollTo(x, y)
null
+ or undefined
to have no effect.cm.getScrollInfo()
{left, top, width, height, clientWidth,
+ clientHeight}
object that represents the current scroll
+ position, the size of the scrollable area, and the size of the
+ visible area (minus scrollbars).cm.scrollIntoView(pos)
pos
may be
+ either a {line, ch}
position, referring to a given
+ character, null
, to refer to the cursor, or
+ a {left, top, right, bottom}
object, in
+ editor-local coordinates.cm.cursorCoords(where, mode) → object
{left, top, bottom}
object
+ containing the coordinates of the cursor position.
+ If mode
is "local"
, they will be
+ relative to the top-left corner of the editable document. If it
+ is "page"
or not given, they are relative to the
+ top-left corner of the page. where
can be a boolean
+ indicating whether you want the start (true
) or the
+ end (false
) of the selection, or, if a {line,
+ ch}
object is given, it specifies the precise position at
+ which you want to measure.cm.charCoords(pos, mode) → object
pos
should be a {line, ch}
+ object. This differs from cursorCoords
in that
+ it'll give the size of the whole character, rather than just the
+ position that the cursor would have when it would sit at that
+ position.cm.coordsChar(object) → pos
{left, top}
object (in page coordinates),
+ returns the {line, ch}
position that corresponds to
+ it.cm.defaultTextHeight() → number
cm.getViewport() → object
{from, to}
object indicating the
+ start (inclusive) and end (exclusive) of the currently rendered
+ part of the document. In big documents, when most content is
+ scrolled out of view, CodeMirror will only render the visible
+ part, and a margin around it. See also
+ the viewportChange
+ event.cm.refresh()
When writing language-aware functionality, it can often be + useful to hook into the knowledge thate the CodeMirror language + mode has. See the section on modes for a + more detailed description of how these work.
+ +doc.getMode() → object
getOption("mode")
, which gives you
+ the mode specification, rather than the resolved, instantiated
+ mode object.cm.getTokenAt(pos) → object
{line, ch}
object). The
+ returned object has the following properties:
+ start
end
string
type
"keyword"
+ or "comment"
(may also be null).state
cm.getStateAfter(line) → state
cm.operation(func) → result
cm.indentLine(line, dir)
"smart"
) may be one of:
+ "prev"
"smart"
"prev"
otherwise."add"
"subtract"
doc.posFromIndex(index) → object
{line, ch}
object for a
+ zero-based index
who's value is relative to the start of the
+ editor's text. If the index
is out of range of the text then
+ the returned object is clipped to start or end of the text
+ respectively.doc.indexFromPos(object) → number
posFromIndex
.cm.focus()
cm.getInputField() → textarea
cm.getWrapperElement() → node
cm.getScrollerElement() → node
cm.getGutterElement() → node
The CodeMirror
object itself provides
+ several useful properties. Firstly, its version
+ property contains a string that indicates the version of the
+ library. For releases, this simply
+ contains "major.minor"
(for
+ example "2.33"
. For beta versions, " B"
+ (space, capital B) is added at the end of the string, for
+ development snapshots, " +"
(space, plus) is
+ added.
The CodeMirror.fromTextArea
+ method provides another way to initialize an editor. It takes a
+ textarea DOM node as first argument and an optional configuration
+ object as second. It will replace the textarea with a CodeMirror
+ instance, and wire up the form of that textarea (if any) to make
+ sure the editor contents are put into the textarea when the form
+ is submitted. A CodeMirror instance created this way has three
+ additional methods:
cm.save()
cm.toTextArea()
cm.getTextArea() → textarea
If you want to define extra methods in terms
+ of the CodeMirror API, it is possible to
+ use CodeMirror.defineExtension(name, value)
. This
+ will cause the given value (usually a method) to be added to all
+ CodeMirror instances created from then on.
Similarly, CodeMirror.defineOption(name,
+ default, updateFunc)
can be used to define new options for
+ CodeMirror. The updateFunc
will be called with the
+ editor instance and the new value when an editor is initialized,
+ and whenever the option is modified
+ through setOption
.
If your extention just needs to run some
+ code whenever a CodeMirror instance is initialized,
+ use CodeMirror.defineInitHook
. Give it a function as
+ its only argument, and from then on, that function will be called
+ (with the instance as argument) whenever a new CodeMirror instance
+ is initialized.
The addon
directory in the distribution contains a
+ number of reusable components that implement extra editor
+ functionality. In brief, they are:
dialog/dialog.js
openDialog
method to CodeMirror instances,
+ which can be called with an HTML fragment that provides the
+ prompt (should include an input
tag), and a
+ callback function that is called when text has been entered.
+ Depends on addon/dialog/dialog.css
.search/searchcursor.js
getSearchCursor(query, start, caseFold) →
+ cursor
method to CodeMirror instances, which can be used
+ to implement search/replace functionality. query
+ can be a regular expression or a string (only strings will match
+ across lines—if they contain newlines). start
+ provides the starting position of the search. It can be
+ a {line, ch}
object, or can be left off to default
+ to the start of the document. caseFold
is only
+ relevant when matching a string. It will cause the search to be
+ case-insensitive. A search cursor has the following methods:
+ findNext(), findPrevious() → boolean
match
method, in case you
+ want to extract matched groups.from(), to() → object
findNext
or findPrevious
did
+ not return false. They will return {line, ch}
+ objects pointing at the start and end of the match.replace(text)
search/search.js
searchcursor.js
, and will make use
+ of openDialog
when
+ available to make prompting for search queries less ugly.edit/matchbrackets.js
matchBrackets
which, when set
+ to true, causes matching brackets to be highlighted whenever the
+ cursor is next to them. It also adds a
+ method matchBrackets
that forces this to happen
+ once, and a method findMatchingBracket
that can be
+ used to run the bracket-finding algorithm that this uses
+ internally.edit/closebrackets.js
autoCloseBrackets
that will
+ auto-close brackets and quotes when typed. By default, it'll
+ auto-close ()[]{}''""
, but you can pass it a
+ string similar to that (containing pairs of matching characters)
+ to customize it. Demo
+ here.fold/foldcode.js
CodeMirror.newFoldFunction
with a range-finder
+ helper function to create a function that will, when applied to
+ a CodeMirror instance and a line number, attempt to fold or
+ unfold the block starting at the given line. A range-finder is a
+ language-specific function that also takes an instance and a
+ line number, and returns an range to be folded, or null if
+ no block is started on that line. This file
+ provides CodeMirror.braceRangeFinder
, which finds
+ blocks in brace languages (JavaScript, C, Java,
+ etc), CodeMirror.indentRangeFinder
, for languages
+ where indentation determines block structure (Python, Haskell),
+ and CodeMirror.tagRangeFinder
, for XML-style
+ languages.fold/collapserange.js
runmode/runmode.js
mode/overlay.js
CodeMirror.overlayMode
, which is used to
+ create such a mode. See this
+ demo for a detailed example.mode/multiplex.js
CodeMirror.multiplexingMode
which, when
+ given as first argument a mode object, and as other arguments
+ any number of {open, close, mode [, delimStyle]}
+ objects, will return a mode object that starts parsing using the
+ mode passed as first argument, but will switch to another mode
+ as soon as it encounters a string that occurs in one of
+ the open
fields of the passed objects. When in a
+ sub-mode, it will go back to the top mode again when
+ the close
string is encountered.
+ Pass "\n"
for open
or close
+ if you want to switch on a blank line.
+ When delimStyle
is specified, it will be the token
+ style returned for the delimiter tokens. The outer mode will not
+ see the content between the delimiters.
+ See this demo for an
+ example.hint/show-hint.js
CodeMirror.showHint
, which takes a
+ CodeMirror instance and a hinting function, and pops up a widget
+ that allows the user to select a completion. Hinting functions
+ are function that take an editor instance, and return
+ a {list, from, to}
object, where list
+ is an array of strings (the completions), and from
+ and to
give the start and end of the token that is
+ being completed. Depends
+ on addon/hint/show-hint.css
. See the other files in
+ the addon/hint
for
+ hint sources for various languages. Check
+ out the demo for an
+ example.match-highlighter.js
highlightSelectionMatches
option that
+ can be enabled to highlight all instances of a currently
+ selected word.
+ Demo here.lint/lint.js
json-lint.js
+ and javascript-lint.js
+ in the same directory). Defines a lintWith
option
+ that can be set to a warning source (for
+ example CodeMirror.javascriptValidator
). Depends
+ on addon/lint/lint.css
. A demo can be
+ found here.selection/mark-selection.js
CodeMirror-selectedtext
when the styleSelectedText
option
+ is enabled. Useful to change the colour of the selection (in addition to the background),
+ like in this demo.selection/active-line.js
styleActiveLine
option that, when enabled,
+ gives the wrapper of the active line the class CodeMirror-activeline
,
+ and adds a background with the class CodeMirror-activeline-background
.
+ is enabled. See the demo.edit/closetag.js
mode/loadmode.js
CodeMirror.requireMode(modename,
+ callback)
function that will try to load a given mode and
+ call the callback when it succeeded. You'll have to
+ set CodeMirror.modeURL
to a string that mode paths
+ can be constructed from, for
+ example "mode/%N/%N.js"
—the %N
's will
+ be replaced with the mode name. Also
+ defines CodeMirror.autoLoadMode(instance, mode)
,
+ which will ensure the given mode is loaded and cause the given
+ editor instance to refresh its mode when the loading
+ succeeded. See the demo.edit/continuecomment.js
newlineAndIndentContinueComment
that you can
+ bind Enter
to in order to have the editor prefix
+ new lines inside C-like block comments with an asterisk.Modes typically consist of a single JavaScript file. This file + defines, in the simplest case, a lexer (tokenizer) for your + language—a function that takes a character stream as input, + advances it past a token, and returns a style for that token. More + advanced modes can also handle indentation for the language.
+ +The mode script should
+ call CodeMirror.defineMode
to register itself with
+ CodeMirror. This function takes two arguments. The first should be
+ the name of the mode, for which you should use a lowercase string,
+ preferably one that is also the name of the files that define the
+ mode (i.e. "xml"
is defined in xml.js
). The
+ second argument should be a function that, given a CodeMirror
+ configuration object (the thing passed to
+ the CodeMirror
function) and an optional mode
+ configuration object (as in
+ the mode
option), returns
+ a mode object.
Typically, you should use this second argument
+ to defineMode
as your module scope function (modes
+ should not leak anything into the global scope!), i.e. write your
+ whole mode inside this function.
The main responsibility of a mode script is parsing + the content of the editor. Depending on the language and the + amount of functionality desired, this can be done in really easy + or extremely complicated ways. Some parsers can be stateless, + meaning that they look at one element (token) of the code + at a time, with no memory of what came before. Most, however, will + need to remember something. This is done by using a state + object, which is an object that is always passed when + reading a token, and which can be mutated by the tokenizer.
+ +Modes that use a state must define
+ a startState
method on their mode object. This is a
+ function of no arguments that produces a state object to be used
+ at the start of a document.
The most important part of a mode object is
+ its token(stream, state)
method. All modes must
+ define this method. It should read one token from the stream it is
+ given as an argument, optionally update its state, and return a
+ style string, or null
for tokens that do not have to
+ be styled. For your styles, you are encouraged to use the
+ 'standard' names defined in the themes (without
+ the cm-
prefix). If that fails, it is also possible
+ to come up with your own and write your own CSS theme file.
+ +
The stream object that's passed
+ to token
encapsulates a line of code (tokens may
+ never span lines) and our current position in that line. It has
+ the following API:
eol() → boolean
sol() → boolean
peek() → character
null
at the end of the
+ line.next() → character
null
when no more characters are
+ available.eat(match) → character
match
can be a character, a regular expression,
+ or a function that takes a character and returns a boolean. If
+ the next character in the stream 'matches' the given argument,
+ it is consumed and returned. Otherwise, undefined
+ is returned.eatWhile(match) → boolean
eat
with the given argument,
+ until it fails. Returns true if any characters were eaten.eatSpace() → boolean
eatWhile
when matching
+ white-space.skipToEnd()
skipTo(ch) → boolean
match(pattern, consume, caseFold) → boolean
eat
—if consume
is true
+ or not given—or a look-ahead that doesn't update the stream
+ position—if it is false. pattern
can be either a
+ string or a regular expression starting with ^
.
+ When it is a string, caseFold
can be set to true to
+ make the match case-insensitive. When successfully matching a
+ regular expression, the returned value will be the array
+ returned by match
, in case you need to extract
+ matched groups.backUp(n)
n
characters. Backing it up
+ further than the start of the current token will cause things to
+ break, so be careful.column() → integer
indentation() → integer
current() → string
By default, blank lines are simply skipped when
+ tokenizing a document. For languages that have significant blank
+ lines, you can define a blankLine(state)
method on
+ your mode that will get called whenever a blank line is passed
+ over, so that it can update the parser state.
Because state object are mutated, and CodeMirror
+ needs to keep valid versions of a state around so that it can
+ restart a parse at any line, copies must be made of state objects.
+ The default algorithm used is that a new state object is created,
+ which gets all the properties of the old object. Any properties
+ which hold arrays get a copy of these arrays (since arrays tend to
+ be used as mutable stacks). When this is not correct, for example
+ because a mode mutates non-array properties of its state object, a
+ mode object should define a copyState
method,
+ which is given a state and should return a safe copy of that
+ state.
If you want your mode to provide smart indentation
+ (through the indentLine
+ method and the indentAuto
+ and newlineAndIndent
commands, to which keys can be
+ bound), you must define
+ an indent(state, textAfter)
method on your mode
+ object.
The indentation method should inspect the given state object,
+ and optionally the textAfter
string, which contains
+ the text on the line that is being indented, and return an
+ integer, the amount of spaces to indent. It should usually take
+ the indentUnit
+ option into account. An indentation method may
+ return CodeMirror.Pass
to indicate that it
+ could not come up with a precise indentation.
Finally, a mode may define
+ an electricChars
property, which should hold a string
+ containing all the characters that should trigger the behaviour
+ described for
+ the electricChars
+ option.
So, to summarize, a mode must provide
+ a token
method, and it may
+ provide startState
, copyState
,
+ and indent
methods. For an example of a trivial mode,
+ see the diff mode, for a more
+ involved example, see the C-like
+ mode.
Sometimes, it is useful for modes to nest—to have one
+ mode delegate work to another mode. An example of this kind of
+ mode is the mixed-mode HTML
+ mode. To implement such nesting, it is usually necessary to
+ create mode objects and copy states yourself. To create a mode
+ object, there are CodeMirror.getMode(options,
+ parserConfig)
, where the first argument is a configuration
+ object as passed to the mode constructor function, and the second
+ argument is a mode specification as in
+ the mode
option. To copy a
+ state object, call CodeMirror.copyState(mode, state)
,
+ where mode
is the mode that created the given
+ state.
In a nested mode, it is recommended to add an
+ extra methods, innerMode
which, given a state object,
+ returns a {state, mode}
object with the inner mode
+ and its state for the current position. These are used by utility
+ scripts such as the autoformatter
+ and the tag closer to get context
+ information. Use the CodeMirror.innerMode
helper
+ function to, starting from a mode and a state, recursively walk
+ down to the innermost mode and state.
To make indentation work properly in a nested parser, it is
+ advisable to give the startState
method of modes that
+ are intended to be nested an optional argument that provides the
+ base indentation for the block of code. The JavaScript and CSS
+ parser do this, for example, to allow JavaScript and CSS code
+ inside the mixed-mode HTML mode to be properly indented.
It is possible, and encouraged, to associate your mode, or a
+ certain configuration of your mode, with
+ a MIME type. For
+ example, the JavaScript mode associates itself
+ with text/javascript
, and its JSON variant
+ with application/json
. To do this,
+ call CodeMirror.defineMIME(mime, modeSpec)
,
+ where modeSpec
can be a string or object specifying a
+ mode, as in the mode
+ option.
Sometimes, it is useful to add or override mode
+ object properties from external code.
+ The CodeMirror.extendMode
can be used to add
+ properties to mode objects produced for a specific mode. Its first
+ argument is the name of the mode, its second an object that
+ specifies the properties that should be added. This is mostly
+ useful to add utilities that can later be looked
+ up through getMode
.
+/* Full list of + modes */ ++
Every mode in the distribution. The list on the front-page leaves +out some of the more obscure ones.
+ ++/* Old release + history */ ++
19-09-2012: Version 2.34:
+ +compareStates
is no longer needed.onHighlightComplete
no longer works.CodeMirror.version
property.19-09-2012: Version 3.0, beta 1:
+ +23-08-2012: Version 2.33:
+ +getViewPort
and onViewportChange
API.false
disabling handling (again).innerHTML
. Remove CodeMirror.htmlEscape
.23-07-2012: Version 2.32:
+ +Emergency fix for a bug where an editor with + line wrapping on IE will break when there is no + scrollbar.
+ +20-07-2012: Version 2.31:
+ +setSize
method for programmatic resizing.getHistory
and setHistory
methods.getValue
and getRange
.22-06-2012: Version 2.3:
+ +getScrollInfo
method.23-05-2012: Version 2.25:
+ +23-04-2012: Version 2.24:
+ +dragDrop
+ and onDragEvent
+ options.compoundChange
API method.catchall
in key maps,
+ add nofallthrough
boolean field instead.26-03-2012: Version 2.23:
+ +setLineClass
.charCoords
+ and cursorCoords
with a mode
argument.autofocus
option.findMarksAt
method.27-02-2012: Version 2.22:
+ +autoClearEmptyLines
option.27-01-2012: Version 2.21:
+ +smartIndent
+ option.readOnly
-mode.scrollTo
method.20-12-2011: Version 2.2:
+ +coordsFromIndex
+ to posFromIndex
,
+ add indexFromPos
+ method.21-11-2011: Version 2.18:
+Fixes TextMarker.clear
, which is broken in 2.17.
21-11-2011: Version 2.17:
+setBookmark
method.lib/util
.27-10-2011: Version 2.16:
+coordsFromIndex
method.setValue
now no longer clears history. Use clearHistory
for that.markText
now
+ returns an object with clear
and find
+ methods. Marked text is now more robust when edited.26-09-2011: Version 2.15:
+Fix bug that snuck into 2.14: Clicking the + character that currently has the cursor didn't re-focus the + editor.
+ +26-09-2011: Version 2.14:
+fixedGutter
option.setValue
breaking cursor movement.23-08-2011: Version 2.13:
+getGutterElement
to API.smartHome
option.25-07-2011: Version 2.12:
+innerHTML
for HTML-escaping.04-07-2011: Version 2.11:
+replace
method to search cursors, for cursor-preserving replacements.getStateAfter
API and compareState
mode API methods for finer-grained mode magic.getScrollerElement
API method to manipulate the scrolling DIV.07-06-2011: Version 2.1:
+Add + a theme system + (demo). Note that this is not + backwards-compatible—you'll have to update your styles and + modes!
+ +07-06-2011: Version 2.02:
+26-05-2011: Version 2.01:
+coordsChar
now worksonCursorActivity
interfered with onChange
.onChange
."nocursor"
mode for readOnly
option.onHighlightComplete
option.28-03-2011: Version 2.0:
+CodeMirror 2 is a complete rewrite that's + faster, smaller, simpler to use, and less dependent on browser + quirks. See this + and this + for more information. + +
28-03-2011: Version 1.0:
+22-02-2011: Version 2.0 beta 2:
+Somewhat more mature API, lots of bugs shaken out. + +
17-02-2011: Version 0.94:
+tabMode: "spaces"
was modified slightly (now indents when something is selected).08-02-2011: Version 2.0 beta 1:
+CodeMirror 2 is a complete rewrite of + CodeMirror, no longer depending on an editable frame.
+ +19-01-2011: Version 0.93:
+save
method to instances created with fromTextArea
.17-12-2010: Version 0.92:
+styleNumbers
option is now officially
+ supported and documented.onLineNumberClick
option added.onLoad
and
+ onCursorActivity
callbacks. Old names still work, but
+ are deprecated.11-11-2010: Version 0.91:
+toTextArea
to update the code in the textarea.noScriptCaching
option (hack to ease development).02-10-2010: Version 0.9:
+height: "dynamic"
more robust.enterMode
and electricChars
options to make indentation even more customizable.firstLineNumber
option.@media
rules by the CSS parser.22-07-2010: Version 0.8:
+cursorCoords
method to find the screen
+ coordinates of the cursor.height: dynamic
mode, where the editor's
+ height will adjust to the size of its content.toTextArea
method in instances created with
+ fromTextArea
.27-04-2010: Version + 0.67:
+More consistent page-up/page-down behaviour
+ across browsers. Fix some issues with hidden editors looping forever
+ when line-numbers were enabled. Make PHP parser parse
+ "\\"
correctly. Have jumpToLine
work on
+ line handles, and add cursorLine
function to fetch the
+ line handle where the cursor currently is. Add new
+ setStylesheet
function to switch style-sheets in a
+ running editor.
01-03-2010: Version + 0.66:
+Adds removeLine
method to API.
+ Introduces the PLSQL parser.
+ Marks XML errors by adding (rather than replacing) a CSS class, so
+ that they can be disabled by modifying their style. Fixes several
+ selection bugs, and a number of small glitches.
12-11-2009: Version + 0.65:
+Add support for having both line-wrapping and
+ line-numbers turned on, make paren-highlighting style customisable
+ (markParen
and unmarkParen
config
+ options), work around a selection bug that Opera
+ reintroduced in version 10.
23-10-2009: Version + 0.64:
+Solves some issues introduced by the
+ paste-handling changes from the previous release. Adds
+ setSpellcheck
, setTextWrapping
,
+ setIndentUnit
, setUndoDepth
,
+ setTabMode
, and setLineNumbers
to
+ customise a running editor. Introduces an SQL parser. Fixes a few small
+ problems in the Python
+ parser. And, as usual, add workarounds for various newly discovered
+ browser incompatibilities.
31-08-2009: Version +0.63:
+Overhaul of paste-handling (less fragile), fixes for several +serious IE8 issues (cursor jumping, end-of-document bugs) and a number +of small problems.
+ +30-05-2009: Version +0.62:
+Introduces Python
+and Lua parsers. Add
+setParser
(on-the-fly mode changing) and
+clearHistory
methods. Make parsing passes time-based
+instead of lines-based (see the passTime
option).
+/* Real world uses, + full list */ ++
Contact me if you'd like + your project to be added to this list.
+ ++/* Reporting bugs + effectively */ ++
So you found a problem in CodeMirror. By all means, report it! Bug +reports from users are the main drive behind improvements to +CodeMirror. But first, please read over these points:
+ ++/* Upgrading to + v2.2 */ ++
There are a few things in the 2.2 release that require some care +when upgrading.
+ +The default theme is now included
+in codemirror.css
, so
+you do not have to included it separately anymore. (It was tiny, so
+even if you're not using it, the extra data overhead is negligible.)
+
+
CodeMirror has moved to a system +where keymaps are used to +bind behavior to keys. This means custom +bindings are now possible.
+ +Three options that influenced key
+behavior, tabMode
, enterMode
,
+and smartHome
, are no longer supported. Instead, you can
+provide custom bindings to influence the way these keys act. This is
+done through the
+new extraKeys
+option, which can hold an object mapping key names to functionality. A
+simple example would be:
extraKeys: { + "Ctrl-S": function(instance) { saveText(instance.getValue()); }, + "Ctrl-/": "undo" + }+ +
Keys can be mapped either to functions, which will be given the
+editor instance as argument, or to strings, which are mapped through
+functions through the CodeMirror.commands
table, which
+contains all the built-in editing commands, and can be inspected and
+extended by external code.
By default, the Home
key is bound to
+the "goLineStartSmart"
command, which moves the cursor to
+the first non-whitespace character on the line. You can set do this to
+make it always go to the very start instead:
extraKeys: {"Home": "goLineStart"}+ +
Similarly, Enter
is bound
+to "newlineAndIndent"
by default. You can bind it to
+something else to get different behavior. To disable special handling
+completely and only get a newline character inserted, you can bind it
+to false
:
extraKeys: {"Enter": false}+ +
The same works for Tab
. If you don't want CodeMirror
+to handle it, bind it to false
. The default behaviour is
+to indent the current line more ("indentMore"
command),
+and indent it less when shift is held ("indentLess"
).
+There are also "indentAuto"
(smart indent)
+and "insertTab"
commands provided for alternate
+behaviors. Or you can write your own handler function to do something
+different altogether.
Handling of tabs changed completely. The display width of tabs can
+now be set with the tabSize
option, and tabs can
+be styled by setting CSS rules
+for the cm-tab
class.
The default width for tabs is now 4, as opposed to the 8 that is
+hard-wired into browsers. If you are relying on 8-space tabs, make
+sure you explicitly set tabSize: 8
in your options.
+/* Upgrading to + version 3 */ ++
Version 3 does not depart too much from 2.x API, and sites that use +CodeMirror in a very simple way might be able to upgrade without +trouble. But it does introduce a number of incompatibilities. Please +at least skim this text before upgrading.
+ +Note that version 3 drops full support for Internet +Explorer 7. The editor will mostly work on that browser, but +it'll be significantly glitchy.
+ +This one is the most likely to cause problems. The internal +structure of the editor has changed quite a lot, mostly to implement a +new scrolling model.
+ +Editor height is now set on the outer wrapper element (CSS
+class CodeMirror
), not on the scroller element
+(CodeMirror-scroll
).
Other nodes were moved, dropped, and added. If you have any code +that makes assumptions about the internal DOM structure of the editor, +you'll have to re-test it and probably update it to work with v3.
+ +See the styling section of the +manual for more information.
+ +In CodeMirror 2.x, there was a single gutter, and line markers
+created with setMarker
would have to somehow coexist with
+the line numbers (if present). Version 3 allows you to specify an
+array of gutters, by class
+name,
+use setGutterMarker
+to add or remove markers in individual gutters, and clear whole
+gutters
+with clearGutter
.
+Gutter markers are now specified as DOM nodes, rather than HTML
+snippets.
The gutters no longer horizontally scrolls along with the content.
+The fixedGutter
option was removed (since it is now the
+only behavior).
+<style> + /* Define a gutter style */ + .note-gutter { width: 3em; background: cyan; } +</style> +<script> + // Create an instance with two gutters -- line numbers and notes + var cm = new CodeMirror(document.body, { + gutters: ["note-gutter", "CodeMirror-linenumbers"], + lineNumbers: true + }); + // Add a note to line 0 + cm.setGutterMarker(0, "note-gutter", document.createTextNode("hi")); +</script> ++ +
Most of the onXYZ
options have been removed. The same
+effect is now obtained by calling
+the on
method with a string
+identifying the event type. Multiple handlers can now be registered
+(and individually unregistered) for an event, and objects such as line
+handlers now also expose events. See the
+full list here.
(The onKeyEvent
and onDragEvent
options,
+which act more as hooks than as event handlers, are still there in
+their old form.)
+cm.on("change", function(cm, change) { + console.log("something changed! (" + change.origin + ")"); +}); ++ +
The markText
method
+(which has gained some interesting new features, such as creating
+atomic and read-only spans, or replacing spans with widgets) no longer
+takes the CSS class name as a separate argument, but makes it an
+optional field in the options object instead.
+// Style first ten lines, and forbid the cursor from entering them +cm.markText({line: 0, ch: 0}, {line: 10, ch: 0}, { + className: "magic-text", + inclusiveLeft: true, + atomic: true +}); ++ +
The interface for hiding lines has been
+removed. markText
can
+now be used to do the same in a more flexible and powerful way.
The folding script has been +updated to use the new interface, and should now be more robust.
+ ++// Fold a range, replacing it with the text "??" +var range = cm.markText({line: 4, ch: 2}, {line: 8, ch: 1}, { + replacedWith: document.createTextNode("??"), + // Auto-unfold when cursor moves into the range + clearOnEnter: true +}); +// Get notified when auto-unfolding +CodeMirror.on(range, "clear", function() { + console.log("boom"); +}); ++ +
The setLineClass
method has been replaced
+by addLineClass
+and removeLineClass
,
+which allow more modular control over the classes attached to a line.
+var marked = cm.addLineClass(10, "background", "highlighted-line"); +setTimeout(function() { + cm.removeLineClass(marked, "background", "highlighted-line"); +}); ++ +
All methods that take or return objects that represent screen
+positions now use {left, top, bottom, right}
properties
+(not always all of them) instead of the {x, y, yBot}
used
+by some methods in v2.x.
Affected methods
+are cursorCoords
, charCoords
, coordsChar
,
+and getScrollInfo
.
The matchBrackets
+option is no longer defined in the core editor.
+Load addon/edit/matchbrackets.js
to enable it.
The CodeMirror.listModes
+and CodeMirror.listMIMEs
functions, used for listing
+defined modes, are gone. You are now encouraged to simply
+inspect CodeMirror.modes
(mapping mode names to mode
+constructors) and CodeMirror.mimeModes
(mapping MIME
+strings to mode specs).
Some more reasons to upgrade to version 3.
+ +CodeMirror.defineOption
.+/* In-browser code editing + made bearable */ ++
CodeMirror is a JavaScript component that + provides a code editor in the browser. When a mode is available for + the language you are coding in, it will color your code, and + optionally help with indentation.
+ +A rich programming API and a CSS + theming system are available for customizing CodeMirror to fit your + application, and extending it with new functionality.
+ +All of CodeMirror is released under a MIT-style license. To get it, you can download + the latest + release or the current development + snapshot as zip files. To create a custom minified script file, + you can use the compression API.
+ +We use git for version control. + The main repository can be fetched in this way:
+ +git clone http://marijnhaverbeke.nl/git/codemirror+ +
CodeMirror can also be found on GitHub at marijnh/CodeMirror. + If you plan to hack on the code and contribute patches, the best way + to do it is to create a GitHub fork, and send pull requests.
+ +The manual is your first stop for + learning how to use this library. It starts with a quick explanation + of how to use the editor, and then describes the API in detail.
+ +For those who want to learn more about the code, there is + a series of + posts on CodeMirror on my blog, and the + old overview of the editor + internals. + The source code + itself is, for the most part, also very readable.
+ +Community discussion, questions, and informal bug reporting is + done on + the CodeMirror + Google group. There is a separate + group, CodeMirror-announce, + which is lower-volume, and is only used for major announcements—new + versions and such. These will be cross-posted to both groups, so you + don't need to subscribe to both.
+ +Though bug reports through e-mail are responded to, the preferred + way to report bugs is to use + the GitHub + issue tracker. Before reporting a + bug, read these pointers. Also, + the issue tracker is for bugs, not requests for help.
+ +When none of these seem fitting, you can + simply e-mail the maintainer + directly.
+ +The following desktop browsers are able to run CodeMirror:
+ +<!doctype
+ html>
is recommended.)I am not actively testing against every new browser release, and + vendors have a habit of introducing bugs all the time, so I am + relying on the community to tell me when something breaks. + See here for information on how to contact + me.
+ +Mobile browsers mostly kind of work, but, because of limitations + and their fundamentally different UI assumptions, show a lot of + quirks that are hard to work around.
+ +CodeMirror is developed and maintained by me, Marijn Haverbeke, + in my own time. If your company is getting value out of CodeMirror, + please consider purchasing a support contract.
+ +CodeMirror support contracts exist in two + forms—basic at €100 per month, + and premium at €500 per + month. Contact me for further + information.
+ +21-02-2013: Version 3.1:
+ +CodeMirror.Pass
to signal they
+ didn't handle the key.simple-hint.js
.insertLeft
option
+ to setBookmark
.eachLine
+ method to iterate over a document."beforeChange"
+ and "beforeSelectionChange"
+ events."hide"
+ and "unhide"
+ events to marked ranges.coordsChar
's
+ interpretation of its argument to match the documentation.25-01-2013: Version 3.02:
+ +Single-bugfix release. Fixes a problem that + prevents CodeMirror instances from being garbage-collected after + they become unused.
+ +21-01-2013: Version 3.01:
+ +/addon
. You might have to adjust your
+ paths.rtlMoveVisually
option.showIfHidden
option for line widgets.fixedGutter
option.21-01-2013: Version 2.38:
+ +Integrate some bugfixes, enhancements to the vim keymap, and new + modes + (D, Sass, APL) + from the v3 branch.
+ +20-12-2012: Version 2.37:
+ +10-12-2012: Version 3.0:
+ +New major version. Only + partially backwards-compatible. See + the upgrading guide for more + information. Changes since release candidate 2:
+ +20-11-2012: Version 3.0, release candidate 2:
+ +addKeyMap
and removeKeyMap
methods.formatting
and closetag
add-ons.20-11-2012: Version 2.36:
+ +scrollIntoView
public.defaultTextHeight
method.20-11-2012: Version 3.0, release candidate 1:
+ +addLineClass
+ and removeLineClass
,
+ drop setLineClass
.isClean
/markClean
methods.compoundChange
method, use better undo-event-combining heuristic.22-10-2012: Version 2.35:
+ +markText
/undo interaction.defineInitHook
function.22-10-2012: Version 3.0, beta 2:
+ +gutterClick
event.cursorHeight
option.viewportMargin
option.flattenSpans
option.Simple mode that tries to handle APL as well as it can.
+It attempts to label functions/operators based upon + monadic/dyadic usage (but this is far from fully fleshed out). + This means there are meaningful classnames so hover states can + have popups etc.
+ +MIME types defined: text/apl
(APL code)
MIME types defined: text/x-asterisk
.
Simple mode that tries to handle C-like languages as well as it
+ can. Takes two configuration parameters: keywords
, an
+ object whose property names are the keywords in the language,
+ and useCPP
, which determines whether C preprocessor
+ directives are recognized.
MIME types defined: text/x-csrc
+ (C code), text/x-c++src
(C++
+ code), text/x-java
(Java
+ code), text/x-csharp
(C#).
MIME types defined: text/x-clojure
.
MIME types defined: text/x-coffeescript
.
The CoffeeScript mode was written by Jeff Pickhardt (license).
+ + + diff --git a/lib/codemirror-3.1/mode/commonlisp/commonlisp.js b/lib/codemirror-3.1/mode/commonlisp/commonlisp.js new file mode 100644 index 0000000000000000000000000000000000000000..eeba759668f3fbc4e605607d16c5babf8d59109d --- /dev/null +++ b/lib/codemirror-3.1/mode/commonlisp/commonlisp.js @@ -0,0 +1,101 @@ +CodeMirror.defineMode("commonlisp", function (config) { + var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/; + var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/; + var symbol = /[^\s'`,@()\[\]";]/; + var type; + + function readSym(stream) { + var ch; + while (ch = stream.next()) { + if (ch == "\\") stream.next(); + else if (!symbol.test(ch)) { stream.backUp(1); break; } + } + return stream.current(); + } + + function base(stream, state) { + if (stream.eatSpace()) {type = "ws"; return null;} + if (stream.match(numLiteral)) return "number"; + var ch = stream.next(); + if (ch == "\\") ch = stream.next(); + + if (ch == '"') return (state.tokenize = inString)(stream, state); + else if (ch == "(") { type = "open"; return "bracket"; } + else if (ch == ")" || ch == "]") { type = "close"; return "bracket"; } + else if (ch == ";") { stream.skipToEnd(); type = "ws"; return "comment"; } + else if (/['`,@]/.test(ch)) return null; + else if (ch == "|") { + if (stream.skipTo("|")) { stream.next(); return "symbol"; } + else { stream.skipToEnd(); return "error"; } + } else if (ch == "#") { + var ch = stream.next(); + if (ch == "[") { type = "open"; return "bracket"; } + else if (/[+\-=\.']/.test(ch)) return null; + else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null; + else if (ch == "|") return (state.tokenize = inComment)(stream, state); + else if (ch == ":") { readSym(stream); return "meta"; } + else return "error"; + } else { + var name = readSym(stream); + if (name == ".") return null; + type = "symbol"; + if (name == "nil" || name == "t") return "atom"; + if (name.charAt(0) == ":") return "keyword"; + if (name.charAt(0) == "&") return "variable-2"; + return "variable"; + } + } + + function inString(stream, state) { + var escaped = false, next; + while (next = stream.next()) { + if (next == '"' && !escaped) { state.tokenize = base; break; } + escaped = !escaped && next == "\\"; + } + return "string"; + } + + function inComment(stream, state) { + var next, last; + while (next = stream.next()) { + if (next == "#" && last == "|") { state.tokenize = base; break; } + last = next; + } + type = "ws"; + return "comment"; + } + + return { + startState: function () { + return {ctx: {prev: null, start: 0, indentTo: 0}, tokenize: base}; + }, + + token: function (stream, state) { + if (stream.sol() && typeof state.ctx.indentTo != "number") + state.ctx.indentTo = state.ctx.start + 1; + + type = null; + var style = state.tokenize(stream, state); + if (type != "ws") { + if (state.ctx.indentTo == null) { + if (type == "symbol" && assumeBody.test(stream.current())) + state.ctx.indentTo = state.ctx.start + config.indentUnit; + else + state.ctx.indentTo = "next"; + } else if (state.ctx.indentTo == "next") { + state.ctx.indentTo = stream.column(); + } + } + if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null}; + else if (type == "close") state.ctx = state.ctx.prev || state.ctx; + return style; + }, + + indent: function (state, _textAfter) { + var i = state.ctx.indentTo; + return typeof i == "number" ? i : state.ctx.start + 1; + } + }; +}); + +CodeMirror.defineMIME("text/x-common-lisp", "commonlisp"); diff --git a/lib/codemirror-3.1/mode/commonlisp/index.html b/lib/codemirror-3.1/mode/commonlisp/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f9766a844ce5948e91966c5f13346533f8632134 --- /dev/null +++ b/lib/codemirror-3.1/mode/commonlisp/index.html @@ -0,0 +1,165 @@ + + + + +MIME types defined: text/x-common-lisp
.
MIME types defined: text/css
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/lib/codemirror-3.1/mode/css/test.js b/lib/codemirror-3.1/mode/css/test.js new file mode 100644 index 0000000000000000000000000000000000000000..4336ddabdf7d5091e7efd6779f094860aa37dfbd --- /dev/null +++ b/lib/codemirror-3.1/mode/css/test.js @@ -0,0 +1,106 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "css"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 2)); } + + // Requires at least one media query + MT("atMediaEmpty", + "[def @media] [error {] }"); + + MT("atMediaMultiple", + "[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }"); + + MT("atMediaCheckStack", + "[def @media] [attribute screen] { } [tag foo] { }"); + + MT("atMediaCheckStack", + "[def @media] [attribute screen] ([property color]) { } [tag foo] { }"); + + MT("atMediaCheckStackInvalidAttribute", + "[def @media] [attribute&error foobarhello] { } [tag foo] { }"); + + // Error, because "and" is only allowed immediately preceding a media expression + MT("atMediaInvalidAttribute", + "[def @media] [attribute&error foobarhello] { }"); + + // Error, because "and" is only allowed immediately preceding a media expression + MT("atMediaInvalidAnd", + "[def @media] [error and] [attribute screen] { }"); + + // Error, because "not" is only allowed as the first item in each media query + MT("atMediaInvalidNot", + "[def @media] [attribute screen] [error not] ([error not]) { }"); + + // Error, because "only" is only allowed as the first item in each media query + MT("atMediaInvalidOnly", + "[def @media] [attribute screen] [error only] ([error only]) { }"); + + // Error, because "foobarhello" is neither a known type or property, but + // property was expected (after "and"), and it should be in parenthese. + MT("atMediaUnknownType", + "[def @media] [attribute screen] [operator and] [error foobarhello] { }"); + + // Error, because "color" is not a known type, but is a known property, and + // should be in parentheses. + MT("atMediaInvalidType", + "[def @media] [attribute screen] [operator and] [error color] { }"); + + // Error, because "print" is not a known property, but is a known type, + // and should not be in parenthese. + MT("atMediaInvalidProperty", + "[def @media] [attribute screen] [operator and] ([error print]) { }"); + + // Soft error, because "foobarhello" is not a known property or type. + MT("atMediaUnknownProperty", + "[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }"); + + MT("tagSelector", + "[tag foo] { }"); + + MT("classSelector", + "[qualifier .foo-bar_hello] { }"); + + MT("idSelector", + "[builtin #foo] { [error #foo] }"); + + MT("tagSelectorUnclosed", + "[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }"); + + MT("tagStringNoQuotes", + "[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }"); + + MT("tagStringDouble", + "[tag foo] { [property font-family][operator :] [string \"hello world\"]; }"); + + MT("tagStringSingle", + "[tag foo] { [property font-family][operator :] [string 'hello world']; }"); + + MT("tagColorKeyword", + "[tag foo] { [property color][operator :] [keyword black]; }"); + + MT("tagColorHex3", + "[tag foo] { [property background][operator :] [atom #fff]; }"); + + MT("tagColorHex6", + "[tag foo] { [property background][operator :] [atom #ffffff]; }"); + + MT("tagColorHex4", + "[tag foo] { [property background][operator :] [atom&error #ffff]; }"); + + MT("tagColorHexInvalid", + "[tag foo] { [property background][operator :] [atom&error #ffg]; }"); + + MT("tagNegativeNumber", + "[tag foo] { [property margin][operator :] [number -5px]; }"); + + MT("tagPositiveNumber", + "[tag foo] { [property padding][operator :] [number 5px]; }"); + + MT("tagVendor", + "[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }"); + + MT("tagBogusProperty", + "[tag foo] { [property&error barhelloworld][operator :] [number 0]; }"); + + MT("tagTwoProperties", + "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }"); +})(); diff --git a/lib/codemirror-3.1/mode/d/d.js b/lib/codemirror-3.1/mode/d/d.js new file mode 100644 index 0000000000000000000000000000000000000000..ab345f1a0d9947e1db94a4f8fc4c1d4d832eaed7 --- /dev/null +++ b/lib/codemirror-3.1/mode/d/d.js @@ -0,0 +1,205 @@ +CodeMirror.defineMode("d", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + keywords = parserConfig.keywords || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings; + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("+")) { + state.tokenize = tokenComment; + return tokenNestedComment(stream, state); + } + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + if (builtin.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "builtin"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenNestedComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "+"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}" + }; +}); + +(function() { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var blockKeywords = "body catch class do else enum for foreach foreach_reverse if in interface mixin " + + "out scope struct switch try union unittest version while with"; + + CodeMirror.defineMIME("text/x-d", { + name: "d", + keywords: words("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue " + + "debug default delegate delete deprecated export extern final finally function goto immutable " + + "import inout invariant is lazy macro module new nothrow override package pragma private " + + "protected public pure ref return shared short static super synchronized template this " + + "throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters " + + blockKeywords), + blockKeywords: words(blockKeywords), + builtin: words("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte " + + "ucent uint ulong ushort wchar wstring void size_t sizediff_t"), + atoms: words("exit failure success true false null"), + hooks: { + "@": function(stream, _state) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); +}()); diff --git a/lib/codemirror-3.1/mode/d/index.html b/lib/codemirror-3.1/mode/d/index.html new file mode 100644 index 0000000000000000000000000000000000000000..13332727ad6185a642c6b56b284dc5a84f22dbe2 --- /dev/null +++ b/lib/codemirror-3.1/mode/d/index.html @@ -0,0 +1,262 @@ + + + + +Simple mode that handle D-Syntax (DLang Homepage).
+ +MIME types defined: text/x-d
+ .
MIME types defined: text/x-diff
.
Based on CodeMirror's clike mode. For more information see HPCC Systems web site.
+MIME types defined: text/x-ecl
.
MIME types defined: text/x-erlang
.
Optionally depends on other modes for properly highlighted code blocks.
+ +Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/lib/codemirror-3.1/mode/gfm/test.js b/lib/codemirror-3.1/mode/gfm/test.js new file mode 100644 index 0000000000000000000000000000000000000000..cf97df66a571f2138894fd396b0f1d79d1736de6 --- /dev/null +++ b/lib/codemirror-3.1/mode/gfm/test.js @@ -0,0 +1,84 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "gfm"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("emInWordAsterisk", + "foo[em *bar*]hello"); + + MT("emInWordUnderscore", + "foo_bar_hello"); + + MT("emStrongUnderscore", + "[strong __][emstrong _foo__][em _] bar"); + + MT("fencedCodeBlocks", + "[comment ```]", + "[comment foo]", + "", + "[comment ```]", + "bar"); + + MT("fencedCodeBlockModeSwitching", + "[comment ```javascript]", + "[variable foo]", + "", + "[comment ```]", + "bar"); + + MT("SHA", + "foo [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] bar"); + + MT("shortSHA", + "foo [link be6a8cc] bar"); + + MT("tooShortSHA", + "foo be6a8c bar"); + + MT("longSHA", + "foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar"); + + MT("badSHA", + "foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar"); + + MT("userSHA", + "foo [link bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] hello"); + + MT("userProjectSHA", + "foo [link bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] world"); + + MT("num", + "foo [link #1] bar"); + + MT("badNum", + "foo #1bar hello"); + + MT("userNum", + "foo [link bar#1] hello"); + + MT("userProjectNum", + "foo [link bar/hello#1] world"); + + MT("vanillaLink", + "foo [link http://www.example.com/] bar"); + + MT("vanillaLinkPunctuation", + "foo [link http://www.example.com/]. bar"); + + MT("vanillaLinkExtension", + "foo [link http://www.example.com/index.html] bar"); + + MT("notALink", + "[comment ```css]", + "[tag foo] {[property color][operator :][keyword black];}", + "[comment ```][link http://www.example.com/]"); + + MT("notALink", + "[comment ``foo `bar` http://www.example.com/``] hello"); + + MT("notALink", + "[comment `foo]", + "[link http://www.example.com/]", + "[comment `foo]", + "", + "[link http://www.example.com/]"); +})(); diff --git a/lib/codemirror-3.1/mode/go/go.js b/lib/codemirror-3.1/mode/go/go.js new file mode 100644 index 0000000000000000000000000000000000000000..8b84a5ca42def13bf909dca6bb5553c7539b987e --- /dev/null +++ b/lib/codemirror-3.1/mode/go/go.js @@ -0,0 +1,165 @@ +CodeMirror.defineMode("go", function(config) { + var indentUnit = config.indentUnit; + + var keywords = { + "break":true, "case":true, "chan":true, "const":true, "continue":true, + "default":true, "defer":true, "else":true, "fallthrough":true, "for":true, + "func":true, "go":true, "goto":true, "if":true, "import":true, + "interface":true, "map":true, "package":true, "range":true, "return":true, + "select":true, "struct":true, "switch":true, "type":true, "var":true, + "bool":true, "byte":true, "complex64":true, "complex128":true, + "float32":true, "float64":true, "int8":true, "int16":true, "int32":true, + "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true, + "uint64":true, "int":true, "uint":true, "uintptr":true + }; + + var atoms = { + "true":true, "false":true, "iota":true, "nil":true, "append":true, + "cap":true, "close":true, "complex":true, "copy":true, "imag":true, + "len":true, "make":true, "new":true, "panic":true, "print":true, + "println":true, "real":true, "recover":true + }; + + var isOperatorChar = /[+\-*&^%:=<>!|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\d\.]/.test(ch)) { + if (ch == ".") { + stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); + } else if (ch == "0") { + stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); + } else { + stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); + } + return "number"; + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (cur == "case" || cur == "default") curPunc = "case"; + return "keyword"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || quote == "`")) + state.tokenize = tokenBase; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + if (ctx.type == "case") ctx.type = "}"; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "case") ctx.type = "case"; + else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state); + else if (curPunc == ctx.type) popContext(state); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return 0; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) { + state.context.type = "}"; + return ctx.indented; + } + var closing = firstChar == ctx.type; + if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}:" + }; +}); + +CodeMirror.defineMIME("text/x-go", "go"); diff --git a/lib/codemirror-3.1/mode/go/index.html b/lib/codemirror-3.1/mode/go/index.html new file mode 100644 index 0000000000000000000000000000000000000000..8a6aafca29de358e10ae2c6c16057098ff97e7a1 --- /dev/null +++ b/lib/codemirror-3.1/mode/go/index.html @@ -0,0 +1,74 @@ + + + + +MIME type: text/x-go
MIME types defined: text/x-groovy
MIME types defined: text/x-haskell
.
MIME types defined: text/x-haxe
.
Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
+ JavaScript, CSS and XML.
Other dependancies include those of the scriping language chosen.
MIME types defined: application/x-aspx
(ASP.NET),
+ application/x-ejs
(Embedded Javascript), application/x-jsp
(JavaServer Pages)
The HTML mixed mode depends on the XML, JavaScript, and CSS modes.
+ +It takes an optional mode configuration
+ option, scriptTypes
, which can be used to add custom
+ behavior for specific <script type="...">
tags. If
+ given, it should hold an array of {matches, mode}
+ objects, where matches
is a string or regexp that
+ matches the script type, and mode
is
+ either null
, for script types that should stay in
+ HTML mode, or a mode
+ spec corresponding to the mode that should be used for the
+ script.
MIME types defined: text/html
+ (redefined, only takes effect if you load this parser after the
+ XML parser).
MIME types defined: message/http
.
+ JavaScript mode supports a two configuration + options: +
json
which will set the mode to expect JSON data rather than a JavaScript program.typescript
which will activate additional syntax highlighting and some other things for TypeScript code (demo).
+ MIME types defined: text/javascript
, application/json
, text/typescript
, application/typescript
.
This is a specialization of the JavaScript mode.
+ + diff --git a/lib/codemirror-3.1/mode/jinja2/index.html b/lib/codemirror-3.1/mode/jinja2/index.html new file mode 100644 index 0000000000000000000000000000000000000000..7cd1da2335a245730dc5fe94ca6d74d5e9e444a5 --- /dev/null +++ b/lib/codemirror-3.1/mode/jinja2/index.html @@ -0,0 +1,38 @@ + + + + +MIME types defined: text/x-less
, text/css
(if not previously defined).
Loosely based on Franciszek
+ Wawrzak's CodeMirror
+ 1 mode. One configuration parameter is
+ supported, specials
, to which you can provide an
+ array of strings to have those identifiers highlighted with
+ the lua-special
style.
MIME types defined: text/x-lua
.
Optionally depends on the XML mode for properly highlighted inline XML blocks.
+ +MIME types defined: text/x-markdown
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/lib/codemirror-3.1/mode/markdown/markdown.js b/lib/codemirror-3.1/mode/markdown/markdown.js new file mode 100644 index 0000000000000000000000000000000000000000..63de81e6eecf63ed6a78fa87efb35e6d77cf6a48 --- /dev/null +++ b/lib/codemirror-3.1/mode/markdown/markdown.js @@ -0,0 +1,475 @@ +CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { + + var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html"); + var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain"); + var aliases = { + html: "htmlmixed", + js: "javascript", + json: "application/json", + c: "text/x-csrc", + "c++": "text/x-c++src", + java: "text/x-java", + csharp: "text/x-csharp", + "c#": "text/x-csharp", + scala: "text/x-scala" + }; + + var getMode = (function () { + var i, modes = {}, mimes = {}, mime; + + var list = []; + for (var m in CodeMirror.modes) + if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m); + for (i = 0; i < list.length; i++) { + modes[list[i]] = list[i]; + } + var mimesList = []; + for (var m in CodeMirror.mimeModes) + if (CodeMirror.mimeModes.propertyIsEnumerable(m)) + mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]}); + for (i = 0; i < mimesList.length; i++) { + mime = mimesList[i].mime; + mimes[mime] = mimesList[i].mime; + } + + for (var a in aliases) { + if (aliases[a] in modes || aliases[a] in mimes) + modes[a] = aliases[a]; + } + + return function (lang) { + return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null; + }; + }()); + + // Should underscores in words open/close em/strong? + if (modeCfg.underscoresBreakWords === undefined) + modeCfg.underscoresBreakWords = true; + + // Turn on fenced code blocks? ("```" to start/end) + if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false; + + var codeDepth = 0; + var prevLineHasContent = false + , thisLineHasContent = false; + + var header = 'header' + , code = 'comment' + , quote = 'quote' + , list = 'string' + , hr = 'hr' + , image = 'tag' + , linkinline = 'link' + , linkemail = 'link' + , linktext = 'link' + , linkhref = 'string' + , em = 'em' + , strong = 'strong' + , emstrong = 'emstrong'; + + var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/ + , ulRE = /^[*\-+]\s+/ + , olRE = /^[0-9]+\.\s+/ + , headerRE = /^(?:\={1,}|-{1,})$/ + , textRE = /^[^!\[\]*_\\<>` "'(]+/; + + function switchInline(stream, state, f) { + state.f = state.inline = f; + return f(stream, state); + } + + function switchBlock(stream, state, f) { + state.f = state.block = f; + return f(stream, state); + } + + + // Blocks + + function blankLine(state) { + // Reset linkTitle state + state.linkTitle = false; + // Reset EM state + state.em = false; + // Reset STRONG state + state.strong = false; + // Reset state.quote + state.quote = false; + if (!htmlFound && state.f == htmlBlock) { + state.f = inlineNormal; + state.block = blockNormal; + } + return null; + } + + function blockNormal(stream, state) { + + if (state.list !== false && state.indentationDiff >= 0) { // Continued list + if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block + state.indentation -= state.indentationDiff; + } + state.list = null; + } else { // No longer a list + state.list = false; + } + + if (state.indentationDiff >= 4) { + state.indentation -= 4; + stream.skipToEnd(); + return code; + } else if (stream.eatSpace()) { + return null; + } else if (stream.peek() === '#' || (prevLineHasContent && stream.match(headerRE)) ) { + state.header = true; + } else if (stream.eat('>')) { + state.indentation++; + state.quote = true; + } else if (stream.peek() === '[') { + return switchInline(stream, state, footnoteLink); + } else if (stream.match(hrRE, true)) { + return hr; + } else if (stream.match(ulRE, true) || stream.match(olRE, true)) { + state.indentation += 4; + state.list = true; + } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) { + // try switching mode + state.localMode = getMode(RegExp.$1); + if (state.localMode) state.localState = state.localMode.startState(); + switchBlock(stream, state, local); + return code; + } + + return switchInline(stream, state, state.inline); + } + + function htmlBlock(stream, state) { + var style = htmlMode.token(stream, state.htmlState); + if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) { + state.f = inlineNormal; + state.block = blockNormal; + } + if (state.md_inside && stream.current().indexOf(">")!=-1) { + state.f = inlineNormal; + state.block = blockNormal; + state.htmlState.context = undefined; + } + return style; + } + + function local(stream, state) { + if (stream.sol() && stream.match(/^```/, true)) { + state.localMode = state.localState = null; + state.f = inlineNormal; + state.block = blockNormal; + return code; + } else if (state.localMode) { + return state.localMode.token(stream, state.localState); + } else { + stream.skipToEnd(); + return code; + } + } + + // Inline + function getType(state) { + var styles = []; + + if (state.strong) { styles.push(state.em ? emstrong : strong); } + else if (state.em) { styles.push(em); } + + if (state.linkText) { styles.push(linktext); } + + if (state.code) { styles.push(code); } + + if (state.header) { styles.push(header); } + if (state.quote) { styles.push(quote); } + if (state.list !== false) { styles.push(list); } + + return styles.length ? styles.join(' ') : null; + } + + function handleText(stream, state) { + if (stream.match(textRE, true)) { + return getType(state); + } + return undefined; + } + + function inlineNormal(stream, state) { + var style = state.text(stream, state); + if (typeof style !== 'undefined') + return style; + + if (state.list) { // List marker (*, +, -, 1., etc) + state.list = null; + return list; + } + + var ch = stream.next(); + + if (ch === '\\') { + stream.next(); + return getType(state); + } + + // Matches link titles present on next line + if (state.linkTitle) { + state.linkTitle = false; + var matchCh = ch; + if (ch === '(') { + matchCh = ')'; + } + matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; + if (stream.match(new RegExp(regex), true)) { + return linkhref; + } + } + + // If this block is changed, it may need to be updated in GFM mode + if (ch === '`') { + var t = getType(state); + var before = stream.pos; + stream.eatWhile('`'); + var difference = 1 + stream.pos - before; + if (!state.code) { + codeDepth = difference; + state.code = true; + return getType(state); + } else { + if (difference === codeDepth) { // Must be exact + state.code = false; + return t; + } + return getType(state); + } + } else if (state.code) { + return getType(state); + } + + if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { + stream.match(/\[[^\]]*\]/); + state.inline = state.f = linkHref; + return image; + } + + if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) { + state.linkText = true; + return getType(state); + } + + if (ch === ']' && state.linkText) { + var type = getType(state); + state.linkText = false; + state.inline = state.f = linkHref; + return type; + } + + if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) { + return switchInline(stream, state, inlineElement(linkinline, '>')); + } + + if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) { + return switchInline(stream, state, inlineElement(linkemail, '>')); + } + + if (ch === '<' && stream.match(/^\w/, false)) { + if (stream.string.indexOf(">")!=-1) { + var atts = stream.string.substring(1,stream.string.indexOf(">")); + if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) { + state.md_inside = true; + } + } + stream.backUp(1); + return switchBlock(stream, state, htmlBlock); + } + + if (ch === '<' && stream.match(/^\/\w*?>/)) { + state.md_inside = false; + return "tag"; + } + + var ignoreUnderscore = false; + if (!modeCfg.underscoresBreakWords) { + if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { + var prevPos = stream.pos - 2; + if (prevPos >= 0) { + var prevCh = stream.string.charAt(prevPos); + if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { + ignoreUnderscore = true; + } + } + } + } + var t = getType(state); + if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { + if (state.strong === ch && stream.eat(ch)) { // Remove STRONG + state.strong = false; + return t; + } else if (!state.strong && stream.eat(ch)) { // Add STRONG + state.strong = ch; + return getType(state); + } else if (state.em === ch) { // Remove EM + state.em = false; + return t; + } else if (!state.em) { // Add EM + state.em = ch; + return getType(state); + } + } else if (ch === ' ') { + if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces + if (stream.peek() === ' ') { // Surrounded by spaces, ignore + return getType(state); + } else { // Not surrounded by spaces, back up pointer + stream.backUp(1); + } + } + } + + return getType(state); + } + + function linkHref(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + var ch = stream.next(); + if (ch === '(' || ch === '[') { + return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']')); + } + return 'error'; + } + + function footnoteLink(stream, state) { + if (stream.match(/^[^\]]*\]:/, true)) { + state.f = footnoteUrl; + return linktext; + } + return switchInline(stream, state, inlineNormal); + } + + function footnoteUrl(stream, state) { + // Check if space, and return NULL if so (to avoid marking the space) + if(stream.eatSpace()){ + return null; + } + // Match URL + stream.match(/^[^\s]+/, true); + // Check for link title + if (stream.peek() === undefined) { // End of line, set flag to check next line + state.linkTitle = true; + } else { // More content on line, check if link title + stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); + } + state.f = state.inline = inlineNormal; + return linkhref; + } + + var savedInlineRE = []; + function inlineRE(endChar) { + if (!savedInlineRE[endChar]) { + // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) + endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); + // Match any non-endChar, escaped character, as well as the closing + // endChar. + savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); + } + return savedInlineRE[endChar]; + } + + function inlineElement(type, endChar, next) { + next = next || inlineNormal; + return function(stream, state) { + stream.match(inlineRE(endChar)); + state.inline = state.f = next; + return type; + }; + } + + return { + startState: function() { + prevLineHasContent = false; + thisLineHasContent = false; + return { + f: blockNormal, + + block: blockNormal, + htmlState: CodeMirror.startState(htmlMode), + indentation: 0, + + inline: inlineNormal, + text: handleText, + + linkText: false, + linkTitle: false, + em: false, + strong: false, + header: false, + list: false, + quote: false + }; + }, + + copyState: function(s) { + return { + f: s.f, + + block: s.block, + htmlState: CodeMirror.copyState(htmlMode, s.htmlState), + indentation: s.indentation, + + localMode: s.localMode, + localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, + + inline: s.inline, + text: s.text, + linkTitle: s.linkTitle, + em: s.em, + strong: s.strong, + header: s.header, + list: s.list, + quote: s.quote, + md_inside: s.md_inside + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (stream.match(/^\s*$/, true)) { + prevLineHasContent = false; + return blankLine(state); + } else { + if(thisLineHasContent){ + prevLineHasContent = true; + thisLineHasContent = false; + } + thisLineHasContent = true; + } + + // Reset state.header + state.header = false; + + // Reset state.code + state.code = false; + + state.f = state.block; + var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; + var difference = Math.floor((indentation - state.indentation) / 4) * 4; + if (difference > 4) difference = 4; + var adjustedIndentation = state.indentation + difference; + state.indentationDiff = adjustedIndentation - state.indentation; + state.indentation = adjustedIndentation; + if (indentation > 0) return null; + } + return state.f(stream, state); + }, + + blankLine: blankLine, + + getType: getType + }; + +}, "xml"); + +CodeMirror.defineMIME("text/x-markdown", "markdown"); diff --git a/lib/codemirror-3.1/mode/markdown/test.js b/lib/codemirror-3.1/mode/markdown/test.js new file mode 100644 index 0000000000000000000000000000000000000000..eaa7343a20616a58da8e738b11900c8ee3dbe83d --- /dev/null +++ b/lib/codemirror-3.1/mode/markdown/test.js @@ -0,0 +1,579 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "markdown"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("plainText", + "foo"); + + // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) + MT("codeBlocksUsing4Spaces", + " [comment foo]"); + + // Code blocks using 4 spaces with internal indentation + MT("codeBlocksUsing4SpacesIndentation", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + "bar"); + + // Code blocks using 4 spaces with internal indentation + MT("codeBlocksUsing4SpacesIndentation", + " foo", + " [comment bar]", + " [comment hello]", + " [comment world]"); + + // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value) + MT("codeBlocksUsing1Tab", + "\t[comment foo]"); + + // Inline code using backticks + MT("inlineCodeUsingBackticks", + "foo [comment `bar`]"); + + // Block code using single backtick (shouldn't work) + MT("blockCodeSingleBacktick", + "[comment `]", + "foo", + "[comment `]"); + + // Unclosed backticks + // Instead of simply marking as CODE, it would be nice to have an + // incomplete flag for CODE, that is styled slightly different. + MT("unclosedBackticks", + "foo [comment `bar]"); + + // Per documentation: "To include a literal backtick character within a + // code span, you can use multiple backticks as the opening and closing + // delimiters" + MT("doubleBackticks", + "[comment ``foo ` bar``]"); + + // Tests based on Dingus + // http://daringfireball.net/projects/markdown/dingus + // + // Multiple backticks within an inline code block + MT("consecutiveBackticks", + "[comment `foo```bar`]"); + + // Multiple backticks within an inline code block with a second code block + MT("consecutiveBackticks", + "[comment `foo```bar`] hello [comment `world`]"); + + // Unclosed with several different groups of backticks + MT("unclosedBackticks", + "[comment ``foo ``` bar` hello]"); + + // Closed with several different groups of backticks + MT("closedBackticks", + "[comment ``foo ``` bar` hello``] world"); + + // atx headers + // http://daringfireball.net/projects/markdown/syntax#header + + MT("atxH1", + "[header # foo]"); + + MT("atxH2", + "[header ## foo]"); + + MT("atxH3", + "[header ### foo]"); + + MT("atxH4", + "[header #### foo]"); + + MT("atxH5", + "[header ##### foo]"); + + MT("atxH6", + "[header ###### foo]"); + + // H6 - 7x '#' should still be H6, per Dingus + // http://daringfireball.net/projects/markdown/dingus + MT("atxH6NotH7", + "[header ####### foo]"); + + // Setext headers - H1, H2 + // Per documentation, "Any number of underlining =’s or -’s will work." + // http://daringfireball.net/projects/markdown/syntax#header + // Ideally, the text would be marked as `header` as well, but this is + // not really feasible at the moment. So, instead, we're testing against + // what works today, to avoid any regressions. + // + // Check if single underlining = works + MT("setextH1", + "foo", + "[header =]"); + + // Check if 3+ ='s work + MT("setextH1", + "foo", + "[header ===]"); + + // Check if single underlining - works + MT("setextH2", + "foo", + "[header -]"); + + // Check if 3+ -'s work + MT("setextH2", + "foo", + "[header ---]"); + + // Single-line blockquote with trailing space + MT("blockquoteSpace", + "[quote > foo]"); + + // Single-line blockquote + MT("blockquoteNoSpace", + "[quote >foo]"); + + // Single-line blockquote followed by normal paragraph + MT("blockquoteThenParagraph", + "[quote >foo]", + "", + "bar"); + + // Multi-line blockquote (lazy mode) + MT("multiBlockquoteLazy", + "[quote >foo]", + "[quote bar]"); + + // Multi-line blockquote followed by normal paragraph (lazy mode) + MT("multiBlockquoteLazyThenParagraph", + "[quote >foo]", + "[quote bar]", + "", + "hello"); + + // Multi-line blockquote (non-lazy mode) + MT("multiBlockquote", + "[quote >foo]", + "[quote >bar]"); + + // Multi-line blockquote followed by normal paragraph (non-lazy mode) + MT("multiBlockquoteThenParagraph", + "[quote >foo]", + "[quote >bar]", + "", + "hello"); + + // Check list types + + MT("listAsterisk", + "[string * foo]", + "[string * bar]"); + + MT("listPlus", + "[string + foo]", + "[string + bar]"); + + MT("listDash", + "[string - foo]", + "[string - bar]"); + + MT("listNumber", + "[string 1. foo]", + "[string 2. bar]"); + + // Formatting in lists (*) + MT("listAsteriskFormatting", + "[string * ][string&em *foo*][string bar]", + "[string * ][string&strong **foo**][string bar]", + "[string * ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string * ][string&comment `foo`][string bar]"); + + // Formatting in lists (+) + MT("listPlusFormatting", + "[string + ][string&em *foo*][string bar]", + "[string + ][string&strong **foo**][string bar]", + "[string + ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string + ][string&comment `foo`][string bar]"); + + // Formatting in lists (-) + MT("listDashFormatting", + "[string - ][string&em *foo*][string bar]", + "[string - ][string&strong **foo**][string bar]", + "[string - ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string - ][string&comment `foo`][string bar]"); + + // Formatting in lists (1.) + MT("listNumberFormatting", + "[string 1. ][string&em *foo*][string bar]", + "[string 2. ][string&strong **foo**][string bar]", + "[string 3. ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string 4. ][string&comment `foo`][string bar]"); + + // Paragraph lists + MT("listParagraph", + "[string * foo]", + "", + "[string * bar]"); + + // Multi-paragraph lists + // + // 4 spaces + MT("listMultiParagraph", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]"); + + // 4 spaces, extra blank lines (should still be list, per Dingus) + MT("listMultiParagraphExtra", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]"); + + // 4 spaces, plus 1 space (should still be list, per Dingus) + MT("listMultiParagraphExtraSpace", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]", + "", + " [string world]"); + + // 1 tab + MT("listTab", + "[string * foo]", + "", + "[string * bar]", + "", + "\t[string hello]"); + + // No indent + MT("listNoIndent", + "[string * foo]", + "", + "[string * bar]", + "", + "hello"); + + // Blockquote + MT("blockquote", + "[string * foo]", + "", + "[string * bar]", + "", + " [string"e > hello]"); + + // Code block + MT("blockquoteCode", + "[string * foo]", + "", + "[string * bar]", + "", + " [comment > hello]", + "", + " [string world]"); + + // Code block followed by text + MT("blockquoteCodeText", + "[string * foo]", + "", + " [string bar]", + "", + " [comment hello]", + "", + " [string world]"); + + // Nested list + + MT("listAsteriskNested", + "[string * foo]", + "", + " [string * bar]"); + + MT("listPlusNested", + "[string + foo]", + "", + " [string + bar]"); + + MT("listDashNested", + "[string - foo]", + "", + " [string - bar]"); + + MT("listNumberNested", + "[string 1. foo]", + "", + " [string 2. bar]"); + + MT("listMixed", + "[string * foo]", + "", + " [string + bar]", + "", + " [string - hello]", + "", + " [string 1. world]"); + + MT("listBlockquote", + "[string * foo]", + "", + " [string + bar]", + "", + " [quote&string > hello]"); + + MT("listCode", + "[string * foo]", + "", + " [string + bar]", + "", + " [comment hello]"); + + // Code with internal indentation + MT("listCodeIndentation", + "[string * foo]", + "", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + " [string bar]"); + + // Code followed by text + MT("listCodeText", + "[string * foo]", + "", + " [comment bar]", + "", + "hello"); + + // Following tests directly from official Markdown documentation + // http://daringfireball.net/projects/markdown/syntax#hr + + MT("hrSpace", + "[hr * * *]"); + + MT("hr", + "[hr ***]"); + + MT("hrLong", + "[hr *****]"); + + MT("hrSpaceDash", + "[hr - - -]"); + + MT("hrDashLong", + "[hr ---------------------------------------]"); + + // Inline link with title + MT("linkTitle", + "[link [[foo]]][string (http://example.com/ \"bar\")] hello"); + + // Inline link without title + MT("linkNoTitle", + "[link [[foo]]][string (http://example.com/)] bar"); + + // Inline link with image + MT("linkImage", + "[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar"); + + // Inline link with Em + MT("linkEm", + "[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar"); + + // Inline link with Strong + MT("linkStrong", + "[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar"); + + // Inline link with EmStrong + MT("linkEmStrong", + "[link [[][link&strong **][link&emstrong *foo**][link&em *][link ]]][string (http://example.com/)] bar"); + + // Image with title + MT("imageTitle", + "[tag ![[foo]]][string (http://example.com/ \"bar\")] hello"); + + // Image without title + MT("imageNoTitle", + "[tag ![[foo]]][string (http://example.com/)] bar"); + + // Image with asterisks + MT("imageAsterisks", + "[tag ![[*foo*]]][string (http://example.com/)] bar"); + + // Not a link. Should be normal text due to square brackets being used + // regularly in text, especially in quoted material, and no space is allowed + // between square brackets and parentheses (per Dingus). + MT("notALink", + "[[foo]] (bar)"); + + // Reference-style links + MT("linkReference", + "[link [[foo]]][string [[bar]]] hello"); + + // Reference-style links with Em + MT("linkReferenceEm", + "[link [[][link&em *foo*][link ]]][string [[bar]]] hello"); + + // Reference-style links with Strong + MT("linkReferenceStrong", + "[link [[][link&strong **foo**][link ]]][string [[bar]]] hello"); + + // Reference-style links with EmStrong + MT("linkReferenceEmStrong", + "[link [[][link&strong **][link&emstrong *foo**][link&em *][link ]]][string [[bar]]] hello"); + + // Reference-style links with optional space separator (per docuentation) + // "You can optionally use a space to separate the sets of brackets" + MT("linkReferenceSpace", + "[link [[foo]]] [string [[bar]]] hello"); + + // Should only allow a single space ("...use *a* space...") + MT("linkReferenceDoubleSpace", + "[[foo]] [[bar]] hello"); + + // Reference-style links with implicit link name + MT("linkImplicit", + "[link [[foo]]][string [[]]] hello"); + + // @todo It would be nice if, at some point, the document was actually + // checked to see if the referenced link exists + + // Link label, for reference-style links (taken from documentation) + + MT("labelNoTitle", + "[link [[foo]]:] [string http://example.com/]"); + + MT("labelIndented", + " [link [[foo]]:] [string http://example.com/]"); + + MT("labelSpaceTitle", + "[link [[foo bar]]:] [string http://example.com/ \"hello\"]"); + + MT("labelDoubleTitle", + "[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\""); + + MT("labelTitleDoubleQuotes", + "[link [[foo]]:] [string http://example.com/ \"bar\"]"); + + MT("labelTitleSingleQuotes", + "[link [[foo]]:] [string http://example.com/ 'bar']"); + + MT("labelTitleParenthese", + "[link [[foo]]:] [string http://example.com/ (bar)]"); + + MT("labelTitleInvalid", + "[link [[foo]]:] [string http://example.com/] bar"); + + MT("labelLinkAngleBrackets", + "[link [[foo]]:] [string!! This mode is deprecated in favor of the generic SQL mode (which can be configured to handle MySQL).
+ +MIME types defined: text/x-mysql
.
MIME types defined: text/n-triples
.
MIME types defined: text/x-ocaml
.
MIME types defined: text/x-pascal
.
MIME types defined: text/x-perl
.
Simple HTML/PHP mode based on + the C-like mode. Depends on XML, + JavaScript, CSS, HTMLMixed, and C-like modes.
+ +MIME types defined: application/x-httpd-php
(HTML with PHP code), text/x-php
(plain, non-wrapped PHP code).
+ Simple mode that handles Pig Latin language. +
+ +MIME type defined: text/x-pig
+ (PIG code)
+
diff --git a/lib/codemirror-3.1/mode/pig/pig.js b/lib/codemirror-3.1/mode/pig/pig.js
new file mode 100644
index 0000000000000000000000000000000000000000..f8818a9b66b88bc294d1f34e8d4e109f88183d01
--- /dev/null
+++ b/lib/codemirror-3.1/mode/pig/pig.js
@@ -0,0 +1,171 @@
+/*
+ * Pig Latin Mode for CodeMirror 2
+ * @author Prasanth Jayachandran
+ * @link https://github.com/prasanthj/pig-codemirror-2
+ * This implementation is adapted from PL/SQL mode in CodeMirror 2.
+*/
+CodeMirror.defineMode("pig", function(_config, parserConfig) {
+ var keywords = parserConfig.keywords,
+ builtins = parserConfig.builtins,
+ types = parserConfig.types,
+ multiLineStrings = parserConfig.multiLineStrings;
+
+ var isOperatorChar = /[*+\-%<>=&?:\/!|]/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenComment(stream, state) {
+ var isEnd = false;
+ var ch;
+ while(ch = stream.next()) {
+ if(ch == "/" && isEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ isEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ end = true; break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "error");
+ };
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ // is a start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special chars
+ else if(/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // is it a number?
+ else if(/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or operator
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or operator
+ else if (ch=="-") {
+ if(stream.eat("-")){
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // is it an operator
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the while word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {
+ if (stream.eat(")") || stream.eat(".")) {
+ //keywords can be used as variables like flatten(group), group.$0 etc..
+ }
+ else {
+ return ("keyword", "keyword");
+ }
+ }
+ // is it one of the builtin functions?
+ if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))
+ {
+ return ("keyword", "variable-2");
+ }
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))
+ return ("keyword", "variable-3");
+ // default is a 'variable'
+ return ret("variable", "pig-word");
+ }
+ }
+
+ // Interface
+ return {
+ startState: function() {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if(stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+
+ // builtin funcs taken from trunk revision 1303237
+ var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
+ + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER ";
+
+ // taken from QueryLexer.g
+ var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "NEQ MATCHES TRUE FALSE ";
+
+ // data types
+ var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP ";
+
+ CodeMirror.defineMIME("text/x-pig", {
+ name: "pig",
+ builtins: keywords(pBuiltins),
+ keywords: keywords(pKeywords),
+ types: keywords(pTypes)
+ });
+}());
diff --git a/lib/codemirror-3.1/mode/plsql/index.html b/lib/codemirror-3.1/mode/plsql/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..52e60710d56b716714e971405b05453d505aa09c
--- /dev/null
+++ b/lib/codemirror-3.1/mode/plsql/index.html
@@ -0,0 +1,64 @@
+
+
+
!! This mode is deprecated in favor of the generic SQL mode (which can be configured to handle PL/SQL).
+ ++ Simple mode that handles Oracle PL/SQL language (and Oracle SQL, of course). +
+ +MIME type defined: text/x-plsql
+ (PLSQL code)
+
diff --git a/lib/codemirror-3.1/mode/plsql/plsql.js b/lib/codemirror-3.1/mode/plsql/plsql.js
new file mode 100644
index 0000000000000000000000000000000000000000..df119baee195b6bba14529dcf2491761e51547cc
--- /dev/null
+++ b/lib/codemirror-3.1/mode/plsql/plsql.js
@@ -0,0 +1,216 @@
+CodeMirror.defineMode("plsql", function(_config, parserConfig) {
+ var keywords = parserConfig.keywords,
+ functions = parserConfig.functions,
+ types = parserConfig.types,
+ sqlplus = parserConfig.sqlplus,
+ multiLineStrings = parserConfig.multiLineStrings;
+ var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+ // start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special signs []{}().,;? Seperator?
+ else if (/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // start of a number value?
+ else if (/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or simple operator?
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or simple operator?
+ else if (ch == "-") {
+ if (stream.eat("-")) {
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // pl/sql variable?
+ else if (ch == "@" || ch == "$") {
+ stream.eatWhile(/[\w\d\$_]/);
+ return ret("word", "variable");
+ }
+ // is it a operator?
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the whole word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "keyword");
+ // is it one of the listed functions?
+ if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "builtin");
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-2");
+ // is it one of the listed sqlplus keywords?
+ if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-3");
+ // default: just a "variable"
+ return ret("word", "variable");
+ }
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) {end = true; break;}
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "plsql-string");
+ };
+ }
+
+ function tokenComment(stream, state) {
+ var maybeEnd = false, ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ maybeEnd = (ch == "*");
+ }
+ return ret("comment", "plsql-comment");
+ }
+
+ // Interface
+
+ return {
+ startState: function() {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
+});
+
+(function() {
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
+ var cKeywords = "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 cFunctions = "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 cTypes = "bfile blob " +
+ "character clob " +
+ "dec " +
+ "float " +
+ "int integer " +
+ "mlslabel " +
+ "natural naturaln nchar nclob number numeric nvarchar2 " +
+ "real rowtype " +
+ "signtype smallint string " +
+ "varchar varchar2";
+
+ var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " +
+ "blockterminator break btitle " +
+ "cmdsep colsep compatibility compute concat copycommit copytypecheck " +
+ "define describe " +
+ "echo editfile embedded escape exec execute " +
+ "feedback flagger flush " +
+ "heading headsep " +
+ "instance " +
+ "linesize lno loboffset logsource long longchunksize " +
+ "markup " +
+ "native newpage numformat numwidth " +
+ "pagesize pause pno " +
+ "recsep recsepchar release repfooter repheader " +
+ "serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " +
+ "sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " +
+ "tab term termout time timing trimout trimspool ttitle " +
+ "underline " +
+ "verify version " +
+ "wrap";
+
+ CodeMirror.defineMIME("text/x-plsql", {
+ name: "plsql",
+ keywords: keywords(cKeywords),
+ functions: keywords(cFunctions),
+ types: keywords(cTypes),
+ sqlplus: keywords(cSqlplus)
+ });
+}());
diff --git a/lib/codemirror-3.1/mode/properties/index.html b/lib/codemirror-3.1/mode/properties/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..e21e02abd28d5e5d813f73c9fb1ad1da0b5ce350
--- /dev/null
+++ b/lib/codemirror-3.1/mode/properties/index.html
@@ -0,0 +1,41 @@
+
+
+
MIME types defined: text/x-properties
,
+ text/x-ini
.
Usefull for superset of python syntax like Enthought enaml, IPython magics and questionmark help
+^[\\+\\-\\*/%&|\\^~<>!]
^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]
^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))
^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
^((//=)|(>>=)|(<<=)|(\\*\\*=))
^[_A-Za-z][_A-Za-z0-9]*
MIME types defined: text/x-python
.
MIME type defined: text/x-q
.
MIME types defined: text/x-rsrc
.
Development of the CodeMirror R mode was kindly sponsored + by Ubalo, who hold + the license.
+ + + diff --git a/lib/codemirror-3.1/mode/r/r.js b/lib/codemirror-3.1/mode/r/r.js new file mode 100644 index 0000000000000000000000000000000000000000..6410efbb22723c98a48efafe4519d958f73508d4 --- /dev/null +++ b/lib/codemirror-3.1/mode/r/r.js @@ -0,0 +1,141 @@ +CodeMirror.defineMode("r", function(config) { + function wordObj(str) { + var words = str.split(" "), res = {}; + for (var i = 0; i < words.length; ++i) res[words[i]] = true; + return res; + } + var atoms = wordObj("NULL NA Inf NaN NA_integer_ NA_real_ NA_complex_ NA_character_"); + var builtins = wordObj("list quote bquote eval return call parse deparse"); + var keywords = wordObj("if else repeat while function for in next break"); + var blockkeywords = wordObj("if else repeat while function for"); + var opChars = /[+\-*\/^<>=!&|~$:]/; + var curPunc; + + function tokenBase(stream, state) { + curPunc = null; + var ch = stream.next(); + if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "0" && stream.eat("x")) { + stream.eatWhile(/[\da-f]/i); + return "number"; + } else if (ch == "." && stream.eat(/\d/)) { + stream.match(/\d*(?:e[+\-]?\d+)?/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/\d*(?:\.\d+)?(?:e[+\-]\d+)?L?/); + return "number"; + } else if (ch == "'" || ch == '"') { + state.tokenize = tokenString(ch); + return "string"; + } else if (ch == "." && stream.match(/.[.\d]+/)) { + return "keyword"; + } else if (/[\w\.]/.test(ch) && ch != "_") { + stream.eatWhile(/[\w\.]/); + var word = stream.current(); + if (atoms.propertyIsEnumerable(word)) return "atom"; + if (keywords.propertyIsEnumerable(word)) { + if (blockkeywords.propertyIsEnumerable(word)) curPunc = "block"; + return "keyword"; + } + if (builtins.propertyIsEnumerable(word)) return "builtin"; + return "variable"; + } else if (ch == "%") { + if (stream.skipTo("%")) stream.next(); + return "variable-2"; + } else if (ch == "<" && stream.eat("-")) { + return "arrow"; + } else if (ch == "=" && state.ctx.argList) { + return "arg-is"; + } else if (opChars.test(ch)) { + if (ch == "$") return "dollar"; + stream.eatWhile(opChars); + return "operator"; + } else if (/[\(\){}\[\];]/.test(ch)) { + curPunc = ch; + if (ch == ";") return "semi"; + return null; + } else { + return null; + } + } + + function tokenString(quote) { + return function(stream, state) { + if (stream.eat("\\")) { + var ch = stream.next(); + if (ch == "x") stream.match(/^[a-f0-9]{2}/i); + else if ((ch == "u" || ch == "U") && stream.eat("{") && stream.skipTo("}")) stream.next(); + else if (ch == "u") stream.match(/^[a-f0-9]{4}/i); + else if (ch == "U") stream.match(/^[a-f0-9]{8}/i); + else if (/[0-7]/.test(ch)) stream.match(/^[0-7]{1,2}/); + return "string-2"; + } else { + var next; + while ((next = stream.next()) != null) { + if (next == quote) { state.tokenize = tokenBase; break; } + if (next == "\\") { stream.backUp(1); break; } + } + return "string"; + } + }; + } + + function push(state, type, stream) { + state.ctx = {type: type, + indent: state.indent, + align: null, + column: stream.column(), + prev: state.ctx}; + } + function pop(state) { + state.indent = state.ctx.indent; + state.ctx = state.ctx.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, + ctx: {type: "top", + indent: -config.indentUnit, + align: false}, + indent: 0, + afterIdent: false}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.ctx.align == null) state.ctx.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (style != "comment" && state.ctx.align == null) state.ctx.align = true; + + var ctype = state.ctx.type; + if ((curPunc == ";" || curPunc == "{" || curPunc == "}") && ctype == "block") pop(state); + if (curPunc == "{") push(state, "}", stream); + else if (curPunc == "(") { + push(state, ")", stream); + if (state.afterIdent) state.ctx.argList = true; + } + else if (curPunc == "[") push(state, "]", stream); + else if (curPunc == "block") push(state, "block", stream); + else if (curPunc == ctype) pop(state); + state.afterIdent = style == "variable" || style == "keyword"; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.ctx, + closing = firstChar == ctx.type; + if (ctx.type == "block") return ctx.indent + (firstChar == "{" ? 0 : config.indentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indent + (closing ? 0 : config.indentUnit); + } + }; +}); + +CodeMirror.defineMIME("text/x-rsrc", "r"); diff --git a/lib/codemirror-3.1/mode/rpm/changes/changes.js b/lib/codemirror-3.1/mode/rpm/changes/changes.js new file mode 100644 index 0000000000000000000000000000000000000000..14a08d9700849eb74c727fb4e2bff8ee78befa73 --- /dev/null +++ b/lib/codemirror-3.1/mode/rpm/changes/changes.js @@ -0,0 +1,19 @@ +CodeMirror.defineMode("changes", function() { + var headerSeperator = /^-+$/; + var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /; + var simpleEmail = /^[\w+.-]+@[\w.-]+/; + + return { + token: function(stream) { + if (stream.sol()) { + if (stream.match(headerSeperator)) { return 'tag'; } + if (stream.match(headerLine)) { return 'tag'; } + } + if (stream.match(simpleEmail)) { return 'string'; } + stream.next(); + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-rpm-changes", "changes"); diff --git a/lib/codemirror-3.1/mode/rpm/changes/index.html b/lib/codemirror-3.1/mode/rpm/changes/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e0e2d8778bd0e8e128ac8348b60a4b77d49fb97d --- /dev/null +++ b/lib/codemirror-3.1/mode/rpm/changes/index.html @@ -0,0 +1,53 @@ + + + + +MIME types defined: text/x-rpm-changes
.
MIME types defined: text/x-rpm-spec
.
The reStructuredText mode supports one configuration parameter:
+verbatim (string)
If python
mode is available,
+ it will be used for highlighting blocks containing Python/IPython terminal
+ sessions (blocks starting with >>>
(for Python) or
+ In [num]:
(for IPython).
+
+
MIME types defined: text/x-rst
.
MIME types defined: text/x-ruby
.
Development of the CodeMirror Ruby mode was kindly sponsored + by Ubalo, who hold + the license.
+ + + diff --git a/lib/codemirror-3.1/mode/ruby/ruby.js b/lib/codemirror-3.1/mode/ruby/ruby.js new file mode 100644 index 0000000000000000000000000000000000000000..d106a542db5d7846a3087978a6d84c5db1d84808 --- /dev/null +++ b/lib/codemirror-3.1/mode/ruby/ruby.js @@ -0,0 +1,195 @@ +CodeMirror.defineMode("ruby", function(config) { + function wordObj(words) { + var o = {}; + for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; + return o; + } + var keywords = wordObj([ + "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", + "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", + "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", + "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", + "caller", "lambda", "proc", "public", "protected", "private", "require", "load", + "require_relative", "extend", "autoload" + ]); + var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then", + "catch", "loop", "proc", "begin"]); + var dedentWords = wordObj(["end", "until"]); + var matching = {"[": "]", "{": "}", "(": ")"}; + var curPunc; + + function chain(newtok, stream, state) { + state.tokenize.push(newtok); + return newtok(stream, state); + } + + function tokenBase(stream, state) { + curPunc = null; + if (stream.sol() && stream.match("=begin") && stream.eol()) { + state.tokenize.push(readBlockComment); + return "comment"; + } + if (stream.eatSpace()) return null; + var ch = stream.next(), m; + if (ch == "`" || ch == "'" || ch == '"' || + (ch == "/" && !stream.eol() && stream.peek() != " ")) { + return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); + } else if (ch == "%") { + var style, embed = false; + if (stream.eat("s")) style = "atom"; + else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; } + else if (stream.eat(/[wxqr]/)) style = "string"; + var delim = stream.eat(/[^\w\s]/); + if (!delim) return "operator"; + if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; + return chain(readQuoted(delim, style, embed, true), stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) { + return chain(readHereDoc(m[1]), stream, state); + } else if (ch == "0") { + if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); + else if (stream.eat("b")) stream.eatWhile(/[01]/); + else stream.eatWhile(/[0-7]/); + return "number"; + } else if (/\d/.test(ch)) { + stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); + return "number"; + } else if (ch == "?") { + while (stream.match(/^\\[CM]-/)) {} + if (stream.eat("\\")) stream.eatWhile(/\w/); + else stream.next(); + return "string"; + } else if (ch == ":") { + if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state); + if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state); + stream.eatWhile(/[\w\?]/); + return "atom"; + } else if (ch == "@") { + stream.eat("@"); + stream.eatWhile(/[\w\?]/); + return "variable-2"; + } else if (ch == "$") { + stream.next(); + stream.eatWhile(/[\w\?]/); + return "variable-3"; + } else if (/\w/.test(ch)) { + stream.eatWhile(/[\w\?]/); + if (stream.eat(":")) return "atom"; + return "ident"; + } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { + curPunc = "|"; + return null; + } else if (/[\(\)\[\]{}\\;]/.test(ch)) { + curPunc = ch; + return null; + } else if (ch == "-" && stream.eat(">")) { + return "arrow"; + } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { + stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); + return "operator"; + } else { + return null; + } + } + + function tokenBaseUntilBrace() { + var depth = 1; + return function(stream, state) { + if (stream.peek() == "}") { + depth--; + if (depth == 0) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length-1](stream, state); + } + } else if (stream.peek() == "{") { + depth++; + } + return tokenBase(stream, state); + }; + } + function readQuoted(quote, style, embed, unescaped) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && (unescaped || !escaped)) { + state.tokenize.pop(); + break; + } + if (embed && ch == "#" && !escaped && stream.eat("{")) { + state.tokenize.push(tokenBaseUntilBrace(arguments.callee)); + break; + } + escaped = !escaped && ch == "\\"; + } + return style; + }; + } + function readHereDoc(phrase) { + return function(stream, state) { + if (stream.match(phrase)) state.tokenize.pop(); + else stream.skipToEnd(); + return "string"; + }; + } + function readBlockComment(stream, state) { + if (stream.sol() && stream.match("=end") && stream.eol()) + state.tokenize.pop(); + stream.skipToEnd(); + return "comment"; + } + + return { + startState: function() { + return {tokenize: [tokenBase], + indented: 0, + context: {type: "top", indented: -config.indentUnit}, + continuedLine: false, + lastTok: null, + varList: false}; + }, + + token: function(stream, state) { + if (stream.sol()) state.indented = stream.indentation(); + var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype; + if (style == "ident") { + var word = stream.current(); + style = keywords.propertyIsEnumerable(stream.current()) ? "keyword" + : /^[A-Z]/.test(word) ? "tag" + : (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" + : "variable"; + if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; + else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; + else if ((word == "if" || word == "unless") && stream.column() == stream.indentation()) + kwtype = "indent"; + } + if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style; + if (curPunc == "|") state.varList = !state.varList; + + if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) + state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; + else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) + state.context = state.context.prev; + + if (stream.eol()) + state.continuedLine = (curPunc == "\\" || style == "operator"); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0); + var ct = state.context; + var closing = ct.type == matching[firstChar] || + ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter); + return ct.indented + (closing ? 0 : config.indentUnit) + + (state.continuedLine ? config.indentUnit : 0); + }, + electricChars: "}de" // enD and rescuE + + }; +}); + +CodeMirror.defineMIME("text/x-ruby", "ruby"); + diff --git a/lib/codemirror-3.1/mode/rust/index.html b/lib/codemirror-3.1/mode/rust/index.html new file mode 100644 index 0000000000000000000000000000000000000000..a6d47fe84db98e7804c6d36370c4124dab41d9c7 --- /dev/null +++ b/lib/codemirror-3.1/mode/rust/index.html @@ -0,0 +1,48 @@ + + + + +MIME types defined: text/x-rustsrc
.
MIME types defined: text/x-sass
.
MIME types defined: text/x-scheme
.
MIME types defined: text/x-sh
.
MIME types defined: application/sieve
.
Simple Smalltalk mode.
+ +MIME types defined: text/x-stsrc
.
A plain text/Smarty mode which allows for custom delimiter tags (defaults to { and }).
+ +MIME types defined: text/x-smarty
MIME types defined: application/x-sparql-query
.
MIME types defined:
+ text/x-sql
,
+ text/x-mysql
,
+ text/x-mariadb
,
+ text/x-plsql
.
+
+ Tests: + normal, + verbose. +
+ + diff --git a/lib/codemirror-3.1/mode/sql/sql.js b/lib/codemirror-3.1/mode/sql/sql.js new file mode 100644 index 0000000000000000000000000000000000000000..2a16882aea8ef2fabfd0c832b8abd68e5e26a433 --- /dev/null +++ b/lib/codemirror-3.1/mode/sql/sql.js @@ -0,0 +1,268 @@ +CodeMirror.defineMode("sql", function(config, parserConfig) { + "use strict"; + + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, + builtin = parserConfig.builtin || {}, + keywords = parserConfig.keywords, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/)) { + // hex + return "number"; + } else if (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) + || (ch == "0" && stream.match(/^b[01]+/))) { + // bitstring + return "number"; + } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); + return "number"; + } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { + // placeholders + return "variable-3"; + } else if (ch == '"' || ch == "'") { + // strings + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning + return null; + } else if (ch == "#" || (ch == "-" && stream.eat("-") && stream.eat(" "))) { + // 1-line comments + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (stream.match(/^[0-9eE]+/) && support.zerolessFloat == true) { + return "number"; + } + // .table_name (ODBC) + if (stream.match(/^[a-zA-Z_]+/) && support.ODBCdotTable == true) { + return "variable-2"; + } + } else if (operatorChars.test(ch)) { + // operators + stream.eatWhile(operatorChars); + return null; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + return "number"; + } else { + stream.eatWhile(/^[_\w\d]/); + var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + function tokenComment(stream, state) { + while (true) { + if (stream.skipTo("*")) { + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } + } else { + stream.skipToEnd(); + break; + } + } + return "comment"; + } + + function pushContext(stream, state, type) { + state.context = { + prev: state.context, + indent: stream.indentation(), + col: stream.column(), + type: type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent: function(state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + if (cx.align) return cx.col + (textAfter.charAt(0) == cx.type ? 0 : 1); + else return cx.indent + config.indentUnit; + } + }; +}); + +(function() { + "use strict"; + + // `identifier` + function hookIdentifier(stream) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !escaped) return "variable-2"; + escaped = !escaped && ch == "`"; + } + return null; + } + + // variable token + function hookVar(stream) { + // variables + // @@ and prefix + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + }; + + // short client keyword token + function hookClient(stream) { + // \g, etc + return stream.match(/^[a-zA-Z]\b/) ? "variable-2" : null; + } + + var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where "; + + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + CodeMirror.defineMIME("text/x-sql", { + name: "sql", + keywords: set(sqlKeywords + "begin"), + builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable") + }); + + CodeMirror.defineMIME("text/x-mysql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable zerolessFloat"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + CodeMirror.defineMIME("text/x-mariadb", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable zerolessFloat"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + // this is based on Peter Raganitsch's 'plsql' mode + CodeMirror.defineMIME("text/x-plsql", { + name: "sql", + client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), + keywords: set("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"), + functions: set("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"), + builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), + operatorChars: /^[*+\-%<>!=~]/, + dateSQL: set("date time timestamp") + }); +}()); diff --git a/lib/codemirror-3.1/mode/stex/index.html b/lib/codemirror-3.1/mode/stex/index.html new file mode 100644 index 0000000000000000000000000000000000000000..2dafe698160dfd7015cb9c68a286228b8f91d8f8 --- /dev/null +++ b/lib/codemirror-3.1/mode/stex/index.html @@ -0,0 +1,98 @@ + + + + +MIME types defined: text/x-stex
.
Parsing/Highlighting Tests: normal, verbose.
+ + + diff --git a/lib/codemirror-3.1/mode/stex/stex.js b/lib/codemirror-3.1/mode/stex/stex.js new file mode 100644 index 0000000000000000000000000000000000000000..42ed82c6690f93471b3e403f84fedd021f5191dc --- /dev/null +++ b/lib/codemirror-3.1/mode/stex/stex.js @@ -0,0 +1,175 @@ +/* + * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de) + * Licence: MIT + */ + +CodeMirror.defineMode("stex", function() +{ + function pushCommand(state, command) { + state.cmdState.push(command); + } + + function peekCommand(state) { + if (state.cmdState.length>0) + return state.cmdState[state.cmdState.length-1]; + else + return null; + } + + function popCommand(state) { + if (state.cmdState.length>0) { + var plug = state.cmdState.pop(); + plug.closeBracket(); + } + } + + function applyMostPowerful(state) { + var context = state.cmdState; + for (var i = context.length - 1; i >= 0; i--) { + var plug = context[i]; + if (plug.name=="DEFAULT") + continue; + return plug.styleIdentifier(); + } + return null; + } + + function addPluginPattern(pluginName, cmdStyle, brackets, styles) { + return function () { + this.name=pluginName; + this.bracketNo = 0; + this.style=cmdStyle; + this.styles = styles; + this.brackets = brackets; + + this.styleIdentifier = function() { + if (this.bracketNo<=this.styles.length) + return this.styles[this.bracketNo-1]; + else + return null; + }; + this.openBracket = function() { + this.bracketNo++; + return "bracket"; + }; + this.closeBracket = function() {}; + }; + } + + var plugins = new Array(); + + plugins["importmodule"] = addPluginPattern("importmodule", "tag", "{[", ["string", "builtin"]); + plugins["documentclass"] = addPluginPattern("documentclass", "tag", "{[", ["", "atom"]); + plugins["usepackage"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + plugins["begin"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + plugins["end"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + + plugins["DEFAULT"] = function () { + this.name="DEFAULT"; + this.style="tag"; + + this.styleIdentifier = this.openBracket = this.closeBracket = function() {}; + }; + + function setState(state, f) { + state.f = f; + } + + function normal(source, state) { + if (source.match(/^\\[a-zA-Z@]+/)) { + var cmdName = source.current(); + cmdName = cmdName.substr(1, cmdName.length-1); + var plug; + if (plugins.hasOwnProperty(cmdName)) { + plug = plugins[cmdName]; + } else { + plug = plugins["DEFAULT"]; + } + plug = new plug(); + pushCommand(state, plug); + setState(state, beginParams); + return plug.style; + } + + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + + // white space control characters + if (source.match(/^\\[,;!\/]/)) { + return "tag"; + } + + var ch = source.next(); + if (ch == "%") { + // special case: % at end of its own line; stay in same state + if (!source.eol()) { + setState(state, inCComment); + } + return "comment"; + } + else if (ch=='}' || ch==']') { + plug = peekCommand(state); + if (plug) { + plug.closeBracket(ch); + setState(state, beginParams); + } else + return "error"; + return "bracket"; + } else if (ch=='{' || ch=='[') { + plug = plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + return "bracket"; + } + else if (/\d/.test(ch)) { + source.eatWhile(/[\w.%]/); + return "atom"; + } + else { + source.eatWhile(/[\w-_]/); + return applyMostPowerful(state); + } + } + + function inCComment(source, state) { + source.skipToEnd(); + setState(state, normal); + return "comment"; + } + + function beginParams(source, state) { + var ch = source.peek(); + if (ch == '{' || ch == '[') { + var lastPlug = peekCommand(state); + lastPlug.openBracket(ch); + source.eat(ch); + setState(state, normal); + return "bracket"; + } + if (/[ \t\r]/.test(ch)) { + source.eat(ch); + return null; + } + setState(state, normal); + lastPlug = peekCommand(state); + if (lastPlug) { + popCommand(state); + } + return normal(source, state); + } + + return { + startState: function() { return { f:normal, cmdState:[] }; }, + copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; }, + + token: function(stream, state) { + var t = state.f(stream, state); + return t; + } + }; +}); + +CodeMirror.defineMIME("text/x-stex", "stex"); +CodeMirror.defineMIME("text/x-latex", "stex"); diff --git a/lib/codemirror-3.1/mode/stex/test.js b/lib/codemirror-3.1/mode/stex/test.js new file mode 100644 index 0000000000000000000000000000000000000000..e7e9c29c1e1de002381804ae86da00db6d68789c --- /dev/null +++ b/lib/codemirror-3.1/mode/stex/test.js @@ -0,0 +1,104 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "stex"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("word", + "foo"); + + MT("twoWords", + "foo bar"); + + MT("beginEndDocument", + "[tag \\begin][bracket {][atom document][bracket }]", + "[tag \\end][bracket {][atom document][bracket }]"); + + MT("beginEndEquation", + "[tag \\begin][bracket {][atom equation][bracket }]", + " E=mc^2", + "[tag \\end][bracket {][atom equation][bracket }]"); + + MT("beginModule", + "[tag \\begin][bracket {][atom module][bracket }[[]]]"); + + MT("beginModuleId", + "[tag \\begin][bracket {][atom module][bracket }[[]id=bbt-size[bracket ]]]"); + + MT("importModule", + "[tag \\importmodule][bracket [[][string b-b-t][bracket ]]{][builtin b-b-t][bracket }]"); + + MT("importModulePath", + "[tag \\importmodule][bracket [[][tag \\KWARCslides][bracket {][string dmath/en/cardinality][bracket }]]{][builtin card][bracket }]"); + + MT("psForPDF", + "[tag \\PSforPDF][bracket [[][atom 1][bracket ]]{]#1[bracket }]"); + + MT("comment", + "[comment % foo]"); + + MT("tagComment", + "[tag \\item][comment % bar]"); + + MT("commentTag", + " [comment % \\item]"); + + MT("commentLineBreak", + "[comment %]", + "foo"); + + MT("tagErrorCurly", + "[tag \\begin][error }][bracket {]"); + + MT("tagErrorSquare", + "[tag \\item][error ]]][bracket {]"); + + MT("commentCurly", + "[comment % }]"); + + MT("tagHash", + "the [tag \\#] key"); + + MT("tagNumber", + "a [tag \\$][atom 5] stetson"); + + MT("tagPercent", + "[atom 100][tag \\%] beef"); + + MT("tagAmpersand", + "L [tag \\&] N"); + + MT("tagUnderscore", + "foo[tag \\_]bar"); + + MT("tagBracketOpen", + "[tag \\emph][bracket {][tag \\{][bracket }]"); + + MT("tagBracketClose", + "[tag \\emph][bracket {][tag \\}][bracket }]"); + + MT("tagLetterNumber", + "section [tag \\S][atom 1]"); + + MT("textTagNumber", + "para [tag \\P][atom 2]"); + + MT("thinspace", + "x[tag \\,]y"); + + MT("thickspace", + "x[tag \\;]y"); + + MT("negativeThinspace", + "x[tag \\!]y"); + + MT("periodNotSentence", + "J.\\ L.\\ is"); + + MT("periodSentence", + "X[tag \\@]. The"); + + MT("italicCorrection", + "[bracket {][tag \\em] If[tag \\/][bracket }] I"); + + MT("tagBracket", + "[tag \\newcommand][bracket {][tag \\pop][bracket }]"); +})(); diff --git a/lib/codemirror-3.1/mode/tiddlywiki/index.html b/lib/codemirror-3.1/mode/tiddlywiki/index.html new file mode 100644 index 0000000000000000000000000000000000000000..848f33a592b55d4099fa22bc674cf90554f134a4 --- /dev/null +++ b/lib/codemirror-3.1/mode/tiddlywiki/index.html @@ -0,0 +1,142 @@ + + + + +TiddlyWiki mode supports a single configuration.
+ +MIME types defined: text/x-tiddlywiki
.
MIME types defined: text/turtle
.
MIME type defined: text/x-vb
.
MIME types defined: text/vbscript
.
MIME types defined: text/velocity
.
Simple mode that tries to handle Verilog-like languages as well as it
+ can. Takes one configuration parameters: keywords
, an
+ object whose property names are the keywords in the language.
MIME types defined: text/x-verilog
(Verilog code).
The XML mode supports two configuration parameters:
+htmlMode (boolean)
br
) do not require a closing tag.alignCDATA (boolean)
MIME types defined: application/xml
, text/html
.
MIME types defined: application/xquery
.
Development of the CodeMirror XQuery mode was sponsored by + MarkLogic and developed by + Mike Brevoort. +
+ + + diff --git a/lib/codemirror-3.1/mode/xquery/test.js b/lib/codemirror-3.1/mode/xquery/test.js new file mode 100644 index 0000000000000000000000000000000000000000..41719dd169dc3c7acdae6f67c2db3a3293611ef9 --- /dev/null +++ b/lib/codemirror-3.1/mode/xquery/test.js @@ -0,0 +1,64 @@ +// Don't take these too seriously -- the expected results appear to be +// based on the results of actual runs without any serious manual +// verification. If a change you made causes them to fail, the test is +// as likely to wrong as the code. + +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "xquery"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("eviltest", + "[keyword xquery] [keyword version] [variable "1][keyword .][atom 0][keyword -][variable ml"][def&variable ;] [comment (: this is : a \"comment\" :)]", + " [keyword let] [variable $let] [keyword :=] [variable <x] [variable attr][keyword =][variable "value">"test"<func>][def&variable ;function]() [variable $var] {[keyword function]()} {[variable $var]}[variable <][keyword /][variable func><][keyword /][variable x>]", + " [keyword let] [variable $joe][keyword :=][atom 1]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [atom 1] },", + " [keyword element] [variable test] { [variable 'a'] }, [keyword attribute] [variable foo] { [variable "bar"] },", + " [def&variable fn:doc]()[[ [variable foo][keyword /][variable @bar] [keyword eq] [variable $let] ]],", + " [keyword //][variable x] } [comment (: a more 'evil' test :)]", + " [comment (: Modified Blakeley example (: with nested comment :) ... :)]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:declare]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:private]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:function]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:local]() {()}[variable ;]", + " [keyword let] [variable $let] [keyword :=] [variable <let>let] [variable $let] [keyword :=] [variable "let"<][keyword /let][variable >]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [keyword try] { [def&variable xdmp:version]() } [keyword catch]([variable $e]) { [def&variable xdmp:log]([variable $e]) } },", + " [keyword attribute] [variable fn:doc] { [variable "bar"] [variable castable] [keyword as] [atom xs:string] },", + " [keyword element] [variable text] { [keyword text] { [variable "text"] } },", + " [def&variable fn:doc]()[[ [qualifier child::][variable eq][keyword /]([variable @bar] [keyword |] [qualifier attribute::][variable attribute]) [keyword eq] [variable $let] ]],", + " [keyword //][variable fn:doc]", + " }"); + + MT("testEmptySequenceKeyword", + "[string \"foo\"] [keyword instance] [keyword of] [keyword empty-sequence]()"); + + MT("testMultiAttr", + "[tag][variable hello] [variable world][tag
]"); + + MT("test namespaced variable", + "[keyword declare] [keyword namespace] [variable e] [keyword =] [string \"http://example.com/ANamespace\"][variable ;declare] [keyword variable] [variable $e:exampleComThisVarIsNotRecognized] [keyword as] [keyword element]([keyword *]) [variable external;]"); + + MT("test EQName variable", + "[keyword declare] [keyword variable] [variable $\"http://www.example.com/ns/my\":var] [keyword :=] [atom 12][variable ;]", + "[tagMIME types defined: text/x-yaml
.
MIME type defined: text/x-z80
.
A limited set of programmatic sanity tests for CodeMirror.
+ +Please enable JavaScript...
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/codemirror-3.1/test/lint/acorn.js b/lib/codemirror-3.1/test/lint/acorn.js new file mode 100644 index 0000000000000000000000000000000000000000..6323b1fc6a039760ac7f87ebd03052669fe84269 --- /dev/null +++ b/lib/codemirror-3.1/test/lint/acorn.js @@ -0,0 +1,1593 @@ +// Acorn is a tiny, fast JavaScript parser written in JavaScript. +// +// Acorn was written by Marijn Haverbeke and released under an MIT +// license. The Unicode regexps (for identifiers and whitespace) were +// taken from [Esprima](http://esprima.org) by Ariya Hidayat. +// +// Git repositories for Acorn are available at +// +// http://marijnhaverbeke.nl/git/acorn +// https://github.com/marijnh/acorn.git +// +// Please use the [github bug tracker][ghbt] to report issues. +// +// [ghbt]: https://github.com/marijnh/acorn/issues + +(function(exports) { + "use strict"; + + exports.version = "0.0.1"; + + // The main exported interface (under `window.acorn` when in the + // browser) is a `parse` function that takes a code string and + // returns an abstract syntax tree as specified by [Mozilla parser + // API][api], with the caveat that the SpiderMonkey-specific syntax + // (`let`, `yield`, inline XML, etc) is not recognized. + // + // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API + + var options, input, inputLen, sourceFile; + + exports.parse = function(inpt, opts) { + input = String(inpt); inputLen = input.length; + options = opts || {}; + for (var opt in defaultOptions) if (!options.hasOwnProperty(opt)) + options[opt] = defaultOptions[opt]; + sourceFile = options.sourceFile || null; + return parseTopLevel(options.program); + }; + + // A second optional argument can be given to further configure + // the parser process. These options are recognized: + + var defaultOptions = exports.defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3 or 5. This + // influences support for strict mode, the set of reserved words, and + // support for getters and setter. + ecmaVersion: 5, + // Turn on `strictSemicolons` to prevent the parser from doing + // automatic semicolon insertion. + strictSemicolons: false, + // When `allowTrailingCommas` is false, the parser will not allow + // trailing commas in array and object literals. + allowTrailingCommas: true, + // By default, reserved words are not enforced. Enable + // `forbidReserved` to enforce them. + forbidReserved: false, + // When `trackComments` is turned on, the parser will attach + // `commentsBefore` and `commentsAfter` properties to AST nodes + // holding arrays of strings. A single comment may appear in both + // a `commentsBefore` and `commentsAfter` array (of the nodes + // after and before it), but never twice in the before (or after) + // array of different nodes. + trackComments: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `location` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null + }; + + // The `getLineInfo` function is mostly useful when the + // `locations` option is off (for performance reasons) and you + // want to find the line/column position for a given character + // offset. `input` should be the code string that the offset refers + // into. + + var getLineInfo = exports.getLineInfo = function(input, offset) { + for (var line = 1, cur = 0;;) { + lineBreak.lastIndex = cur; + var match = lineBreak.exec(input); + if (match && match.index < offset) { + ++line; + cur = match.index + match[0].length; + } else break; + } + return {line: line, column: offset - cur}; + }; + + // Acorn is organized as a tokenizer and a recursive-descent parser. + // Both use (closure-)global variables to keep their state and + // communicate. We already saw the `options`, `input`, and + // `inputLen` variables above (set in `parse`). + + // The current position of the tokenizer in the input. + + var tokPos; + + // The start and end offsets of the current token. + + var tokStart, tokEnd; + + // When `options.locations` is true, these hold objects + // containing the tokens start and end line/column pairs. + + var tokStartLoc, tokEndLoc; + + // The type and value of the current token. Token types are objects, + // named by variables against which they can be compared, and + // holding properties that describe them (indicating, for example, + // the precedence of an infix operator, and the original name of a + // keyword token). The kind of value that's held in `tokVal` depends + // on the type of the token. For literals, it is the literal value, + // for operators, the operator name, and so on. + + var tokType, tokVal; + + // These are used to hold arrays of comments when + // `options.trackComments` is true. + + var tokCommentsBefore, tokCommentsAfter; + + // Interal state for the tokenizer. To distinguish between division + // operators and regular expressions, it remembers whether the last + // token was one that is allowed to be followed by an expression. + // (If it is, a slash is probably a regexp, if it isn't it's a + // division operator. See the `parseStatement` function for a + // caveat.) + + var tokRegexpAllowed, tokComments; + + // When `options.locations` is true, these are used to keep + // track of the current line, and know when a new line has been + // entered. See the `curLineLoc` function. + + var tokCurLine, tokLineStart, tokLineStartNext; + + // These store the position of the previous token, which is useful + // when finishing a node and assigning its `end` position. + + var lastStart, lastEnd, lastEndLoc; + + // This is the parser's state. `inFunction` is used to reject + // `return` statements outside of functions, `labels` to verify that + // `break` and `continue` have somewhere to jump to, and `strict` + // indicates whether strict mode is on. + + var inFunction, labels, strict; + + // This function is used to raise exceptions on parse errors. It + // takes either a `{line, column}` object or an offset integer (into + // the current `input`) as `pos` argument. It attaches the position + // to the end of the error message, and then raises a `SyntaxError` + // with that message. + + function raise(pos, message) { + if (typeof pos == "number") pos = getLineInfo(input, pos); + message += " (" + pos.line + ":" + pos.column + ")"; + throw new SyntaxError(message); + } + + // ## Token types + + // The assignment of fine-grained, information-carrying type objects + // allows the tokenizer to store the information it has about a + // token in a way that is very cheap for the parser to look up. + + // All token type variables start with an underscore, to make them + // easy to recognize. + + // These are the general types. The `type` property is only used to + // make them recognizeable when debugging. + + var _num = {type: "num"}, _regexp = {type: "regexp"}, _string = {type: "string"}; + var _name = {type: "name"}, _eof = {type: "eof"}; + + // Keyword tokens. The `keyword` property (also used in keyword-like + // operators) indicates that the token originated from an + // identifier-like word, which is used when parsing property names. + // + // The `beforeExpr` property is used to disambiguate between regular + // expressions and divisions. It is set on all token types that can + // be followed by an expression (thus, a slash after them would be a + // regular expression). + // + // `isLoop` marks a keyword as starting a loop, which is important + // to know when parsing a label, in order to allow or disallow + // continue jumps to that label. + + var _break = {keyword: "break"}, _case = {keyword: "case", beforeExpr: true}, _catch = {keyword: "catch"}; + var _continue = {keyword: "continue"}, _debugger = {keyword: "debugger"}, _default = {keyword: "default"}; + var _do = {keyword: "do", isLoop: true}, _else = {keyword: "else", beforeExpr: true}; + var _finally = {keyword: "finally"}, _for = {keyword: "for", isLoop: true}, _function = {keyword: "function"}; + var _if = {keyword: "if"}, _return = {keyword: "return", beforeExpr: true}, _switch = {keyword: "switch"}; + var _throw = {keyword: "throw", beforeExpr: true}, _try = {keyword: "try"}, _var = {keyword: "var"}; + var _while = {keyword: "while", isLoop: true}, _with = {keyword: "with"}, _new = {keyword: "new", beforeExpr: true}; + var _this = {keyword: "this"}; + + // The keywords that denote values. + + var _null = {keyword: "null", atomValue: null}, _true = {keyword: "true", atomValue: true}; + var _false = {keyword: "false", atomValue: false}; + + // Some keywords are treated as regular operators. `in` sometimes + // (when parsing `for`) needs to be tested against specifically, so + // we assign a variable name to it for quick comparing. + + var _in = {keyword: "in", binop: 7, beforeExpr: true}; + + // Map keyword names to token types. + + var keywordTypes = {"break": _break, "case": _case, "catch": _catch, + "continue": _continue, "debugger": _debugger, "default": _default, + "do": _do, "else": _else, "finally": _finally, "for": _for, + "function": _function, "if": _if, "return": _return, "switch": _switch, + "throw": _throw, "try": _try, "var": _var, "while": _while, "with": _with, + "null": _null, "true": _true, "false": _false, "new": _new, "in": _in, + "instanceof": {keyword: "instanceof", binop: 7}, "this": _this, + "typeof": {keyword: "typeof", prefix: true}, + "void": {keyword: "void", prefix: true}, + "delete": {keyword: "delete", prefix: true}}; + + // Punctuation token types. Again, the `type` property is purely for debugging. + + var _bracketL = {type: "[", beforeExpr: true}, _bracketR = {type: "]"}, _braceL = {type: "{", beforeExpr: true}; + var _braceR = {type: "}"}, _parenL = {type: "(", beforeExpr: true}, _parenR = {type: ")"}; + var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true}; + var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true}; + + // Operators. These carry several kinds of properties to help the + // parser use them properly (the presence of these properties is + // what categorizes them as operators). + // + // `binop`, when present, specifies that this operator is a binary + // operator, and will refer to its precedence. + // + // `prefix` and `postfix` mark the operator as a prefix or postfix + // unary operator. `isUpdate` specifies that the node produced by + // the operator should be of type UpdateExpression rather than + // simply UnaryExpression (`++` and `--`). + // + // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as + // binary operators with a very low precedence, that should result + // in AssignmentExpression nodes. + + var _slash = {binop: 10, beforeExpr: true}, _eq = {isAssign: true, beforeExpr: true}; + var _assign = {isAssign: true, beforeExpr: true}, _plusmin = {binop: 9, prefix: true, beforeExpr: true}; + var _incdec = {postfix: true, prefix: true, isUpdate: true}, _prefix = {prefix: true, beforeExpr: true}; + var _bin1 = {binop: 1, beforeExpr: true}, _bin2 = {binop: 2, beforeExpr: true}; + var _bin3 = {binop: 3, beforeExpr: true}, _bin4 = {binop: 4, beforeExpr: true}; + var _bin5 = {binop: 5, beforeExpr: true}, _bin6 = {binop: 6, beforeExpr: true}; + var _bin7 = {binop: 7, beforeExpr: true}, _bin8 = {binop: 8, beforeExpr: true}; + var _bin10 = {binop: 10, beforeExpr: true}; + + // This is a trick taken from Esprima. It turns out that, on + // non-Chrome browsers, to check whether a string is in a set, a + // predicate containing a big ugly `switch` statement is faster than + // a regular expression, and on Chrome the two are about on par. + // This function uses `eval` (non-lexical) to produce such a + // predicate from a space-separated string of words. + // + // It starts by sorting the words by length. + + function makePredicate(words) { + words = words.split(" "); + var f = "", cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; + f += "return true}return false;"; + } + + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. + + if (cats.length > 3) { + cats.sort(function(a, b) {return b.length - a.length;}); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; + + // Otherwise, simply generate a flat `switch` statement. + + } else { + compareTo(words); + } + return new Function("str", f); + } + + // The ECMAScript 3 reserved word list. + + var isReservedWord3 = makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"); + + // ECMAScript 5 reserved words. + + var isReservedWord5 = makePredicate("class enum extends super const export import"); + + // The additional reserved words in strict mode. + + var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield"); + + // The forbidden variable names in strict mode. + + var isStrictBadIdWord = makePredicate("eval arguments"); + + // And the keywords. + + var isKeyword = makePredicate("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"); + + // ## Character categories + + // Big ugly regular expressions that match characters in the + // whitespace, identifier, and identifier-start categories. These + // are only applied when a character is found to actually have a + // code point above 128. + + var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/; + var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; + var nonASCIIidentifierChars = "\u0371-\u0374\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; + var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); + var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); + + // Whether a single character denotes a newline. + + var newline = /[\n\r\u2028\u2029]/; + + // Matches a whole line break (where CRLF is considered a single + // line break). Used to count lines. + + var lineBreak = /\r\n|[\n\r\u2028\u2029]/g; + + // Test whether a given character code starts an identifier. + + function isIdentifierStart(code) { + if (code < 65) return code === 36; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123)return true; + return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); + } + + // Test whether a given character is part of an identifier. + + function isIdentifierChar(code) { + if (code < 48) return code === 36; + if (code < 58) return true; + if (code < 65) return false; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123)return true; + return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); + } + + // ## Tokenizer + + // These are used when `options.locations` is on, in order to track + // the current line number and start of line offset, in order to set + // `tokStartLoc` and `tokEndLoc`. + + function nextLineStart() { + lineBreak.lastIndex = tokLineStart; + var match = lineBreak.exec(input); + return match ? match.index + match[0].length : input.length + 1; + } + + function curLineLoc() { + while (tokLineStartNext <= tokPos) { + ++tokCurLine; + tokLineStart = tokLineStartNext; + tokLineStartNext = nextLineStart(); + } + return {line: tokCurLine, column: tokPos - tokLineStart}; + } + + // Reset the token state. Used at the start of a parse. + + function initTokenState() { + tokCurLine = 1; + tokPos = tokLineStart = 0; + tokLineStartNext = nextLineStart(); + tokRegexpAllowed = true; + tokComments = null; + skipSpace(); + } + + // Called at the end of every token. Sets `tokEnd`, `tokVal`, + // `tokCommentsAfter`, and `tokRegexpAllowed`, and skips the space + // after the token, so that the next one's `tokStart` will point at + // the right position. + + function finishToken(type, val) { + tokEnd = tokPos; + if (options.locations) tokEndLoc = curLineLoc(); + tokType = type; + skipSpace(); + tokVal = val; + tokCommentsAfter = tokComments; + tokRegexpAllowed = type.beforeExpr; + } + + function skipBlockComment() { + var end = input.indexOf("*/", tokPos += 2); + if (end === -1) raise(tokPos - 2, "Unterminated comment"); + if (options.trackComments) + (tokComments || (tokComments = [])).push(input.slice(tokPos, end)); + tokPos = end + 2; + } + + function skipLineComment() { + var start = tokPos; + var ch = input.charCodeAt(tokPos+=2); + while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8329) { + ++tokPos; + ch = input.charCodeAt(tokPos); + } + (tokComments || (tokComments = [])).push(input.slice(start, tokPos)); + } + + // Called at the start of the parse and after every token. Skips + // whitespace and comments, and, if `options.trackComments` is on, + // will store all skipped comments in `tokComments`. + + function skipSpace() { + tokComments = null; + while (tokPos < inputLen) { + var ch = input.charCodeAt(tokPos); + if (ch === 47) { // '/' + var next = input.charCodeAt(tokPos+1); + if (next === 42) { // '*' + skipBlockComment(); + } else if (next === 47) { // '/' + skipLineComment(); + } else break; + } else if (ch < 14 && ch > 8) { + ++tokPos; + } else if (ch === 32 || ch === 160) { // ' ', '\xa0' + ++tokPos; + } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++tokPos; + } else { + break; + } + } + } + + // ### Token reading + + // This is the function that is called to fetch the next token. It + // is somewhat obscure, because it works in character codes rather + // than characters, and because operator parsing has been inlined + // into it. + // + // All in the name of speed. + // + // The `forceRegexp` parameter is used in the one case where the + // `tokRegexpAllowed` trick does not work. See `parseStatement`. + + function readToken(forceRegexp) { + tokStart = tokPos; + if (options.locations) tokStartLoc = curLineLoc(); + tokCommentsBefore = tokComments; + if (forceRegexp) return readRegexp(); + if (tokPos >= inputLen) return finishToken(_eof); + + var code = input.charCodeAt(tokPos); + // Identifier or keyword. '\uXXXX' sequences are allowed in + // identifiers, so '\' also dispatches to that. + if (isIdentifierStart(code) || code === 92 /* '\' */) return readWord(); + var next = input.charCodeAt(tokPos+1); + + switch(code) { + // The interpretation of a dot depends on whether it is followed + // by a digit. + case 46: // '.' + if (next >= 48 && next <= 57) return readNumber(String.fromCharCode(code)); + ++tokPos; + return finishToken(_dot); + + // Punctuation tokens. + case 40: ++tokPos; return finishToken(_parenL); + case 41: ++tokPos; return finishToken(_parenR); + case 59: ++tokPos; return finishToken(_semi); + case 44: ++tokPos; return finishToken(_comma); + case 91: ++tokPos; return finishToken(_bracketL); + case 93: ++tokPos; return finishToken(_bracketR); + case 123: ++tokPos; return finishToken(_braceL); + case 125: ++tokPos; return finishToken(_braceR); + case 58: ++tokPos; return finishToken(_colon); + case 63: ++tokPos; return finishToken(_question); + + // '0x' is a hexadecimal number. + case 48: // '0' + if (next === 120 || next === 88) return readHexNumber(); + // Anything else beginning with a digit is an integer, octal + // number, or float. + case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: // 1-9 + return readNumber(String.fromCharCode(code)); + + // Quotes produce strings. + case 34: case 39: // '"', "'" + return readString(code); + + // Operators are parsed inline in tiny state machines. '=' (61) is + // often referred to. `finishOp` simply skips the amount of + // characters it is given as second argument, and returns a token + // of the type given by its first argument. + + case 47: // '/' + if (tokRegexpAllowed) {++tokPos; return readRegexp();} + if (next === 61) return finishOp(_assign, 2); + return finishOp(_slash, 1); + + case 37: case 42: // '%*' + if (next === 61) return finishOp(_assign, 2); + return finishOp(_bin10, 1); + + case 124: case 38: // '|&' + if (next === code) return finishOp(code === 124 ? _bin1 : _bin2, 2); + if (next === 61) return finishOp(_assign, 2); + return finishOp(code === 124 ? _bin3 : _bin5, 1); + + case 94: // '^' + if (next === 61) return finishOp(_assign, 2); + return finishOp(_bin4, 1); + + case 43: case 45: // '+-' + if (next === code) return finishOp(_incdec, 2); + if (next === 61) return finishOp(_assign, 2); + return finishOp(_plusmin, 1); + + case 60: case 62: // '<>' + var size = 1; + if (next === code) { + size = code === 62 && input.charCodeAt(tokPos+2) === 62 ? 3 : 2; + if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1); + return finishOp(_bin8, size); + } + if (next === 61) + size = input.charCodeAt(tokPos+2) === 61 ? 3 : 2; + return finishOp(_bin7, size); + + case 61: case 33: // '=!' + if (next === 61) return finishOp(_bin6, input.charCodeAt(tokPos+2) === 61 ? 3 : 2); + return finishOp(code === 61 ? _eq : _prefix, 1); + + case 126: // '~' + return finishOp(_prefix, 1); + } + + // If we are here, we either found a non-ASCII identifier + // character, or something that's entirely disallowed. + var ch = String.fromCharCode(code); + if (ch === "\\" || nonASCIIidentifierStart.test(ch)) return readWord(); + raise(tokPos, "Unexpected character '" + ch + "'"); + } + + function finishOp(type, size) { + var str = input.slice(tokPos, tokPos + size); + tokPos += size; + finishToken(type, str); + } + + // Parse a regular expression. Some context-awareness is necessary, + // since a '/' inside a '[]' set does not end the expression. + + function readRegexp() { + var content = "", escaped, inClass, start = tokPos; + for (;;) { + if (tokPos >= inputLen) raise(start, "Unterminated regular expression"); + var ch = input.charAt(tokPos); + if (newline.test(ch)) raise(start, "Unterminated regular expression"); + if (!escaped) { + if (ch === "[") inClass = true; + else if (ch === "]" && inClass) inClass = false; + else if (ch === "/" && !inClass) break; + escaped = ch === "\\"; + } else escaped = false; + ++tokPos; + } + var content = input.slice(start, tokPos); + ++tokPos; + // Need to use `readWord1` because '\uXXXX' sequences are allowed + // here (don't ask). + var mods = readWord1(); + if (mods && !/^[gmsiy]*$/.test(mods)) raise(start, "Invalid regexp flag"); + return finishToken(_regexp, new RegExp(content, mods)); + } + + // Read an integer in the given radix. Return null if zero digits + // were read, the integer value otherwise. When `len` is given, this + // will return `null` unless the integer has exactly `len` digits. + + function readInt(radix, len) { + var start = tokPos, total = 0; + for (;;) { + var code = input.charCodeAt(tokPos), val; + if (code >= 97) val = code - 97 + 10; // a + else if (code >= 65) val = code - 65 + 10; // A + else if (code >= 48 && code <= 57) val = code - 48; // 0-9 + else val = Infinity; + if (val >= radix) break; + ++tokPos; + total = total * radix + val; + } + if (tokPos === start || len != null && tokPos - start !== len) return null; + + return total; + } + + function readHexNumber() { + tokPos += 2; // 0x + var val = readInt(16); + if (val == null) raise(tokStart + 2, "Expected hexadecimal number"); + if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); + return finishToken(_num, val); + } + + // Read an integer, octal integer, or floating-point number. + + function readNumber(ch) { + var start = tokPos, isFloat = ch === "."; + if (!isFloat && readInt(10) == null) raise(start, "Invalid number"); + if (isFloat || input.charAt(tokPos) === ".") { + var next = input.charAt(++tokPos); + if (next === "-" || next === "+") ++tokPos; + if (readInt(10) === null && ch === ".") raise(start, "Invalid number"); + isFloat = true; + } + if (/e/i.test(input.charAt(tokPos))) { + var next = input.charAt(++tokPos); + if (next === "-" || next === "+") ++tokPos; + if (readInt(10) === null) raise(start, "Invalid number") + isFloat = true; + } + if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, "Identifier directly after number"); + + var str = input.slice(start, tokPos), val; + if (isFloat) val = parseFloat(str); + else if (ch !== "0" || str.length === 1) val = parseInt(str, 10); + else if (/[89]/.test(str) || strict) raise(start, "Invalid number"); + else val = parseInt(str, 8); + return finishToken(_num, val); + } + + // Read a string value, interpreting backslash-escapes. + + function readString(quote) { + tokPos++; + var str = []; + for (;;) { + if (tokPos >= inputLen) raise(tokStart, "Unterminated string constant"); + var ch = input.charCodeAt(tokPos); + if (ch === quote) { + ++tokPos; + return finishToken(_string, String.fromCharCode.apply(null, str)); + } + if (ch === 92) { // '\' + ch = input.charCodeAt(++tokPos); + var octal = /^[0-7]+/.exec(input.slice(tokPos, tokPos + 3)); + if (octal) octal = octal[0]; + while (octal && parseInt(octal, 8) > 255) octal = octal.slice(0, octal.length - 1); + if (octal === "0") octal = null; + ++tokPos; + if (octal) { + if (strict) raise(tokPos - 2, "Octal literal in strict mode"); + str.push(parseInt(octal, 8)); + tokPos += octal.length - 1; + } else { + switch (ch) { + case 110: str.push(10); break; // 'n' -> '\n' + case 114: str.push(13); break; // 'r' -> '\r' + case 120: str.push(readHexChar(2)); break; // 'x' + case 117: str.push(readHexChar(4)); break; // 'u' + case 85: str.push(readHexChar(8)); break; // 'U' + case 116: str.push(9); break; // 't' -> '\t' + case 98: str.push(8); break; // 'b' -> '\b' + case 118: str.push(11); break; // 'v' -> '\u000b' + case 102: str.push(12); break; // 'f' -> '\f' + case 48: str.push(0); break; // 0 -> '\0' + case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; // '\r\n' + case 10: break; // ' \n' + default: str.push(ch); break; + } + } + } else { + if (ch === 13 || ch === 10 || ch === 8232 || ch === 8329) raise(tokStart, "Unterminated string constant"); + if (ch !== 92) str.push(ch); // '\' + ++tokPos; + } + } + } + + // Used to read character escape sequences ('\x', '\u', '\U'). + + function readHexChar(len) { + var n = readInt(16, len); + if (n === null) raise(tokStart, "Bad character escape sequence"); + return n; + } + + // Used to signal to callers of `readWord1` whether the word + // contained any escape sequences. This is needed because words with + // escape sequences must not be interpreted as keywords. + + var containsEsc; + + // Read an identifier, and return it as a string. Sets `containsEsc` + // to whether the word contained a '\u' escape. + // + // Only builds up the word character-by-character when it actually + // containeds an escape, as a micro-optimization. + + function readWord1() { + containsEsc = false; + var word, first = true, start = tokPos; + for (;;) { + var ch = input.charCodeAt(tokPos); + if (isIdentifierChar(ch)) { + if (containsEsc) word += input.charAt(tokPos); + ++tokPos; + } else if (ch === 92) { // "\" + if (!containsEsc) word = input.slice(start, tokPos); + containsEsc = true; + if (input.charCodeAt(++tokPos) != 117) // "u" + raise(tokPos, "Expecting Unicode escape sequence \\uXXXX"); + ++tokPos; + var esc = readHexChar(4); + var escStr = String.fromCharCode(esc); + if (!escStr) raise(tokPos - 1, "Invalid Unicode escape"); + if (!(first ? isIdentifierStart(esc) : isIdentifierChar(esc))) + raise(tokPos - 4, "Invalid Unicode escape"); + word += escStr; + } else { + break; + } + first = false; + } + return containsEsc ? word : input.slice(start, tokPos); + } + + // Read an identifier or keyword token. Will check for reserved + // words when necessary. + + function readWord() { + var word = readWord1(); + var type = _name; + if (!containsEsc) { + if (isKeyword(word)) type = keywordTypes[word]; + else if (options.forbidReserved && + (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(word) || + strict && isStrictReservedWord(word)) + raise(tokStart, "The keyword '" + word + "' is reserved"); + } + return finishToken(type, word); + } + + // ## Parser + + // A recursive descent parser operates by defining functions for all + // syntactic elements, and recursively calling those, each function + // advancing the input stream and returning an AST node. Precedence + // of constructs (for example, the fact that `!x[1]` means `!(x[1])` + // instead of `(!x)[1]` is handled by the fact that the parser + // function that parses unary prefix operators is called first, and + // in turn calls the function that parses `[]` subscripts — that + // way, it'll receive the node for `x[1]` already parsed, and wraps + // *that* in the unary operator node. + // + // Acorn uses an [operator precedence parser][opp] to handle binary + // operator precedence, because it is much more compact than using + // the technique outlined above, which uses different, nesting + // functions to specify precedence, for all of the ten binary + // precedence levels that JavaScript defines. + // + // [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser + + // ### Parser utilities + + // Continue to the next token. + + function next() { + lastStart = tokStart; + lastEnd = tokEnd; + lastEndLoc = tokEndLoc; + readToken(); + } + + // Enter strict mode. Re-reads the next token to please pedantic + // tests ("use strict"; 010; -- should fail). + + function setStrict(strct) { + strict = strct; + tokPos = lastEnd; + skipSpace(); + readToken(); + } + + // Start an AST node, attaching a start offset and optionally a + // `commentsBefore` property to it. + + function startNode() { + var node = {type: null, start: tokStart, end: null}; + if (options.trackComments && tokCommentsBefore) { + node.commentsBefore = tokCommentsBefore; + tokCommentsBefore = null; + } + if (options.locations) + node.loc = {start: tokStartLoc, end: null, source: sourceFile}; + if (options.ranges) + node.range = [tokStart, 0]; + return node; + } + + // Start a node whose start offset/comments information should be + // based on the start of another node. For example, a binary + // operator node is only started after its left-hand side has + // already been parsed. + + function startNodeFrom(other) { + var node = {type: null, start: other.start}; + if (other.commentsBefore) { + node.commentsBefore = other.commentsBefore; + other.commentsBefore = null; + } + if (options.locations) + node.loc = {start: other.loc.start, end: null, source: other.loc.source}; + if (options.ranges) + node.range = [other.range[0], 0]; + + return node; + } + + // Finish an AST node, adding `type`, `end`, and `commentsAfter` + // properties. + // + // We keep track of the last node that we finished, in order + // 'bubble' `commentsAfter` properties up to the biggest node. I.e. + // in '`1 + 1 // foo', the comment should be attached to the binary + // operator node, not the second literal node. + + var lastFinishedNode; + + function finishNode(node, type) { + node.type = type; + node.end = lastEnd; + if (options.trackComments) { + if (tokCommentsAfter) { + node.commentsAfter = tokCommentsAfter; + tokCommentsAfter = null; + } else if (lastFinishedNode && lastFinishedNode.end === lastEnd) { + node.commentsAfter = lastFinishedNode.commentsAfter; + lastFinishedNode.commentsAfter = null; + } + lastFinishedNode = node; + } + if (options.locations) + node.loc.end = lastEndLoc; + if (options.ranges) + node.range[1] = lastEnd; + return node; + } + + // Test whether a statement node is the string literal `"use strict"`. + + function isUseStrict(stmt) { + return options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && + stmt.expression.type === "Literal" && stmt.expression.value === "use strict"; + } + + // Predicate that tests whether the next token is of the given + // type, and if yes, consumes it as a side effect. + + function eat(type) { + if (tokType === type) { + next(); + return true; + } + } + + // Test whether a semicolon can be inserted at the current position. + + function canInsertSemicolon() { + return !options.strictSemicolons && + (tokType === _eof || tokType === _braceR || newline.test(input.slice(lastEnd, tokStart))); + } + + // Consume a semicolon, or, failing that, see if we are allowed to + // pretend that there is a semicolon at this position. + + function semicolon() { + if (!eat(_semi) && !canInsertSemicolon()) unexpected(); + } + + // Expect a token of a given type. If found, consume it, otherwise, + // raise an unexpected token error. + + function expect(type) { + if (tokType === type) next(); + else unexpected(); + } + + // Raise an unexpected token error. + + function unexpected() { + raise(tokStart, "Unexpected token"); + } + + // Verify that a node is an lval — something that can be assigned + // to. + + function checkLVal(expr) { + if (expr.type !== "Identifier" && expr.type !== "MemberExpression") + raise(expr.start, "Assigning to rvalue"); + if (strict && expr.type === "Identifier" && isStrictBadIdWord(expr.name)) + raise(expr.start, "Assigning to " + expr.name + " in strict mode"); + } + + // ### Statement parsing + + // Parse a program. Initializes the parser, reads any number of + // statements, and wraps them in a Program node. Optionally takes a + // `program` argument. If present, the statements will be appended + // to its body instead of creating a new node. + + function parseTopLevel(program) { + initTokenState(); + lastStart = lastEnd = tokPos; + if (options.locations) lastEndLoc = curLineLoc(); + inFunction = strict = null; + labels = []; + readToken(); + + var node = program || startNode(), first = true; + if (!program) node.body = []; + while (tokType !== _eof) { + var stmt = parseStatement(); + node.body.push(stmt); + if (first && isUseStrict(stmt)) setStrict(true); + first = false; + } + return finishNode(node, "Program"); + }; + + var loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}; + + // Parse a single statement. + // + // If expecting a statement and finding a slash operator, parse a + // regular expression literal. This is to handle cases like + // `if (foo) /blah/.exec(foo);`, where looking at the previous token + // does not help. + + function parseStatement() { + if (tokType === _slash) + readToken(true); + + var starttype = tokType, node = startNode(); + + // Most types of statements are recognized by the keyword they + // start with. Many are trivial to parse, some require a bit of + // complexity. + + switch (starttype) { + case _break: case _continue: + next(); + var isBreak = starttype === _break; + if (eat(_semi) || canInsertSemicolon()) node.label = null; + else if (tokType !== _name) unexpected(); + else { + node.label = parseIdent(); + semicolon(); + } + + // Verify that there is an actual destination to break or + // continue to. + for (var i = 0; i < labels.length; ++i) { + var lab = labels[i]; + if (node.label == null || lab.name === node.label.name) { + if (lab.kind != null && (isBreak || lab.kind === "loop")) break; + if (node.label && isBreak) break; + } + } + if (i === labels.length) raise(node.start, "Unsyntactic " + starttype.keyword); + return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); + + case _debugger: + next(); + return finishNode(node, "DebuggerStatement"); + + case _do: + next(); + labels.push(loopLabel); + node.body = parseStatement(); + labels.pop(); + expect(_while); + node.test = parseParenExpression(); + semicolon(); + return finishNode(node, "DoWhileStatement"); + + // Disambiguating between a `for` and a `for`/`in` loop is + // non-trivial. Basically, we have to parse the init `var` + // statement or expression, disallowing the `in` operator (see + // the second parameter to `parseExpression`), and then check + // whether the next token is `in`. When there is no init part + // (semicolon immediately after the opening parenthesis), it is + // a regular `for` loop. + + case _for: + next(); + labels.push(loopLabel); + expect(_parenL); + if (tokType === _semi) return parseFor(node, null); + if (tokType === _var) { + var init = startNode(); + next(); + parseVar(init, true); + if (init.declarations.length === 1 && eat(_in)) + return parseForIn(node, init); + return parseFor(node, init); + } + var init = parseExpression(false, true); + if (eat(_in)) {checkLVal(init); return parseForIn(node, init);} + return parseFor(node, init); + + case _function: + next(); + return parseFunction(node, true); + + case _if: + next(); + node.test = parseParenExpression(); + node.consequent = parseStatement(); + node.alternate = eat(_else) ? parseStatement() : null; + return finishNode(node, "IfStatement"); + + case _return: + if (!inFunction) raise(tokStart, "'return' outside of function"); + next(); + + // In `return` (and `break`/`continue`), the keywords with + // optional arguments, we eagerly look for a semicolon or the + // possibility to insert one. + + if (eat(_semi) || canInsertSemicolon()) node.argument = null; + else { node.argument = parseExpression(); semicolon(); } + return finishNode(node, "ReturnStatement"); + + case _switch: + next(); + node.discriminant = parseParenExpression(); + node.cases = []; + expect(_braceL); + labels.push(switchLabel); + + // Statements under must be grouped (by label) in SwitchCase + // nodes. `cur` is used to keep the node that we are currently + // adding statements to. + + for (var cur, sawDefault; tokType != _braceR;) { + if (tokType === _case || tokType === _default) { + var isCase = tokType === _case; + if (cur) finishNode(cur, "SwitchCase"); + node.cases.push(cur = startNode()); + cur.consequent = []; + next(); + if (isCase) cur.test = parseExpression(); + else { + if (sawDefault) raise(lastStart, "Multiple default clauses"); sawDefault = true; + cur.test = null; + } + expect(_colon); + } else { + if (!cur) unexpected(); + cur.consequent.push(parseStatement()); + } + } + if (cur) finishNode(cur, "SwitchCase"); + next(); // Closing brace + labels.pop(); + return finishNode(node, "SwitchStatement"); + + case _throw: + next(); + if (newline.test(input.slice(lastEnd, tokStart))) + raise(lastEnd, "Illegal newline after throw"); + node.argument = parseExpression(); + return finishNode(node, "ThrowStatement"); + + case _try: + next(); + node.block = parseBlock(); + node.handlers = []; + while (tokType === _catch) { + var clause = startNode(); + next(); + expect(_parenL); + clause.param = parseIdent(); + if (strict && isStrictBadIdWord(clause.param.name)) + raise(clause.param.start, "Binding " + clause.param.name + " in strict mode"); + expect(_parenR); + clause.guard = null; + clause.body = parseBlock(); + node.handlers.push(finishNode(clause, "CatchClause")); + } + node.finalizer = eat(_finally) ? parseBlock() : null; + if (!node.handlers.length && !node.finalizer) + raise(node.start, "Missing catch or finally clause"); + return finishNode(node, "TryStatement"); + + case _var: + next(); + node = parseVar(node); + semicolon(); + return node; + + case _while: + next(); + node.test = parseParenExpression(); + labels.push(loopLabel); + node.body = parseStatement(); + labels.pop(); + return finishNode(node, "WhileStatement"); + + case _with: + if (strict) raise(tokStart, "'with' in strict mode"); + next(); + node.object = parseParenExpression(); + node.body = parseStatement(); + return finishNode(node, "WithStatement"); + + case _braceL: + return parseBlock(); + + case _semi: + next(); + return finishNode(node, "EmptyStatement"); + + // If the statement does not start with a statement keyword or a + // brace, it's an ExpressionStatement or LabeledStatement. We + // simply start parsing an expression, and afterwards, if the + // next token is a colon and the expression was a simple + // Identifier node, we switch to interpreting it as a label. + + default: + var maybeName = tokVal, expr = parseExpression(); + if (starttype === _name && expr.type === "Identifier" && eat(_colon)) { + for (var i = 0; i < labels.length; ++i) + if (labels[i].name === maybeName) raise(expr.start, "Label '" + maybeName + "' is already declared"); + var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null; + labels.push({name: maybeName, kind: kind}); + node.body = parseStatement(); + node.label = expr; + return finishNode(node, "LabeledStatement"); + } else { + node.expression = expr; + semicolon(); + return finishNode(node, "ExpressionStatement"); + } + } + } + + // Used for constructs like `switch` and `if` that insist on + // parentheses around their expression. + + function parseParenExpression() { + expect(_parenL); + var val = parseExpression(); + expect(_parenR); + return val; + } + + // Parse a semicolon-enclosed block of statements, handling `"use + // strict"` declarations when `allowStrict` is true (used for + // function bodies). + + function parseBlock(allowStrict) { + var node = startNode(), first = true, strict = false, oldStrict; + node.body = []; + expect(_braceL); + while (!eat(_braceR)) { + var stmt = parseStatement(); + node.body.push(stmt); + if (first && isUseStrict(stmt)) { + oldStrict = strict; + setStrict(strict = true); + } + first = false + } + if (strict && !oldStrict) setStrict(false); + return finishNode(node, "BlockStatement"); + } + + // Parse a regular `for` loop. The disambiguation code in + // `parseStatement` will already have parsed the init statement or + // expression. + + function parseFor(node, init) { + node.init = init; + expect(_semi); + node.test = tokType === _semi ? null : parseExpression(); + expect(_semi); + node.update = tokType === _parenR ? null : parseExpression(); + expect(_parenR); + node.body = parseStatement(); + labels.pop(); + return finishNode(node, "ForStatement"); + } + + // Parse a `for`/`in` loop. + + function parseForIn(node, init) { + node.left = init; + node.right = parseExpression(); + expect(_parenR); + node.body = parseStatement(); + labels.pop(); + return finishNode(node, "ForInStatement"); + } + + // Parse a list of variable declarations. + + function parseVar(node, noIn) { + node.declarations = []; + node.kind = "var"; + for (;;) { + var decl = startNode(); + decl.id = parseIdent(); + if (strict && isStrictBadIdWord(decl.id.name)) + raise(decl.id.start, "Binding " + decl.id.name + " in strict mode"); + decl.init = eat(_eq) ? parseExpression(true, noIn) : null; + node.declarations.push(finishNode(decl, "VariableDeclarator")); + if (!eat(_comma)) break; + } + return finishNode(node, "VariableDeclaration"); + } + + // ### Expression parsing + + // These nest, from the most general expression type at the top to + // 'atomic', nondivisible expression types at the bottom. Most of + // the functions will simply let the function(s) below them parse, + // and, *if* the syntactic construct they handle is present, wrap + // the AST node that the inner parser gave them in another node. + + // Parse a full expression. The arguments are used to forbid comma + // sequences (in argument lists, array literals, or object literals) + // or the `in` operator (in for loops initalization expressions). + + function parseExpression(noComma, noIn) { + var expr = parseMaybeAssign(noIn); + if (!noComma && tokType === _comma) { + var node = startNodeFrom(expr); + node.expressions = [expr]; + while (eat(_comma)) node.expressions.push(parseMaybeAssign(noIn)); + return finishNode(node, "SequenceExpression"); + } + return expr; + } + + // Parse an assignment expression. This includes applications of + // operators like `+=`. + + function parseMaybeAssign(noIn) { + var left = parseMaybeConditional(noIn); + if (tokType.isAssign) { + var node = startNodeFrom(left); + node.operator = tokVal; + node.left = left; + next(); + node.right = parseMaybeAssign(noIn); + checkLVal(left); + return finishNode(node, "AssignmentExpression"); + } + return left; + } + + // Parse a ternary conditional (`?:`) operator. + + function parseMaybeConditional(noIn) { + var expr = parseExprOps(noIn); + if (eat(_question)) { + var node = startNodeFrom(expr); + node.test = expr; + node.consequent = parseExpression(true); + expect(_colon); + node.alternate = parseExpression(true, noIn); + return finishNode(node, "ConditionalExpression"); + } + return expr; + } + + // Start the precedence parser. + + function parseExprOps(noIn) { + return parseExprOp(parseMaybeUnary(noIn), -1, noIn); + } + + // Parse binary operators with the operator precedence parsing + // algorithm. `left` is the left-hand side of the operator. + // `minPrec` provides context that allows the function to stop and + // defer further parser to one of its callers when it encounters an + // operator that has a lower precedence than the set it is parsing. + + function parseExprOp(left, minPrec, noIn) { + var prec = tokType.binop; + if (prec != null && (!noIn || tokType !== _in)) { + if (prec > minPrec) { + var node = startNodeFrom(left); + node.left = left; + node.operator = tokVal; + next(); + node.right = parseExprOp(parseMaybeUnary(noIn), prec, noIn); + var node = finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression"); + return parseExprOp(node, minPrec, noIn); + } + } + return left; + } + + // Parse unary operators, both prefix and postfix. + + function parseMaybeUnary(noIn) { + if (tokType.prefix) { + var node = startNode(), update = tokType.isUpdate; + node.operator = tokVal; + node.prefix = true; + next(); + node.argument = parseMaybeUnary(noIn); + if (update) checkLVal(node.argument); + else if (strict && node.operator === "delete" && + node.argument.type === "Identifier") + raise(node.start, "Deleting local variable in strict mode"); + return finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); + } + var expr = parseExprSubscripts(); + while (tokType.postfix && !canInsertSemicolon()) { + var node = startNodeFrom(expr); + node.operator = tokVal; + node.prefix = false; + node.argument = expr; + checkLVal(expr); + next(); + expr = finishNode(node, "UpdateExpression"); + } + return expr; + } + + // Parse call, dot, and `[]`-subscript expressions. + + function parseExprSubscripts() { + return parseSubscripts(parseExprAtom()); + } + + function parseSubscripts(base, noCalls) { + if (eat(_dot)) { + var node = startNodeFrom(base); + node.object = base; + node.property = parseIdent(true); + node.computed = false; + return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); + } else if (eat(_bracketL)) { + var node = startNodeFrom(base); + node.object = base; + node.property = parseExpression(); + node.computed = true; + expect(_bracketR); + return parseSubscripts(finishNode(node, "MemberExpression"), noCalls); + } else if (!noCalls && eat(_parenL)) { + var node = startNodeFrom(base); + node.callee = base; + node.arguments = parseExprList(_parenR, false); + return parseSubscripts(finishNode(node, "CallExpression"), noCalls); + } else return base; + } + + // Parse an atomic expression — either a single token that is an + // expression, an expression started by a keyword like `function` or + // `new`, or an expression wrapped in punctuation like `()`, `[]`, + // or `{}`. + + function parseExprAtom() { + switch (tokType) { + case _this: + var node = startNode(); + next(); + return finishNode(node, "ThisExpression"); + case _name: + return parseIdent(); + case _num: case _string: case _regexp: + var node = startNode(); + node.value = tokVal; + node.raw = input.slice(tokStart, tokEnd); + next(); + return finishNode(node, "Literal"); + + case _null: case _true: case _false: + var node = startNode(); + node.value = tokType.atomValue; + next(); + return finishNode(node, "Literal"); + + case _parenL: + next(); + var val = parseExpression(); + expect(_parenR); + return val; + + case _bracketL: + var node = startNode(); + next(); + node.elements = parseExprList(_bracketR, true, true); + return finishNode(node, "ArrayExpression"); + + case _braceL: + return parseObj(); + + case _function: + var node = startNode(); + next(); + return parseFunction(node, false); + + case _new: + return parseNew(); + + default: + unexpected(); + } + } + + // New's precedence is slightly tricky. It must allow its argument + // to be a `[]` or dot subscript expression, but not a call — at + // least, not without wrapping it in parentheses. Thus, it uses the + + function parseNew() { + var node = startNode(); + next(); + node.callee = parseSubscripts(parseExprAtom(false), true); + if (eat(_parenL)) node.arguments = parseExprList(_parenR, false); + else node.arguments = []; + return finishNode(node, "NewExpression"); + } + + // Parse an object literal. + + function parseObj() { + var node = startNode(), first = true, sawGetSet = false; + node.properties = []; + next(); + while (!eat(_braceR)) { + if (!first) { + expect(_comma); + if (options.allowTrailingCommas && eat(_braceR)) break; + } else first = false; + + var prop = {key: parsePropertyName()}, isGetSet = false, kind; + if (eat(_colon)) { + prop.value = parseExpression(true); + kind = prop.kind = "init"; + } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" && + (prop.key.name === "get" || prop.key.name === "set")) { + isGetSet = sawGetSet = true; + kind = prop.kind = prop.key.name; + prop.key = parsePropertyName(); + if (!tokType === _parenL) unexpected(); + prop.value = parseFunction(startNode(), false); + } else unexpected(); + + // getters and setters are not allowed to clash — either with + // each other or with an init property — and in strict mode, + // init properties are also not allowed to be repeated. + + if (prop.key.type === "Identifier" && (strict || sawGetSet)) { + for (var i = 0; i < node.properties.length; ++i) { + var other = node.properties[i]; + if (other.key.name === prop.key.name) { + var conflict = kind == other.kind || isGetSet && other.kind === "init" || + kind === "init" && (other.kind === "get" || other.kind === "set"); + if (conflict && !strict && kind === "init" && other.kind === "init") conflict = false; + if (conflict) raise(prop.key.start, "Redefinition of property"); + } + } + } + node.properties.push(prop); + } + return finishNode(node, "ObjectExpression"); + } + + function parsePropertyName() { + if (tokType === _num || tokType === _string) return parseExprAtom(); + return parseIdent(true); + } + + // Parse a function declaration or literal (depending on the + // `isStatement` parameter). + + function parseFunction(node, isStatement) { + if (tokType === _name) node.id = parseIdent(); + else if (isStatement) unexpected(); + else node.id = null; + node.params = []; + var first = true; + expect(_parenL); + while (!eat(_parenR)) { + if (!first) expect(_comma); else first = false; + node.params.push(parseIdent()); + } + + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = inFunction, oldLabels = labels; + inFunction = true; labels = []; + node.body = parseBlock(true); + inFunction = oldInFunc; labels = oldLabels; + + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + if (strict || node.body.body.length && isUseStrict(node.body.body[0])) { + for (var i = node.id ? -1 : 0; i < node.params.length; ++i) { + var id = i < 0 ? node.id : node.params[i]; + if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) + raise(id.start, "Defining '" + id.name + "' in strict mode"); + if (i >= 0) for (var j = 0; j < i; ++j) if (id.name === node.params[j].name) + raise(id.start, "Argument name clash in strict mode"); + } + } + + return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); + } + + // Parses a comma-separated list of expressions, and returns them as + // an array. `close` is the token type that ends the list, and + // `allowEmpty` can be turned on to allow subsequent commas with + // nothing in between them to be parsed as `null` (which is needed + // for array literals). + + function parseExprList(close, allowTrailingComma, allowEmpty) { + var elts = [], first = true; + while (!eat(close)) { + if (!first) { + expect(_comma); + if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break; + } else first = false; + + if (allowEmpty && tokType === _comma) elts.push(null); + else elts.push(parseExpression(true)); + } + return elts; + } + + // Parse the next token as an identifier. If `liberal` is true (used + // when parsing properties), it will also convert keywords into + // identifiers. + + function parseIdent(liberal) { + var node = startNode(); + node.name = tokType === _name ? tokVal : (liberal && !options.forbidReserved && tokType.keyword) || unexpected(); + next(); + return finishNode(node, "Identifier"); + } + +})(typeof exports === "undefined" ? (window.acorn = {}) : exports); diff --git a/lib/codemirror-3.1/test/lint/lint.js b/lib/codemirror-3.1/test/lint/lint.js new file mode 100644 index 0000000000000000000000000000000000000000..b1b9381dd20444a6becd3141ac0c5ba5bebfdc8f --- /dev/null +++ b/lib/codemirror-3.1/test/lint/lint.js @@ -0,0 +1,108 @@ +/* + Simple linter, based on the Acorn [1] parser module + + All of the existing linters either cramp my style or have huge + dependencies (Closure). So here's a very simple, non-invasive one + that only spots + + - missing semicolons and trailing commas + - variables or properties that are reserved words + - assigning to a variable you didn't declare + + [1]: https://github.com/marijnh/acorn/ +*/ + +var fs = require("fs"), acorn = require("./acorn.js"), walk = require("./walk.js"); + +var scopePasser = walk.make({ + ScopeBody: function(node, prev, c) { c(node, node.scope); } +}); + +function checkFile(fileName) { + var file = fs.readFileSync(fileName, "utf8"); + var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF]/); + if (badChar) + fail("Undesirable character " + badChar[0].charCodeAt(0) + " at position " + badChar.index, + {source: fileName}); + + try { + var parsed = acorn.parse(file, { + locations: true, + ecmaVersion: 3, + strictSemicolons: true, + allowTrailingCommas: false, + forbidReserved: true, + sourceFile: fileName + }); + } catch (e) { + fail(e.message, {source: fileName}); + return; + } + + var scopes = []; + + walk.simple(parsed, { + ScopeBody: function(node, scope) { + node.scope = scope; + scopes.push(scope); + } + }, walk.scopeVisitor, {vars: Object.create(null)}); + + var ignoredGlobals = Object.create(null); + + function inScope(name, scope) { + for (var cur = scope; cur; cur = cur.prev) + if (name in cur.vars) return true; + } + function checkLHS(node, scope) { + if (node.type == "Identifier" && !(node.name in ignoredGlobals) && + !inScope(node.name, scope)) { + ignoredGlobals[node.name] = true; + fail("Assignment to global variable", node.loc); + } + } + + walk.simple(parsed, { + UpdateExpression: function(node, scope) {checkLHS(node.argument, scope);}, + AssignmentExpression: function(node, scope) {checkLHS(node.left, scope);}, + Identifier: function(node, scope) { + // Mark used identifiers + for (var cur = scope; cur; cur = cur.prev) + if (node.name in cur.vars) { + cur.vars[node.name].used = true; + return; + } + }, + FunctionExpression: function(node) { + if (node.id) fail("Named function expression", node.loc); + } + }, scopePasser); + + for (var i = 0; i < scopes.length; ++i) { + var scope = scopes[i]; + for (var name in scope.vars) { + var info = scope.vars[name]; + if (!info.used && info.type != "catch clause" && info.type != "function name" && name.charAt(0) != "_") + fail("Unused " + info.type + " " + name, info.node.loc); + } + } +} + +var failed = false; +function fail(msg, pos) { + if (pos.start) msg += " (" + pos.start.line + ":" + pos.start.column + ")"; + console.log(pos.source.match(/[^\/]+$/)[0] + ": " + msg); + failed = true; +} + +function checkDir(dir) { + fs.readdirSync(dir).forEach(function(file) { + var fname = dir + "/" + file; + if (/\.js$/.test(file)) checkFile(fname); + else if (fs.lstatSync(fname).isDirectory()) checkDir(fname); + }); +} + +exports.checkDir = checkDir; +exports.checkFile = checkFile; +exports.success = function() { return !failed; }; diff --git a/lib/codemirror-3.1/test/lint/parse-js.js b/lib/codemirror-3.1/test/lint/parse-js.js new file mode 100644 index 0000000000000000000000000000000000000000..c165a273f3ee61cfb83c38cb71a987c2b0a36cdc --- /dev/null +++ b/lib/codemirror-3.1/test/lint/parse-js.js @@ -0,0 +1,1372 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file contains the tokenizer/parser. It is a port to JavaScript + of parse-js [1], a JavaScript parser library written in Common Lisp + by Marijn Haverbeke. Thank you Marijn! + + [1] http://marijn.haverbeke.nl/parse-js/ + + Exported functions: + + - tokenizer(code) -- returns a function. Call the returned + function to fetch the next token. + + - parse(code) -- returns an AST of the given JavaScript code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon +' + text + ''; + s += '
' + text + ''; + s += '
' + + '' + + val.replace(/ /g,'\xb7') + + '' + + ' | '; + } + s += '
' + output[i] + ' | '; + } + s += '
{"version":3,"sources":["es5-shim.js"],"names":["definition","define","YUI","add","Empty","Function","prototype","bind","that","target","this","TypeError","args","_Array_slice_","call","arguments","binder","bound","result","apply","concat","Object","boundLength","Math","max","length","boundArgs","i","push","join","prototypeOfArray","Array","prototypeOfObject","slice","_toString","toString","owns","hasOwnProperty","defineGetter","defineSetter","lookupGetter","lookupSetter","supportsAccessors","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__","splice","array_splice","array_push","array_unshift","unshift","makeArray","l","a","array","lengthBefore","start","deleteCount","addElementsCount","isArray","obj","boxedString","splitString","boxedForEach","forEach","item","fun","object","toObject","self","split","thisp","map","filter","value","every","some","reduce","reduceRight","indexOf","sought","toInteger","lastIndexOf","min","abs","keys","hasDontEnumBug","dontEnums","dontEnumsLength","key","name","ii","dontEnum","negativeDate","negativeYearString","Date","toISOString","year","month","isFinite","RangeError","getUTCFullYear","getUTCMonth","floor","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","dateToJSONIsSupported","toJSON","NaN","e","o","tv","toPrimitive","toISO","parse","NativeDate","Y","M","D","h","m","s","ms","date","String","constructor","isoDateExpression","RegExp","months","dayFromMonth","t","toUTC","Number","now","UTC","string","match","exec","day","hour","minute","second","millisecond","isLocalTime","Boolean","signOffset","hourOffset","minuteOffset","getTime","toFixed","base","size","data","multiply","n","c","divide","pow","x","acc","log","fractionDigits","f","z","j","k","string_split","compliantExecNpcg","separator","limit","output","flags","ignoreCase","multiline","extended","sticky","lastLastIndex","source","separator2","lastIndex","lastLength","index","replace","test","substr","string_substr","ws","trim","trimBeginRegexp","trimEndRegexp","isPrimitive","input","type","val","valueOf"],"mappings":"CAMA,SAAWA,YAEP,SAAWC,SAAU,WAAY,CAC7BA,OAAOD,gBAEJ,UAAWE,MAAO,WAAY,CACjCA,IAAIC,IAAI,MAAOH,gBAEZ,CACHA,gBAEL,WAmBH,QAASI,UAET,IAAKC,SAASC,UAAUC,KAAM,CAC1BF,SAASC,UAAUC,KAAO,QAASA,MAAKC,MAEpC,GAAIC,QAASC,IAEb,UAAWD,SAAU,WAAY,CAC7B,KAAM,IAAIE,WAAU,kDAAoDF,QAK5E,GAAIG,MAAOC,cAAcC,KAAKC,UAAW,EAUzC,IAAIC,QAAS,WAET,GAAIN,eAAgBO,OAAO,CAiBvB,GAAIC,QAAST,OAAOU,MAChBT,KACAE,KAAKQ,OAAOP,cAAcC,KAAKC,YAEnC,IAAIM,OAAOH,UAAYA,OAAQ,CAC3B,MAAOA,QAEX,MAAOR,UAEJ,CAoBH,MAAOD,QAAOU,MACVX,KACAI,KAAKQ,OAAOP,cAAcC,KAAKC,cAa3C,IAAIO,aAAcC,KAAKC,IAAI,EAAGf,OAAOgB,OAASb,KAAKa,OAInD,IAAIC,aACJ,KAAK,GAAIC,GAAI,EAAGA,EAAIL,YAAaK,IAAK,CAClCD,UAAUE,KAAK,IAAMD,GASzB,GAAIV,OAAQZ,SAAS,SAAU,mBAAqBqB,UAAUG,KAAK,KAAO,0CAA0Cb,OAEpH,IAAIP,OAAOH,UAAW,CAClBF,MAAME,UAAYG,OAAOH,SACzBW,OAAMX,UAAY,GAAIF,MAEtBA,OAAME,UAAY,KAwBtB,MAAOW,QAQf,GAAIH,MAAOT,SAASC,UAAUQ,IAC9B,IAAIgB,kBAAmBC,MAAMzB,SAC7B,IAAI0B,mBAAoBX,OAAOf,SAC/B,IAAIO,eAAgBiB,iBAAiBG,KAErC,IAAIC,WAAYpB,KAAKP,KAAKyB,kBAAkBG,SAC5C,IAAIC,MAAOtB,KAAKP,KAAKyB,kBAAkBK,eAGvC,IAAIC,aACJ,IAAIC,aACJ,IAAIC,aACJ,IAAIC,aACJ,IAAIC,kBACJ,IAAKA,kBAAoBN,KAAKJ,kBAAmB,oBAAsB,CACnEM,aAAexB,KAAKP,KAAKyB,kBAAkBW,iBAC3CJ,cAAezB,KAAKP,KAAKyB,kBAAkBY,iBAC3CJ,cAAe1B,KAAKP,KAAKyB,kBAAkBa,iBAC3CJ,cAAe3B,KAAKP,KAAKyB,kBAAkBc,kBAa/C,IAAK,EAAE,GAAGC,OAAO,GAAGtB,QAAU,EAAG,CAC7B,GAAIuB,cAAejB,MAAMzB,UAAUyC,MACnC,IAAIE,YAAalB,MAAMzB,UAAUsB,IACjC,IAAIsB,eAAgBnB,MAAMzB,UAAU6C,OAEpC,IAAI,WACA,QAASC,WAAUC,GACf,GAAIC,KACJ,OAAOD,IAAK,CACRC,EAAEH,QAAQE,GAEd,MAAOC,GAGX,GAAIC,UACEC,YAGND,OAAMR,OAAOxC,KAAKgD,MAAO,EAAG,GAAGpC,MAAM,KAAMiC,UAAU,IACrDG,OAAMR,OAAOxC,KAAKgD,MAAO,EAAG,GAAGpC,MAAM,KAAMiC,UAAU,IAErDI,cAAeD,MAAM9B,MACrB8B,OAAMR,OAAO,EAAG,EAAG,MAEnB,IAAIS,aAAe,GAAKD,MAAM9B,OAAQ,CAClC,MAAO,UAKV,CACDM,MAAMzB,UAAUyC,OAAS,SAASU,MAAOC,aACrC,IAAK3C,UAAUU,OAAQ,CACnB,aACG,CACH,MAAOuB,cAAa7B,MAAMT,MACtB+C,YAAe,GAAI,EAAIA,MACvBC,kBAAqB,GAAKhD,KAAKe,OAASgC,MAASC,aACnDtC,OAAOP,cAAcC,KAAKC,UAAW,WAI9C,CACDgB,MAAMzB,UAAUyC,OAAS,SAASU,MAAOC,aACrC,GAAIxC,QACEN,KAAOC,cAAcC,KAAKC,UAAW,GACrC4C,iBAAmB/C,KAAKa,MAG9B,KAAKV,UAAUU,OAAQ,CACnB,SAGJ,GAAIgC,YAAe,GAAG,CAClBA,MAAQ,EAEZ,GAAIC,kBAAqB,GAAG,CACxBA,YAAchD,KAAKe,OAASgC,MAGhC,GAAIE,iBAAmB,EAAG,CACtB,GAAID,aAAe,EAAG,CAClB,GAAID,OAAS/C,KAAKe,OAAQ,CACtBwB,WAAW9B,MAAMT,KAAME,KACvB,UAGJ,GAAI6C,OAAS,EAAG,CACZP,cAAc/B,MAAMT,KAAME,KAC1B,WAKRM,OAASL,cAAcC,KAAKJ,KAAM+C,MAAOA,MAAQC,YACjD9C,MAAKgB,KAAKT,MAAMP,KAAMC,cAAcC,KAAKJ,KAAM+C,MAAQC,YAAahD,KAAKe,QACzEb,MAAKuC,QAAQhC,MAAMP,KAAMC,cAAcC,KAAKJ,KAAM,EAAG+C,OAGrD7C,MAAKuC,QAAQ,EAAGzC,KAAKe,OAErBuB,cAAa7B,MAAMT,KAAME,KAEzB,OAAOM,QAGX,MAAO8B,cAAalC,KAAKJ,KAAM+C,MAAOC,eAWlD,MAAOP,QAAQ,IAAM,EAAG,CACpB,GAAID,eAAgBnB,MAAMzB,UAAU6C,OACpCpB,OAAMzB,UAAU6C,QAAU,WACtBD,cAAc/B,MAAMT,KAAMK,UAC1B,OAAOL,MAAKe,QAOpB,IAAKM,MAAM6B,QAAS,CAChB7B,MAAM6B,QAAU,QAASA,SAAQC,KAC7B,MAAO3B,WAAU2B,MAAQ,kBAsBjC,GAAIC,aAAczC,OAAO,KACrB0C,YAAcD,YAAY,IAAM,OAAS,IAAKA,aAElD,IAAIE,cAAe,IACnB,IAAIjC,MAAMzB,UAAU2D,QAAS,CACzBlC,MAAMzB,UAAU2D,QAAQnD,KAAK,MAAO,SAASoD,KAAMvC,EAAGkC,KAClD,SAAWA,OAAQ,SAAUG,aAAe,QAIpD,IAAKjC,MAAMzB,UAAU2D,UAAYD,aAAc,CAC3CjC,MAAMzB,UAAU2D,QAAU,QAASA,SAAQE,KACvC,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJI,MAAQzD,UAAU,GAClBY,GAAK,EACLF,OAAS6C,KAAK7C,SAAW,CAG7B,IAAIS,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAGd,QAASgB,EAAIF,OAAQ,CACjB,GAAIE,IAAK2C,MAAM,CAIXH,IAAIrD,KAAK0D,MAAOF,KAAK3C,GAAIA,EAAGyC,WAS5C,IAAKrC,MAAMzB,UAAUmE,IAAK,CACtB1C,MAAMzB,UAAUmE,IAAM,QAASA,KAAIN,KAC/B,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJ3C,OAAS6C,KAAK7C,SAAW,EACzBP,OAASa,MAAMN,QACf+C,MAAQzD,UAAU,EAGtB,IAAImB,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAG9B,IAAK,GAAIxC,GAAI,EAAGA,EAAIF,OAAQE,IAAK,CAC7B,GAAIA,IAAK2C,MACLpD,OAAOS,GAAKwC,IAAIrD,KAAK0D,MAAOF,KAAK3C,GAAIA,EAAGyC,QAEhD,MAAOlD,SAOf,IAAKa,MAAMzB,UAAUoE,OAAQ,CACzB3C,MAAMzB,UAAUoE,OAAS,QAASA,QAAOP,KACrC,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACPH,OACR3C,OAAS6C,KAAK7C,SAAW,EACzBP,UACAyD,MACAH,MAAQzD,UAAU,EAGtB,IAAImB,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAG9B,IAAK,GAAIxC,GAAI,EAAGA,EAAIF,OAAQE,IAAK,CAC7B,GAAIA,IAAK2C,MAAM,CACXK,MAAQL,KAAK3C,EACb,IAAIwC,IAAIrD,KAAK0D,MAAOG,MAAOhD,EAAGyC,QAAS,CACnClD,OAAOU,KAAK+C,SAIxB,MAAOzD,SAOf,IAAKa,MAAMzB,UAAUsE,MAAO,CACxB7C,MAAMzB,UAAUsE,MAAQ,QAASA,OAAMT,KACnC,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJ3C,OAAS6C,KAAK7C,SAAW,EACzB+C,MAAQzD,UAAU,EAGtB,IAAImB,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAG9B,IAAK,GAAIxC,GAAI,EAAGA,EAAIF,OAAQE,IAAK,CAC7B,GAAIA,IAAK2C,QAASH,IAAIrD,KAAK0D,MAAOF,KAAK3C,GAAIA,EAAGyC,QAAS,CACnD,MAAO,QAGf,MAAO,OAOf,IAAKrC,MAAMzB,UAAUuE,KAAM,CACvB9C,MAAMzB,UAAUuE,KAAO,QAASA,MAAKV,KACjC,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJ3C,OAAS6C,KAAK7C,SAAW,EACzB+C,MAAQzD,UAAU,EAGtB,IAAImB,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAG9B,IAAK,GAAIxC,GAAI,EAAGA,EAAIF,OAAQE,IAAK,CAC7B,GAAIA,IAAK2C,OAAQH,IAAIrD,KAAK0D,MAAOF,KAAK3C,GAAIA,EAAGyC,QAAS,CAClD,MAAO,OAGf,MAAO,QAOf,IAAKrC,MAAMzB,UAAUwE,OAAQ,CACzB/C,MAAMzB,UAAUwE,OAAS,QAASA,QAAOX,KACrC,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJ3C,OAAS6C,KAAK7C,SAAW,CAG7B,IAAIS,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAI9B,IAAK1C,QAAUV,UAAUU,QAAU,EAAG,CAClC,KAAM,IAAId,WAAU,+CAGxB,GAAIgB,GAAI,CACR,IAAIT,OACJ,IAAIH,UAAUU,QAAU,EAAG,CACvBP,OAASH,UAAU,OAChB,CACH,EAAG,CACC,GAAIY,IAAK2C,MAAM,CACXpD,OAASoD,KAAK3C,IACd,OAIJ,KAAMA,GAAKF,OAAQ,CACf,KAAM,IAAId,WAAU,sDAEnB,MAGb,KAAOgB,EAAIF,OAAQE,IAAK,CACpB,GAAIA,IAAK2C,MAAM,CACXpD,OAASiD,IAAIrD,SAAU,GAAGI,OAAQoD,KAAK3C,GAAIA,EAAGyC,SAItD,MAAOlD,SAOf,IAAKa,MAAMzB,UAAUyE,YAAa,CAC9BhD,MAAMzB,UAAUyE,YAAc,QAASA,aAAYZ,KAC/C,GAAIC,QAASC,SAAS3D,MAClB4D,KAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXH,OACJ3C,OAAS6C,KAAK7C,SAAW,CAG7B,IAAIS,UAAUiC,MAAQ,oBAAqB,CACvC,KAAM,IAAIxD,WAAUwD,IAAM,sBAI9B,IAAK1C,QAAUV,UAAUU,QAAU,EAAG,CAClC,KAAM,IAAId,WAAU,oDAGxB,GAAIO,QAAQS,EAAIF,OAAS,CACzB,IAAIV,UAAUU,QAAU,EAAG,CACvBP,OAASH,UAAU,OAChB,CACH,EAAG,CACC,GAAIY,IAAK2C,MAAM,CACXpD,OAASoD,KAAK3C,IACd,OAIJ,KAAMA,EAAI,EAAG,CACT,KAAM,IAAIhB,WAAU,2DAEnB,MAGb,GAAIgB,EAAI,EAAG,CACP,MAAOT,QAGX,EAAG,CACC,GAAIS,IAAKjB,MAAM,CACXQ,OAASiD,IAAIrD,SAAU,GAAGI,OAAQoD,KAAK3C,GAAIA,EAAGyC,eAE7CzC,IAET,OAAOT,SAOf,IAAKa,MAAMzB,UAAU0E,UAAa,EAAG,GAAGA,QAAQ,EAAG,KAAO,EAAI,CAC1DjD,MAAMzB,UAAU0E,QAAU,QAASA,SAAQC,QACvC,GAAIX,MAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXF,SAAS3D,MACbe,OAAS6C,KAAK7C,SAAW,CAE7B,KAAKA,OAAQ,CACT,OAAQ,EAGZ,GAAIE,GAAI,CACR,IAAIZ,UAAUU,OAAS,EAAG,CACtBE,EAAIuD,UAAUnE,UAAU,IAI5BY,EAAIA,GAAK,EAAIA,EAAIJ,KAAKC,IAAI,EAAGC,OAASE,EACtC,MAAOA,EAAIF,OAAQE,IAAK,CACpB,GAAIA,IAAK2C,OAAQA,KAAK3C,KAAOsD,OAAQ,CACjC,MAAOtD,IAGf,OAAQ,GAOhB,IAAKI,MAAMzB,UAAU6E,cAAiB,EAAG,GAAGA,YAAY,GAAI,KAAO,EAAI,CACnEpD,MAAMzB,UAAU6E,YAAc,QAASA,aAAYF,QAC/C,GAAIX,MAAOP,aAAe7B,UAAUxB,OAAS,kBACrCA,KAAK6D,MAAM,IACXF,SAAS3D,MACbe,OAAS6C,KAAK7C,SAAW,CAE7B,KAAKA,OAAQ,CACT,OAAQ,EAEZ,GAAIE,GAAIF,OAAS,CACjB,IAAIV,UAAUU,OAAS,EAAG,CACtBE,EAAIJ,KAAK6D,IAAIzD,EAAGuD,UAAUnE,UAAU,KAGxCY,EAAIA,GAAK,EAAIA,EAAIF,OAASF,KAAK8D,IAAI1D,EACnC,MAAOA,GAAK,EAAGA,IAAK,CAChB,GAAIA,IAAK2C,OAAQW,SAAWX,KAAK3C,GAAI,CACjC,MAAOA,IAGf,OAAQ,GAWhB,IAAKN,OAAOiE,KAAM,CAEd,GAAIC,gBAAiB,KACjBC,WACI,WACA,iBACA,UACA,iBACA,gBACA,uBACA,eAEJC,gBAAkBD,UAAU/D,MAEhC,KAAK,GAAIiE,QAAQvD,SAAY,MAAO,CAChCoD,eAAiB,MAGrBlE,OAAOiE,KAAO,QAASA,MAAKlB,QAExB,SACYA,SAAU,gBAAmBA,SAAU,YAC/CA,SAAW,KACb,CACE,KAAM,IAAIzD,WAAU,sCAGxB,GAAI2E,QACJ,KAAK,GAAIK,QAAQvB,QAAQ,CACrB,GAAIhC,KAAKgC,OAAQuB,MAAO,CACpBL,KAAK1D,KAAK+D,OAIlB,GAAIJ,eAAgB,CAChB,IAAK,GAAI5D,GAAI,EAAGiE,GAAKH,gBAAiB9D,EAAIiE,GAAIjE,IAAK,CAC/C,GAAIkE,UAAWL,UAAU7D,EACzB,IAAIS,KAAKgC,OAAQyB,UAAW,CACxBP,KAAK1D,KAAKiE,YAItB,MAAOP,OAiBf,GAAIQ,eAAgB,YAChBC,mBAAqB,SACzB,KACKC,KAAK1F,UAAU2F,aACf,GAAID,MAAKF,cAAcG,cAAcjB,QAAQe,uBAAyB,EACzE,CACEC,KAAK1F,UAAU2F,YAAc,QAASA,eAClC,GAAI/E,QAAQO,OAAQkD,MAAOuB,KAAMC,KACjC,KAAKC,SAAS1F,MAAO,CACjB,KAAM,IAAI2F,YAAW,0DAGzBH,KAAOxF,KAAK4F,gBAEZH,OAAQzF,KAAK6F,aAEbL,OAAQ3E,KAAKiF,MAAML,MAAQ,GAC3BA,QAASA,MAAQ,GAAK,IAAM,EAG5BjF,SAAUiF,MAAQ,EAAGzF,KAAK+F,aACtB/F,KAAKgG,cAAehG,KAAKiG,gBAAiBjG,KAAKkG,gBACnDV,OACKA,KAAO,EAAI,IAAOA,KAAO,KAAO,IAAM,KACtC,QAAU3E,KAAK8D,IAAIa,OACnBjE,MAAM,GAAKiE,MAAQA,MAAQ,MAAQ,GAAK,EAG7CzE,QAASP,OAAOO,MAChB,OAAOA,SAAU,CACbkD,MAAQzD,OAAOO,OAGf,IAAIkD,MAAQ,GAAI,CACZzD,OAAOO,QAAU,IAAMkD,OAI/B,MACIuB,MAAO,IAAMhF,OAAOe,MAAM,EAAG,GAAGJ,KAAK,KACrC,IAAMX,OAAOe,MAAM,GAAGJ,KAAK,KAAO,KACjC,MAAQnB,KAAKmG,sBAAsB5E,OAAO,GAAK,KAU5D,GAAI6E,uBAAwB,KAC5B,KACIA,sBACId,KAAK1F,UAAUyG,QACf,GAAIf,MAAKgB,KAAKD,WAAa,MAC3B,GAAIf,MAAKF,cAAciB,SAAS/B,QAAQe,uBAAyB,GACjEC,KAAK1F,UAAUyG,OAAOjG,MAClBmF,YAAa,WACT,MAAO,SAIrB,MAAOgB,IAET,IAAKH,sBAAuB,CACxBd,KAAK1F,UAAUyG,OAAS,QAASA,QAAOrB,KAOpC,GAAIwB,GAAI7F,OAAOX,MACXyG,GAAKC,YAAYF,GACjBG,KAEJ,UAAWF,MAAO,WAAaf,SAASe,IAAK,CACzC,MAAO,MAIXE,MAAQH,EAAEjB,WAEV,UAAWoB,QAAS,WAAY,CAC5B,KAAM,IAAI1G,WAAU,wCAIxB,MAAO0G,OAAMvG,KAAKoG,IAiB1B,IAAKlB,KAAKsB,OAAS,sBAAuB,CAGtCtB,KAAO,SAAUuB,YAGb,QAASvB,MAAKwB,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,IAC5B,GAAIrG,QAASV,UAAUU,MACvB,IAAIf,eAAgB6G,YAAY,CAC5B,GAAIQ,MAAOtG,QAAU,GAAKuG,OAAOR,KAAOA,EAEpC,GAAID,YAAWvB,KAAKsB,MAAME,IAG1B/F,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,IAC/CrG,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,GAC5CpG,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,EAAGC,EAAGC,EAAGC,GACzCnG,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,EAAGC,EAAGC,GACtClG,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,EAAGC,GACnCjG,QAAU,EAAI,GAAI8F,YAAWC,EAAGC,GAChChG,QAAU,EAAI,GAAI8F,YAAWC,GACf,GAAID,WAEtBQ,MAAKE,YAAcjC,IACnB,OAAO+B,MAEX,MAAOR,YAAWpG,MAAMT,KAAMK,WAIlC,GAAImH,mBAAoB,GAAIC,QAAO,IAC/B,sBAEA,eACA,eACA,MACI,YACA,YACA,MACI,YACA,oBACJ,KACJ,IACI,KACA,MACI,SACA,WACA,YACJ,IACJ,WACJ,IAEA,IAAIC,SACA,EAAG,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAG3D,SAASC,cAAanC,KAAMC,OACxB,GAAImC,GAAInC,MAAQ,EAAI,EAAI,CACxB,OACIiC,QAAOjC,OACP5E,KAAKiF,OAAON,KAAO,KAAOoC,GAAK,GAC/B/G,KAAKiF,OAAON,KAAO,KAAOoC,GAAK,KAC/B/G,KAAKiF,OAAON,KAAO,KAAOoC,GAAK,KAC/B,KAAOpC,KAAO,MAItB,QAASqC,OAAMD,GACX,MAAOE,QAAO,GAAIjB,YAAW,KAAM,EAAG,EAAG,EAAG,EAAG,EAAGe,IAItD,IAAK,GAAI5C,OAAO6B,YAAY,CACxBvB,KAAKN,KAAO6B,WAAW7B,KAI3BM,KAAKyC,IAAMlB,WAAWkB,GACtBzC,MAAK0C,IAAMnB,WAAWmB,GACtB1C,MAAK1F,UAAYiH,WAAWjH,SAC5B0F,MAAK1F,UAAU2H,YAAcjC,IAG7BA,MAAKsB,MAAQ,QAASA,OAAMqB,QACxB,GAAIC,OAAQV,kBAAkBW,KAAKF,OACnC,IAAIC,MAAO,CAIP,GAAI1C,MAAOsC,OAAOI,MAAM,IACpBzC,MAAQqC,OAAOI,MAAM,IAAM,GAAK,EAChCE,IAAMN,OAAOI,MAAM,IAAM,GAAK,EAC9BG,KAAOP,OAAOI,MAAM,IAAM,GAC1BI,OAASR,OAAOI,MAAM,IAAM,GAC5BK,OAAST,OAAOI,MAAM,IAAM,GAC5BM,YAAc3H,KAAKiF,MAAMgC,OAAOI,MAAM,IAAM,GAAK,KAIjDO,YAAcC,QAAQR,MAAM,KAAOA,MAAM,IACzCS,WAAaT,MAAM,KAAO,IAAM,GAAK,EACrCU,WAAad,OAAOI,MAAM,KAAO,GACjCW,aAAef,OAAOI,MAAM,KAAO,GACnC1H,MACJ,IACI6H,MACIC,OAAS,GAAKC,OAAS,GAAKC,YAAc,EAC1C,GAAK,KAETF,OAAS,IAAMC,OAAS,IAAMC,YAAc,KAC5C/C,OAAS,GAAKA,MAAQ,IAAMmD,WAAa,IACzCC,aAAe,IACfT,KAAO,GACPA,IACIT,aAAanC,KAAMC,MAAQ,GAC3BkC,aAAanC,KAAMC,OAEzB,CACEjF,SACKmH,aAAanC,KAAMC,OAAS2C,KAAO,GACpCC,KACAO,WAAaD,YACb,EACJnI,UACKA,OAAS8H,OAASO,aAAeF,YAAc,GAChDJ,QACA,IAAOC,WACX,IAAIC,YAAa,CACbjI,OAASqH,MAAMrH,QAEnB,IAAK,QAAWA,QAAUA,QAAU,OAAS,CACzC,MAAOA,SAGf,MAAO8F,KAEX,MAAOO,YAAWD,MAAMnG,MAAMT,KAAMK,WAGxC,OAAOiF,OACRA,MAKP,IAAKA,KAAKyC,IAAK,CACXzC,KAAKyC,IAAM,QAASA,OAChB,OAAO,GAAIzC,OAAOwD,WAY1B,IAAKhB,OAAOlI,UAAUmJ,SAAW,KAAUA,QAAQ,KAAO,SAAW,GAAMA,QAAQ,KAAO,KAAO,MAAQA,QAAQ,KAAO,QAAU,kBAAsBA,QAAQ,KAAO,sBAAuB,EAEzL,WACG,GAAIC,MAAMC,KAAMC,KAAMjI,CAEtB+H,MAAO,GACPC,MAAO,CACPC,OAAQ,EAAG,EAAG,EAAG,EAAG,EAAG,EAEvB,SAASC,UAASC,EAAGC,GACjB,GAAIpI,IAAK,CACT,SAASA,EAAIgI,KAAM,CACfI,GAAKD,EAAIF,KAAKjI,EACdiI,MAAKjI,GAAKoI,EAAIL,IACdK,GAAIxI,KAAKiF,MAAMuD,EAAIL,OAI3B,QAASM,QAAOF,GACZ,GAAInI,GAAIgI,KAAMI,EAAI,CAClB,SAASpI,GAAK,EAAG,CACboI,GAAKH,KAAKjI,EACViI,MAAKjI,GAAKJ,KAAKiF,MAAMuD,EAAID,EACzBC,GAAKA,EAAID,EAAKJ,MAItB,QAASvH,YACL,GAAIR,GAAIgI,IACR,IAAI9B,GAAI,EACR,SAASlG,GAAK,EAAG,CACb,GAAIkG,IAAM,IAAMlG,IAAM,GAAKiI,KAAKjI,KAAO,EAAG,CACtC,GAAI2G,GAAIN,OAAO4B,KAAKjI,GACpB,IAAIkG,IAAM,GAAI,CACVA,EAAIS,MACD,CACHT,GAAK,UAAU5F,MAAM,EAAG,EAAIqG,EAAE7G,QAAU6G,IAIpD,MAAOT,GAGX,QAASoC,KAAIC,EAAGJ,EAAGK,KACf,MAAQL,KAAM,EAAIK,IAAOL,EAAI,IAAM,EAAIG,IAAIC,EAAGJ,EAAI,EAAGK,IAAMD,GAAKD,IAAIC,EAAIA,EAAGJ,EAAI,EAAGK,KAGtF,QAASC,KAAIF,GACT,GAAIJ,GAAI,CACR,OAAOI,GAAK,KAAM,CACdJ,GAAK,EACLI,IAAK,KAET,MAAOA,GAAK,EAAG,CACXJ,GAAK,CACLI,IAAK,EAET,MAAOJ,GAGXtB,OAAOlI,UAAUmJ,QAAU,SAAUY,gBACjC,GAAIC,GAAGJ,EAAGrC,EAAGD,EAAGX,EAAGsD,EAAGC,EAAGC,CAGzBH,GAAI9B,OAAO6B,eACXC,GAAIA,IAAMA,EAAI,EAAI/I,KAAKiF,MAAM8D,EAE7B,IAAIA,EAAI,GAAKA,EAAI,GAAI,CACjB,KAAM,IAAIjE,YAAW,yDAGzB6D,EAAI1B,OAAO9H,KAGX,IAAIwJ,IAAMA,EAAG,CACT,MAAO,MAIX,GAAIA,IAAM,MAAQA,GAAK,KAAM,CACzB,MAAOlC,QAAOkC,GAGlBrC,EAAI,EAEJ,IAAIqC,EAAI,EAAG,CACPrC,EAAI,GACJqC,IAAKA,EAGTtC,EAAI,GAEJ,IAAIsC,EAAI,MAAO,CAGXjD,EAAImD,IAAIF,EAAID,IAAI,EAAG,GAAI,IAAM,EAC7BM,GAAKtD,EAAI,EAAIiD,EAAID,IAAI,GAAIhD,EAAG,GAAKiD,EAAID,IAAI,EAAGhD,EAAG,EAC/CsD,IAAK,gBACLtD,GAAI,GAAKA,CAIT,IAAIA,EAAI,EAAG,CACP4C,SAAS,EAAGU,EACZC,GAAIF,CAEJ,OAAOE,GAAK,EAAG,CACXX,SAAS,IAAK,EACdW,IAAK,EAGTX,SAASI,IAAI,GAAIO,EAAG,GAAI,EACxBA,GAAIvD,EAAI,CAER,OAAOuD,GAAK,GAAI,CACZR,OAAO,GAAK,GACZQ,IAAK,GAGTR,OAAO,GAAKQ,EACZX,UAAS,EAAG,EACZG,QAAO,EACPpC,GAAIzF,eACD,CACH0H,SAAS,EAAGU,EACZV,UAAS,IAAO5C,EAAI,EACpBW,GAAIzF,WAAa,yBAAyBF,MAAM,EAAG,EAAIqI,IAI/D,GAAIA,EAAI,EAAG,CACPG,EAAI7C,EAAEnG,MAEN,IAAIgJ,GAAKH,EAAG,CACR1C,EAAIC,EAAI,wBAAwB5F,MAAM,EAAGqI,EAAIG,EAAI,GAAK7C,MACnD,CACHA,EAAIC,EAAID,EAAE3F,MAAM,EAAGwI,EAAIH,GAAK,IAAM1C,EAAE3F,MAAMwI,EAAIH,QAE/C,CACH1C,EAAIC,EAAID,EAGZ,MAAOA,QA2BnB,GAAI8C,cAAe1C,OAAO1H,UAAUiE,KACpC,IACI,KAAKA,MAAM,WAAW9C,SAAW,GACjC,IAAI8C,MAAM,YAAY9C,SAAW,GACjC,QAAQ8C,MAAM,QAAQ,KAAO,KAC7B,GAAGA,MAAM,MAAM9C,QACf,IAAI8C,MAAM,QAAQ9C,OAAS,EAC7B,EACG,WACG,GAAIkJ,mBAAoB,OAAO9B,KAAK,IAAI,SAAY,EAEpDb,QAAO1H,UAAUiE,MAAQ,SAAUqG,UAAWC,OAC1C,GAAIlC,QAASjI,IACb,IAAIkK,gBAAmB,IAAKC,QAAU,EAClC,QAGJ,IAAIxJ,OAAOf,UAAU6B,SAASrB,KAAK8J,aAAe,kBAAmB,CACjE,MAAOF,cAAavJ,MAAMT,KAAMK,WAGpC,GAAI+J,WACAC,OAASH,UAAUI,WAAa,IAAM,KAC7BJ,UAAUK,UAAa,IAAM,KAC7BL,UAAUM,SAAa,IAAM,KAC7BN,UAAUO,OAAa,IAAM,IACtCC,cAAgB,EAEhBR,UAAY,GAAIzC,QAAOyC,UAAUS,OAAQN,MAAQ,KACjDO,WAAY1C,MAAO2C,UAAWC,UAClC7C,SAAU,EACV,KAAKgC,kBAAmB,CAEpBW,WAAa,GAAInD,QAAO,IAAMyC,UAAUS,OAAS,WAAYN,OASjEF,MAAQA,YAAe,IAClB,IAAM,EACPA,QAAU,CACd,OAAOjC,MAAQgC,UAAU/B,KAAKF,QAAS,CAEnC4C,UAAY3C,MAAM6C,MAAQ7C,MAAM,GAAGnH,MACnC,IAAI8J,UAAYH,cAAe,CAC3BN,OAAOlJ,KAAK+G,OAAO1G,MAAMmJ,cAAexC,MAAM6C,OAG9C,KAAKd,mBAAqB/B,MAAMnH,OAAS,EAAG,CACxCmH,MAAM,GAAG8C,QAAQJ,WAAY,WACzB,IAAK,GAAI3J,GAAI,EAAGA,EAAIZ,UAAUU,OAAS,EAAGE,IAAK,CAC3C,GAAIZ,UAAUY,SAAY,GAAG,CACzBiH,MAAMjH,OAAU,OAKhC,GAAIiH,MAAMnH,OAAS,GAAKmH,MAAM6C,MAAQ9C,OAAOlH,OAAQ,CACjDM,MAAMzB,UAAUsB,KAAKT,MAAM2J,OAAQlC,MAAM3G,MAAM,IAEnDuJ,WAAa5C,MAAM,GAAGnH,MACtB2J,eAAgBG,SAChB,IAAIT,OAAOrJ,QAAUoJ,MAAO,CACxB,OAGR,GAAID,UAAUW,YAAc3C,MAAM6C,MAAO,CACrCb,UAAUW,aAGlB,GAAIH,gBAAkBzC,OAAOlH,OAAQ,CACjC,GAAI+J,aAAeZ,UAAUe,KAAK,IAAK,CACnCb,OAAOlJ,KAAK,SAEb,CACHkJ,OAAOlJ,KAAK+G,OAAO1G,MAAMmJ,gBAE7B,MAAON,QAAOrJ,OAASoJ,MAAQC,OAAO7I,MAAM,EAAG4I,OAASC,gBAU7D,IAAI,IAAIvG,UAAW,GAAG,GAAG9C,OAAQ,CACpCuG,OAAO1H,UAAUiE,MAAQ,SAASqG,UAAWC,OACzC,GAAID,gBAAmB,IAAKC,QAAU,EAAG,QACzC,OAAOH,cAAavJ,MAAMT,KAAMK,YAUxC,GAAI,GAAG6K,QAAU,KAAKA,QAAQ,KAAO,IAAK,CACtC,GAAIC,eAAgB7D,OAAO1H,UAAUsL,MAOrC5D,QAAO1H,UAAUsL,OAAS,SAASnI,MAAOhC,QACtC,MAAOoK,eAAc/K,KACjBJ,KACA+C,MAAQ,GAAMA,MAAQ/C,KAAKe,OAASgC,OAAS,EAAI,EAAIA,MAASA,MAC9DhC,SAOZ,GAAIqK,IAAK,oDACL,qEACA,cACJ,KAAK9D,OAAO1H,UAAUyL,MAAQD,GAAGC,OAAQ,CAGrCD,GAAK,IAAMA,GAAK,GAChB,IAAIE,iBAAkB,GAAI7D,QAAO,IAAM2D,GAAKA,GAAK,KAC7CG,cAAgB,GAAI9D,QAAO2D,GAAKA,GAAK,KACzC9D,QAAO1H,UAAUyL,KAAO,QAASA,QAC7B,GAAIrL,WAAc,IAAKA,OAAS,KAAM,CAClC,KAAM,IAAIC,WAAU,iBAAiBD,KAAK,cAE9C,MAAOsH,QAAOtH,MACTgL,QAAQM,gBAAiB,IACzBN,QAAQO,cAAe,KAapC,QAAS/G,WAAU4E,GACfA,GAAKA,CACL,IAAIA,IAAMA,EAAG,CACTA,EAAI,MACD,IAAIA,IAAM,GAAKA,IAAO,EAAE,GAAMA,MAAQ,EAAE,GAAI,CAC/CA,GAAKA,EAAI,IAAM,GAAKvI,KAAKiF,MAAMjF,KAAK8D,IAAIyE,IAE5C,MAAOA,GAGX,QAASoC,aAAYC,OACjB,GAAIC,YAAcD,MAClB,OACIA,SAAU,MACVC,OAAS,aACTA,OAAS,WACTA,OAAS,UACTA,OAAS,SAIjB,QAAShF,aAAY+E,OACjB,GAAIE,KAAKC,QAASnK,QAClB,IAAI+J,YAAYC,OAAQ,CACpB,MAAOA,OAEXG,QAAUH,MAAMG,OAChB,UAAWA,WAAY,WAAY,CAC/BD,IAAMC,QAAQxL,KAAKqL,MACnB,IAAID,YAAYG,KAAM,CAClB,MAAOA,MAGflK,SAAWgK,MAAMhK,QACjB,UAAWA,YAAa,WAAY,CAChCkK,IAAMlK,SAASrB,KAAKqL,MACpB,IAAID,YAAYG,KAAM,CAClB,MAAOA,MAGf,KAAM,IAAI1L,WAKd,GAAI0D,UAAW,SAAU6C,GACrB,GAAIA,GAAK,KAAM,CACX,KAAM,IAAIvG,WAAU,iBAAiBuG,EAAE,cAE3C,MAAO7F,QAAO6F"}
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
+ |
+ random()
+
+
+ |
+
+ |
+ randomize()
+
+
+ |
+
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ Date.now()
+
+
+ |
+
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
+ |
+ extend(parent)
+
+ Sets prototype of this function to an instance of parent function
+ |
+
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
+ |
+ mod(n)
+
+ Always positive modulus
+ |
+
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ Object.create(o)
+
+ ES5 Object.create
+ |
+
+
+
+
+ Color operations
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Color
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ ROT.Color.add(color1, color2)
+
+ Add two or more colors
+ |
+
<static> | +
+ ROT.Color.add_(color1, color2)
+
+ Add two or more colors, MODIFIES FIRST ARGUMENT
+ |
+
<static> | +
+ ROT.Color.fromString(str)
+
+
+ |
+
<static> | +
+ ROT.Color.hsl2rgb(color)
+
+ Converts an HSL color value to RGB.
+ |
+
<static> | +
+ ROT.Color.interpolate(color1, color2, factor)
+
+ Interpolate (blend) two colors with a given factor
+ |
+
<static> | +
+ ROT.Color.interpolateHSL(color1, color2, factor)
+
+ Interpolate (blend) two colors with a given factor in HSL mode
+ |
+
<static> | +
+ ROT.Color.multiply(color1, color2)
+
+ Multiply (mix) two or more colors
+ |
+
<static> | +
+ ROT.Color.multiply_(color1, color2)
+
+ Multiply (mix) two or more colors, MODIFIES FIRST ARGUMENT
+ |
+
<static> | +
+ ROT.Color.randomize(color, diff)
+
+ Create a new random color based on this one
+ |
+
<static> | +
+ ROT.Color.rgb2hsl(color)
+
+ Converts an RGB color value to HSL.
+ |
+
<static> | +
+ ROT.Color.toHex(color)
+
+
+ |
+
<static> | +
+ ROT.Color.toRGB(color)
+
+
+ |
+
+
+
+
+ Visual map display
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Display(options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ clear()
+
+ Clear the whole display (cover it with background color)
+ |
+
+ |
+ computeFontSize(availWidth, availHeight)
+
+ Compute the maximum font size to fit into a set of given constraints
+ |
+
+ |
+ computeSize(availWidth, availHeight)
+
+ Compute the maximum width/height to fit into a set of given constraints
+ |
+
+ |
+ DEBUG(x, y, what)
+
+ Debug helper, ideal as a map generator callback.
+ |
+
+ |
+ draw(x, y, ch, fg, bg)
+
+
+ |
+
+ |
+ drawText(x, y, text, maxWidth)
+
+ Draws a text at given position.
+ |
+
+ |
+ getContainer()
+
+ Returns the DOM node of this display
+ |
+
+ |
+ getOptions()
+
+ Returns currently set options
+ |
+
+ |
+ setOptions(options)
+
+
+ |
+
+
+
+
+ Asynchronous main loop
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Engine()
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ addActor(actor)
+
+
+ |
+
+ |
+ clear()
+
+ Remove all actors
+ |
+
+ |
+ lock()
+
+ Interrupt the engine by an asynchronous action
+ |
+
+ |
+ removeActor(actor)
+
+ Remove a previously added actor
+ |
+
+ |
+ start()
+
+ Start the main loop.
+ |
+
+ |
+ unlock()
+
+ Resume execution (paused by a previous lock)
+ |
+
+
+
Extends
+ ROT.FOV.
+
+
+ Discrete shadowcasting algorithm
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.FOV.DiscreteShadowcasting(lightPassesCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(x, y, R, callback)
+
+
+ |
+
+
+
Extends
+ ROT.FOV.
+
+
+ Precise shadowcasting algorithm
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.FOV.PreciseShadowcasting(lightPassesCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(x, y, R, callback)
+
+
+ |
+
+
+
+
+ Abstract FOV algorithm
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.FOV(lightPassesCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(x, y, R, callback)
+
+ Compute visibility
+ |
+
+
+
+
+ Lighting computation, based on a traditional FOV for multiple light sources and multiple passes.
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Lighting(reflectivityCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(lightingCallback)
+
+ Compute the lighting
+ |
+
+ |
+ reset()
+
+ Reset the pre-computed topology values.
+ |
+
+ |
+ setFOV(fov)
+
+ Set the used Field-Of-View algo
+ |
+
+ |
+ setLight(x, y, color)
+
+ Set (or remove) a light source
+ |
+
+ |
+ setOptions(options)
+
+ Adjust options at runtime
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Simple empty rectangular room
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Arena(width, height)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Cellular automaton map generator
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Cellular(width, height, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+ |
+ randomize(probability)
+
+ Fill the map with random values
+ |
+
+ |
+ set(x, y, value)
+
+
+ |
+
+
+
Extends
+ ROT.Map.Dungeon.
+
+
+ Random dungeon generator using human-like digging patterns.
+Heavily based on Mike Anderson's ideas from the "Tyrant" algo, mentioned at
+http://www.roguebasin.roguelikedevelopment.org/index.php?title=Dungeon-Building_Algorithm.
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Digger(width, height, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+ Create a map
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Recursively divided maze, http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.DividedMaze(width, height)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Dungeon map: has rooms and corridors
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Dungeon(width, height)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ getCorridors()
+
+ Get all generated corridors
+ |
+
+ |
+ getRooms()
+
+ Get all generated rooms
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Maze generator - Eller's algorithm
+See http://homepages.cwi.nl/~tromp/maze.html for explanation
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.EllerMaze(width, height)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.Feature.
+
+
+ Corridor
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Feature.Corridor(startX, startY, endX, endY)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(digCallback)
+
+
+ |
+
+ |
+ createPriorityWalls(priorityWallCallback)
+
+
+ |
+
<static> | +
+ ROT.Map.Feature.Corridor.createRandomAt(x, y, dx, dy, options)
+
+
+ |
+
+ |
+ debug()
+
+
+ |
+
+ |
+ isValid(isWallCallback, canBeDugCallback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.Feature.
+
+
+ Room
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Feature.Room(x1, y1, x2, y2, doorX, doorY)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ addDoor(x, y)
+
+
+ |
+
+ |
+ clearDoors()
+
+
+ |
+
+ |
+ create(digCallback)
+
+
+ |
+
<static> | +
+ ROT.Map.Feature.Room.createRandom(availWidth, availHeight, options)
+
+ Room of random size within a given dimensions
+ |
+
<static> | +
+ ROT.Map.Feature.Room.createRandomAt(x, y, dx, dy, options)
+
+ Room of random size, with a given doors and direction
+ |
+
<static> | +
+ ROT.Map.Feature.Room.createRandomCenter(cx, cy, options)
+
+ Room of random size, positioned around center coords
+ |
+
+ |
+ debug()
+
+
+ |
+
+ |
+ getBottom()
+
+
+ |
+
+ |
+ getCenter()
+
+
+ |
+
+ |
+ getDoors()
+
+
+ |
+
+ |
+ getLeft()
+
+
+ |
+
+ |
+ getRight()
+
+
+ |
+
+ |
+ getTop()
+
+
+ |
+
+ |
+ isValid(isWallCallback, canBeDugCallback)
+
+
+ |
+
+
+
+
+ Dungeon feature; has own .create() method
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Feature()
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(digCallback)
+
+
+ |
+
<static> | +
+ ROT.Map.Feature.createRandomAt(x, y, dx, dy, options)
+
+
+ |
+
+ |
+ debug()
+
+
+ |
+
+ |
+ isValid(canBeDugCallback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.
+
+
+ Icey's Maze generator
+See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.IceyMaze(width, height, regularity)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+
+
Extends
+ ROT.Map.Dungeon.
+
+
+ Dungeon generator which tries to fill the space evenly. Generates independent rooms and tries to connect them.
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map.Uniform(width, height, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+ Create a map.
+ |
+
+
+
+
+ Base map generator
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Map(width, height)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ create(callback)
+
+
+ |
+
+
+
+
+ 2D simplex noise generator
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Noise.Simplex(gradients)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ get(xin, yin)
+
+
+ |
+
+
+
+
+ Base noise generator
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Noise()
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ get(x, y)
+
+
+ |
+
+
+
Extends
+ ROT.Path.
+
+
+ Simplified A* algorithm: all edges have a value of 1
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Path.AStar(toX, toY, passableCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(fromX, fromY, callback)
+
+ Compute a path from a given point
+ |
+
+
+
Extends
+ ROT.Path.
+
+
+ Simplified Dijkstra's algorithm: all edges have a value of 1
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Path.Dijkstra(toX, toY, passableCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(fromX, fromY, callback)
+
+ Compute a path from a given point
+ |
+
+
+
+
+ Abstract pathfinder
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Path(toX, toY, passableCallback, options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ compute(fromX, fromY, callback)
+
+ Compute a path from a given point
+ |
+
+
+
+
+ This code is an implementation of Alea algorithm; (C) 2010 Johannes Baagøe.
+Alea is licensed according to the http://en.wikipedia.org/wiki/MIT_License.
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.RNG
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ ROT.RNG.getNormal(mean, stddev)
+
+
+ |
+
<static> | +
+ ROT.RNG.getPercentage()
+
+
+ |
+
<static> | +
+ ROT.RNG.getSeed()
+
+
+ |
+
<static> | +
+ ROT.RNG.getState()
+
+ Get RNG state.
+ |
+
<static> | +
+ ROT.RNG.getUniform()
+
+
+ |
+
<static> | +
+ ROT.RNG.getWeightedValue(data)
+
+
+ |
+
<static> | +
+ ROT.RNG.setSeed(seed)
+
+
+ |
+
<static> | +
+ ROT.RNG.setState(state)
+
+ Set a previously retrieved state.
+ |
+
+
+
+
+ Speed-based scheduler
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Scheduler()
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ add(item)
+
+
+ |
+
+ |
+ clear()
+
+ Clear all actors
+ |
+
+ |
+ next()
+
+ Schedule next actor
+ |
+
+ |
+ remove(item)
+
+ Remove a previously added item
+ |
+
+
+
+
+ (Markov process)-based string generator.
+Copied from a RogueBasin article.
+Offers configurable order and prior.
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.StringGenerator(options)
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
+ |
+ clear()
+
+ Remove all learning data
+ |
+
+ |
+ generate()
+
+
+ |
+
+ |
+ getStats()
+
+
+ |
+
+ |
+ observe(string)
+
+ Observe (learn) a string from a training set
+ |
+
+
+
+
+ Contains text tokenization and breaking routines
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT.Text
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ ROT.Text.measure(str, maxWidth)
+
+ Measure size of a resulting text block
+ |
+
<static> | +
+ ROT.Text.tokenize(str, maxWidth)
+
+ Convert string to a series of a formatting commands
+ |
+
+
+
+
+ Top-level ROT namespace
+
+
+
Defined in: <rot.js>.
+
+
Constructor Attributes | +Constructor Name and Description | +
---|---|
+ |
+
+ ROT
+
+
+ |
+
Field Attributes | +Field Name and Description | +
---|---|
<static> | +
+
+ ROT.DEFAULT_HEIGHT
+
+ Default height for display and map generators
+ |
+
<static> | +
+
+ ROT.DEFAULT_WIDTH
+
+ Default with for display and map generators
+ |
+
<static> | +
+
+ ROT.DIRS
+
+ Directional constants.
+ |
+
<static> | +
+
+ ROT.VK_0
+
+
+ |
+
<static> | +
+
+ ROT.VK_1
+
+
+ |
+
<static> | +
+
+ ROT.VK_2
+
+
+ |
+
<static> | +
+
+ ROT.VK_3
+
+
+ |
+
<static> | +
+
+ ROT.VK_4
+
+
+ |
+
<static> | +
+
+ ROT.VK_5
+
+
+ |
+
<static> | +
+
+ ROT.VK_6
+
+
+ |
+
<static> | +
+
+ ROT.VK_7
+
+
+ |
+
<static> | +
+
+ ROT.VK_8
+
+
+ |
+
<static> | +
+
+ ROT.VK_9
+
+
+ |
+
<static> | +
+
+ ROT.VK_A
+
+
+ |
+
<static> | +
+
+ ROT.VK_ACCEPT
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_ADD
+
+ + on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_ALT
+
+ Alt (Option on Mac) key.
+ |
+
<static> | +
+
+ ROT.VK_ALTGR
+
+ AltGr key on Linux.
+ |
+
<static> | +
+
+ ROT.VK_AMPERSAND
+
+ Ampersand (&) key.
+ |
+
<static> | +
+
+ ROT.VK_AT
+
+ Atmark (@) key.
+ |
+
<static> | +
+
+ ROT.VK_B
+
+
+ |
+
<static> | +
+
+ ROT.VK_BACK_QUOTE
+
+ Back tick (`) key.
+ |
+
<static> | +
+
+ ROT.VK_BACK_SLASH
+
+ Back slash (\) key.
+ |
+
<static> | +
+
+ ROT.VK_BACK_SPACE
+
+ Backspace key.
+ |
+
<static> | +
+
+ ROT.VK_C
+
+
+ |
+
<static> | +
+
+ ROT.VK_CANCEL
+
+ Cancel key.
+ |
+
<static> | +
+
+ ROT.VK_CAPS_LOCK
+
+ Caps lock.
+ |
+
<static> | +
+
+ ROT.VK_CIRCUMFLEX
+
+ Circumflex (^) key.
+ |
+
<static> | +
+
+ ROT.VK_CLEAR
+
+ 5 key on Numpad when NumLock is unlocked.
+ |
+
<static> | +
+
+ ROT.VK_CLOSE_BRACKET
+
+ Close square bracket (]) key.
+ |
+
<static> | +
+
+ ROT.VK_CLOSE_CURLY_BRACKET
+
+ Close curly bracket (}) key.
+ |
+
<static> | +
+
+ ROT.VK_CLOSE_PAREN
+
+ Close parenthesis ()) key.
+ |
+
<static> | +
+
+ ROT.VK_COLON
+
+ Colon (:) key.
+ |
+
<static> | +
+
+ ROT.VK_COMMA
+
+ Comma (,) key.
+ |
+
<static> | +
+
+ ROT.VK_CONTEXT_MENU
+
+
+ |
+
<static> | +
+
+ ROT.VK_CONTROL
+
+ Control key.
+ |
+
<static> | +
+
+ ROT.VK_CONVERT
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_D
+
+
+ |
+
<static> | +
+
+ ROT.VK_DECIMAL
+
+ Decimal point on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_DELETE
+
+ Del(ete) key.
+ |
+
<static> | +
+
+ ROT.VK_DIVIDE
+
+ / on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_DOLLAR
+
+ Dollar sign ($) key.
+ |
+
<static> | +
+
+ ROT.VK_DOUBLE_QUOTE
+
+ Double quote () key.
+ |
+
<static> | +
+
+ ROT.VK_DOWN
+
+ Down arrow.
+ |
+
<static> | +
+
+ ROT.VK_E
+
+
+ |
+
<static> | +
+
+ ROT.VK_EISU
+
+ 英数 key on Japanese Mac keyboard.
+ |
+
<static> | +
+
+ ROT.VK_END
+
+ End key.
+ |
+
<static> | +
+
+ ROT.VK_ENTER
+
+ Reserved, but not used.
+ |
+
<static> | +
+
+ ROT.VK_EQUALS
+
+ Equals (=) key.
+ |
+
<static> | +
+
+ ROT.VK_ESCAPE
+
+ Escape key.
+ |
+
<static> | +
+
+ ROT.VK_EXCLAMATION
+
+ Exclamation (!) key.
+ |
+
<static> | +
+
+ ROT.VK_EXECUTE
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_F
+
+
+ |
+
<static> | +
+
+ ROT.VK_F1
+
+ F1 key.
+ |
+
<static> | +
+
+ ROT.VK_F10
+
+ F10 key.
+ |
+
<static> | +
+
+ ROT.VK_F11
+
+ F11 key.
+ |
+
<static> | +
+
+ ROT.VK_F12
+
+ F12 key.
+ |
+
<static> | +
+
+ ROT.VK_F13
+
+ F13 key.
+ |
+
<static> | +
+
+ ROT.VK_F14
+
+ F14 key.
+ |
+
<static> | +
+
+ ROT.VK_F15
+
+ F15 key.
+ |
+
<static> | +
+
+ ROT.VK_F16
+
+ F16 key.
+ |
+
<static> | +
+
+ ROT.VK_F17
+
+ F17 key.
+ |
+
<static> | +
+
+ ROT.VK_F18
+
+ F18 key.
+ |
+
<static> | +
+
+ ROT.VK_F19
+
+ F19 key.
+ |
+
<static> | +
+
+ ROT.VK_F2
+
+ F2 key.
+ |
+
<static> | +
+
+ ROT.VK_F20
+
+ F20 key.
+ |
+
<static> | +
+
+ ROT.VK_F21
+
+ F21 key.
+ |
+
<static> | +
+
+ ROT.VK_F22
+
+ F22 key.
+ |
+
<static> | +
+
+ ROT.VK_F23
+
+ F23 key.
+ |
+
<static> | +
+
+ ROT.VK_F24
+
+ F24 key.
+ |
+
<static> | +
+
+ ROT.VK_F3
+
+ F3 key.
+ |
+
<static> | +
+
+ ROT.VK_F4
+
+ F4 key.
+ |
+
<static> | +
+
+ ROT.VK_F5
+
+ F5 key.
+ |
+
<static> | +
+
+ ROT.VK_F6
+
+ F6 key.
+ |
+
<static> | +
+
+ ROT.VK_F7
+
+ F7 key.
+ |
+
<static> | +
+
+ ROT.VK_F8
+
+ F8 key.
+ |
+
<static> | +
+
+ ROT.VK_F9
+
+ F9 key.
+ |
+
<static> | +
+
+ ROT.VK_FINAL
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_G
+
+
+ |
+
<static> | +
+
+ ROT.VK_GREATER_THAN
+
+ Greater-than (>) key.
+ |
+
<static> | +
+
+ ROT.VK_H
+
+
+ |
+
<static> | +
+
+ ROT.VK_HANGUL
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_HANJA
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_HASH
+
+ Hash (#) key.
+ |
+
<static> | +
+
+ ROT.VK_HELP
+
+ Help key.
+ |
+
<static> | +
+
+ ROT.VK_HOME
+
+ Home key.
+ |
+
<static> | +
+
+ ROT.VK_HYPHEN_MINUS
+
+ Hyphen-US/docs/Minus (-) key.
+ |
+
<static> | +
+
+ ROT.VK_I
+
+
+ |
+
<static> | +
+
+ ROT.VK_INSERT
+
+ Ins(ert) key.
+ |
+
<static> | +
+
+ ROT.VK_J
+
+
+ |
+
<static> | +
+
+ ROT.VK_JUNJA
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_K
+
+
+ |
+
<static> | +
+
+ ROT.VK_KANA
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_KANJI
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_L
+
+
+ |
+
<static> | +
+
+ ROT.VK_LEFT
+
+ Left arrow.
+ |
+
<static> | +
+
+ ROT.VK_LESS_THAN
+
+ Less-than (<) key.
+ |
+
<static> | +
+
+ ROT.VK_M
+
+
+ |
+
<static> | +
+
+ ROT.VK_META
+
+ Meta key on Linux, Command key on Mac.
+ |
+
<static> | +
+
+ ROT.VK_MODECHANGE
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_MULTIPLY
+
+ on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_N
+
+
+ |
+
<static> | +
+
+ ROT.VK_NONCONVERT
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_NUM_LOCK
+
+ Num Lock key.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD0
+
+ 0 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD1
+
+ 1 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD2
+
+ 2 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD3
+
+ 3 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD4
+
+ 4 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD5
+
+ 5 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD6
+
+ 6 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD7
+
+ 7 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD8
+
+ 8 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_NUMPAD9
+
+ 9 on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_O
+
+
+ |
+
<static> | +
+
+ ROT.VK_OPEN_BRACKET
+
+ Open square bracket ([) key.
+ |
+
<static> | +
+
+ ROT.VK_OPEN_CURLY_BRACKET
+
+ Open curly bracket ({) key.
+ |
+
<static> | +
+
+ ROT.VK_OPEN_PAREN
+
+ Open parenthesis (() key.
+ |
+
<static> | +
+
+ ROT.VK_P
+
+
+ |
+
<static> | +
+
+ ROT.VK_PAGE_DOWN
+
+ Page Down key.
+ |
+
<static> | +
+
+ ROT.VK_PAGE_UP
+
+ Page Up key.
+ |
+
<static> | +
+
+ ROT.VK_PAUSE
+
+ Pause key.
+ |
+
<static> | +
+
+ ROT.VK_PERCENT
+
+ Percent (%) key.
+ |
+
<static> | +
+
+ ROT.VK_PERIOD
+
+ Period (.
+ |
+
<static> | +
+
+ ROT.VK_PIPE
+
+ Pipe (|) key.
+ |
+
<static> | +
+
+ ROT.VK_PLUS
+
+ Plus (+) key.
+ |
+
<static> | +
+
+ ROT.VK_PRINT
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_PRINTSCREEN
+
+ Print Screen key.
+ |
+
<static> | +
+
+ ROT.VK_Q
+
+
+ |
+
<static> | +
+
+ ROT.VK_QUESTION_MARK
+
+ Question mark (?) key.
+ |
+
<static> | +
+
+ ROT.VK_QUOTE
+
+ Quote (''') key.
+ |
+
<static> | +
+
+ ROT.VK_R
+
+
+ |
+
<static> | +
+
+ ROT.VK_RETURN
+
+ Return/enter key on the main keyboard.
+ |
+
<static> | +
+
+ ROT.VK_RIGHT
+
+ Right arrow.
+ |
+
<static> | +
+
+ ROT.VK_S
+
+
+ |
+
<static> | +
+
+ ROT.VK_SCROLL_LOCK
+
+ Scroll Lock key.
+ |
+
<static> | +
+
+ ROT.VK_SELECT
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_SEMICOLON
+
+ Semicolon (;) key.
+ |
+
<static> | +
+
+ ROT.VK_SEPARATOR
+
+
+ |
+
<static> | +
+
+ ROT.VK_SHIFT
+
+ Shift key.
+ |
+
<static> | +
+
+ ROT.VK_SLASH
+
+ Slash (/) key.
+ |
+
<static> | +
+
+ ROT.VK_SLEEP
+
+ Linux support for this keycode was added in Gecko 4.0.
+ |
+
<static> | +
+
+ ROT.VK_SPACE
+
+ Space bar.
+ |
+
<static> | +
+
+ ROT.VK_SUBTRACT
+
+ - on the numeric keypad.
+ |
+
<static> | +
+
+ ROT.VK_T
+
+
+ |
+
<static> | +
+
+ ROT.VK_TAB
+
+ Tab key.
+ |
+
<static> | +
+
+ ROT.VK_TILDE
+
+ Tilde (~) key.
+ |
+
<static> | +
+
+ ROT.VK_U
+
+
+ |
+
<static> | +
+
+ ROT.VK_UNDERSCORE
+
+ Underscore (_) key.
+ |
+
<static> | +
+
+ ROT.VK_UP
+
+ Up arrow.
+ |
+
<static> | +
+
+ ROT.VK_V
+
+
+ |
+
<static> | +
+
+ ROT.VK_W
+
+
+ |
+
<static> | +
+
+ ROT.VK_WIN
+
+ Windows logo key on Windows.
+ |
+
<static> | +
+
+ ROT.VK_X
+
+
+ |
+
<static> | +
+
+ ROT.VK_Y
+
+
+ |
+
<static> | +
+
+ ROT.VK_Z
+
+
+ |
+
Method Attributes | +Method Name and Description | +
---|---|
<static> | +
+ ROT.isSupported()
+
+
+ |
+
+ + + + + + +
+ + + + + + + + + + + +Method Attributes | +Method Name and Description | +
---|---|
+ |
+ capitalize()
+
+
+ |
+
<static> | +
+ String.format(template, argv)
+
+ Format a string in a flexible way.
+ |
+
+ |
+ format()
+
+ Convenience shortcut to String.format(this)
+ |
+
+ |
+ lpad(character, count)
+
+ Left pad
+ |
+
+ |
+ rpad(character, count)
+
+ Right pad
+ |
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + ++ rot.js: ROguelike Toolkit in JavaScript ############### +##### #.............# +#...# #.............# +#...# - Github #.............# +#.?.# - Download ############################.............# +#...# - Interactive manual #======.....+............../.............# +#+### - Autogenerated documentation #====.......##########.#####.............# +#.# - Tests #===........# #.# ####/########## +#.# - Tutorial ############# #.# #.# +#.# #.# #.# +#.# #.# #.# +#.# ########################################################.# #.####### +#.# #$$$.........+...........................................# #......^# +#.# #............############################################# ######### +#.##########............# +#........../............# rot.js is a set of JavaScript libraries, designed to help +#.####################### with a roguelike development in browser environment. +#.# +#.# +#.# rot.js is modelled after libtcod and offers the following features and concepts: +#.# +#.## - JS prototype enhancements ######### ######### +#..## - RNG, Map generation, FOV, Lighting #.......###########.......# +##..# - Pathfinding, turn scheduling #......./........./.......# + ##.# - Canvas-based ASCII display #########.......###########.......# +##..# #.......+.......# #.......# +#..## - Does not depend on any JS library #.############### #.......# +#.## - Open-source software, BSD License #.# ##########.......# +#.# #.# #......../.......# +#.# ######################################.################.########.......# +#.# #.......................................................# #.......# +#.# #.####################################################### #.......# +#.##############.# #...>...# +#!...............# #.......# +################## rot.js is (C) 2012-YYYY Ondrej Zara ######### ++ + + diff --git a/lib/rotjs-library/index.html b/lib/rotjs-library/index.html new file mode 100644 index 0000000000000000000000000000000000000000..cd98297120fae2dfdff9e5917424efee5419d616 --- /dev/null +++ b/lib/rotjs-library/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/rotjs-library/license.txt b/lib/rotjs-library/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..035c4f402a2693f505b9f5fbe8917eb275edc037 --- /dev/null +++ b/lib/rotjs-library/license.txt @@ -0,0 +1,25 @@ +Copyright (c) 2012-now(), Ondrej Zara +All rights reserved. + +Redistribution and use 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 Ondrej Zara nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +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 HOLDER 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/lib/rotjs-library/manual/index.html b/lib/rotjs-library/manual/index.html new file mode 100644 index 0000000000000000000000000000000000000000..48ce0a1d0ee5f72b346bbbcc7e041e1375aadb7e --- /dev/null +++ b/lib/rotjs-library/manual/index.html @@ -0,0 +1,58 @@ + + + + + + +
There is no dedicated Color
data type in rot.js
; passing strings around is sufficient in most cases (such as ROT.Display::draw
). However, if you need to perform color adjustments and computations, it is suitable to represent them as arrays of numbers. For this case, the ROT.Color
namespace offers a bunch of useful methods.
These methods accept a variable number of arguments. Methods whose names end with an underscore modify their first argument instead of returning a new array. Note that color values are not clamped to 0..255; this happens only when serializing to a string.
+ +The third argument specifies the interpolation factor (0 = first color, 1 = last color, 0.5 = default = halfway between them).
+ +You can create new colors by adjusting an exiting color by a (normally distributed) random value. Second argument is a set of standard deviations; note that ~95% of generated colors will fall within 2*stddev
.
ROT.Display
provides a canvas-based output that resembles a traditional TTY console.
The display is configured using these values:
+width
– horizontal size, in charactersheight
– vertical size, in charactersfontSize
– in pixels, default 15fontFamily
– string, default "monospace"fps
– int, target frames-per-second rate, default 25fg
– default foreground color; valid CSS color stringbg
– default background color; valid CSS color stringspacing
– spacing adjustment coefficient; 1 = normal, <1 tighter, >1 looserlayout
– what layouting algorithm shall be used; "rect" or "hex"You can configure the display by passing a configuration object to the constructor; alternatively, all options can be changed at runtime using the setOptions
method.
Colors can be changed using a trivial syntax, %c{ foreground }
and %b{ background }
. Empty color name switches to default.
Client-side JavaScript is non-blocking: all long-running operations are asynchronous. The ROT.Engine
loop is well suited for orchestrating the possibly-async coordination of various game actors.
To control a game loop, you add individual entities (called actors) to the engine. Every entity must implement the getSpeed()
method (since it is fed to the built-in scheduler and the act()
method. Once the engine is started, it correctly calls the act()
method on proper actors. It is possible to recursively stop (lock) the engine, should some operation (such as displaying a dialog or waiting for user input) block the execution. Once all lock levels are unlocked, the engine continues its execution.
The String.format
function is used to perform complex replacements within string templates. This functionality is also available in String.prototype
for your convenience:
It is possible to alter and enrich the behavior of this function by adding mappings to the String.format.map
object. Keys correspond to individual formatting specifiers; values are method names to be called. The default value of String.format.map
is {s:"toString"}
.
Finally, using formatting specifier with an upper-case letter will result in a capitalized replacement. Let's show a more convoluted example:
+ +It is possible to pass additional arguments to the formatting function, using the {,} notation.
+ +FOV algorithms return a set coordinates, visible from a starting place. Computing these works in the same fashion +as Map generators do: using a user-supplied callback function. This time, however, user has to supply two callbacks:
+ +compute
method, which receives FOV data.Input callback is called by the FOV algorithm to retrieve visibility information for a given coordinate pair. This callback must return true
(light passes)
+or false
(light does nto pass). Output callback is called with these arguments: x
, y
, r
and visibility
:
+the meaning is that "the place at [x,y] is visible with a distance of r". The last argument specifies the amount of visibility (0..1).
FOV computation is initiated by calling the compute
method with the following arguments:
x
y
r
– maximum visibility radiuscallback
– output callback functionFor now, there is only one FOV algorithm available: the Precise Shadowcasting.
+ +Hexagonal cell layout is supported in several parts of the toolkit, most notably in Console display, Cellular generator, FOV and Pathfinding. This page explains how to uses hexes with rot.js.
+ +While hexagonal cells provide several advantages over the traditional square/rectangular topologies, there is one big complication associated with their usage: there is no canonical way to index individual hexes. A hexagonal indexing comparison document is available for reference; rot.js is using the third variant, called double width. + +
There is a very trivial trick to display a rudimentary hexagonal layout: skip even/odd cells in odd/even rows. No special adjustments are necessary. The result will look good as long as the font aspect ratio is close to 1:√3
– which is the case for most monospaced fonts.
For more advanced hexagonal stuff, switch the display to "hex" layout. This has the following advantages:
+Pass the topology:6
option to the ROT.Map.Cellular
constructor to operate in hexagonal mode.
All pathfinding algorithms accept the topology:6
option as well.
Precise Shadowcasting works in hexagonal topology as well.
+ ++ This page summarizes various types of indexing hexagonal cells. Features examined: storage (in 2D array), neighbors, distance, straight lines. +
+ +Horizontal lines have constant "y" coordinate. "x" coordinate increases "down & right".
+ +sign(dx) == sign(dy) ? max(|dx|, |dy|) : |dx|+|dy|
(−1,0); (1,0); (−1,−1); (1,−1); (−1,1); (1,1)
(x ± n, y); (x ± n, y ± n); (x ∓ n, y ± n)
Horizontal lines have constant "y" coordinate. "x" coordinate increases "right". Odd lines are shifted to the right (half a cell).
+ +max(|dy|, |dx| + floor(|dy|/2) + penalty); penalty = ( (even(y1) && odd(y2) && (x1 < x2)) || (even(y2) && odd(y1) && (x2 < x1)) ) ? 1 : 0
(−1,0); (1,0); (−1,−1); (0,−1); (−1,1); (0,1)
, odd lines (−1,0); (1,0); (0,−1); (1,−1); (0,1); (1,1)
(x ± n, y); (x ± n/2, y ± n); (x ± n/2, y ± n)
, even and odd lines use different roundingHorizontal lines have constant "y" coordinate. "x" coordinate increases "right" by two. Even lines have even "x" values; odd lines have odd "x" values.
+ +|dy| + max(0, (|dx|−|dy|)/2)
(−2,0); (2,0); (−1,−1); (1,1); (−1,1); (1,−1)
(x ± 2n, y); (x ± n, y ± n); (x ∓ n, y ± n)
Horizontal lines have constant "y" coordinate. Diagonal lines have constant "x" and "z" coordinates. Neighboring cells differ by 1 in two coordinates.
+ +max(|dx|,|dy|,|dz|)
(1,0,−1); (−1,0,1); (0,1,−1); (0,−1,1); (1,−1,0); (−1,1,0)
(x ± n, y, z ∓ n); (x ± n, y ∓ n, z); (x, y ± n, z ∓ n)
rot.js was designed to provide help with traditional chores of roguelike programming. It does not use or depend on any other JS framework or library. It is an Open Source Software released under the BSD License.
+ +Just download the rot.js file and include it in your page. You can then start using the functions and objects in the ROT
namespace.
This manual is interactive: click on any example to modify its source and re-run it by clicking elsewhere. Use the navigation menu to the left to access other chapters of this manual.
+
+Note: Examples in this manual use the SHOW
function, which is not a part of rot.js. This helper function is available only to interactive examples.
rot.js works in all recent versions of reasonably modern browsers. More specifically, those who support the HTML5 <canvas>
element:
+Firefox, Chrome, Safari, Opera, Internet Explorer 9. You can check if the browser is supported:
rot.js adds several new methods to JavaScript primordial objects: Array
, String
, Number
, Date
, Object
and Function
. Some of these are ECMAScript 5
+polyfills, some are purely syntactic sugar.
A more verbose explanation about how String.format
works is available on a dedicated string formatting page.
+
+
The built-in modulus operator (%) yields negative results for negative arguments. Number.prototype.mod
is guaranteed to return a positive value.
Object.create
is a standardized way to create a new object with a hidden prototype link to other given object.
Taking care of user input boils down to listening for proper keyboard events (keydown, keypress, keyup) and processing them. rot.js
does not offer any support methods or objects; instead, it defines a large set of ROT.VK_*
constants to distinguish between pressed keys. For a complete listing, please check out the generated docs.
There are also several general keyboard-related JavaScript guidelines:
+ +keyCode
property and compare with ROT.VK_*
constants.charCode
property; String.fromCharCode(x)
will create the corresponding character.A very simple keyboard handler is shown below:
+ +Lighting module is one of the most convoluted parts of rot.js
: it is a mix of various concepts introduced in simpler components. ROT.Lighting
is used to compute how multiple light sources mix and reflect in a cellular map (using a highly simplified radiosity-like algorithm).
To compute a lighting, you need the following:
+ROT.FOV
instance, which is used to compute the areas lit by light sources;lightingCallback
which notifies you about the resulting light for a given coordinates;If you decide to use a two-pass lighting (more light, more realistic light spread, more computation time), you also need:
+reflectivityCallback
which is used to return how much individual map cells reflect incoming light. Please note that wall cells should not reflect any light for the purpose of lighting computation.Finally, the ROT.Lighting
function accepts an optional configuration object as its second argument. This object may contain:
range
– maximum range for the most powerful light sourcepasses
– number of computation passes (1: no reflectivity used, 2: reflectivity used)emissionThreshold
– minimal amount of light at a cell to be re-emited (only for passes>1)There are several map generator tools in rot.js
; they all share the same usage pattern. You first need to instantialize the proper ROT.Map.*
+object and pass size (plus any additional relevant options) to its constructor; you can then call the main create
method (repeatedly, if you want).
This toolkit does not force usage of any particular memory structure to store the map data. Instead, the map creation process is callback-based:
+you supply a callback function as an argument to the create
method;
+the map creator will call your function repeatedly and pass it the generated map information. Your callback should accept these arguments:
x
– horizontal coordinate of a map's celly
– vertical coordinate of a map's cellvalue
– integer value corresponding to the type of generated cell (different values might be supplied by different map generators)These examples use the simplest map generator, Arena
: a fully dug room.
We can use ROT.Display
to show the generated map (although it would make more sense to store the generated data as well). For debugging purposes,
+ROT.Display
provides a built-in convenience method DEBUG
, which works as a universal debugging callback.
Read more about various types of generators: Maze, Cellular and Dungeon.
diff --git a/lib/rotjs-library/manual/pages/map/cellular.html b/lib/rotjs-library/manual/pages/map/cellular.html new file mode 100644 index 0000000000000000000000000000000000000000..4c24ac9e04e276c0de68c56915bfa9fbc91db054 --- /dev/null +++ b/lib/rotjs-library/manual/pages/map/cellular.html @@ -0,0 +1,62 @@ +Interesting cave systems can be created using ROT.Map.Cellular
, a generator which simulates a cellular automaton. Using this generator is a bit more complex,
+because it offers richer features and is more configurable.
Apart from the traditional width and height arguments, ROT.Map.Cellular
accepts also a configuration object with the following optional keys:
born
– array of neighbor counts; when an empty cell has this number of neighbors, a new cell is bornsurvive
– array of neighbor counts; when an existing cell has this number of neighbors, it will survive into next iterationtopology
– how are neighbors defined: a cell can have four, six or eight neighbors. Six neighbors correspond to the "hex" layouting algorithm
+ of ROT.Display.It is also possible to initialize/set values for the first generation of cells. Two methods are provided:
+set(x, y, value)
to directly set a cellrandomize(probability)
set all cells to "alive" with a given probability (0 = no cells, 1 = all cells)It is possible (and desirable) to call the create
method repeatedly: every call will create a new generation. There is no need to specify a callback,
+if you only want to advance into next generation, without actually retrieving the current map data. By default, the born and survive options
+are set according to this Roguebasin article.
ROT.Map.Cellular
uses the following callback values:
0
: no cell1
: alive cellThis family of map generators produces corridors and rooms. Room information can be retrieved after the map has been created by calling getRooms()
; corridor information can be retrieved via getCorridors()
:
Random dungeon generator using human-like digging patterns; based on Mike Anderson's ideas from the "Tyrant" algo, mentioned at +Roguebasin. +Third constructor argument is a configuration object; allowed options:
+roomWidth
– [min, max] room sizeroomHeight
– [min, max] room sizecorridorLength
– [min, max] corridor lengthdugPercentage
– algorithm stops after this fraction of map area has been dug out; default = 0.2timeLimit
– algorithm stops after this amount of milliseconds has passedGenerates a set of rooms; tries to connect them afterwards. Third constructor argument is a configuration object; allowed options:
+roomWidth
– [min, max] room sizeroomHeight
– [min, max] room sizeroomDugPercentage
– algorithm stops after this fraction of map area has been filled with rooms; default = 0.2timeLimit
– algorithm stops after this amount of milliseconds has passedThis family of algorithms uses the following callback values:
+0
: empty space1
: wallBased on a Recursive division method.
+ +Cool mazes with a configurable regularity can be created using this algorithm, +taken from a Rogue Basin wiki. Regularity is an integer value, specified as a third argument; 0 = most random.
+ +For a full explanation of this wonderful Eller's algorithm, please see +http://homepages.cwi.nl/~tromp/maze.html. +Not only it generates a Perfect maze (every two cells are connected by exactly one path), +but it only requires 2*N memory to generate a maze of N*N size!
+ +The ROT.Path
namespace provides utils for pathfinding: retrieving a set of coordinates represeting shortest route between two points. All pathfinding algorithms share the same usage paradigm:
targetX
, targetY
and inputCallback
to the constructor
+ topology
(values 4/6/8)compute
method with three arguments: sourceX
, sourceY
and outputCallback
The pathfinder will periodically call your outputCallback
; once for every cell in the path from [sourceX, sourceY]
to [targetX, targetY]
.
+If no such path exists, outputCallback
will never be called.
NOTE: you can call the compute
method multiple times
+(which is especially useful, performance-wise, when using ROT.Path.Dijkstra
),
+but you must make sure that the passability information of the map never changes once
+the pathfinder is created.
Simplified version of Dijkstra's algorithm: all edges have a length of 1.
+ +Simplified version of A* algorithm: all edges have a length of 1.
+ +ROT.Display.Rect.cache = true
. This enables rendering into tiny cacheable canvases, but will improve performance only if you do not use too many glyph/color/bgcolor combinations. Your mileage may vary.While the built-in Math.random()
function provides suitable results for game development purposes, it has its own weaknesses.
+Most notably, it is not possible to seed the generator in order to reproduce a deterministic sequence of values. This is where ROT.RNG
object comes to play.
Note: We use the excellent Alea algorithm, developed by Johannes Baagøe. For more information about the code, please see +his article on RNGs in JavaScript. Alea is distributed under the MIT License.
+ +Three main modes of operation are available:
+ +ROT.RNG.getUniform()
– random number [0..1) with uniform distribution (similar to Math.random()
)ROT.RNG.getNormal(mean, stddev)
– random number with normal distribution, parametrized by a mean value and standard deviationROT.RNG.getPercentage()
– random integer 1..100RNG's internal state can be retrieved and set to produce identical results.
+ +The RNG can be seeded by a given number. Seeding initializes RNG's internal state. +Retrieving the current seed is not very useful, but might come handy if you want to reproduce a behavior resulting from a random seed.
+ +In turn-based games, actors (player, enemies, everything that moves or acts) often differ by their speed. However, since the game happens in turns,
+the speed is more accurately described as a frequency in which turns happen for a particular actor. ROT.Scheduler
is a simple tool designed to
+simplify the task of selecting proper actor for a turn, based on the abstract speed of all actors.
First, you need to fill the scheduler instance with actors. There are very few requirements on actors: they need to be JS objects with method getSpeed()
,
+which returns a number. An actor with speed=100 will get twice as many turns as actor with speed=50.
+You can then repeatedly call the scheduler's next()
method: it returns the actor whose turn should start.
ROT.StringGenerator
is an implementation of a high order Markov process. This machine learning technique needs to be trained first (with a set of typical strings); after training, it generates strings similar to those used as a training set.
Read more about the implementation (Dirichlet prior, simplified Katz back-off) in this RogueBasin article. The constructor accepts an optional configuration object with the following keys:
+ +words
– use word mode? (default: false, use letters instead)order
– how many preceding characters are used to generate next characterprior
– default probability weight for all (unexpected) events (Dirichlet prior)There are only two important public methods: observe()
for training and generate()
for producing results. In the following example, we will use all standard Java 7 class names as a training set; let's see what new Java stuff our generator produces.
" + code + ""; + + while (tmp.firstChild.firstChild) { node.appendChild(tmp.firstChild.firstChild); } + tmp.parentNode.removeChild(tmp); + } else { + node.innerHTML = code; + } + }, + + _append: function(syntax) { + var s = document.createElement("script"); + s.src = this.base + "syntax-"+syntax+".js"; + + var thisp = this; + var loaded = function() { thisp._loaded(); } + + if (s.addEventListener) { + s.addEventListener("load", loaded, false); + } else { + s.attachEvent("onreadystatechange", loaded); + } + + document.body.insertBefore(s, document.body.firstChild); + }, + + _loaded: function() { + for (var syntax in this._registry) { + if (!(syntax in this._todo)) { continue; } + while (this._todo[syntax].length) { + this._process(this._todo[syntax].shift(), syntax); + } + delete this._todo[syntax]; + } + } +}; + +Syntax.init(); + diff --git a/lib/rotjs-library/push.sh b/lib/rotjs-library/push.sh new file mode 100644 index 0000000000000000000000000000000000000000..cd2116ab07700874a9da60521ce44e7b5f15636f --- /dev/null +++ b/lib/rotjs-library/push.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +hg bookmark -f master +hg bookmark -f gh-pages +hg push github +hg push -B master -B gh-pages diff --git a/lib/rotjs-library/rot.js b/lib/rotjs-library/rot.js new file mode 100644 index 0000000000000000000000000000000000000000..c4226b9e019dcf617ae11b87abb4442260d0805f --- /dev/null +++ b/lib/rotjs-library/rot.js @@ -0,0 +1,4092 @@ +/* + This is rot.js, the ROguelike Toolkit in JavaScript. + Version 0.4~dev, generated on Fri Mar 8 11:07:22 CET 2013. +*/ + +/** + * @namespace Top-level ROT namespace + */ +var ROT = { + /** + * @returns {bool} Is rot.js supported by this browser? + */ + isSupported: function() { + return !!(document.createElement("canvas").getContext && Function.prototype.bind); + }, + + /** Default with for display and map generators */ + DEFAULT_WIDTH: 80, + /** Default height for display and map generators */ + DEFAULT_HEIGHT: 25, + + /** Directional constants. Ordering is important! */ + DIRS: { + "4": [ + [ 0, -1], + [ 1, 0], + [ 0, 1], + [-1, 0] + ], + "8": [ + [ 0, -1], + [ 1, -1], + [ 1, 0], + [ 1, 1], + [ 0, 1], + [-1, 1], + [-1, 0], + [-1, -1] + ], + "6": [ + [-1, -1], + [ 1, -1], + [ 2, 0], + [ 1, 1], + [-1, 1], + [-2, 0] + ] + }, + + /** Cancel key. */ + VK_CANCEL: 3, + /** Help key. */ + VK_HELP: 6, + /** Backspace key. */ + VK_BACK_SPACE: 8, + /** Tab key. */ + VK_TAB: 9, + /** 5 key on Numpad when NumLock is unlocked. Or on Mac, clear key which is positioned at NumLock key. */ + VK_CLEAR: 12, + /** Return/enter key on the main keyboard. */ + VK_RETURN: 13, + /** Reserved, but not used. */ + VK_ENTER: 14, + /** Shift key. */ + VK_SHIFT: 16, + /** Control key. */ + VK_CONTROL: 17, + /** Alt (Option on Mac) key. */ + VK_ALT: 18, + /** Pause key. */ + VK_PAUSE: 19, + /** Caps lock. */ + VK_CAPS_LOCK: 20, + /** Escape key. */ + VK_ESCAPE: 27, + /** Space bar. */ + VK_SPACE: 32, + /** Page Up key. */ + VK_PAGE_UP: 33, + /** Page Down key. */ + VK_PAGE_DOWN: 34, + /** End key. */ + VK_END: 35, + /** Home key. */ + VK_HOME: 36, + /** Left arrow. */ + VK_LEFT: 37, + /** Up arrow. */ + VK_UP: 38, + /** Right arrow. */ + VK_RIGHT: 39, + /** Down arrow. */ + VK_DOWN: 40, + /** Print Screen key. */ + VK_PRINTSCREEN: 44, + /** Ins(ert) key. */ + VK_INSERT: 45, + /** Del(ete) key. */ + VK_DELETE: 46, + /***/ + VK_0: 48, + /***/ + VK_1: 49, + /***/ + VK_2: 50, + /***/ + VK_3: 51, + /***/ + VK_4: 52, + /***/ + VK_5: 53, + /***/ + VK_6: 54, + /***/ + VK_7: 55, + /***/ + VK_8: 56, + /***/ + VK_9: 57, + /** Colon (:) key. Requires Gecko 15.0 */ + VK_COLON: 58, + /** Semicolon (;) key. */ + VK_SEMICOLON: 59, + /** Less-than (<) key. Requires Gecko 15.0 */ + VK_LESS_THAN: 60, + /** Equals (=) key. */ + VK_EQUALS: 61, + /** Greater-than (>) key. Requires Gecko 15.0 */ + VK_GREATER_THAN: 62, + /** Question mark (?) key. Requires Gecko 15.0 */ + VK_QUESTION_MARK: 63, + /** Atmark (@) key. Requires Gecko 15.0 */ + VK_AT: 64, + /***/ + VK_A: 65, + /***/ + VK_B: 66, + /***/ + VK_C: 67, + /***/ + VK_D: 68, + /***/ + VK_E: 69, + /***/ + VK_F: 70, + /***/ + VK_G: 71, + /***/ + VK_H: 72, + /***/ + VK_I: 73, + /***/ + VK_J: 74, + /***/ + VK_K: 75, + /***/ + VK_L: 76, + /***/ + VK_M: 77, + /***/ + VK_N: 78, + /***/ + VK_O: 79, + /***/ + VK_P: 80, + /***/ + VK_Q: 81, + /***/ + VK_R: 82, + /***/ + VK_S: 83, + /***/ + VK_T: 84, + /***/ + VK_U: 85, + /***/ + VK_V: 86, + /***/ + VK_W: 87, + /***/ + VK_X: 88, + /***/ + VK_Y: 89, + /***/ + VK_Z: 90, + /***/ + VK_CONTEXT_MENU: 93, + /** 0 on the numeric keypad. */ + VK_NUMPAD0: 96, + /** 1 on the numeric keypad. */ + VK_NUMPAD1: 97, + /** 2 on the numeric keypad. */ + VK_NUMPAD2: 98, + /** 3 on the numeric keypad. */ + VK_NUMPAD3: 99, + /** 4 on the numeric keypad. */ + VK_NUMPAD4: 100, + /** 5 on the numeric keypad. */ + VK_NUMPAD5: 101, + /** 6 on the numeric keypad. */ + VK_NUMPAD6: 102, + /** 7 on the numeric keypad. */ + VK_NUMPAD7: 103, + /** 8 on the numeric keypad. */ + VK_NUMPAD8: 104, + /** 9 on the numeric keypad. */ + VK_NUMPAD9: 105, + /** * on the numeric keypad. */ + VK_MULTIPLY: 106, + /** + on the numeric keypad. */ + VK_ADD: 107, + /***/ + VK_SEPARATOR: 108, + /** - on the numeric keypad. */ + VK_SUBTRACT: 109, + /** Decimal point on the numeric keypad. */ + VK_DECIMAL: 110, + /** / on the numeric keypad. */ + VK_DIVIDE: 111, + /** F1 key. */ + VK_F1: 112, + /** F2 key. */ + VK_F2: 113, + /** F3 key. */ + VK_F3: 114, + /** F4 key. */ + VK_F4: 115, + /** F5 key. */ + VK_F5: 116, + /** F6 key. */ + VK_F6: 117, + /** F7 key. */ + VK_F7: 118, + /** F8 key. */ + VK_F8: 119, + /** F9 key. */ + VK_F9: 120, + /** F10 key. */ + VK_F10: 121, + /** F11 key. */ + VK_F11: 122, + /** F12 key. */ + VK_F12: 123, + /** F13 key. */ + VK_F13: 124, + /** F14 key. */ + VK_F14: 125, + /** F15 key. */ + VK_F15: 126, + /** F16 key. */ + VK_F16: 127, + /** F17 key. */ + VK_F17: 128, + /** F18 key. */ + VK_F18: 129, + /** F19 key. */ + VK_F19: 130, + /** F20 key. */ + VK_F20: 131, + /** F21 key. */ + VK_F21: 132, + /** F22 key. */ + VK_F22: 133, + /** F23 key. */ + VK_F23: 134, + /** F24 key. */ + VK_F24: 135, + /** Num Lock key. */ + VK_NUM_LOCK: 144, + /** Scroll Lock key. */ + VK_SCROLL_LOCK: 145, + /** Circumflex (^) key. Requires Gecko 15.0 */ + VK_CIRCUMFLEX: 160, + /** Exclamation (!) key. Requires Gecko 15.0 */ + VK_EXCLAMATION: 161, + /** Double quote () key. Requires Gecko 15.0 */ + VK_DOUBLE_QUOTE: 162, + /** Hash (#) key. Requires Gecko 15.0 */ + VK_HASH: 163, + /** Dollar sign ($) key. Requires Gecko 15.0 */ + VK_DOLLAR: 164, + /** Percent (%) key. Requires Gecko 15.0 */ + VK_PERCENT: 165, + /** Ampersand (&) key. Requires Gecko 15.0 */ + VK_AMPERSAND: 166, + /** Underscore (_) key. Requires Gecko 15.0 */ + VK_UNDERSCORE: 167, + /** Open parenthesis (() key. Requires Gecko 15.0 */ + VK_OPEN_PAREN: 168, + /** Close parenthesis ()) key. Requires Gecko 15.0 */ + VK_CLOSE_PAREN: 169, + /* Asterisk (*) key. Requires Gecko 15.0 */ + VK_ASTERISK: 170, + /** Plus (+) key. Requires Gecko 15.0 */ + VK_PLUS: 171, + /** Pipe (|) key. Requires Gecko 15.0 */ + VK_PIPE: 172, + /** Hyphen-US/docs/Minus (-) key. Requires Gecko 15.0 */ + VK_HYPHEN_MINUS: 173, + /** Open curly bracket ({) key. Requires Gecko 15.0 */ + VK_OPEN_CURLY_BRACKET: 174, + /** Close curly bracket (}) key. Requires Gecko 15.0 */ + VK_CLOSE_CURLY_BRACKET: 175, + /** Tilde (~) key. Requires Gecko 15.0 */ + VK_TILDE: 176, + /** Comma (,) key. */ + VK_COMMA: 188, + /** Period (.) key. */ + VK_PERIOD: 190, + /** Slash (/) key. */ + VK_SLASH: 191, + /** Back tick (`) key. */ + VK_BACK_QUOTE: 192, + /** Open square bracket ([) key. */ + VK_OPEN_BRACKET: 219, + /** Back slash (\) key. */ + VK_BACK_SLASH: 220, + /** Close square bracket (]) key. */ + VK_CLOSE_BRACKET: 221, + /** Quote (''') key. */ + VK_QUOTE: 222, + /** Meta key on Linux, Command key on Mac. */ + VK_META: 224, + /** AltGr key on Linux. Requires Gecko 15.0 */ + VK_ALTGR: 225, + /** Windows logo key on Windows. Or Super or Hyper key on Linux. Requires Gecko 15.0 */ + VK_WIN: 91, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANA: 21, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANGUL: 21, + /** 英数 key on Japanese Mac keyboard. Requires Gecko 15.0 */ + VK_EISU: 22, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_JUNJA: 23, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_FINAL: 24, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANJA: 25, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANJI: 25, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_CONVERT: 28, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_NONCONVERT: 29, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_ACCEPT: 30, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_MODECHANGE: 31, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SELECT: 41, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_PRINT: 42, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_EXECUTE: 43, + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SLEEP: 95 +}; +/** + * @namespace + * Contains text tokenization and breaking routines + */ +ROT.Text = { + RE_COLORS: /%([bc]){([^}]*)}/g, + + /* token types */ + TYPE_TEXT: 0, + TYPE_NEWLINE: 1, + TYPE_FG: 2, + TYPE_BG: 3, + + /** + * Measure size of a resulting text block + */ + measure: function(str, maxWidth) { + var result = {width:0, height:1}; + var tokens = this.tokenize(str, maxWidth); + var lineWidth = 0; + + for (var i=0;i
jasmine.undefined
instead of undefined
, since undefined
is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to jasmine.log
in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @returns a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a disabled Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&')
+ .replace(//g, '>');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ if (this.actual.callCount === 0) {
+ // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+ ];
+ } else {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+ ];
+ }
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ var multiplier = Math.pow(10, precision);
+ var actual = Math.round(this.actual * multiplier);
+ expected = Math.round(expected * multiplier);
+ return expected == actual;
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} expected
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return 'jasmine.log
in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this));
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 2,
+ "build": 0,
+ "revision": 1337005947
+};
diff --git a/lib/rotjs-library/tests/reporters/jasmine.console_reporter.js b/lib/rotjs-library/tests/reporters/jasmine.console_reporter.js
new file mode 100644
index 0000000000000000000000000000000000000000..7995bd09cd01791c2f83b034ab06bbba72c8ffcf
--- /dev/null
+++ b/lib/rotjs-library/tests/reporters/jasmine.console_reporter.js
@@ -0,0 +1,142 @@
+(function() {
+ if (! jasmine) {
+ throw new Exception("jasmine library does not exist in global namespace!");
+ }
+
+ /**
+ * Basic reporter that outputs spec results to the browser console.
+ * Useful if you need to test an html page and don't want the TrivialReporter
+ * markup mucking things up.
+ *
+ * Usage:
+ *
+ * jasmine.getEnv().addReporter(new jasmine.ConsoleReporter());
+ * jasmine.getEnv().execute();
+ */
+ var ConsoleReporter = function() {
+ this.started = false;
+ this.finished = false;
+ };
+
+ ConsoleReporter.prototype = {
+ reportRunnerResults: function(runner) {
+ if (this.hasGroupedConsole()) {
+ var suites = runner.suites();
+ startGroup(runner.results(), 'tests');
+ for (var i=0; i